mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
Reading both floors over the signers let a set shrink to its signers, and a rung whose floors are read over n is satisfiable at every n. TwoThirdsCount(1) is 1, so one signature over a one-signer set clears the count floor and the stake floor together and mints export finality. Byzantine tolerance is f = ⌊(n−1)/3⌋, which is ZERO for n of one, two and three: such a certificate absorbs no fault at all, and one compromised key among its signers forges it outright. So the export rung refuses a signing set below minBFTCommittee — the same constant bftCommittee floors committee SELECTION at, read at the certificate instead of at the sampler, and reused rather than restated. It is a floor on the SET, stated beside the n<1 refusal because neither quorum floor implies it: both are read over n and both shrink with it. Nova has no such clause and must not grow one — it authorizes local execution the chain can still reorg away, so a small or partitioned chain has to be able to make progress. A three-validator chain now PRODUCES and never CERTIFIES; operators need n ≥ 4 to export with any fault tolerance. Rust mirrors it as CertError::MinCommittee, which the corpus vocabulary folds into Go's one belowThreshold class. The transcription guard was reading the wrong denominator. verdict_test computed n as len(c.Set), the membership ROLL, so a floor moved onto the roll would agree with the guard and be re-blessed by -update — the second line of defence agreeing with the regression it exists to catch. It now counts the seats that hold a key, on the Quasar branch and the Nova one, and transcribes the committee floor as a search for the least n whose fault budget reaches one rather than as the constant. Proven by construction: with the corpus source reporting the roll as its signer count and the golden re-blessed, the old guard passes and the new one fails. The corpus could not have caught it either. quasar_keyless_third had three signers on a roll of four, and ⌊2·3/3⌋+1 and ⌊2·4/3⌋+1 are both three, so its count half was vacuous. Two rows now separate the denominators one at a time: quasar_keyless_stake (six signers, a seventh member holding a third of the roll — the count floor is five either way, so only stake decides) and quasar_keyless_count (four signers, two members holding one unit each — the stake clears under either reading, so only the count decides). TestKeylessRowsBind- BothDenominators fails if either is lost or flattened. quasar_keyless_third itself FLIPS to a refusal, and it is the row that states the new clause: the recorded stake floor is 200 over the three hundred that can sign and not 333 over the five hundred the chain carries, so the denominator IS the signers — and the certificate is refused anyway, on neither quorum floor. Reading the floors over the signers stops a spectator stranding a chain; it is not a way for a chain with three signers to export. Every other frozen verdict is byte-identical, and the admission section and the signed vectors are untouched. StakeSource gains CarriedStake, and no floor may read it. SignerStake alone decides a certificate correctly and cannot show the set shrinking underneath one: a chain whose signable stake has fallen to a sliver of what it carries still certifies at ⅔ of the sliver, and ResponsiveStakePct — voted over signer — stays at one the whole way down. FinalityStatus.SignerStakePct is the number that falls, and the one to alarm on. Rust has carried(), C++ has total_stake(); Go had lost the projection when the denominator moved. Co-authored-by: Hanzo Dev <[email protected]>
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.