Move the consensus Quasar PQ integration to the dealerless threshold-signature
stack (RSS keygen + no-reconstruct signing + dealer ripped). Refresh the
re-tagged luxfi/pq v1.0.3 go.sum entry.
Fix a latent bug the bump exposed: ValidateMithrilSigningCommittee documented +
tested an N<=6 consensus small-committee cap but only called rss.ValidateCommittee
to enforce it. rss loosened its gate from a hard N<=6 to the norm bound
(tau*C*eta < gamma2, up to N<=63) at dkg v0.3.4+, so (2,7) — norm-viable — began
passing and the consensus policy cap silently vanished. Restored the explicit
N<=MithrilMaxCommittee cap (layered before the rss crypto bound), preserving the
small-committee security design (Avalanche subsampling carries chain safety;
Pulsar emits compact PQ evidence). Quasar suite green.
Adds REAL go test -bench measurements (M1 Max) of VERIFY latency, cert
SIZE, and SIGN cost for every Quasar finality lane, composed into the five
named policy tiers (BLS_FAST .. POLARIS_MAX). Drives the operator policy-tier
+ deployment decision with data, not estimates.
- bench_pq_policy_tiers_test.go: per-lane verify/sign sub-benchmarks over the
PRODUCTION verify functions and real crypto (Beam BLS, Pulsar TALUS compact,
Pulsar sampled r-of-m, Corona Ring-LWE, Magnetar-Quorum N SLH-DSA, P3Q direct
N ML-DSA) + a composed-tier summary table (verify ns, cert bytes, x-overhead
vs BLS) printed via fmt.Printf (go test truncates large b.Log in benchmarks).
- Widen 8 shared real-key test harness helpers from *testing.T to testing.TB
(the canonical Go idiom) so benchmarks reuse the exact production cert
builders; strict interface widening, zero behaviour/caller change.
No production code touched; test/bench-only. Suites green except the
pre-existing flaky quantum-bundle threshold tests (a different one fails each
run on clean main too).
Proves the Track-A claim end to end with real SLH-DSA-192s keys:
- independent FIPS-205 sigs -> MagnetarQuorumCert -> VerifyMagnetarQuorum
accepts (standalone + leg + full VerifyConsensusCert envelope);
- each inner record verifies under the STOCK FIPS-205 verifier (magnetar
VerifyCtx over circl/slhdsa) with no Lux machinery — the trustless,
independently-auditable wire-identity claim;
- tamper (flipped sig, re-committed), sub-threshold, and root-mismatch are
hard rejects; the BFT floor is the verifier's, not the cert's;
- cross-family diversity: an ML-DSA cert set is refused at BOTH build and
verify (ErrMagnetarNotHashBased) — a Module-LWE break can't satisfy the
hash-based leg;
- the STARK succinct seam fails closed (ErrMagnetarBackendNotAuditGated);
- suite dispatch can't cross lanes (P3Q suite rejected), hit an unknown
suite, downgrade the param set, or land on the wrong leg kind;
- POLARIS_HASH_PQ / POLARIS_MAX require the right legs and admit Magnetar
ONLY as the trustless rollup, NEVER a threshold sig;
- structural no-dealer/no-shared-secret: disjoint committees with fully
independent keypairs each verify; no shared public key anywhere.
All 16 green (53s).
Two new finality postures wiring the hash-based diversity lane:
POLARIS_HASH_PQ = Beam ∧ Pulsar ∧ Magnetar-Quorum
POLARIS_MAX = Beam ∧ Pulsar ∧ Corona ∧ Magnetar-Quorum
(Module-LWE ∥ Ring-LWE ∥ hash-based diversity)
The Magnetar leg is admitted ONLY as the trustless EvidenceMagnetarRollup
(independent per-validator FIPS-205 sigs; no dealer/DKG/shared secret), ONLY
under the policy's SLH-DSA param. Magnetar-Threshold (THBS-SE reveal-and-
aggregate, a signing-time TCB) is structurally excluded: SLH-DSA may not be
proven by a threshold-sig mode (I7), and no SLH-DSA threshold-sig mode exists.
POLARIS_MAX also extends the Corona allow-gate (previously STRICT-only).
- magnetarParam field (default SLH-DSA-192s) + WithMagnetarParam override.
- RequiredLegs / Allows updated for both postures; Pulsar required as the
compact threshold sig (the '∧ Pulsar'), Magnetar as the rollup.
Full quasar suite green (172s).
The Magnetar-Quorum relation: prove a >= policy-threshold WEIGHTED quorum of
INDEPENDENT validator SLH-DSA signatures each verify under stock FIPS-205 over
the same consensus subject M, every signer a committed validator-set member.
- VerifyMagnetarQuorum(policy, validators, cert, M, mc) — the standalone
public verifier the directive names; VerifyMagnetarQuorumLeg is the
LegEvidence dispatch form, wired into dispatchEvidence (EvidenceMagnetarRollup).
- Direct path (live today, trustless transparent aggregation): bind rollup
root -> raw SLH-DSA cert set; enforce the cross-family diversity invariant
(every inner record is SLH-DSA / FIPS-205, ErrMagnetarNotHashBased); then
COMPOSE the audited VerifyWeightedSigSet (N stock FIPS-205 verifies +
weighted-Merkle validator-set binding + BFT threshold floor + envelope
position). No dealer / DKG / shared secret — structurally independent keys.
- STARK path (AssumptionPQSuccinct): the OPTIMIZATION SEAM. Pin the public
statement so an audited backend can only ever attest THIS relation, then
FAIL CLOSED (ErrMagnetarBackendNotAuditGated) — the raw set stays
challengeable via Direct. Succinctness makes the lane compact, not more
trustless. No classical-assumption path for a hash-based lane.
The full SLH-DSA-verify STARK circuit is deferred; the trustless lane is the
Direct transparent-aggregation path, with the p3q-succinct proof clearly
labelled as the follow-on compaction (still trustless — no dealer/shared-secret).
Magnetar-Quorum (Track A) is the trustless-TODAY hash-based PQ finality lane:
validators hold INDEPENDENT ordinary FIPS-205 SLH-DSA keypairs (no DKG, no
dealer, no shared seed) and sign the same consensus subject; a P3Q rollup
proves a >= policy-threshold WEIGHTED quorum of those independent signatures
verified under the STOCK FIPS-205 verifier. It sidesteps threshold SLH-DSA
entirely — trustless the moment the rollup relation is sound.
This commit adds the value-level vocabulary and the wire type:
- MagnetarQuorumCert{SuiteID, RollupRoot, CertSet, Proof} + deterministic,
fail-closed codec (magnetar_codec.go), mirroring the P3Q ML-DSA pattern.
- MagnetarRollupRoot + magnetarPublicStatement domain-separated commitments.
- BuildMagnetarQuorumCert (Direct constructor) enforcing the cross-family
diversity invariant: every signer record must be SLH-DSA (FIPS-205).
- EvidenceMagnetarRollup evidence mode (own primitive, not bolted onto Pulsar).
- EvidenceMagnetarP3QSLHDSARollup kind 'magnetar-p3q-slhdsa-rollup' + lane
mapping to (LegMagnetarSLHDSA, EvidenceMagnetarRollup).
- Suites Lux-Magnetar-SLHDSA{192s,256s}-Direct-v1 + -192s-STARK-v1 (succinct
seam). NO classical-assumption suite — a hash-based diversity lane must
never rest on a pairing.
Composes the audited, scheme-generic WeightedQuorumCert (which already
dispatches SLH-DSA records to stock magnetar.VerifyCtx); verifier wired next.
Composable lane-verifier closures mapped onto the existing Quasar
evidence-mode table:
FAST = Beam only -> PolicyBLSFast
HYBRID_PQ = Beam AND VerifyPulsarSampled -> PolicyHybridPQCheckpoint (DEFAULT)
PQ_ROOT = P3Q >=2/3 weighted ML-DSA(+Beam)-> PolicyRecoveryMode
The policy owns ONLY the tier->required-lane AND structure; it constructs
no M and re-implements no Beam/P3Q. Each lane is a fully-bound closure the
caller wires (PulsarSampledLane adapts VerifyPulsarSampled). Fail-closed:
a missing required lane is ErrTierLaneMissing, never an implicit pass; the
first failing lane's error surfaces unchanged so errors.Is sees the
underlying cause. 8 tests incl. real end-to-end propagation of
ErrSampledPlanMismatch / ErrInsufficientCommittees through the tier.
Trust-minimised by re-derivation: the verifier re-derives the committee
plan from the unbiasable seed (so a cert naming an unsampled committee is
rejected) and re-derives the subject M from that plan's committeePlanHash
(so a cert whose committees signed any other M is rejected). The six
checks: (a) committeePlanHash bound into the re-derived M; (b) every
counted committee InPlan; (c) each a dealerless Mithril key-era (mode +
(t,n) + PubKeyHash binding the resolved key); (d) each sig stock-verifies
via verifyPulsarLeg (pulsarwire.VerifyBytes, unmodified FIPS-204) over M;
(e) >= r DISTINCT independent committees; (f) all over the same M.
Per-committee failures are EXCLUSIONS (offline-like) not whole-cert
errors — the r-of-m model tolerates up to m-r. CommitteeKeyResolver is
the one trusted input (registry of dealerless-DKG-activated keys); the
cert binds itself to its exact key bytes. 15 tests: positive + full-m +
r-of-m boundary + liveness slack + adversarial battery (out-of-plan,
wrong-M, non-dealerless, pubkeyhash mismatch, wrong (t,n), duplicates,
structural rejects, nil guards, wrong finality position).
The one canonical subject every r-of-m sampled Mithril committee signs.
Binds the finalized position (chainID/height/round/blockID/stateRoot),
the Beam QC over that block (beamQCHash, non-transferable across QCs),
the P-Chain-pinned signer set (signerSetID/pChainHeight), the policy
posture, and the frozen committeePlanHash — so committees are
un-reselectable after the block is seen. Distinct subject domain
('Lux/PulsarSampledSubject/v1') makes a sampled-committee signature
non-transferable vs the envelope single-committee Pulsar leg. Full
field-binding + non-transferability tests.
Deterministic, verifiable stake-weighted committee selection from an
UNBIASABLE seed (hash of already-final consensus state, never a
proposer-grindable value), with the committeePlanHash that commits the
entire sampling plan for binding into the finality subject M. m=12
committees of n=8 stake-weighted-without-replacement members each
(Pulsar-HYBRID-PQ-v1), SHAKE256 DRBG with rejection-sampled unbiased
draws. Fail-closed params + tests (determinism, unbiasable-inputs-change-
plan, distinctness, stake-proportionality, fail-closed).
The ML-DSA analogue of Avalanche's repeated-small-sample path: r-of-m
dealerless Mithril committees each sign the SAME finalized subject M;
post-quantum confidence is committee-capture probability accumulated over
repetition r (~p^r), NOT one committee as a finality quorum. Compact: r~8-16
ordinary FIPS-204 signatures, never 1000+. Cert value types only -- sortition,
subject, verify, policy decomplected into sibling files.
The dealerless RSS Pulsar (ML-DSA) leg is only stock-FIPS-204-signable for a
small committee (C(N,N-T+1) replicated shares grow combinatorially). Adds the
consensus-side bound — delegated to luxfi/dkg v0.3.0 rss.ValidateCommittee for
ONE definition — plus ClampMithrilCommitteeSize and the grouped-epoch sortition
cap, with the full security argument: consensus quorum != signing committee, so
broad security comes from Avalanche subsampling + rotating committees + 2/3
group quorum + dual-PQ AND-mode, never from committee size. Default group size
(3) already complies; the cap only constrains over-large configs. quasar suite
green (77s).
NOTE: pre-existing luxfi/[email protected] go.sum mismatch (force-moved tag) breaks the
whole-repo 'go build ./...' on main independent of this change (proven on clean
HEAD); the quasar package and its full test suite are green.
pulsar v1.2.0 removes the small-committee threshold-signer surface
(NewThresholdSigner / ThresholdSigner / Round1Message / Round2Message /
Combine) in favour of the TALUS no-reconstruct BCC/CEF path. The Pulsar
leg of a Quasar cert verifies under the UNMODIFIED FIPS-204 verifier, so
a single-key signature under the group key is valid leg evidence — no
DKG, no ceremony is needed to GENERATE valid leg bytes for a
cert-composition test.
Replace signPulsarThresholdLeg (deleted threshold ceremony) with
signPulsarLegStock: GenerateKey + Sign via threshold/protocols/pulsar's
stock single-key path, returning the same *pulsar.Signature /
*pulsar.PublicKey alias types that ComposePolaris and
pulsarGroupPK.MarshalBinary already consume. The negative tests
(removed / tampered / missing-key Pulsar leg) still reject, so the leg
bytes remain load-bearing, not a stub.
Corona keygen (threshold/protocols/corona.GenerateKeys) is unchanged —
the trusted-dealer fixture name survives in the threshold corona adapter,
so no rename was needed in these consensus tests.
Production build unaffected (0 non-test refs to the removed APIs).
go test ./protocol/quasar/... ./protocol/auth/... ./config/... green;
go vet ./protocol/quasar/ clean.
The compact group-key era was named for a place (Pulsar) when it is a
generic value serving every threshold lane, scheme-qualified. Drop the
Pulsar prefix and generalise the verifier so ONE type + ONE entry point
covers both the Pulsar (FIPS-204 ML-DSA) and Corona (Ring-LWE Ringtail)
lanes. Pure decomplect: same behaviour, value-not-place naming.
- Type: PulsarKeyEra -> KeyEra (file pulsar_key_era.go -> key_era.go)
- Field: MLDSAPubKey []byte -> GroupPubKey []byte (scheme-interpreted via
SchemeID; not ML-DSA-specific). The unrelated Validator.MLDSAPubKey
(*mldsa.PublicKey, a per-validator identity key) is left untouched.
- Registry: PulsarKeyEraRegistry -> KeyEraRegistry (lane-agnostic; holds
Pulsar and Corona eras alike), NewPulsarKeyEraRegistry -> NewKeyEraRegistry.
Generalised verifier dispatch:
- VerifyThresholdLeg(ev, M, era) is the ONE compact-threshold verify entry
point. It resolves the era's lane through the suite registry
(era.eraSuite, Pulsar|Corona only) and routes the group-signature check
to that lane's boring verifier: pulsarwire.VerifyBytes for Pulsar,
coronaThreshold.Verify for Corona (via new verifyCoronaGroupKeyLeg, which
decodes the era's wire-byte group key and reuses verifyCoronaLeg). Both
the era scheme and the evidence suite are resolved through the registry
and must name the SAME lane + param set, so no suite string can reach the
wrong verifier (reuses LookupSuite/resolveSuiteForLane lane safety).
- VerifyPulsar is retained as a thin Pulsar-suite wrapper that refuses any
non-Pulsar era at the door, then defers to VerifyThresholdLeg.
Tests: existing boring-verifier + suite-dispatch-safety (VerifyPulsar) and
dualpq tests hold unchanged; KeyEra registry test now proves lane-agnostic
acceptance (corona era registers, non-threshold Beam refused); new
TestCompact_VerifyThresholdLeg_CoronaLane proves a corona-suite era
verifies via the corona path through the same KeyEra/dispatch with a real
multi-node Ring-LWE signature, and that a pulsar suite can never reach the
corona verifier.
GOWORK=off go build ./... green; go test ./protocol/quasar/ green.
SECURITY FIX (self-review): the first P3Q direct verifier checked N ML-DSA
signatures and summed their CLAIMED weights but never bound the (validatorID,
pubkey, weight) leaves to the committed validator set — a zero-stake attacker
could forge a rollup of fresh keys with threshold weight and pass.
The 'MLDSACertSet' (independent per-validator ML-DSA certs + weighted quorum) IS
the existing WeightedQuorumCert (EvidenceWeightedSigSet), already bound to
validators.Root() via weighted-Merkle membership. P3Q now COMPOSES it: the
Direct path = rollup-root commitment over the marshalled WeightedQuorumCert,
then the audited validator-set-bound weighted-sig-set verify (membership + N
FIPS-204 verifies + threshold floor). No reinvented per-leaf verification, no
gap. Succinct STARK/Groth16 paths unchanged (audit-gated; classical caveat).
Also trim 4 unused speculative helpers (LaneFor + three IsPostQuantum methods) —
the suite registry is the single mapping authority.
Tests reworked to wrap a real fourMLDSA WeightedQuorumCert; sub-threshold and
corrupt-cert-set cases now prove the inner validator-set-bound verify runs.
- STRICT_QUASAR (Beam ∧ Pulsar ∧ Corona) over one M verifies with real BLS
aggregate + FIPS-204 ML-DSA + multi-node Ring-LWE threshold; missing Corona
rejects (AND-mode).
- Policy table enforced: BLS_FAST Beam-only; HYBRID accepts Pulsar OR P3Q;
RECOVERY accepts P3Q and REFUSES the Pulsar threshold mode; STRICT refuses
the P3Q mode.
- COMPACTNESS: Beam aggregate size invariant under committee growth; compact
checkpoint footprint is O(1) and 957x smaller than the naive O(N) 1000-raw-
ML-DSA-cert object at N=1000 (3466 B vs 3.32 MB).
- Boring VerifyPulsar + suite dispatch safety: wrong-era / suite-mismatch /
cross-lane suite / unknown suite / corrupt-sig / replayed-M each reject with
a distinct typed error; exhaustive suite-registry lane invariant; no suite
string reaches the wrong verifier.
- P3Q fallback: Direct path verifies a rollup root and rejects a tampered root,
a corrupt leaf, and sub-threshold weight; STARK gated; Groth16 refused unless
the policy opts into classical proof assumptions (then still backend-gated).
- PulsarKeyEra registry register/lookup/conflict; one-M property
(QuasarFinalityMessage == consensusCertMessage).
Four typed compact evidence kinds, a PulsarKeyEra registry + deliberately
boring VerifyPulsar, the named policy table (BLS_FAST / HYBRID_PQ_CHECKPOINT /
STRICT_QUASAR / RECOVERY_MODE), and the P3Q ML-DSA-rollup fallback leg — all
layered on the existing decomplected ConsensusCert envelope (LegKind x
EvidenceMode orthogonal axes), reusing not rewriting.
- compact_evidence.go : EvidenceKind vocabulary (beam-bls / pulsar-threshold-
mldsa / corona-ringtail / p3q-mldsa-rollup) + lane mapping + the suite-ID ->
verifier dispatch registry. No suite string can reach the wrong verifier;
suites carry the param set (ML-DSA-44/65/87).
- pulsar_key_era.go : PulsarKeyEra (one compact ML-DSA group key per validator-
set era) + VerifyPulsar (boring: normal FIPS-204 verify under the era key) +
the era registry. Production trust model (talus/ceremony/tee) is audit-only,
orthogonal to verification.
- quasar_finality.go : the ONE canonical finality message M; consensusCertMessage
now delegates to it, so all lanes provably sign byte-identical M.
- p3q_rollup.go / p3q_codec.go : the P3Q fallback as its own primitive (own
mode/verifier/codec). Direct path re-verifies the raw MLDSACertSet (PQ-safe,
O(N), challengeable); succinct STARK/Groth16 paths audit-gated; classical
proof assumption enforced via policy opt-in.
- cert_policy_table.go : the four postures; the Pulsar-OR-P3Q is a MODE gate on
one required leg KIND.
- consensus_cert.go : KeyEraID + StateRoot bound into M; EvidenceP3QRollup mode
wired into dispatch.
Beam/Pulsar/Corona stay O(1) (one sig each); P3Q is fallback only. Raw
1000-cert-sets are never the normal finality object.
Add the canonical parallel post-quantum finality posture: every cert carries
a Pulsar (Module-LWE / FIPS-204 ML-DSA) leg AND a Corona (Ring-LWE, dealerless)
leg, in parallel, AND-mode (both required to finalize). Security is the safest
surviving leg: an adversary must break BOTH the Module-LWE leg and the Ring-LWE
leg in the same round (orthogonal hardness, conjunctive acceptance).
dualpq.go (production):
- DualPQRequiredLegs(paramSet): the canonical {Pulsar, Corona} AND-mode
required-leg set (matches config CertModeStrict+CertVariantStrict).
- ComposeDualPQEvidence(...): pure-function composition of the two
threshold-sig leg evidences from a real Corona threshold signature + a
real Pulsar FIPS-204 signature over the same envelope message. Composition
over inheritance — wraps each primitive's output, extends neither.
consensus_cert_dualpq_test.go (multi-node proof):
- Corona leg: genuine multi-node two-round t-of-n threshold ceremony — N
separate single-share Signers, Round1/Round2 over an explicit message bus,
aggregated by one node from Round2 DATA (never shares).
- Pulsar leg: real FIPS-204 ML-DSA-65 signature accepted byte-for-byte by
the on-chain verifier (verifyPulsarLeg -> pulsarwire.VerifyBytes).
- Proves: AND-mode (both legs required + verify), sub-quorum on EITHER leg
fails finality, corrupt either leg fails, composer refuses a half cert.
- Single-share invariant: compile-time witness that the only Corona signing
constructor takes EXACTLY ONE *KeyShare; aggregator takes Round2 DATA.
Permissionless-safe today via the dealerless Corona leg in AND-mode; the
Pulsar leg's no-reconstruct t-of-n threshold production is documented as
blocked on a poly-vector secret-share type (ML-DSA s1 is non-linear in the
GF(257) seed-share) — see luxfi/pulsar BLOCKERS.md PULSAR-V12-PARALLEL-PQ.
No fakes: the Pulsar leg signature is a real FIPS-204 group-key signature,
not a claimed threshold ceremony.
Add scripts/no-trusted-dealer-guard.sh: greps non-test .go in the consensus
tree for NewTrustedDealer / func GenerateKeys / GenerateDualKeys /
GenerateThresholdKeys / GenerateDualThresholdKeys and exits non-zero if any
land in production code. Wired as a prerequisite of `make test` and
`make security` so the regression that dropped the test-only relocation
(97b2dfe7c) on a merge cannot silently return.
Also delete the stale polaris.go comment "Produced by the
pulsar.ThresholdSigner ceremony" — that v0.1 reconstruct-then-sign Combine
path was ripped; the leg is filled by the corrected lattice kernel.
GenerateDualKeys / GenerateThresholdKeys / GenerateDualThresholdKeys sampled
the full secret in one process (BLS NewTrustedDealer + coronaThreshold.
GenerateKeys) — a trusted-dealer keygen sitting in non-test code (quasar.go).
Every real caller is a package-quasar _test.go (dual_threshold, cert_size,
triple_sign, cert_roundtrip, witness_fixtures, comprehensive); none is
production.
Production epoch/genesis keying already runs the dealerless Pedersen DKG via
keyera.Bootstrap (EpochManager.InitializeEpoch, epoch.go) — unchanged. Moved
the three helpers verbatim into keygen_testsupport_test.go (package quasar) so
NO non-test code in the consensus engine can route keying through a trusted
dealer. Pairs with the wave_signer deletion (5fe753c42): consensus now has zero
non-test reconstruct-then-sign and zero non-test trusted-dealer keygen.
Verified: GOWORK=off go build ./... exit 0; go vet clean; gofmt clean;
go test ./protocol/quasar/ (Dual/Triple/Cert/Witness) ok.
(cherry picked from commit 97b2dfe7ceac24404395c9c2fdb08bc91fc39572)
RoundSigner/RunRound in protocol/quasar/wave_signer.go had ZERO non-test
callers. It was a thin per-round adapter wrapping the pulsar v0.1
reconstruct-then-sign ceremony; consensus's real PQ-threshold signing
lane is corona (epoch.go), and the cert's pulsar leg is verify-only on
the live path. Deleting it removes consensus's only live invocation of
pulsar's reconstruct-then-sign (Combine) path.
- Delete wave_signer.go + wave_signer_test.go.
- cert_policy_verify_test.go / polaris_compose_test.go: the Pulsar leg
in these cert-composition tests was produced by RoundSigner. Replace
with a test-only ceremony helper (pulsar_leg_test.go) that runs the
same canonical t-of-n ceremony directly over the DKG outputs the tests
already build — the leg stays a real threshold signature (no stub),
verifying under unmodified FIPS 204 ML-DSA via pulsar.VerifyCtx.
- Drop now-unused ids/prism/context imports from both tests.
Verified: GOWORK=off go build ./protocol/quasar green; cert-composition
+ policy tests pass (real ceremony exercised); full -short suite green.
corona v0.7.9 (commit 7c102d2, a descendant of the old single-return
4d9334ee) re-added the error return on Signer.Round1 as kernel-boundary
hardening on SignRound1. consensus quasar still called it single-value
(with now-stale 'error return was removed upstream' comments), so node
v1.30.40 failed to compile: 'assignment mismatch: 1 variable but Round1
returns 2 values' at epoch.go:679/1052, grouped_threshold.go:510,
quasar.go:269. Thread the error through all four production sites
(enclosing funcs already return error) and the 11 quasar test sites.
Forward-only fix; corona v0.7.9 is the intended current API.
The chain engine pins a block's weighted validator set to a P-CHAIN epoch
height: the set-root commitment, the 2/3-by-stake tally, AND per-voter pubkey
resolution all read the height-indexed validators.State at that ONE height
(MEDIUM-1/CRITICAL-1/RESIDUAL-B). The height is captured off the VM block at the
engine boundary (pChainHeightOf) into Block.pChainHeight, read back by
epochHeightLocked, and stamped into every VotePosition's set-root. When a block
exposes no PChainHeight the read falls back to height 0 (genesis set): non-empty,
identical on every node, <= current -> finality stays LIVE. The node-layer
wrapper (separate repo) delivers the REAL height so post-genesis staking-change
epochs track the LIVE set.
VerifyVote/Weight/TotalStake/ValidatorSetRoot now all take epochHeight so the
four reads share one height; the engine threads it from the block.
Adds exported TrackOwnProposalForTest: a cross-module test seam (the node b2 test
lives in another module) that inserts a verified own-proposal exactly as
buildBlocksLocked does and returns the bound position. It captures pChainHeightOf
off the supplied VM block and NEVER force-finalizes -> the real alpha-of-K cert
path is exercised end to end.
TDD: quorum_pchain_epoch_finality_test.go proves (A) a 2/3-stake epoch quorum
finalizes through the real source path, (B) the engine reads the set at the
P-chain epoch height not the value height, (C) a validator absent from the
current map but present at the epoch still has its vote verified (RESIDUAL-B),
(D) an empty epoch fails closed. Full engine/chain + quasar suites green
(CGO_ENABLED=0).
MEDIUM (epoch binding): stake-weighted finality must be measured at the
cert-position epoch, not at verification time. Bind the active weighted
validator-set commitment into VotePosition.ValidatorSetRoot and fold it into
CanonicalVoteMessage + the wire codec, so a cert is cryptographically pinned to
the exact set it was certified under: re-presenting an epoch-E cert as
certifying under a different epoch's set fails clause-6 signature verification,
and a later stake change cannot retroactively flip an already-correct cert.
Mirrors quasar.ConsensusCert.ValidatorSetRoot. New optional ValidatorSetRootSource
(WithValidatorSetRoot / NetworkConfig.ValidatorSetRoot), stamped in
blockPositionLocked; nil source => ids.Empty => behavior identical to before
(backward-safe for fixed-set chains). QuorumCertVersion bumped 1->2 so a
mixed-version cert fails loudly (version + signature) rather than mis-parsing —
a deliberate forward-only break (the set upgrades together in one cascade).
TDD: TestEpochBinding_{CrossEpochCertRejected,StakeReadAtCertHeight,RoundTripPreservesRoot}
(proven to fail without the canonical-message binding).
INFO-2 (SyncState monotonic guard): ChainConsensus.SyncState bypasses
markFinalizedLocked by design (import is an out-of-band reconcile), so the
monotonic invariant is re-asserted explicitly — a backward import (height below
the already-finalized height) is refused (ErrSyncStateRegression) and leaves
finalized state untouched; an equal-height re-import must agree on the block;
forward + empty-reset still succeed. SyncState now returns error; the sole caller
(Transitive.SyncState) propagates it and does NOT partially mutate on refusal.
TDD: TestSyncState_{RefusesBackwardRegression,EqualHeightDifferentBlockRefused,
ForwardImportAdvances,EmptyResetAllowed} (proven to fail without the guard).
INFO-3 (BFT message): ErrKTooLowForMainnet/Testnet now state the real bound
(2*AlphaPreference-K >= floor((K-1)/3)+1 with f>=3 / f>=1) instead of a bare
"K>=11" magic number. Sentinel-based assertions unaffected.
INFO-1 (dead code): delete the VerkleWitness apparatus (witness.go + its tests +
the VerkleWitness funcs in comprehensive_test.go + the verifyIPAOpening test) —
zero non-test callers; verifyBLSAggregate was a deserialize-only (no-pairing)
forgery sink if ever revived. The live deserialization path that matters is
crypto/bls.SignatureFromBytes (fixed + tested in the crypto module);
TestVerifyBLSAggregate_C1_ActualDeserialization was proven green in CGO_ENABLED=0
against the crypto fix BEFORE this deletion removed it.
pulsar v1.1.1->v1.1.5, magnetar v1.2.0->v1.2.3, threshold v1.9.4->v1.9.9,
corona v0.7.6->v0.7.9 (indirect). The ConsensusCert envelope + all legs now
verify against the just-finalized PQ crypto. corona/threshold.Round1 added an
error return; adapted 4 production + 12 test call sites. quasar suite ok, gate PASS.
The QuasarCert verifier made BLS mandatory and PQ legs optional/
cert-byte-driven: a CRQC that broke BLS-12-381 could ship a BLS-only
cert (omit every PQ leg) and verify true, while a legitimate pure-PQ
(no-BLS) cert was wrongly rejected. config.CertPolicy.RequiredLegs()
(the canonical leg-set authority) had zero production callers.
Wire it in:
- New cert_policy_verify.go: VerifyUnderPolicy(message, CertPolicy, CertKeys)
is the canonical verifier. For every leg in RequiredLegs() it rejects
unless the leg is BOTH present in the cert AND backed by a supplied key,
BEFORE any signature math — leg presence is policy-driven, not
attacker-controlled cert bytes. BLS is required iff the policy includes
it (Variant=Hybrid); a Strict-variant policy yields a pure-PQ required
set so a no-BLS cert verifies. Identity rollup is required under any PQ
policy (downgrade-resistant), present-implies-verify otherwise.
- Decomplect leg crypto into verify{BLS,Corona,Magnetar,MLDSARollup}Leg
helpers; VerifyWithRealKeys / VerifyWithRealKeysPolaris reimplemented on
them with the BLS-mandatory bug fixed (BLS required iff key supplied;
pure-PQ allowed; each PQ leg required iff its key supplied — an adversary
cannot strip a leg the verifier was configured to check).
- Migrate callers to policy intent: engine/pq gains SetCertPolicy +
policy-driven verify path; pkg/wire QuantumPolicy enforces requireRT
(Corona key mandatory) when set.
Tests (real crypto, no stubs): leg-removal negatives for each required
leg reject; missing-key-for-required-leg rejects; pure-PQ cert verifies
under Strict-variant policy AND via VerifyWithRealKeysPolaris(nil BLS);
Red PoC (BLS-only cert + PQ keys configured) now rejected. Existing
ComposeAllThreeSchemes / cert roundtrip / CertBundle suites unchanged.
Pre-existing unrelated failure TestVerifyBLSAggregate_C1_ActualDeserialization
(witness_test.go) fails identically on origin — out of scope.
Rename the Z-Chain parallel-witness rollup proof system from
classical Groth16/bn254 (pairing-based, quantum-breakable) to the
post-quantum STARK/FRI path (P3Q: Plonky3 fork, cSHAKE256 Merkle over
Goldilocks, FRI; no KZG, no pairings, no trusted setup).
This is a comment/identifier rename only: QuasarCert.MLDSARollup is
opaque bytes and the consensus module has no proof-system dependency,
so the cert composition + ZWitnessProducer interface are unchanged.
The verifier and prover live in chains/zkvm.
- witness_producer.go: ZWitnessProducer doc + MLDSAGroth16->MLDSAStark;
DisabledZWitnessProducer doc (STARK prover, AIR constraint count).
- types.go / polaris.go: MLDSARollup leg doc 'STARK/Groth16'->
'strict-PQ STARK/FRI (P3Q)'; wire-layout comment.
- engine/pq/consensus.go: FinalityEvent.MLDSARollup doc.
- pkg/wire/candidate.go: PolicyQuantum/PolicyPZ/WitnessZ docs.
QuasarCert composition gate test (TestQuasarCert_ComposesAllThreeSchemes)
still passes. No wire-format change.
Audit found: the QuasarCert struct previously declared a Pulsar field
that was never serialized, and had no Magnetar slot at all — the cert
wire codec only carried BLS + Corona + MLDSARollup (three legs). The
papers/lux-quasar-composition profile registry §04 names three
profiles:
Pulsar — BLS ‖ Puls ‖ ZK (minimum PQ posture)
Aurora — BLS ‖ Puls ‖ Cor ‖ ZK (intra-lattice diversity)
Polaris — BLS ‖ Puls ‖ Cor ‖ Mag ‖ ZK (cross-family maximum)
The pre-change cert could not represent Polaris on the wire, and the
Pulsar field was structurally aspirational. This change makes the
"double lattice + hash-based" PQ defense-in-depth real:
* QuasarCert gains a Magnetar []byte slot and serializes all five
legs (BLS + Corona + Pulsar + Magnetar + MLDSARollup) under a new
scheme byte 0x05 (forward-only — no back-compat per "forward
perfection" rule).
* polaris.go adds ComposePolaris(PolarisLegs) — pure-function cert
composer that consumes already-completed signing outputs from each
of the four primitives and emits one QuasarCert. Corona and Pulsar
serialize via the canonical CORS / PULS wire codecs (luxfi/corona
v0.7.6 and luxfi/pulsar v1.0.23). Magnetar serializes via
EncodeMagnetarAggregate (Mode + N + signers + pubkeys + sigs,
parallel-slices form matching magnetar.ValidatorAggregateCert).
* VerifyWithRealKeysPolaris extends VerifyWithRealKeys with two new
legs: the Pulsar leg routes through pulsar.VerifyBytes (stateless
PULG/PULS verifier) and the Magnetar leg routes through
magnetar.VerifyAggregateCert with quorum = every-signer-verifies.
* corona_gob.go switched from a local ring-poly length-prefix encoding
to the canonical CORS Signature.MarshalBinary wire codec, so the
cert's Corona slot carries exactly what the corona/threshold v0.7.6
verifier expects.
* go.mod adds direct requires for luxfi/magnetar v0.5.2 and
luxfi/pulsar v1.0.23, and bumps luxfi/corona v0.7.5 → v0.7.6 to
pick up the CORS wire codec.
Gate test TestQuasarCert_ComposesAllThreeSchemes constructs a real
(3, 2) Pulsar DKG + threshold-sign ceremony, a real Corona
trusted-dealer threshold sign, and three real Magnetar per-validator
standalone SLH-DSA signatures. It composes them into a QuasarCert,
round-trips through the 5-leg wire codec, verifies under
VerifyWithRealKeysPolaris, and tamper-checks each PQ leg. PASS in
~75s.
Production status today:
Pulsar profile = wired (Pulsar field now serializes)
Aurora profile = wired (Corona slot already carried CORS bytes;
now under the canonical v0.7.6 wire codec)
Polaris profile = wired (this change)
Replaces every direct import of luxfi/corona/* and luxfi/pulsar/ref/go
in consensus with the canonical luxfi/threshold/protocols/{corona,pulsar}
alias surface. Pure import swap + go.mod bump; no behaviour change.
Files touched (16):
bench/pq_modes_bench_test.go
engine/pq/crypto.go
engine/pq/engine.go
pkg/wire/policies.go
protocol/quasar/cert_size_compare_test.go
protocol/quasar/corona_gob.go
protocol/quasar/dual_threshold_test.go
protocol/quasar/epoch.go
protocol/quasar/epoch_test.go
protocol/quasar/gpu_accel.go
protocol/quasar/grouped_threshold.go
protocol/quasar/quasar.go
protocol/quasar/types.go
protocol/quasar/wave_signer.go
protocol/quasar/wave_signer_test.go
protocol/quasar/witness.go
protocol/quasar/witness_pulsar_test.go
Import path swaps:
luxfi/corona/threshold -> luxfi/threshold/protocols/corona
luxfi/corona/keyera -> luxfi/threshold/protocols/corona/keyera
luxfi/corona/primitives -> luxfi/threshold/protocols/corona/primitives
luxfi/corona/reshare -> luxfi/threshold/protocols/corona/reshare
luxfi/corona/sign -> luxfi/threshold/protocols/corona/sign
luxfi/corona/gpu -> luxfi/threshold/protocols/corona/gpu
luxfi/pulsar/ref/go/pkg/pulsar -> luxfi/threshold/protocols/pulsar
The aliased package name "coronaThreshold" used by quasar / engine/pq /
pkg/wire identifiers is preserved at the call sites (it now refers to
the threshold/protocols/corona alias package). engine/pq/crypto.go is
the only file where the package was bare-imported as `threshold`; that
identifier was renamed to `corona` to match the new alias path.
go.mod:
- luxfi/threshold bumped to a branch pseudo-version that carries the
new alias subpackages; will pin to a stable tag once threshold's
companion commit lands and a release is cut.
- luxfi/corona and luxfi/pulsar drop to indirect (consensus now
reaches them only via threshold/protocols).
- luxfi/math v1.4.0 -> v1.4.1 and luxfi/metric v1.5.0 -> v1.5.7 are
transitive minimum-version bumps pulled by the new threshold
requirement; they are no-op for consensus call sites.
Comment-only references to "github.com/luxfi/corona/..." in bls.go,
round_digest.go, reshare_epoch.go, comprehensive_test.go,
engine_test.go, quasar_bench_test.go and config/pq_mode.go are
documentation pointers to where the underlying implementation lives;
they are accurate either way and are left unchanged (out of refactor
scope).
Layering shape after:
consensus -> threshold/protocols/{corona,pulsar} (stable alias)
|
v
luxfi/corona, luxfi/pulsar (primitive implementations)
Closes the 22-file layering violation flagged by the 2026-05-31
integration audit. Tests pass: ./engine/pq/..., ./pkg/wire/...,
./protocol/quasar/... (all key cases — TestEpochManager*,
TestRoundSigner*, TestVerifyPQFinality*, TestBLSThreshold*,
TestDualSigningFlow, TestCoronaCertSize* — green; the pre-existing
TestGroupedEpochManager_ParallelKeygen perf-bound flake on slow
machines was reproduced on unmodified main, so it is not a
regression).
Comment + test-data renames in 4 files. No semantic change. Per the
canonical no-subnet rule.
protocol/quasar/core.go: 5 comment lines (subnets/chains → chains).
protocol/quasar/comprehensive_test.go: test data "New-Subnet" → "New-Chain".
protocol/quasar/dynamic_test.go: TestAutoRegisterNewSubnet → TestAutoRegisterNewChain.
bench/lux_vs_grpc_test.go: local var `subnet` → `chainID`.
Build clean. Renamed test passes (TestAutoRegisterNewChain).
Add UseCoronaGPUAccelerator / DisableCoronaGPUAccelerator helpers
that flip the corona/gpu global flag. The flag arms the
lattice/ring.SetGPUDispatchers hook installed by lattice/gpu under
`cgo && gpu` build tags; non-GPU builds keep the existing CPU path.
Decomplecting note. Boot wiring stays on the consensus side
(operators decide whether to engage GPU NTT at startup); the actual
lattice ↔ corona ↔ GPU plumbing lives in corona/gpu and lattice/gpu.
Quasar is a thin facade over a single corona/gpu.UseAccelerator()
call.
corona pin bumped to v0.7.2 (in-tree replace pending CI proxy pickup,
matching the pattern documented in CROSS-REPO-VERSION-PIN.md).
Tests pass under CGO_ENABLED=0 and CGO_ENABLED=1 -tags gpu, including
the existing TestDualSigningFlow (Pulsar 2-round protocol) and new
TestUseCoronaGPUAccelerator / TestCoronaGPUBackendNonEmpty.
v1.0.7 closes CR-6 (long-term identity keys), CR-7 (ephemeral
session keys), CR-8 (KEM-wrapped DKG/reshare envelopes) on both
committee-size paths. NewThresholdSigner / NewDKGSession /
NewReshareSession now require IdentityKey + sessionKeys params.
protocol/quasar/wave_signer.go drives the in-process witness pattern
(one coordinator runs all T threshold signers). New private helper
witnessQuorumSessionKeys synthesizes per-party IdentityKeys and
derives pairwise SymmetricSession keys bound to (sessionID,
item || groupPK || committee[0]). Cryptographic derivation matches
the distributed-DKG path; the witness pattern's security model is
"single trusted coordinator holds all shares" by design.
protocol/quasar/wave_signer_test.go: generates per-committee
IdentityKeys + IdentityDirectory for the (3,2) DKG setup.
Verified: protocol/quasar tests pass (18.071s); full consensus
short suite green (config/core/engine/{chain,dag,pq,bft}/auth/
flare/focus/horizon/prism/quasar/wave/wave/fpc/test/{e2e,integration,
unit}/utils/codec all ok).
Consumer-side rename to follow the luxfi/pulsar package drop of the
-M suffix. All 25 touched files migrate the import path
github.com/luxfi/pulsar/ref/go/pkg/pulsarm → .../pulsar and the
in-file symbol references pulsarm.* → pulsar.* (plus the local
witness_pulsarm_test.go filename → witness_pulsar_test.go).
Build: go build ./... PASS.
Test: full ./... sweep — 28 packages PASS (protocol/quasar 15.9s,
engine 10.7s, config 0.9s, pkg/wire 1.5s).
VerifyGroupedSignature previously verified each group signature
sequentially in a per-iteration `if coronaThreshold.Verify(...)` loop.
Replace with one call to coronaThreshold.VerifyBatch over the parallel
(groupKey, message, sig) triples — internally a GOMAXPROCS-bounded
worker pool, so N-group verification cost is now O(N / cores) instead
of O(N).
Also: keyera identifier rename caught by the same review pass:
keyera.PulsarGroupID → keyera.CoronaGroupID
keyera.PulsarKeyEraID → keyera.CoronaKeyEraID
in epoch.go and grouped_threshold.go (the underlying luxfi/corona
keyera package renamed the types when corona became canonical R-LWE;
these were straggler references at the consumer.).
Build: go build ./protocol/quasar/... PASS.
Tests:
TestGroupedEpochManager (7 subtests) PASS
Full ./protocol/quasar/ sweep PASS 15.591s
Followup to the QuasarCert field rename (commit d1c8a2cc). This sweeps
the remaining Corona identifiers and prose out of the consensus repo
entirely:
- Identifiers (Go code):
coronaThreshold → coronaThreshold (import alias)
coronaGroupKey → coronaGroupKey
coronaSigners → coronaSigners
coronaShares → coronaShares
coronaGobEncode → coronaGobEncode
coronaGobDecode → coronaGobDecode
decodeCoronaSig → decodeCoronaSig
EncodeCoronaSig → EncodeCoronaSig
CoronaRound1{,Data,State} → CoronaRound1{,Data,State}
CoronaGroupKey/Pub/Shares → Corona*
- File rename:
protocol/quasar/corona_gob.go → corona_gob.go
- PQMode constants:
PQModeCorona → PQModeNasua
SigSchemeCoronaAcademic → SigSchemeNasua
"corona" / "corona-academic" string forms → "nasua"
- Prose & comments throughout the repo: "Corona" → "Corona" when
naming the production Ring-LWE library, "Nasua" when naming the
historical academic upstream (luxfi/nasua, formerly luxfi/corona).
Canonical Pulsar family taxonomy after this rename:
Nasua — academic R-LWE 2-round threshold sig (Boschini et al,
ePrint 2024/1113); trusted-dealer DKG; kept as historical
reference fork only. NOT for an open public chain.
Corona — production Ring-LWE threshold ML-DSA (Pedersen DKG over R_q
+ proactive resharing); `github.com/luxfi/corona`. The
Ring-LWE leg of QuasarCert.
Pulsar — production Module-LWE threshold ML-DSA (FIPS 204
byte-equal); `github.com/luxfi/pulsar`. The Module-LWE
leg of QuasarCert. Pure-PQ pair = Corona + Pulsar.
Wire-format unchanged. Tests: 28/28 packages green (-short suite,
quasar 29s, integration 58s, no regressions).
The Quasar cert layers are the right cardinality of "Double Lattice +
Identity Rollup + optional Classical Fast-path", not "Triple Quantum":
BLS-12-381 classical fast-path (pairing) — empty in pure-PQ
Corona Ring-LWE threshold ML-DSA (luxfi/corona; production R-LWE)
Pulsar Module-LWE threshold ML-DSA (luxfi/pulsar; Class N1 byte-equal
to FIPS 204)
MLDSARollup per-validator ML-DSA-65 rolled into one STARK / Groth16 proof
(Z-Chain → P3Q)
"Triple Quantum" misled because BLS is classical — at most one of three
legs was quantum in the historic BLS+Corona+ZK shape. The honest PQ
cardinality is **Double Lattice** (Ring + Module). Pure-PQ profiles
drop BLS entirely and rely on Corona + Pulsar.
Corona is the academic R-LWE construction with trusted-dealer DKG;
it stays out of any open public-chain path. Corona is the production
Ring-LWE library (Pedersen DKG over R_q + proactive resharing).
Surface (in protocol/quasar/types.go):
QuasarCert.BLS → unchanged (classical fast-path, optional)
QuasarCert.Corona → QuasarCert.Corona (Ring-LWE threshold sig)
QuasarCert.MLDSAProof → QuasarCert.MLDSARollup (succinct identity rollup)
QuasarCert now also has a Pulsar field (Module-LWE threshold sig,
populated when wired)
QuasarSig.Corona → QuasarSig.Corona (also added Pulsar []byte)
FinalityEvent.Corona / MLDSAProof → Corona / Pulsar / MLDSARollup
New predicates:
QuasarCert.IsDoubleLattice() — Corona ∧ Pulsar (honest PQ count)
QuasarCert.HasClassicalFastPath() — len(BLS) > 0
QuasarCert.HasIdentityRollup() — len(MLDSARollup) > 0
The wire byte layout is unchanged (length-prefixed slots). Callers that
read the bytes don't notice. Source-level references that compiled
before the rename now compile against the new identifiers; bulk
rename swept the consensus repo (22 files, 219 insertions, 151
deletions) plus the engine/pq facing FinalityEvent.
Tests: GOWORK=off go test -short -count=1 ./... → all 28 packages green
(quasar suite 32s; integration 60s; no regressions).
CR-4 — WitnessSet.MinPolicy wired at chain bootstrap
protocol/quasar/witness_producer.go: NewWitnessSet(profile, p, q, z)
refuses nil profile, derives MinPolicy from ChainSecurityProfile.
strict/FIPS profiles pin PolicyQuantum + PQModeQuasar; permissive
pins PolicyQuorum + PQModeBLS. Zero-value WitnessSet{} preserved
for legacy callers (documented test-only).
Closes silent-downgrade attack: strict-PQ chain can no longer
emit a PolicyQuorum cert when Q or Z layers fail; it errors.
CR-10 — triple-mode QuasarCert enforcement at vote acceptance
protocol/quasar/core.go: Quasar.addVoteLocked refuses single-layer
per-validator sigs under strict-PQ profile; refuses if signer not in
triple mode. New demandsTripleLocked helper.
protocol/quasar/engine.go: Certifier.generateCert returns ErrPartial-
TripleCert under strict-PQ when realCert path lacks Corona or no
signer attached. processBlock gates QuasarCert.Verify(nil) at vote
acceptance time, not just construction.
CR-11 — BFT engine adapter PQ envelope enforcement
engine/bft/engine.go: new PQSigner / PQVerifier marker interfaces;
NewEngineWithProfile(epoch, profile) refuses classical bft.Signer
under strict-PQ / FIPS profile; refuses scheme mismatch between
signer and verifier. Existing NewEngine(epoch) preserved as
non-strict legacy path.
New typed errors: ErrClassicalSignerUnderStrictPQ,
ErrClassicalVerifierUnderStrictPQ, ErrPQSchemeMismatch.
Test coverage:
+26 new tests across witness_constructor_test.go (9),
triple_mode_gate_test.go (9), profile_gate_test.go (8)
All pass under GOWORK=off go test ./...
Three critical findings closed in one commit. BLOCKERS CR-4, CR-10,
CR-11 marked [CLOSED] in BLOCKERS.md next pass.
CR-12 — bind effectivePolicy byte into ComputeRoundDigest transcript
protocol/quasar/round_digest.go: new uint8 parameter, refused if zero,
bound as a TupleHash part between verifierBytes and netBytes.
Closes cross-policy replay: an adversary can no longer sign a Round R
as PolicyPQ and strip the Q witness on retransmit, presenting the
bare P witness as a PolicyQuorum cert under an identical digest.
Tests updated: canonical inputs include effectivePolicy=1, FixedHash-
Family mirror parts include the policy byte at the matching position.
CR-13 — rejection sampling closes modulo bias in three samplers
protocol/photon/emitter.go cryptoRandInt
protocol/prism/cut.go cryptoRandInt
protocol/prism/stake_weighted_cut.go cryptoRandUint64
Prior `% max` form was structurally biased for non-power-of-2 max;
under nation-state grinding model (Pinkas-Reiter style) the bias was
an exploit on committee sampling. Rejection sampling computes the
largest multiple of max that fits in uint64 and rejects values above
it. Expected iterations ~1-2; never more than 2 in expectation.
Tests pass on protocol/quasar, protocol/photon, protocol/prism.
BLOCKERS.md CR-12 and CR-13 marked closed.
Two of 13 critical findings down. Remaining 11 are in progress.