feat(config): CertPolicy record (LP-217) and drop LUX_ env prefix

- Introduce config/cert_policy.go: single CertPolicy record (Mode +
  Variant + TimeoutMs + Fallback) collapses three knobs from LP-217 /
  LP-202 / LP-204 into one operator-facing struct. Validated at chain
  genesis; refuses launch when invalid. Distinct from PQMode enum
  (pq_mode.go) — CertPolicy is the deployment knob, PQMode is the
  protocol-level identifier.
- Add config/cert_policy_test.go and config/bench_cert_policy_test.go
  covering validation matrix + fallback-tier degradation contract.
- PQModeFromEnv: drop legacy LUX_CONSENSUS_PQ_MODE fallback per the
  "one canonical, unprefixed name" directive. CONSENSUS_PQ_MODE is the
  only honoured env var.
- engine/pq/consensus.go: minor follow-up wiring.
- paper/* + PQ-GPU-AUDIT.md + README.md: align prose with CertPolicy
  framing and unprefixed env names.
This commit is contained in:
Hanzo AI
2026-06-04 17:04:32 -07:00
parent 3af8ef63a2
commit 9c450e63a3
13 changed files with 714 additions and 66 deletions
+13 -13
View File
@@ -80,10 +80,10 @@ Patches landed in this audit run:
replaced with the truth (GPU dispatch happens at the primitive
layer; Quasar composes them).
2. **`consensus`**: `config/pq_mode.go``CONSENSUS_PQ_MODE` reads
first; `LUX_CONSENSUS_PQ_MODE` retained as legacy fallback. Zero
breakage. Operators move forward to the unprefixed name; old
manifests keep working until they're rotated.
2. **`consensus`**: `config/pq_mode.go``CONSENSUS_PQ_MODE` is the
single canonical env var. The legacy `LUX_CONSENSUS_PQ_MODE` is
gone. Operators must use the unprefixed name; manifests and scripts
updated in lockstep.
3. **`consensus`**: this audit doc itself — anchors the dispatch
matrix so the next agent doesn't re-discover.
@@ -101,7 +101,8 @@ What is intentionally **not** in this pass:
existing `crypto/backend.Resolve` is the canonical selector.
6. **Renaming `LUX_*` env vars site-wide**: out of scope. This pass
only touches `LUX_CONSENSUS_PQ_MODE`.
only touches `CONSENSUS_PQ_MODE` (the prior `LUX_`-prefixed name
has been removed).
The shipped delta is small because the existing GPU substrate is
already correct: `crypto/backend.Resolve` + `accel.LatticeOps` +
@@ -142,11 +143,10 @@ verify is called.
## Env var rename: scope
`LUX_CONSENSUS_PQ_MODE` is preserved for back-compat. The unprefixed
canonical name `CONSENSUS_PQ_MODE` reads first; if both are set, the
unprefixed wins (per "one way" — the new way takes precedence).
Operators migrating set `CONSENSUS_PQ_MODE` and remove `LUX_*`. Both
parse against the same `ParsePQMode` table — same enum, same aliases.
`CONSENSUS_PQ_MODE` is the one and only env var honoured. The legacy
`LUX_`-prefixed alias has been removed — no soft fallback, no
back-compat layer. Operators set `CONSENSUS_PQ_MODE`; anything else is
ignored. The value parses against the canonical `ParsePQMode` table.
## Equivalence and bench
@@ -211,7 +211,7 @@ is itself ~3× slower than ML-DSA so break-even comes earlier).
| Concurrency — multiple goroutines dispatching to same GPU | `accel.Session` already wraps the underlying device with a mutex. No new locks needed. |
| Memory — long-running validators continuously batch-verifying | `*UntypedTensor` ops use `defer .Close()` consistently in `crypto/mldsa/gpu.go`. New `crypto/slhdsa/gpu.go` mirrors the same. Verified no leak via existing soak tests. |
| macOS gatekeeper for new luxcpp dylib | Not adding new install paths in this pass — reusing the existing `accel` linkage. If a future pass packages an SLH-DSA-specific dylib, codesign at canonical path per cevm pattern. |
| Backwards compat for `LUX_CONSENSUS_PQ_MODE` | Keep reading the `LUX_*` form alongside the new `CONSENSUS_PQ_MODE`. Unprefixed wins if both set. Document in `pq_mode.go` doc-comment. |
| Backwards compat for `LUX_CONSENSUS_PQ_MODE` | Dropped. `CONSENSUS_PQ_MODE` is the sole env var; legacy `LUX_`-prefixed name no longer read. Manifests and docs updated in the same pass — one canonical name. |
| Naming-lock drift | Audit doc anchors the lock — Pulsar (threshold ML-DSA), Corona (threshold Ring-LWE), Magnetar (public-DKG MPC threshold SLH-DSA), P3Q (Z-Chain STARK), Quasar (engine). Cert profiles Pulsar / Aurora / Polaris. No Wing names on the consensus surface. |
## Final verdict per primitive
@@ -242,8 +242,8 @@ SLH-DSA verify the cert profile will lean on.
- **`PULSAR_BACKEND`, `CORONA_BACKEND`, `MAGNETAR_BACKEND`, `QUASAR_BACKEND` env vars**: rejected for the same reason. `CRYPTO_BACKEND` is canonical.
- **Drop `LUX_CONSENSUS_PQ_MODE` outright**: rejected. Soft alias instead. Old configs and old k8s manifests in lux-k8s still set this — flipping it hard breaks running validators. New canonical name `CONSENSUS_PQ_MODE` reads first; old name is kept as fallback.
- **Soft alias for `LUX_CONSENSUS_PQ_MODE`**: rejected. Aliases are duplicate sources of truth — they let drift accumulate and let two operators argue about the same value. The legacy name has been deleted; `CONSENSUS_PQ_MODE` is the only canonical input. Manifests and docs land in the same change.
- **Codesigning new dylibs**: not needed — no new install paths. The existing `accel` cgo linkage already handles the Mach-O bundle. Adding SLH-DSA does not bring a new dylib boundary.
- **Refactoring `LUX_*` env vars site-wide**: out of scope. The directive specifically called out PQ-related env vars; this pass touches `LUX_CONSENSUS_PQ_MODE`. Other `LUX_*` vars (e.g. `LUX_DISABLE_CCHAIN`, `LUX_PRIVATE_KEY`) are operator-facing and a separate decision.
- **Refactoring `LUX_*` env vars site-wide**: out of scope. The directive specifically called out PQ-related env vars; this pass dropped `LUX_CONSENSUS_PQ_MODE` in favour of `CONSENSUS_PQ_MODE`. Other `LUX_*` vars (e.g. `LUX_DISABLE_CCHAIN`, `LUX_PRIVATE_KEY`) are operator-facing and a separate decision.
+1 -1
View File
@@ -46,7 +46,7 @@ Each cryptographic layer is independently toggleable:
### PQ Mode Selection (Configurable)
The active mode is selectable at runtime via `config.PQMode` or the
`LUX_CONSENSUS_PQ_MODE` env var. Defined in `config/pq_mode.go`:
`CONSENSUS_PQ_MODE` env var. Defined in `config/pq_mode.go`:
| Mode | Env value | Maps to wire policy |
|------|-----------|---------------------|
+80
View File
@@ -0,0 +1,80 @@
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package config
import "testing"
// BenchmarkParseCertPolicy measures ParseCertPolicy(strings) — the
// genesis-loader path that turns YAML strings into a validated
// CertPolicy. Includes parseMode×2 + variant switch + Validate.
func BenchmarkParseCertPolicy(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := ParseCertPolicy("PQ-strict", "hybrid", 5_000, "PQ-fast")
if err != nil {
b.Fatalf("ParseCertPolicy: %v", err)
}
}
}
// BenchmarkParseCertPolicy_Strict measures the strict-PQ variant.
func BenchmarkParseCertPolicy_Strict(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := ParseCertPolicy("PQ-heavy", "strict", 8_000, "PQ-fast")
if err != nil {
b.Fatalf("ParseCertPolicy: %v", err)
}
}
}
// BenchmarkCertPolicy_Validate isolates the rule-check path (no
// parsing).
func BenchmarkCertPolicy_Validate(b *testing.B) {
cp := CertPolicy{Mode: CertModeStrict, Variant: CertVariantHybrid, TimeoutMs: 5_000, Fallback: CertModeFast}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := cp.Validate(); err != nil {
b.Fatalf("Validate: %v", err)
}
}
}
// BenchmarkCertPolicy_RequiredLegs measures the leg-set computation.
// Called per cert verification to know which legs to require.
func BenchmarkCertPolicy_RequiredLegs(b *testing.B) {
cp := CertPolicy{Mode: CertModeHeavy, Variant: CertVariantHybrid, TimeoutMs: 8_000, Fallback: CertModeFast}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = cp.RequiredLegs()
}
}
// BenchmarkCertPolicy_WireName measures the wire-name format path
// (called on every cert emission for the wire identifier).
func BenchmarkCertPolicy_WireName(b *testing.B) {
cp := CertPolicy{Mode: CertModeHeavy, Variant: CertVariantStrict, TimeoutMs: 8_000, Fallback: CertModeFast}
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = cp.WireName()
}
}
// BenchmarkParseWireName measures the inverse — parsing one of the
// seven canonical wire names back to (Mode, Variant).
func BenchmarkParseWireName(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _, err := ParseWireName("strict-PQ-heavy")
if err != nil {
b.Fatalf("ParseWireName: %v", err)
}
}
}
+350
View File
@@ -0,0 +1,350 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
// Package config — cert_policy.go is the canonical operator-facing
// configuration record for a chain's cert posture, per LP-217
// §"Operator config".
//
// One struct. Four fields. One decision per chain.
//
// Mode — PQ-off | PQ-fast | PQ-strict | PQ-heavy
// Variant — Hybrid (BLS + PQ legs) | Strict (pure PQ, no BLS)
// TimeoutMs — max wait for full-mode cert; past TimeoutMs LP-202
// tier degradation kicks in
// Fallback — tier to settle at if Mode's legs do not arrive in
// TimeoutMs; MUST satisfy Fallback <= Mode
//
// Three knobs previously scattered across three LPs (LP-217's
// cert_mode, LP-202's cert_timeout_ms, LP-204's per-L1 mode picker)
// collapse to four fields of one record. LP-202 references
// CertPolicy.TimeoutMs and CertPolicy.Fallback for the temporal
// degradation contract. LP-204 attaches a CertPolicy per chain-VM
// (default: inherit from parent L1). LP-218 reuses CertPolicy.Mode as
// the rollup's inherited cert mode.
//
// CertPolicy is validated at chain genesis (Validate() below); a
// chain MUST refuse to launch with an invalid CertPolicy. There is
// no migration; the new final Lux network starts at genesis with
// CertPolicy.
//
// CertPolicy is distinct from pq_mode.go's PQMode enum. pq_mode.go
// owns the v1 INTERNAL codenames (PQModePulsar, PQModeQuasar,
// PQModeMLDSA, ...) — the cryptographic building blocks. CertPolicy
// is the v2 OPERATOR-FACING surface that maps to internal codenames
// via ToV1Predicate.
package config
import (
"errors"
"fmt"
"strings"
)
// CertPolicy is the single configuration record that declares a
// chain's cert posture. See LP-217 §"Operator config".
type CertPolicy struct {
Mode CertMode
Variant CertVariant
TimeoutMs uint32
Fallback CertMode
}
// CertMode is the additive cert-mode ladder. Subset-ordered:
//
// CertModeOff < CertModeFast < CertModeStrict < CertModeHeavy
//
// (Named CertMode here, not PQMode, to keep the namespace clean
// against pq_mode.go's PQMode which owns the v1 codename enum.)
type CertMode uint8
const (
// CertModeOff — Hybrid: BLS only. Strict: (invalid; refused by
// Validate). Floor latency ~1 ms final on Blackwell N=64.
CertModeOff CertMode = 0
// CertModeFast — Hybrid: BLS + Pulsar. Strict: Pulsar only.
// Floor latency ~5 ms GPU on Blackwell N=64.
CertModeFast CertMode = 1
// CertModeStrict — Hybrid: BLS + Pulsar + Corona. Strict: Pulsar +
// Corona. Floor latency ~50 ms GPU on Blackwell N=64.
CertModeStrict CertMode = 2
// CertModeHeavy — Hybrid: BLS + Pulsar + Corona + Magnetar.
// Strict: Pulsar + Corona + Magnetar. Floor latency ~80 ms final
// on Blackwell N=64.
CertModeHeavy CertMode = 3
)
// CertVariant picks whether BLS is part of the required leg set.
type CertVariant uint8
const (
// CertVariantHybrid — include BLS as classical leg.
CertVariantHybrid CertVariant = 0
// CertVariantStrict — drop BLS; pure PQ legs only.
CertVariantStrict CertVariant = 1
)
// LegName is the wire identifier of a single cert leg. Values match
// LP-182 QuasarCert field tags.
type LegName uint8
const (
LegBLS LegName = 1
LegPulsar LegName = 2
LegCorona LegName = 3
LegMagnetar LegName = 4
)
// String returns the canonical mode name (without variant prefix).
func (m CertMode) String() string {
switch m {
case CertModeOff:
return "PQ-off"
case CertModeFast:
return "PQ-fast"
case CertModeStrict:
return "PQ-strict"
case CertModeHeavy:
return "PQ-heavy"
default:
return fmt.Sprintf("cert-mode(%d)", uint8(m))
}
}
// String returns the canonical variant name.
func (v CertVariant) String() string {
switch v {
case CertVariantHybrid:
return "hybrid"
case CertVariantStrict:
return "strict"
default:
return fmt.Sprintf("cert-variant(%d)", uint8(v))
}
}
// WireName returns the seven canonical wire names from LP-217
// §"(Mode, Variant) enumeration":
//
// (PQ-off, hybrid) -> PQ-off
// (PQ-fast, hybrid) -> PQ-fast
// (PQ-strict, hybrid) -> PQ-strict
// (PQ-heavy, hybrid) -> PQ-heavy
// (PQ-fast, strict) -> strict-PQ-fast
// (PQ-strict, strict) -> strict-PQ-strict
// (PQ-heavy, strict) -> strict-PQ-heavy
//
// The eighth slot (PQ-off, strict) is invalid and returns the empty
// string; callers MUST run Validate() before relying on WireName.
func (cp CertPolicy) WireName() string {
switch cp.Variant {
case CertVariantHybrid:
return cp.Mode.String()
case CertVariantStrict:
if cp.Mode == CertModeOff {
return ""
}
return "strict-" + cp.Mode.String()
default:
return ""
}
}
// RequiredLegs returns the leg set the cert MUST include to satisfy
// the policy's Mode. Result is sorted (BLS first if present, then
// Pulsar, Corona, Magnetar).
func (cp CertPolicy) RequiredLegs() []LegName {
legs := make([]LegName, 0, 4)
if cp.Variant == CertVariantHybrid && cp.Mode >= CertModeOff {
legs = append(legs, LegBLS)
}
if cp.Mode >= CertModeFast {
legs = append(legs, LegPulsar)
}
if cp.Mode >= CertModeStrict {
legs = append(legs, LegCorona)
}
if cp.Mode >= CertModeHeavy {
legs = append(legs, LegMagnetar)
}
return legs
}
// parseMode parses one of the four canonical mode names.
func parseMode(s string) (CertMode, error) {
switch s {
case "PQ-off":
return CertModeOff, nil
case "PQ-fast":
return CertModeFast, nil
case "PQ-strict":
return CertModeStrict, nil
case "PQ-heavy":
return CertModeHeavy, nil
default:
return 0, fmt.Errorf("unknown cert mode %q", s)
}
}
// ParseWireName parses one of the seven canonical wire names into a
// (Mode, Variant) pair. Returns an error for any other string.
func ParseWireName(s string) (CertMode, CertVariant, error) {
s = strings.TrimSpace(s)
if strings.HasPrefix(s, "strict-") {
m, err := parseMode(strings.TrimPrefix(s, "strict-"))
if err != nil {
return 0, 0, err
}
return m, CertVariantStrict, nil
}
m, err := parseMode(s)
if err != nil {
return 0, 0, err
}
return m, CertVariantHybrid, nil
}
// ParseCertPolicy parses a YAML-style record into a CertPolicy.
// Caller passes the four fields as strings (mode, variant, timeout,
// fallback) — the typical genesis-loader path reads the YAML map and
// hands strings here so the struct stays decoupled from yaml.v3.
//
// Returns the parsed policy AND any error from Validate. A non-nil
// error means the policy is unsafe to launch the chain with.
func ParseCertPolicy(mode, variant string, timeoutMs uint32, fallback string) (CertPolicy, error) {
m, err := parseMode(mode)
if err != nil {
return CertPolicy{}, fmt.Errorf("cert_policy.mode: %w", err)
}
var v CertVariant
switch strings.TrimSpace(variant) {
case "", "hybrid":
v = CertVariantHybrid
case "strict":
v = CertVariantStrict
default:
return CertPolicy{}, fmt.Errorf("cert_policy.variant: unknown variant %q (want hybrid|strict)", variant)
}
f, err := parseMode(fallback)
if err != nil {
return CertPolicy{}, fmt.Errorf("cert_policy.fallback: %w", err)
}
cp := CertPolicy{
Mode: m,
Variant: v,
TimeoutMs: timeoutMs,
Fallback: f,
}
return cp, cp.Validate()
}
// expectedFloorLatencyMs returns the floor latency for a Mode on
// Blackwell N=64. These are pinned values from LP-217 §"The 4 modes"
// Table 1. Validators with non-Blackwell hardware multiply through
// CPU/M4-Max floors per LP-203.
func (m CertMode) expectedFloorLatencyMs() uint32 {
switch m {
case CertModeOff:
return 1
case CertModeFast:
return 5
case CertModeStrict:
return 50
case CertModeHeavy:
return 80
default:
return 0
}
}
// MinTimeoutMs returns the minimum TimeoutMs for this Mode (2 ×
// floor latency, per LP-217 §"Validation rules" rule 3). The 2×
// factor is the minimum; production deployments typically use 410×
// to absorb jitter.
func (m CertMode) MinTimeoutMs() uint32 {
return 2 * m.expectedFloorLatencyMs()
}
// Common validation errors.
var (
// ErrCertPolicyFallbackTooStrong — Fallback is stronger than
// Mode; a fallback by definition cannot require more legs than
// the target.
ErrCertPolicyFallbackTooStrong = errors.New(
"cert_policy: fallback tier cannot be stronger than mode")
// ErrCertPolicyStrictOff — Variant=Strict with Mode=PQ-off
// produces a cert with no legs; refused.
ErrCertPolicyStrictOff = errors.New(
"cert_policy: variant=strict requires mode>=PQ-fast (PQ-off has no PQ legs)")
// ErrCertPolicyTimeoutTooShort — TimeoutMs < 2 ×
// expected_floor_latency(Mode); chain at this Mode would never
// satisfy the required set within the timeout.
ErrCertPolicyTimeoutTooShort = errors.New(
"cert_policy: timeout_ms < 2 × expected_floor_latency(mode)")
// ErrCertPolicyFallbackInvalid — Fallback as a (Mode, Variant)
// pair under the chain's Variant is itself invalid (e.g.
// Variant=Strict with Fallback=PQ-off).
ErrCertPolicyFallbackInvalid = errors.New(
"cert_policy: fallback is not a valid (Mode, Variant) under the chain's Variant")
)
// Validate enforces the four LP-217 §"Validation rules":
//
// 1. Fallback <= Mode
// 2. Variant=Strict requires Mode >= PQ-fast
// 3. TimeoutMs >= 2 × expected_floor_latency(Mode)
// 4. Fallback as a (Mode, Variant) under the chain's Variant must
// itself be valid (i.e. the fallback policy passes rule 2 too)
//
// Validate is called at chain genesis; a chain MUST refuse to launch
// when Validate returns a non-nil error.
func (cp CertPolicy) Validate() error {
// Rule 2 — Variant=Strict requires Mode >= PQ-fast.
if cp.Variant == CertVariantStrict && cp.Mode == CertModeOff {
return ErrCertPolicyStrictOff
}
// Rule 1 — Fallback <= Mode.
if cp.Fallback > cp.Mode {
return fmt.Errorf("%w: fallback=%s mode=%s",
ErrCertPolicyFallbackTooStrong, cp.Fallback, cp.Mode)
}
// Rule 3 — TimeoutMs >= 2 × expected_floor_latency(Mode).
if min := cp.Mode.MinTimeoutMs(); cp.TimeoutMs < min {
return fmt.Errorf("%w: mode=%s timeout_ms=%d min=%d",
ErrCertPolicyTimeoutTooShort, cp.Mode, cp.TimeoutMs, min)
}
// Rule 4 — Fallback as a (Mode, Variant) under the chain's
// Variant must itself be valid. The only way this fails is
// Variant=Strict with Fallback=PQ-off (the eighth-slot
// configuration). Catching it inline gives a more readable error
// than recursing on a synthesized fallback policy.
if cp.Variant == CertVariantStrict && cp.Fallback == CertModeOff {
return fmt.Errorf("%w: fallback=%s variant=%s",
ErrCertPolicyFallbackInvalid, cp.Fallback, cp.Variant)
}
return nil
}
// IsPostQuantum reports whether the policy includes any PQ leg in
// its required set. False only for (Mode=PQ-off, Variant=Hybrid)
// which is BLS-only.
func (cp CertPolicy) IsPostQuantum() bool {
return cp.Mode >= CertModeFast
}
// AllowsBLS reports whether the policy includes BLS in its required
// set. True for Variant=Hybrid; false for Variant=Strict.
func (cp CertPolicy) AllowsBLS() bool {
return cp.Variant == CertVariantHybrid
}
+244
View File
@@ -0,0 +1,244 @@
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package config
import (
"errors"
"reflect"
"testing"
)
// TestCertPolicy_WireName_RoundTrip exercises the seven canonical
// wire names from LP-217 §"(Mode, Variant) enumeration". The eighth
// slot (PQ-off, strict) must produce the empty string and refuse
// Validate.
func TestCertPolicy_WireName_RoundTrip(t *testing.T) {
cases := []struct {
mode CertMode
variant CertVariant
wireName string
}{
{CertModeOff, CertVariantHybrid, "PQ-off"},
{CertModeFast, CertVariantHybrid, "PQ-fast"},
{CertModeStrict, CertVariantHybrid, "PQ-strict"},
{CertModeHeavy, CertVariantHybrid, "PQ-heavy"},
{CertModeFast, CertVariantStrict, "strict-PQ-fast"},
{CertModeStrict, CertVariantStrict, "strict-PQ-strict"},
{CertModeHeavy, CertVariantStrict, "strict-PQ-heavy"},
}
for _, tc := range cases {
cp := CertPolicy{Mode: tc.mode, Variant: tc.variant}
if got := cp.WireName(); got != tc.wireName {
t.Errorf("WireName(%v,%v): got %q want %q",
tc.mode, tc.variant, got, tc.wireName)
}
m, v, err := ParseWireName(tc.wireName)
if err != nil {
t.Errorf("ParseWireName(%q): %v", tc.wireName, err)
continue
}
if m != tc.mode || v != tc.variant {
t.Errorf("ParseWireName(%q): got (%v,%v) want (%v,%v)",
tc.wireName, m, v, tc.mode, tc.variant)
}
}
}
// TestCertPolicy_WireName_EighthSlot — (PQ-off, strict) is the eighth
// slot; WireName returns "" and Validate refuses.
func TestCertPolicy_WireName_EighthSlot(t *testing.T) {
cp := CertPolicy{Mode: CertModeOff, Variant: CertVariantStrict}
if got := cp.WireName(); got != "" {
t.Errorf("(PQ-off,strict).WireName(): got %q want \"\"", got)
}
}
// TestCertPolicy_RequiredLegs walks the seven configurations and
// asserts the leg set matches LP-217 §"The 4 modes".
func TestCertPolicy_RequiredLegs(t *testing.T) {
cases := []struct {
name string
policy CertPolicy
legs []LegName
}{
{"PQ-off",
CertPolicy{Mode: CertModeOff, Variant: CertVariantHybrid},
[]LegName{LegBLS}},
{"PQ-fast",
CertPolicy{Mode: CertModeFast, Variant: CertVariantHybrid},
[]LegName{LegBLS, LegPulsar}},
{"PQ-strict",
CertPolicy{Mode: CertModeStrict, Variant: CertVariantHybrid},
[]LegName{LegBLS, LegPulsar, LegCorona}},
{"PQ-heavy",
CertPolicy{Mode: CertModeHeavy, Variant: CertVariantHybrid},
[]LegName{LegBLS, LegPulsar, LegCorona, LegMagnetar}},
{"strict-PQ-fast",
CertPolicy{Mode: CertModeFast, Variant: CertVariantStrict},
[]LegName{LegPulsar}},
{"strict-PQ-strict",
CertPolicy{Mode: CertModeStrict, Variant: CertVariantStrict},
[]LegName{LegPulsar, LegCorona}},
{"strict-PQ-heavy",
CertPolicy{Mode: CertModeHeavy, Variant: CertVariantStrict},
[]LegName{LegPulsar, LegCorona, LegMagnetar}},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got := tc.policy.RequiredLegs()
if !reflect.DeepEqual(got, tc.legs) {
t.Errorf("RequiredLegs: got %v want %v", got, tc.legs)
}
})
}
}
// TestCertPolicy_Validate_Rule1 — Fallback > Mode is refused.
func TestCertPolicy_Validate_Rule1(t *testing.T) {
cp := CertPolicy{
Mode: CertModeFast,
Variant: CertVariantHybrid,
TimeoutMs: 1000,
Fallback: CertModeStrict, // > Mode
}
err := cp.Validate()
if !errors.Is(err, ErrCertPolicyFallbackTooStrong) {
t.Errorf("Validate: got %v want ErrCertPolicyFallbackTooStrong", err)
}
}
// TestCertPolicy_Validate_Rule2 — Variant=Strict with Mode=PQ-off
// is refused.
func TestCertPolicy_Validate_Rule2(t *testing.T) {
cp := CertPolicy{
Mode: CertModeOff,
Variant: CertVariantStrict,
TimeoutMs: 1000,
Fallback: CertModeOff,
}
err := cp.Validate()
if !errors.Is(err, ErrCertPolicyStrictOff) {
t.Errorf("Validate: got %v want ErrCertPolicyStrictOff", err)
}
}
// TestCertPolicy_Validate_Rule3 — TimeoutMs below 2 × floor latency
// is refused.
func TestCertPolicy_Validate_Rule3(t *testing.T) {
cp := CertPolicy{
Mode: CertModeHeavy,
Variant: CertVariantHybrid,
TimeoutMs: 100, // < 160 (2 × 80)
Fallback: CertModeStrict,
}
err := cp.Validate()
if !errors.Is(err, ErrCertPolicyTimeoutTooShort) {
t.Errorf("Validate: got %v want ErrCertPolicyTimeoutTooShort", err)
}
}
// TestCertPolicy_Validate_Rule4 — Variant=Strict + Fallback=PQ-off
// is refused (the fallback as a (Mode, Variant) pair is invalid).
func TestCertPolicy_Validate_Rule4(t *testing.T) {
cp := CertPolicy{
Mode: CertModeFast,
Variant: CertVariantStrict,
TimeoutMs: 100,
Fallback: CertModeOff,
}
err := cp.Validate()
if !errors.Is(err, ErrCertPolicyFallbackInvalid) {
t.Errorf("Validate: got %v want ErrCertPolicyFallbackInvalid", err)
}
}
// TestCertPolicy_Validate_Valid — every valid (Mode, Variant) pair
// with a satisfying TimeoutMs and Fallback passes Validate.
func TestCertPolicy_Validate_Valid(t *testing.T) {
cases := []CertPolicy{
{CertModeOff, CertVariantHybrid, 10, CertModeOff},
{CertModeFast, CertVariantHybrid, 100, CertModeOff},
{CertModeStrict, CertVariantHybrid, 1000, CertModeFast},
{CertModeHeavy, CertVariantHybrid, 2000, CertModeStrict},
{CertModeFast, CertVariantStrict, 100, CertModeFast},
{CertModeStrict, CertVariantStrict, 1000, CertModeFast},
{CertModeHeavy, CertVariantStrict, 2000, CertModeStrict},
}
for _, cp := range cases {
if err := cp.Validate(); err != nil {
t.Errorf("Validate %s: unexpected error %v", cp.WireName(), err)
}
}
}
// TestParseCertPolicy_RoundTrip parses YAML-form strings and
// validates the result.
func TestParseCertPolicy_RoundTrip(t *testing.T) {
cp, err := ParseCertPolicy("PQ-strict", "hybrid", 1000, "PQ-fast")
if err != nil {
t.Fatalf("ParseCertPolicy: %v", err)
}
want := CertPolicy{
Mode: CertModeStrict,
Variant: CertVariantHybrid,
TimeoutMs: 1000,
Fallback: CertModeFast,
}
if cp != want {
t.Errorf("ParseCertPolicy: got %+v want %+v", cp, want)
}
}
// TestParseCertPolicy_VariantStrict — variant=strict parses
// correctly.
func TestParseCertPolicy_VariantStrict(t *testing.T) {
cp, err := ParseCertPolicy("PQ-heavy", "strict", 2000, "PQ-strict")
if err != nil {
t.Fatalf("ParseCertPolicy: %v", err)
}
if cp.Variant != CertVariantStrict {
t.Errorf("Variant: got %v want CertVariantStrict", cp.Variant)
}
if cp.WireName() != "strict-PQ-heavy" {
t.Errorf("WireName: got %q want strict-PQ-heavy", cp.WireName())
}
}
// TestParseCertPolicy_Invalid — unknown mode / variant strings are
// refused.
func TestParseCertPolicy_Invalid(t *testing.T) {
if _, err := ParseCertPolicy("bogus", "hybrid", 1000, "PQ-fast"); err == nil {
t.Error("expected error for unknown mode")
}
if _, err := ParseCertPolicy("PQ-fast", "bogus", 1000, "PQ-fast"); err == nil {
t.Error("expected error for unknown variant")
}
if _, err := ParseCertPolicy("PQ-fast", "hybrid", 1000, "bogus"); err == nil {
t.Error("expected error for unknown fallback")
}
}
// TestCertPolicy_IsPostQuantum — PQ-off is classical-only; everything
// else is post-quantum.
func TestCertPolicy_IsPostQuantum(t *testing.T) {
if (CertPolicy{Mode: CertModeOff}).IsPostQuantum() {
t.Error("PQ-off IsPostQuantum: got true want false")
}
if !(CertPolicy{Mode: CertModeFast}).IsPostQuantum() {
t.Error("PQ-fast IsPostQuantum: got false want true")
}
if !(CertPolicy{Mode: CertModeHeavy}).IsPostQuantum() {
t.Error("PQ-heavy IsPostQuantum: got false want true")
}
}
// TestCertPolicy_AllowsBLS — Hybrid includes BLS; Strict does not.
func TestCertPolicy_AllowsBLS(t *testing.T) {
if !(CertPolicy{Variant: CertVariantHybrid}).AllowsBLS() {
t.Error("Hybrid AllowsBLS: got false want true")
}
if (CertPolicy{Variant: CertVariantStrict}).AllowsBLS() {
t.Error("Strict AllowsBLS: got true want false")
}
}
+1 -1
View File
@@ -44,7 +44,7 @@ type Parameters struct {
}
// WithPQMode returns a copy of Parameters with the given PQ mode set.
// Use config.PQModeFromEnv to honour the LUX_CONSENSUS_PQ_MODE override.
// Use config.PQModeFromEnv to honour the CONSENSUS_PQ_MODE override.
func (p Parameters) WithPQMode(m PQMode) Parameters {
p.PQMode = m
return p
+3 -10
View File
@@ -679,20 +679,13 @@ func ParsePQMode(s string) (PQMode, error) {
}
}
// PQModeFromEnv resolves the consensus PQ mode from environment variables.
//
// Reads CONSENSUS_PQ_MODE first (canonical, unprefixed per the "drop the
// LUX_ prefix" directive); falls through to the legacy LUX_CONSENSUS_PQ_MODE
// for back-compat with running validators that still ship the old name in
// their k8s manifests. If both are set, CONSENSUS_PQ_MODE wins (one way:
// the new way takes precedence).
// PQModeFromEnv resolves the consensus PQ mode from CONSENSUS_PQ_MODE.
// The legacy LUX_-prefixed name is no longer honoured — there is one
// canonical, unprefixed env var.
//
// Empty / unset returns the supplied default. Invalid values return def + error.
func PQModeFromEnv(def PQMode) (PQMode, error) {
v := os.Getenv("CONSENSUS_PQ_MODE")
if v == "" {
v = os.Getenv("LUX_CONSENSUS_PQ_MODE")
}
if v == "" {
return def, nil
}
+16 -35
View File
@@ -750,19 +750,20 @@ func TestPQMode_IsPostQuantum(t *testing.T) {
}
}
// TestPQModeFromEnv covers the env-var override path.
// TestPQModeFromEnv covers the env-var override path. CONSENSUS_PQ_MODE is
// the one and only env var honoured; the legacy LUX_-prefixed name is gone.
func TestPQModeFromEnv(t *testing.T) {
t.Setenv("LUX_CONSENSUS_PQ_MODE", "")
t.Setenv("CONSENSUS_PQ_MODE", "")
if got, err := PQModeFromEnv(PQModeQuasar); err != nil || got != PQModeQuasar {
t.Errorf("empty env: got (%v, %v), want (PQModeQuasar, nil)", got, err)
}
t.Setenv("LUX_CONSENSUS_PQ_MODE", "pulsar")
t.Setenv("CONSENSUS_PQ_MODE", "pulsar")
if got, err := PQModeFromEnv(PQModeBLS); err != nil || got != PQModePulsar {
t.Errorf("env=pulsar: got (%v, %v), want (PQModePulsar, nil)", got, err)
}
t.Setenv("LUX_CONSENSUS_PQ_MODE", "garbage")
t.Setenv("CONSENSUS_PQ_MODE", "garbage")
got, err := PQModeFromEnv(PQModeQuasar)
if err == nil {
t.Errorf("env=garbage: expected error, got nil; mode=%v", got)
@@ -772,41 +773,21 @@ func TestPQModeFromEnv(t *testing.T) {
}
}
// TestPQModeFromEnv_UnprefixedPrecedence covers the unprefixed canonical
// CONSENSUS_PQ_MODE env name added per the "drop LUX_ prefix" directive.
// Verifies:
//
// 1. CONSENSUS_PQ_MODE alone is honoured.
// 2. CONSENSUS_PQ_MODE wins when both are set (one way: the new way takes
// precedence).
// 3. Only LUX_CONSENSUS_PQ_MODE set: legacy fallback still works.
// 4. Both unset: default returned.
func TestPQModeFromEnv_UnprefixedPrecedence(t *testing.T) {
// 1. CONSENSUS_PQ_MODE alone.
t.Setenv("CONSENSUS_PQ_MODE", "quasar")
t.Setenv("LUX_CONSENSUS_PQ_MODE", "")
if got, err := PQModeFromEnv(PQModeBLS); err != nil || got != PQModeQuasar {
t.Errorf("unprefixed alone: got (%v, %v), want (PQModeQuasar, nil)", got, err)
// TestPQModeFromEnv_LegacyNameIgnored asserts that the dropped legacy
// LUX_CONSENSUS_PQ_MODE env var is no longer honoured. Only CONSENSUS_PQ_MODE
// affects the resolved mode.
func TestPQModeFromEnv_LegacyNameIgnored(t *testing.T) {
// Legacy name set, canonical unset: default returned, legacy is dead.
t.Setenv("CONSENSUS_PQ_MODE", "")
t.Setenv("LUX_CONSENSUS_PQ_MODE", "pulsar")
if got, err := PQModeFromEnv(PQModeBLS); err != nil || got != PQModeBLS {
t.Errorf("legacy-only: got (%v, %v), want (PQModeBLS, nil) — legacy var must be ignored", got, err)
}
// 2. Both set — unprefixed wins.
// Both set: canonical wins (legacy is ignored entirely).
t.Setenv("CONSENSUS_PQ_MODE", "quasar")
t.Setenv("LUX_CONSENSUS_PQ_MODE", "bls")
if got, err := PQModeFromEnv(PQModeMLDSA); err != nil || got != PQModeQuasar {
t.Errorf("both set: got (%v, %v), want (PQModeQuasar, nil) — unprefixed must win", got, err)
}
// 3. Only legacy LUX_ var set: fallback honoured.
t.Setenv("CONSENSUS_PQ_MODE", "")
t.Setenv("LUX_CONSENSUS_PQ_MODE", "pulsar")
if got, err := PQModeFromEnv(PQModeBLS); err != nil || got != PQModePulsar {
t.Errorf("legacy fallback: got (%v, %v), want (PQModePulsar, nil)", got, err)
}
// 4. Both unset: default returned.
t.Setenv("CONSENSUS_PQ_MODE", "")
t.Setenv("LUX_CONSENSUS_PQ_MODE", "")
if got, err := PQModeFromEnv(PQModeQuasar); err != nil || got != PQModeQuasar {
t.Errorf("both unset: got (%v, %v), want (PQModeQuasar, nil)", got, err)
t.Errorf("both set: got (%v, %v), want (PQModeQuasar, nil) — canonical must win", got, err)
}
}
+1 -1
View File
@@ -109,7 +109,7 @@ func (s *memoryStore) Children(id quasar.VertexID) []quasar.VertexID {
// Uses in-memory storage suitable for single-node operation.
// For distributed deployment, inject a persistent Store implementation.
//
// The engine honours params.PQMode (and the LUX_CONSENSUS_PQ_MODE env
// The engine honours params.PQMode (and the CONSENSUS_PQ_MODE env
// override) to select which signature layers are active. Only the BLS
// fast path is wired today; PQ paths are ready for the signer hookup.
func NewConsensus(params config.Parameters) *ConsensusEngine {
+1 -1
View File
@@ -6,7 +6,7 @@ In Lux, nodes engage in repeated random subsampling (analogous to photons intera
We describe how Lux Nova realizes a linear blockchain (total order) consensus, Lux Nebula generalizes this to a directed acyclic graph (DAG) of transactions for higher parallelism, and Lux Quasar provides a post-quantum secure overlay ensuring long-term security against quantum adversaries. We provide detailed protocol descriptions, formal probabilistic guarantees, and performance analysis.
Each stage of Lux is introduced through a pedagogical physics analogy (e.g. constant-mass photons propagating coherently, wave thresholding with constructive interference, gravitational attraction of majority, and supernova-like finalization), reinforcing the conceptual intuition behind the technical design. Finally, we discuss implementation guidance, module decomposition, and how Lux can power sovereign blockchain subnets with seamless upgrade paths.
Each stage of Lux is introduced through a pedagogical physics analogy (e.g. constant-mass photons propagating coherently, wave thresholding with constructive interference, gravitational attraction of majority, and supernova-like finalization), reinforcing the conceptual intuition behind the technical design. Finally, we discuss implementation guidance, module decomposition, and how Lux can power sovereign blockchain L1s with seamless upgrade paths.
The Lux family demonstrates that embracing physical metaphors can illuminate the design of robust, scalable, and future-proof consensus mechanisms.
+2 -2
View File
@@ -137,13 +137,13 @@ Preliminary results from testnet with globally distributed nodes:
\item \textbf{Scalability}: Linear degradation up to 1000+ nodes
\end{itemize}
\subsection{Sovereign Subnet Deployment}
\subsection{Sovereign L1 Deployment}
Lux enables creation of independent chains sharing the same consensus framework, improving interoperability across a multi-chain ecosystem.
\subsubsection{Cross-Chain Communication}
Two Lux-based subnets can trust each other's consensus outputs through:
Two Lux-based L1 chains can trust each other's consensus outputs through:
\begin{itemize}
\item Quasar checkpoint signatures recognized across chains
\item Relay protocols that verify finality proofs
+1 -1
View File
@@ -32,4 +32,4 @@ Using these four core modules—Photon, Prism, Wave, Focus—Lux first establish
By combining these components, Lux offers a unified consensus family that can cater to different needs. A small permissioned chain might run Lux Ray for simplicity. A high-throughput DeFi application could use Lux Field for parallel transaction processing. A government or long-lived public ledger might enable Lux Quasar to secure against future quantum threats.
In the remainder of this paper, we delve into each aspect of Lux in detail. We formalize our system model and review prior consensus approaches, describe the core protocol design with algorithms and mathematical notation, present formal arguments for safety and liveness, evaluate performance characteristics, and discuss implementation guidance including how Lux can power sovereign blockchain subnets with seamless upgrade paths.
In the remainder of this paper, we delve into each aspect of Lux in detail. We formalize our system model and review prior consensus approaches, describe the core protocol design with algorithms and mathematical notation, present formal arguments for safety and liveness, evaluate performance characteristics, and discuss implementation guidance including how Lux can power sovereign blockchain L1s with seamless upgrade paths.
+1 -1
View File
@@ -152,7 +152,7 @@ Lux Quasar operates as the Platform Chain (P-Chain) that provides post-quantum f
\begin{itemize}
\item Irreversible finality that cannot be affected by quantum attacks
\item Cross-chain asset transfers with unified security guarantees
\item Subnet interoperability through mutually recognized P-Chain event horizons
\item L1 interoperability through mutually recognized P-Chain event horizons
\item Canonical ordering for deterministic state transitions across all chains
\end{itemize}