Files
zeekay f77da86cda Initial luxfi/license — Ed25519-signed offline license tokens for commercial Lux features.
- Stdlib-only deterministic binary token format (no JWT / CBOR dep).
- Go API: VerifyToken, LoadFromEnv, HasFeature, HasFeatureOrDie.
- Stable C ABI + C++17 RAII wrapper for non-Go commercial binaries (luxcpp/cevm).
- cmd/lux-license: keygen / issue / inspect / verify.
- Embedded development key; warns once at runtime until production key swap.
- 22 Go tests + 1 cgo round-trip test, all passing.
2026-05-15 17:08:32 -07:00

86 lines
3.2 KiB
Go

// Copyright (C) 2020-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package license
import (
"bytes"
"crypto/ed25519"
"fmt"
"os"
"sync"
)
// IssuerPublicKey is the 32-byte Ed25519 public key whose private counterpart
// signs all production Lux commercial license tokens.
//
// REPLACE WITH PRODUCTION KEY BEFORE FIRST CUSTOMER ISSUANCE.
//
// The current value is the *development* key derived deterministically from
// the seed "lux-license-development-seed-001" (see TestDevKeyMatchesSeed in
// pubkey_test.go). Tokens signed with the matching development private key
// will verify against builds compiled with this constant. When a real customer
// token must be issued:
//
// 1. Generate a fresh Ed25519 keypair on an air-gapped machine, or inside
// the Lux KMS / HashiCorp Vault transit engine. (Never via the dev seed.)
// 2. Store the *private* key inside that vault. Never commit it.
// 3. Replace the bytes below with the corresponding 32-byte public key.
// 4. Tag a new release; downstream consumers re-build to pick up the rotated
// public key.
var IssuerPublicKey = ed25519.PublicKey{
0xd1, 0x1a, 0x95, 0xe3, 0xf1, 0x77, 0x89, 0x38,
0x6f, 0xc4, 0x4b, 0x34, 0xde, 0xf7, 0x0b, 0xdc,
0x16, 0xcf, 0xff, 0xcc, 0xc0, 0x37, 0xa2, 0x03,
0x59, 0xf5, 0xb1, 0xea, 0x1c, 0x36, 0x36, 0x73,
}
// devSeed is the 32-byte deterministic seed used to derive the development
// keypair embedded above. Never use this seed in production: anyone with this
// repository can mint tokens that verify against IssuerPublicKey until the
// production key is swapped in.
const devSeed = "lux-license-development-seed-001"
// DevPublicKey returns the development public key derived from devSeed. Equal
// to IssuerPublicKey until the production key is installed.
func DevPublicKey() ed25519.PublicKey {
priv := ed25519.NewKeyFromSeed([]byte(devSeed))
return priv.Public().(ed25519.PublicKey)
}
// DevPrivateKey returns the development private key derived from devSeed. Used
// by tests and by `lux-license issue --dev`.
func DevPrivateKey() ed25519.PrivateKey {
return ed25519.NewKeyFromSeed([]byte(devSeed))
}
// IsUsingDevKey reports whether the embedded IssuerPublicKey is still the
// development key. Production builds should swap the key before shipping.
func IsUsingDevKey() bool {
return bytes.Equal(IssuerPublicKey, DevPublicKey())
}
// EnvSuppressDevKeyWarning silences the once-per-process warning emitted at
// init when IssuerPublicKey is still the development key. Set this only in
// internal Lux test environments.
const EnvSuppressDevKeyWarning = "LUX_LICENSE_SUPPRESS_DEV_WARNING"
var devKeyWarnOnce sync.Once
// warnIfDevKey writes a single stderr line per process if the binary is using
// the development public key. Called from VerifyToken on the first verify, so
// silent (no-op) builds that never check a license never emit anything.
func warnIfDevKey() {
if !IsUsingDevKey() {
return
}
devKeyWarnOnce.Do(func() {
if os.Getenv(EnvSuppressDevKeyWarning) != "" {
return
}
fmt.Fprintln(os.Stderr,
"warning: luxfi/license is using the DEVELOPMENT public key. "+
"Production binaries must replace pubkey.go:IssuerPublicKey before issuing customer tokens.")
})
}