Documentation
¶
Overview ¶
Package quasar is the node-side integration of the luxfi/consensus Quasar post-quantum finality-certificate layer.
luxd finalizes blocks on the classical Snow/Avalanche path (fast, every block). On top, at CHECKPOINTS (epoch boundaries — NOT every block), a sampled committee produces a QuasarCert over the finalized digest and validators VERIFY it. This package wires the VERIFY half: it consumes github.com/luxfi/consensus/protocol/quasar.VerifyConsensusCert as an OPTIONAL, FORWARD-DATED, DORMANT-BY-DEFAULT check in the block-accept path.
Safety contract ¶
The forward-dated dormant activation is the whole reason this package has the shape it does:
- Pre-activation (the default): VerifyAccepted is a pure no-op. Classical Snow finality is UNCHANGED. A nil *Gate, a zero Gate, or an unset activation height all mean "dormant" — zero behavior change.
- Post-activation (owner sets Activation.Height to a real, forward-dated height): at every checkpoint height the gate REQUIRES a valid QuasarCert bound to the just-finalized block and FAILS CLOSED — a missing or invalid cert returns an error from Accept(), halting the chain rather than finalizing a checkpoint without post-quantum evidence.
Activation is therefore a deliberate switch the owner flips only AFTER the cert PRODUCER (the per-validator committee signer) is live and certs flow at the checkpoint cadence — otherwise every checkpoint would halt. See producer.go.
Default posture ¶
HYBRID_PQ = Beam(BLS) ∧ Pulsar (standard FIPS-204 threshold ML-DSA), at checkpoint cadence. Per the measured policy-tier benchmarks, Pulsar verify (~140µs) is cheaper than BLS itself and the cert is compact (~27KB) — the right default production finality posture. STRICT_DUAL_PQ (∧ Corona) and the POLARIS tiers (∧ Magnetar) are configurable for stricter mainnet finality.
Index ¶
- Constants
- Variables
- type ActivationConfig
- type CertStore
- type Checkpoint
- type Config
- type Gate
- type MemCertStore
- type Producer
- type StaticValidatorSetProvider
- type Subject
- type ValidatorSet
- func (v *ValidatorSet) ClassicalAggregateKey(scheme qcert.ClassicalScheme) ([]byte, bool)
- func (v *ValidatorSet) Epoch() uint64
- func (v *ValidatorSet) Root() [48]byte
- func (v *ValidatorSet) ThresholdGroupKey(kind qcert.LegKind) (qcert.ThresholdGroupKey, bool)
- func (v *ValidatorSet) WeightedConfig() qcert.QuorumVerifierConfig
- func (v *ValidatorSet) WeightedEnvelope() qcert.QuorumMessageEnvelope
- type ValidatorSetProvider
Constants ¶
const DefaultCheckpointInterval uint64 = 256
DefaultCheckpointInterval is the default checkpoint cadence in blocks. PQ certs ride epoch-boundary checkpoints, never every block (Magnetar sign is checkpoint-only; even the cheap Pulsar sign is checkpoint cadence). The owner overrides this to match the producer's cadence at activation time.
const DefaultMode = qcert.PolicyHybridPQCheckpoint
DefaultMode is the default Quasar posture: HYBRID_PQ (Beam ∧ Pulsar).
Variables ¶
var ( // ErrFinalityCertMissing — a checkpoint was finalized post-activation but no // QuasarCert is available for it (the producer has not delivered one). ErrFinalityCertMissing = errors.New("quasar: finality cert missing for checkpoint") // ErrFinalityCertMismatch — a cert exists but does not bind the finalized // block (chain/height/block/state mismatch). Anti-replay. ErrFinalityCertMismatch = errors.New("quasar: finality cert does not bind the finalized block") // ErrFinalityCertInvalid — the cert is bound correctly but failed consensus // verification (policy, validator-set root, or a leg signature). ErrFinalityCertInvalid = errors.New("quasar: finality cert failed verification") // epoch (the verifier cannot resolve the per-leg verification keys). ErrValidatorSetUnavailable = errors.New("quasar: validator set unavailable for epoch") ErrPolicyUnavailable = errors.New("quasar: policy unavailable") // ErrPolicyMismatch — the cert's PolicyID is not the configured policy. A // cert cannot select its own (weaker) posture. ErrPolicyMismatch = errors.New("quasar: cert policy id does not match configured policy") // ErrGateMisconfigured — the gate is activated at a checkpoint but has no // cert store or validator provider. Fail closed rather than panic. ErrGateMisconfigured = errors.New("quasar: gate activated but missing store or validator provider") )
Typed, fail-closed errors. Every one is returned (never swallowed) and, when surfaced from the accept hook post-activation, halts finalization rather than accepting a checkpoint without valid post-quantum evidence.
Functions ¶
This section is empty.
Types ¶
type ActivationConfig ¶ added in v1.31.0
type ActivationConfig struct {
// Height is the block height at and above which PQ-finality verification is
// enforced at checkpoints. 0 == dormant (never).
Height uint64
}
ActivationConfig is the forward-dated activation switch.
The zero value is DORMANT: Height == 0 means "never activate" and the gate is a no-op for every block. This mirrors the genesis upgrade discipline (a far-future / unset activation point cannot affect live finality).
Activation is by HEIGHT ONLY, deliberately. A block height is agreed by consensus, so every honest validator enforces PQ finality at exactly the SAME checkpoints — there is no node-local decision. (A wall-clock gate would split finalization across validators with skewed clocks: some halting on a missing cert while others finalize without one. Timestamp-based forward-dating is expressed by choosing the activation HEIGHT at the target time.)
type CertStore ¶ added in v1.31.0
type CertStore interface {
Lookup(chainID uint32, height uint64, blockID [32]byte) (*qcert.ConsensusCert, bool)
}
CertStore resolves the QuasarCert that certifies a finalized block. In production it is filled by the cert gossip/ingest path (the producer follow-on, producer.go); the verify gate only READS from it. Keyed by the finalized position (chainID, height, blockID) so a cert can never be returned for the wrong block.
type Checkpoint ¶ added in v1.31.0
type Checkpoint struct {
Epoch uint64
Height uint64
Round uint32
BlockID [32]byte
StateRoot [32]byte
}
Checkpoint is the finalized-block position the accept hook hands the gate. It is the binding the cert must match (anti-replay): a valid cert for a DIFFERENT block must never satisfy THIS checkpoint. The chain id is gate-level config, not a per-block field.
type Config ¶ added in v1.22.79
type Config struct {
// ChainID is THIS chain's numeric identifier (the sovereign/EVM chain id),
// bound into every cert and checked against it. A per-chain constant sourced
// from chain config at gate construction — NOT pulled from a block, because
// the proposervm layer carries the 32-byte validator-set id, not the numeric
// chain id. Inert while dormant.
ChainID uint32
// Activation is the forward-dated dormant switch. Zero => dormant.
Activation ActivationConfig
// Mode is the Quasar evidence posture. Zero => DefaultMode (HYBRID_PQ).
Mode qcert.QuasarEvidenceMode
// MLDSAParam selects the ML-DSA parameter set for the Pulsar leg. 0 =>
// ML-DSA-65 (the consensus default).
MLDSAParam uint8
// Threshold is the BFT quorum floor (minimum aggregate signer weight) every
// leg's evidence must establish.
Threshold uint64
// CheckpointInterval is the checkpoint cadence in blocks. 0 =>
// DefaultCheckpointInterval.
CheckpointInterval uint64
}
Config is the node-surfaced PQ-finality configuration. Its zero value is dormant + HYBRID_PQ + default cadence.
type Gate ¶ added in v1.31.0
type Gate struct {
// contains filtered or unexported fields
}
Gate enforces (or, dormant, ignores) PQ-finality at checkpoints. It is the single node-side seam between the classical accept path and the consensus Quasar verifier.
func NewGate ¶ added in v1.31.0
func NewGate(cfg Config, store CertStore, validators ValidatorSetProvider) *Gate
NewGate constructs a Gate. A Gate is meaningful even with a dormant Config: VerifyAccepted is a no-op until Activation.Height is set. store and validators are only consulted post-activation at checkpoints.
func (*Gate) Activated ¶ added in v1.31.0
Activated reports whether enforcement is live for a block at the given height and the current wall clock. Used by the producer-request site to decide whether a cert is needed at a checkpoint.
func (*Gate) IsCheckpoint ¶ added in v1.31.0
IsCheckpoint reports whether the given height is a checkpoint under the gate's configured cadence. Exported so the producer-request site shares ONE cadence definition with the verify path (no second source of truth).
func (*Gate) MaybeProduce ¶ added in v1.31.0
func (g *Gate) MaybeProduce(ctx context.Context, producer Producer, cp Checkpoint) (*qcert.ConsensusCert, error)
MaybeProduce is the checkpoint producer-request site. It is nil-safe and activation-aware so the accept hook can call it unconditionally: a nil gate, dormant activation, a non-checkpoint height, or a nil producer all short- circuit to (nil, nil) — the verify-only default. When a producer IS wired and the checkpoint is live, it requests the cert; the caller gossips/stores it.
This keeps producer cadence and verify cadence on ONE definition (g.IsCheckpoint), so producer and verifier can never disagree on which heights carry certs.
func (*Gate) VerifyAccepted ¶ added in v1.31.0
func (g *Gate) VerifyAccepted(cp Checkpoint) error
VerifyAccepted is the accept-path hook and the SAFETY BOUNDARY.
- g == nil OR dormant activation => returns nil immediately. This is the default and guarantees classical Snow finality is unchanged.
- height below activation, or activation time not yet reached => nil.
- not a checkpoint height => nil (certs ride checkpoints only).
- checkpoint, activated => REQUIRE a valid cert bound to this block; FAIL CLOSED. A missing, mis-bound, or invalid cert is an error (the caller returns it from Accept, halting rather than finalizing without PQ evidence).
It is intentionally nil-safe so the proposervm hook can call vm.quasarGate.VerifyAccepted(...) unconditionally with a nil gate.
type MemCertStore ¶ added in v1.31.0
type MemCertStore struct {
// contains filtered or unexported fields
}
MemCertStore is an in-memory CertStore keyed by (chainID, height, blockID). It is the ingest sink the cert-gossip handler writes into (Put) and the gate reads from (Lookup). Safe for concurrent use.
func NewMemCertStore ¶ added in v1.31.0
func NewMemCertStore() *MemCertStore
NewMemCertStore returns an empty in-memory cert store.
func (*MemCertStore) Lookup ¶ added in v1.31.0
func (m *MemCertStore) Lookup(chainID uint32, height uint64, blockID [32]byte) (*qcert.ConsensusCert, bool)
Lookup returns the cert for the finalized position, or (nil, false).
func (*MemCertStore) Put ¶ added in v1.31.0
func (m *MemCertStore) Put(cert *qcert.ConsensusCert)
Put indexes a cert by its own (ChainID, Height, BlockHash). The ingest path MUST verify a cert before Put (verify-before-store), exactly as the gossip layer verifies before re-gossip; the gate re-verifies at the checkpoint so a store poisoned by an unverified Put still cannot finalize an invalid cert.
type Producer ¶ added in v1.31.0
type Producer interface {
Produce(ctx context.Context, subject Subject) (*qcert.ConsensusCert, error)
}
Producer is the committee cert-signing service contract (the per-validator "pulsard" committee). At a checkpoint, a producing validator calls Produce to obtain the QuasarCert over the finalized subject, then gossips it so peers can verify and store it (via a CertStore).
SCAFFOLDING — this is the seam, not the service. This milestone wires the VERIFY half (gate.go) and this interface. luxd ships with a nil Producer (verify-only): a node VERIFIES certs it receives but does not itself produce them. A nil Producer is the correct default — most of the rollout window is verify-only, and the producer is brought up before activation is forward-dated.
Implementation path for the follow-on:
- github.com/luxfi/consensus/protocol/quasar already defines the producer-side abstractions: PWitnessProducer / QWitnessProducer / ZWitnessProducer + NewWitnessSet, and ComposeDualPQEvidence. The concrete committee signer implements Producer over those.
- The signer needs the live Pulsar key share + nonce pool + offline preprocessing + one-round sign + verify-before-gossip + nonce-erase (the no-reconstruct hyperball signer), which lands with pulsar v1.7.1.
- REQUIRED CONSENSUS EXPORT: the ConsensusCert envelope + per-leg payload ENCODERS are package-private in consensus v1.29.0 (only the verifiers are exported). An external producer — and any end-to-end "valid cert verifies through the gate" test — needs those encoders exported (a small, additive consensus change). The verify path here needs no such export: it consumes a fully-formed *ConsensusCert.
type StaticValidatorSetProvider ¶ added in v1.31.0
type StaticValidatorSetProvider struct{ Set qcert.ConsensusValidatorSet }
StaticValidatorSetProvider returns the same committed set for every (chain, epoch). It is the single-era / test provider; the production provider resolves per-epoch sets from the P-Chain validator manager + KeyEra registry.
func (StaticValidatorSetProvider) ValidatorSet ¶ added in v1.31.0
func (p StaticValidatorSetProvider) ValidatorSet(_ uint32, _ uint64) (qcert.ConsensusValidatorSet, error)
ValidatorSet implements ValidatorSetProvider.
type Subject ¶ added in v1.31.0
type Subject struct {
ChainID uint32
Epoch uint64
Height uint64
Round uint32
BlockID [32]byte
StateRoot [32]byte
}
Subject is the finalized-block position a cert must certify — the producer's input at a checkpoint. Mirrors Checkpoint (the verify side) so producer and verifier bind the SAME tuple.
type ValidatorSet ¶ added in v1.31.0
type ValidatorSet struct {
// contains filtered or unexported fields
}
ValidatorSet is a concrete ConsensusValidatorSet for one epoch: the committed weighted-validator-set root plus the per-leg verification keys the cert legs verify against (the classical BLS aggregate key for the Beam leg and the Pulsar ML-DSA threshold group key for the Pulsar leg — the HYBRID_PQ pair).
Production wiring (the activation seam): in production these fields are populated from the P-Chain-pinned validator set (Root, Epoch) and the active KeyEra group keys for the epoch. That population is era/rotation-coupled and lands with the producer + KeyEra-registry wiring (see producer.go). Corona (STRICT_DUAL_PQ) and Magnetar/P3Q (POLARIS / RECOVERY) group keys + the weighted-sig-set config are populated by that same follow-on; until then this set serves the HYBRID_PQ pair and reports "no key" for the other lanes.
func NewValidatorSet ¶ added in v1.31.0
func NewValidatorSet(root [48]byte, epoch uint64, blsAggKey, pulsarGroup []byte) *ValidatorSet
NewValidatorSet builds a committed validator set for one epoch from its root and the HYBRID_PQ verification keys.
func (*ValidatorSet) ClassicalAggregateKey ¶ added in v1.31.0
func (v *ValidatorSet) ClassicalAggregateKey(scheme qcert.ClassicalScheme) ([]byte, bool)
ClassicalAggregateKey returns the classical aggregate verification key for a scheme. Serves the BLS-12-381 Beam leg.
func (*ValidatorSet) Epoch ¶ added in v1.31.0
func (v *ValidatorSet) Epoch() uint64
Epoch returns the epoch this set was committed under.
func (*ValidatorSet) Root ¶ added in v1.31.0
func (v *ValidatorSet) Root() [48]byte
Root returns the 48-byte weighted-validator-set commitment.
func (*ValidatorSet) ThresholdGroupKey ¶ added in v1.31.0
func (v *ValidatorSet) ThresholdGroupKey(kind qcert.LegKind) (qcert.ThresholdGroupKey, bool)
ThresholdGroupKey returns the threshold-signature group public key for a leg kind. Serves the Pulsar (ML-DSA) lane; reports (zero, false) for the others until their group keys are wired by the follow-on.
func (*ValidatorSet) WeightedConfig ¶ added in v1.31.0
func (v *ValidatorSet) WeightedConfig() qcert.QuorumVerifierConfig
WeightedConfig returns the QuorumVerifierConfig for the WeightedSigSet evidence mode. HYBRID_PQ does not use weighted-sig-set legs; the zero config is correct here and is populated by the POLARIS / RECOVERY follow-on.
func (*ValidatorSet) WeightedEnvelope ¶ added in v1.31.0
func (v *ValidatorSet) WeightedEnvelope() qcert.QuorumMessageEnvelope
WeightedEnvelope returns the round-digest posture axes for the inner WeightedQuorumCert. Zero for HYBRID_PQ (no weighted-sig-set leg); populated by the POLARIS / RECOVERY follow-on.
type ValidatorSetProvider ¶ added in v1.31.0
type ValidatorSetProvider interface {
ValidatorSet(chainID uint32, epoch uint64) (qcert.ConsensusValidatorSet, error)
}
ValidatorSetProvider resolves the committed validator set the verifier pins a cert against, for a (chain, epoch). Post-activation the gate calls this once per verified checkpoint.