Files
consensus/pkg/rust
zeekay 667bbb4023 vote: carry the vote plane here, and hold it to the certificate's floors
`lux-rs/consensus` is a filtered extraction of this crate that grew two
modules this one never had — a vote on the wire, and the ZAP frame it
travels under. Rust had no reader for that frame at all, so the Rust lane
could not carry a consensus vote between validators; the extraction could,
and that is the only reason it still exists. It is also a second crate
answering the name `lux-consensus`, which is one implementation too many.

So the two modules come here, where the rule they need already lives.

They are not copied. The extraction predates proof of possession and the
export rung's floors, and its `Tally` issued a certificate the moment a
caller-declared count was reached — a threshold anyone could declare and
nobody had to earn. Rewritten against this crate: `NodeId` and the proof
path from `pop`, `ValidatorSet` for who may be counted at all, and
`QuorumCert::verify_weighted` for whether the votes amount to anything.

`Tally::cert` is the only door out of a tally and it runs the whole
predicate — the stake supermajority, the distinct-signer count, and the
minimum Byzantine committee, every one recomputed from the live set. A
tally can no more declare its own quorum than a certificate can. That is
`a_tally_cannot_declare_its_own_quorum`: one valid signature, a declared
threshold of one, a set of seven, and no certificate.

One tally reads one epoch. The height is fixed when it opens and both the
signature check and the stake read use it, so a tally cannot verify against
one set and weigh against another.

`VoteError` spells only what the vote plane owns — the wire, the position,
the accept bit, the signature — and carries every certificate clause as the
`CertError` `cert` already names, so a refusal has one vocabulary.

The frame's constants are pinned against the two lanes that must read it:
`luxfi/api/zap` writes a 4-byte big-endian length, a type byte, and the
payload, with `WriteBytes` prefixing a field the same way; `luxcpp/zap`
matches. Go names no type mask and open-codes the strip, so
`strip_flags_is_gos_own_expression` proves the named one is that expression
over every byte.

62 is free in the Go registry, which spells 60 and 61 of the Quasar block.
It is NOT free everywhere — `mpc/pkg/transport` extends the same frame with
its own 60..69 — and the constant says so rather than claiming a clean id
space this end cannot give.

Public API addition, so 1.22.7.
2026-09-01 23:29:07 -07:00
..

lux-consensus

Pure-Rust SDK for the Lux Quasar consensus stack — Wave threshold voting, FPC (Fast Probabilistic Consensus), Photon validator sampling, Focus confidence accumulation, and post-quantum hybrid finality via BLS12-381 + Pulsar (Module-LWE threshold, FIPS 204 byte-equal).

Features

Flag What it pulls in
default CPU-only, no extra deps beyond blst and hex
simd blake3 (SIMD hashing) + rayon (data-parallel vote tally)
mlx Apple Silicon GPU acceleration via mlx-sys (implies simd)
cuda NVIDIA GPU acceleration (implies simd) — work in progress
gpu mlx + cuda — auto-select per platform

Usage

use lux_consensus::*;

let config = QuasarConfig::mainnet();
let mut engine = QuasarEngine::new(config);
engine.start().unwrap();

let block = Block::new(
    ID::from([1u8; 32]),
    ID::from([0u8; 32]),
    1,
    b"Hello, Lux!".to_vec(),
);
engine.add(block.clone()).unwrap();

// A validator is named by its 20-byte NodeID — never the 32-byte block id.
for i in 0..20 {
    engine.add_validator(NodeID::from([i; 20]), 1).unwrap();
}

for i in 0..20 {
    let vote = Vote::new(block.id.clone(), VoteType::Preference, NodeID::from([i; 20]));
    engine.record_vote(vote).unwrap();
}

assert!(engine.is_accepted(&block.id));
engine.stop().unwrap();

Architecture

  • Wave — adaptive-threshold voting driven by FPC outputs
  • FPC — PRF-derived per-round thresholds for fast probabilistic consensus
  • Photon — luminance-tracked validator sampling
  • Focus — β consecutive rounds of confidence before commit
  • Quasar — a two-thirds-by-stake certificate: the distinct signed accepts themselves, each checked against its own signer's key

License

Lux Ecosystem License 1.2 — see the LICENSE file.