zooqueen fd3e1e88f4 quasar: harden weighted quorum cert envelope binding (5 red-team findings)
The crypto core (TupleHash256, FIPS 204/205 verify, weighted Merkle,
leaf binding, distinct-signer ordering, weight overflow guards) was
sound. The ENVELOPE binding was not. Fixes, smallest correct change,
no new fail-open paths:

F1 (CRITICAL) sub-quorum finality forgery — QuorumThreshold was
   unbound: Verify checked Sum(weight) >= attacker-chosen
   c.QuorumThreshold with no floor and no signature binding. Two-part
   fix:
   (a) bind quorum_threshold into the SIGNED message. Added
       QuorumThreshold to QuorumMessageEnvelope and into the
       QuorumConsensusMessage re-frame parts (quorum_message.go) — the
       quorum-cert-specific layer where qc_type / value_hash already
       live. NOT added to the shared ComputeRoundDigest (that round
       digest is consumed by non-quorum consensus rounds; threshold is
       not one of its axes). QuorumMessageForCert now fills the
       threshold from the cert, so honest signatures over the real
       quorum cannot be re-framed under a lowered one.
   (b) MANDATORY verifier floor: QuorumVerifierConfig.MinThreshold.
       Verify FAILS CLOSED if MinThreshold is unset (zero) and rejects
       any cert whose QuorumThreshold < MinThreshold. A cert may not
       assert its own security parameter.

F2 (HIGH) decode DoS — UnmarshalWeightedQuorumCert reserved capacity
   for an attacker-controlled uint32 SignerCount (0xFFFFFFFF ~= 446 GB).
   Cap SignerCount against the remaining buffer (wqcMinRecordBytes = 66)
   before the make, mirroring the existing step_count cap. O(1)
   rejection, no allocation.

F3 (HIGH) opaque-message trust / role-replay — Verify took a
   caller-supplied message. It now takes the chain envelope and rebuilds
   the position binding ITSELF via QuorumMessageForCert; the raw-message
   form is demoted to the internal verifyWithMessage helper. Folds in
   the LOW finding: Verify asserts envelope.ProofBackend ==
   cert.ProofBackendID() before building the message. QCType
   prepare->commit role-replay and every position axis are now caught at
   the rebuilt-message signature check. VerifyWeightedQuorumLeg updated
   to take the envelope.

F4 (MED) weighted-Merkle proof malleability — weightedProofShape gives
   identical shapes for different LeafCount (e.g. (0,3) and (0,4) both
   "RR"), so a record had multiple valid (LeafIndex,LeafCount) encodings
   -> byte-distinct certs, breaking dedup/equivocation. Bind each
   signer's (LeafIndex,LeafCount) into computeSignerCommitment; any
   malleation now changes the commitment and is rejected.

F5 (MED) mixed-scheme FIPS-context asymmetry — magnetar.ValidatorSign
   signs the empty FIPS-205 context while ML-DSA signs cfg.Context;
   Verify applied one context to all, so mixed certs only worked with
   ctx=nil. Added contextForScheme: ML-DSA -> cfg.Context, SLH-DSA ->
   empty context (the round-digest message carries the domain binding).

Tests: new quorum_redteam_test.go proves each PoC is now REJECTED
((a) forged below-floor threshold, (b) threshold-swap message binding,
(c) 0xFFFFFFFF SignerCount fast-reject, (d) position/QCType/value_hash
tamper, (e) non-canonical (LeafIndex,LeafCount)). Existing tests
updated for the envelope-based Verify signature + mandatory
MinThreshold. config: ProofFormatDirectWeightedQuorumV1 (0x30) and
VerifierDirectWeightedQuorumPQ (0x0030) wire constants for the cert.

Verify: go build ./protocol/quasar/... ok; go test
'Quorum|WeightedMerkle|QuasarCert|RoundDigest|Redteam' 154 PASS / 0
FAIL; gofmt clean; go vet clean; framework fail-open gate ok.
2026-06-21 14:08:05 -07:00

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.

CI Status Go Version

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:

  1. BLS: single-round threshold share via crypto/threshold
  2. Pulsar: 2-round Ring-LWE threshold via luxfi/corona/threshold
  3. 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

  1. Pre-quantum: Attacker must corrupt >= 1/3 stake to fork
  2. Q-day (BLS broken): Lattice certificates prevent unsafe finalization
  3. Post-quantum: Security rests on Module-LWE (Pulsar) + Module-LWE/SIS (ML-DSA)

License

BSD 3-Clause. See LICENSE.

S
Description
Quasar consensus engine: Go implementations of consensus protocols for the Lux Network.
Readme
251 MiB
Languages
Go 85.5%
Rust 7.6%
Python 3.1%
TeX 1.2%
C 0.9%
Other 1.7%