A node could adopt a peer's state and could not serve one. Adoption already existed in engine/chain/summary; nothing answered the two requests it makes, so every node was a client of a service no node provided. The serving half reads the VM and returns what to send, leaving framing and transport to the node. It never consults StateSyncEnabled: a node's own preference says nothing about what its peers may ask, and a chain that answers only when it would also ask leaves a fleet unable to repair itself the moment its healthy members have nothing left to sync to. Silence and an empty reply are distinct answers. No summary, or an error, sends nothing and the requester closes its round on its deadline. A request naming no heights gets an empty reply — "none of those" — which completes the tally at once. Swap them and every round either stalls or under-counts. The op-space carries no wire for a singular by-height request, so nothing here answers one. Also removes the per-summary overflow check in elect. Its stake only ever sums a subset of the ballots `answered` already sums, and `answered` is checked one line earlier per ballot, so the second check could never fire. The invariant is now stated where the addition happens. Coverage is 100% on both halves, reached by deleting the branch rather than by asserting an impossible case. Comments across the engine drop incident detail for the rule each one holds. Co-authored-by: Hanzo Dev <[email protected]>
Lux Consensus
Lux is not merely adding post-quantum signatures to a chain; it defines a hybrid finality architecture for DAG-native consensus, with protocol-agnostic threshold lifecycle, post-quantum threshold sealing, and cross-chain propagation of Horizon finality.
See LP-105 §Claims and evidence for the canonical claims/evidence table and the ten architectural commitments — single source of truth.
Quasar Family of Consensus
Quasar is the consensus engine for the Lux network. It provides unified consensus for linear chains (P-Chain, C-Chain) and DAG chains (X-Chain) with post-quantum finality via three independent cryptographic signing paths.
Sub-Protocols
| Protocol | Role | Package |
|---|---|---|
| Photon | K-of-N committee selection via Fisher-Yates sampling with luminance-weighted reputation | protocol/photon |
| Wave | Per-round threshold voting with FPC (Fast Probabilistic Consensus) | protocol/wave |
| Focus | Confidence accumulation: beta consecutive successes = local finality | protocol/focus |
| Nova | Linear chain consensus mode (P-Chain, C-Chain) -- wraps Ray | protocol/nova |
| Nebula | DAG consensus mode (X-Chain) -- wraps Field | protocol/nebula |
| Prism | DAG geometry: frontiers, cuts, uniform peer sampling | protocol/prism |
| Horizon | DAG order-theory: reachability, LCA, transitive closure, skip lists | protocol/horizon |
| Flare | DAG certificate/skip detection via 2f+1 quorum | protocol/flare |
| Ray | Linear chain finality driver: Wave + Focus + Sink | protocol/ray |
| Field | DAG finality driver: Wave + safe-prefix commit | protocol/field |
| Quasar | BLS + Pulsar + ML-DSA threshold signing, epoch management | protocol/quasar |
Signing Modes
Each cryptographic layer is independently toggleable:
| Mode | Layers | Use Case |
|---|---|---|
| BLS-only | BLS12-381 threshold | Fastest classical consensus |
| BLS + ML-DSA | BLS + FIPS 204 ML-DSA-65 | Dual with PQ identity proof |
| BLS + Pulsar | BLS + Ring-LWE 2-round threshold | Dual with PQ threshold proof |
| BLS + Pulsar + ML-DSA | All three in parallel | Full Quasar (triple mode) |
IsTripleMode() returns true when all three paths are configured.
TripleSignRound1 runs BLS + Pulsar + ML-DSA signing in parallel goroutines.
PQ Mode Selection (Configurable)
The active mode is selectable at runtime via config.PQMode or the
CONSENSUS_PQ_MODE env var. Defined in config/pq_mode.go:
| Mode | Env value | Maps to wire policy |
|---|---|---|
BLSOnly |
bls |
PolicyQuorum |
BLSPlusMLDSA |
bls-mldsa |
PolicyPQ |
BLSPlusCorona |
bls-rt |
PolicyPZ |
BLSPlusGroth16 |
bls-z |
PolicyQuantum (placeholder) |
TripleQuantum |
triple |
PolicyQuantum |
Run bench/pq_modes_bench_test.go for measured per-mode signing /
aggregation / verify costs and cert sizes. Storage and cert size
trade-offs:
| Mode | Sign | Agg | Verify | Cert | Storage 10K |
|---|---|---|---|---|---|
| bls | 312 µs | 8.6 ms | 714 µs | 123 B | 1.17 MB |
| bls-mldsa | 369 µs | 8.5 ms | 3.4 ms | 69 KB | 665 MB |
| bls-rt | 39 ms | 3.3 s | 1.6 ms | 33 KB | 318 MB |
| triple | 40 ms | 3.3 s | 4.3 ms | 102 KB | 981 MB |
Pulsar / triple include the full 2-round Pulsar threshold protocol
(github.com/luxfi/pulsar/threshold — Pulsar is Lux's variant with
DKG2 and Pulsar-SHA3 hash suite). Production parameters M=8, N=7,
LogN=8 (ring degree 256), Q=2^48-ish: classical 2^142, quantum 2^130.
Cert-size floor of ~33 KB is set by the (C, Z, Delta) ring polynomials;
protocol/quasar/cert_size_compare_test.go measures and verifies this.
Architecture
consensus/
protocol/
photon/ Committee selection (Emitter + Luminance)
wave/ Threshold voting + FPC
fpc/ Fast Probabilistic Consensus selector
focus/ Confidence counter (beta tracker)
prism/ DAG cuts, frontiers, uniform sampling
horizon/ DAG reachability, LCA, skip lists
flare/ DAG cert/skip classification (2f+1)
ray/ Linear chain driver (Nova uses this)
field/ DAG finality driver (Nebula uses this)
nova/ Linear chain consensus mode
nebula/ DAG consensus mode
chain/ Block interface primitives
quasar/ BLS + Pulsar + ML-DSA threshold signing
engine/ Consensus engine (Chain, DAG, PQ wrappers)
core/ Core types, DAG structures
types/ Block, Vote, Config, Bag
config/ Parameter presets (single, local, testnet, mainnet)
runtime/ VM wiring (chain IDs, validators, logging)
pkg/wire/ Wire protocol credentials (ML-DSA-44/65/87 + BLS + Ed25519)
bench/ Benchmarks
version/ Re-exports github.com/luxfi/version
Consensus Flow
Linear Chains (Nova)
Photon (select committee) -> Wave (threshold vote) -> Focus (count beta) -> Ray (decide) -> Sink
DAG Chains (Nebula)
Photon (select committee) -> Wave (threshold vote per frontier vertex)
-> Flare (cert/skip) -> Horizon (safe prefix) -> Field (commit ordered prefix) -> Committer
Quasar PQ Finality
After consensus decision, the Quasar signing layer produces threshold certificates:
- BLS: single-round threshold share via
crypto/threshold - Pulsar: 2-round Ring-LWE threshold via
luxfi/corona/threshold - ML-DSA-65: single-round FIPS 204 identity signature
All three run in parallel. A block is quantum-final when all configured certificate layers are valid.
Key Hierarchy
| Layer | Key Type | Purpose |
|---|---|---|
| Node-ID | Ed25519 | P2P transport auth |
| Validator-BLS | BLS12-381 | Classical finality votes |
| Validator-PQ | Pulsar (Ring-LWE) | PQ finality shares |
| Validator-ID | ML-DSA-65 (FIPS 204) | PQ identity attestation |
| Wallet (EVM) | secp256k1 | User transaction signatures |
| Wallet (X-Chain) | secp256k1 | UTXO locking |
Quick Start
import "github.com/luxfi/consensus"
chain := consensus.NewChain(consensus.DefaultConfig())
ctx := context.Background()
if err := chain.Start(ctx); err != nil {
log.Fatal(err)
}
defer chain.Stop()
block := &consensus.Block{
ID: consensus.NewID(),
ParentID: consensus.GenesisID,
Height: 1,
Payload: []byte("Hello, Lux!"),
}
if err := chain.Add(ctx, block); err != nil {
log.Fatal(err)
}
Configuration
// Auto-configure based on validator count
params := consensus.GetConfig(21) // mainnet defaults
// Or use presets
consensus.SingleValidatorParams() // 1 node, dev
consensus.LocalParams() // 5 nodes, local
consensus.TestnetParams() // 11 nodes, testnet
consensus.MainnetParams() // 21 nodes, production
Benchmarks
Measured on Apple M1 Max:
| Component | Operation | Time/Op |
|---|---|---|
| Wave | Vote round | 3.38 us |
| Photon | K-of-N selection | 3.03 us |
| Luminance | Brightness update | 72 ns |
ZAP wire protocol (measured, bench/):
| Configuration | Throughput |
|---|---|
| Single connection | 114K TPS |
| 20 parallel connections | 376K TPS |
| 50 conns + batch 1000 | 20.26M TPS |
Testing
GOWORK=off go test ./...
GOWORK=off go test -bench=. ./bench/
Security Model
- Pre-quantum: Attacker must corrupt >= 1/3 stake to fork
- Q-day (BLS broken): Lattice certificates prevent unsafe finalization
- Post-quantum: Security rests on Module-LWE (Pulsar) + Module-LWE/SIS (ML-DSA)
License
BSD 3-Clause. See LICENSE.