references.bib gave ePrint 2024/1113 the title "Corona: Practical Two-Round Threshold Signatures from Learning with Errors". The paper is "Ringtail: Practical Two-Round Threshold Signatures from Learning with Errors", by the six authors the entry already named correctly. A title is the authors' words. The file's own header asks for exactly this — "verified against https://eprint.iacr.org... Do not paraphrase or guess". Ringtail is their scheme. Corona is Lux's implementation over Ring-LWE; Pulsar retargets the same two-round structure to Module-LWE for FIPS 204. The prose and the citation key now say so, and this spec is the NIST MPTC submission, so it is the last place to get it wrong. patent-notes.tex stated "Corona's open-source repo is Apache-2.0 with no asserted patent claims". Corona is under the Lux Ecosystem License v1.2, which reserves commercial use — no Apache grant and no Apache §3 patent grant. The surrounding paragraph had been flattened by a rename into "Pulsar ... is derivative of Pulsar" and "Pulsar (and therefore Pulsar) is a fork"; it now names Corona and Ringtail where each is meant. Dropped the residual Pulsar-M spelling, including the naming rule that forbade writing "Pulsar" and required writing "Pulsar". Co-authored-by: Hanzo Dev <[email protected]>
46 KiB
Finding registry — luxfi/pulsar
Status (v1.2.0): the TALUS threshold ML-DSA path is BUILT and
PULSAR-V13-W-LEAK is CLOSED (semi-honest, simulation-proven). The v1.1.x
byte-equality / ctx-bound / public-BFT claims remain submission-ready. On the
leaderless threshold path the REAL CSCP secure-comparison circuit closes the
W-LEAK under an honest majority (commit 530c24e); exactly TWO honest
residuals remain open — Residual A (the CSCP malicious-secure /
identifiable-abort layer, plus a networked non-simulation MPC deployment) and
Residual B (dealerless byte-FIPS-204 KEY DKG is proven unreachable ⇒
KEYGEN stays trusted-dealer; permissionless safety is carried by the dealerless
Corona leg of the AND-mode Quasar cert). The EasyCrypt byte-equality proof
still rests on an OPEN reconstruct-then-sign axiom cone
(PULSAR-EC-RECON-MODEL). None of these blocks the single-party / N4 /
interop-tested BCC claims; the two residuals block any "malicious-secure,
networked, permissionless threshold path is proven" statement.
Forward-looking v1.2 extensions are tracked under
## Forward-looking (v1.2) below; they are EXTENSIONS surfaced by the
2026-06 fresh four-dimension audit (AUDIT-2026-06.md), not flaws in
the v1.1.1 claims.
This file is the closed-finding registry. New findings open under
## Open; on fix they move to ## Closed with commit + tag. IDs
are cited from source-code comments and from
docs/cryptographer-sign-off.md, docs/deployment.md,
SUBMISSION.md, spec/blockers.tex.
Earlier IDs CR-6 / CR-7 / CR-8 (KEM-wrap of DKG envelopes,
ephemeral per-pair session keys, identity-bound MAC layer) survive
only as source-code references. They closed in the
luxfi/pulsar-mptc → luxfi/pulsar consolidation (commit 7be057b,
v1.0.7 sign-off); the canonical narrative lives in CHANGELOG.md
and the v1.0.7 sign-off.
Open
Open items (v1.2.0) = exactly two honest residuals on the TALUS threshold path. The old "two novel components fail-closed — (i) tight small-norm lattice range proofs and (ii) HighBits-inside-MPC" framing is retired: component (ii) is now BUILT (that is exactly what the REAL CSCP secure-comparison does, semi-honest — PULSAR-V13-W-LEAK, now CLOSED), and component (i)'s malicious-secure VSS for the nonce DKG folds into Residual A (it is NOT a separate byte-equality blocker). The genuinely-open items are:
- Residual A — CSCP is semi-honest-secure only (+ networked MPC). The REAL
CSCP secure-comparison circuit (
cscpSecureHighBitsVec) closes the W-LEAK under an honest majority (N ≥ 2T−1, enforced byTalusMinPartiesMPC/newCSCPCtx/bgwMulShares), but it is proven leak-free in an in-process N-party SIMULATION, and the malicious-secure / identifiable-abort layer (Feldman/Pedersen-committed shares + verified openings + a bit-validity proof- complaint round, including the malicious-secure VSS for the nonce DKG) is
UN-built, as is a networked non-simulation deployment. A malicious deviation
can never forge or leak —
FindHint+TalusReleaseGatebound it to a LIVENESS fault (abort/retry) (TestCSCP_WrongW1_CaughtByFindHint). Detailed record: PULSAR-V13-HINT-LEAK (malicious-secure gates) + PULSAR-V13-W-LEAK (marked CLOSED below + its "Residual" paragraph).
- complaint round, including the malicious-secure VSS for the nonce DKG) is
UN-built, as is a networked non-simulation deployment. A malicious deviation
can never forge or leak —
- Residual B — dealerless byte-FIPS-204 KEY DKG is impossible (proven).
FIPS-204 KeyGen samples s1,s2 uniformly from S_η = {p : ‖p‖∞ ≤ η}; a
dealerless DKG forms the joint secret as a sum/Lagrange combination of N ≥ 2
contributions each in S_η, whose ℓ∞-support is up to N·η > η — not
S_η-distributed. This breaks BCC byte-validity (‖c·s2‖∞ ≤ N·β > β) AND the
FIPS-204 security-equivalence; forcing back into S_η "is exactly a dealer."
Code:
distributed_bcc_dkg.goreturnsErrDealerlessByteFIPSUnreachable. THEREFORE KEYGEN stays trusted-dealer (DealAlgShares) and the permissionless-public guarantee is carried by Corona (natively dealerless via Pedersen DKG over R_q) in the Quasar AND-mode cert. Detailed record: PULSAR-V12-PARALLEL-PQ item 2 (## Forward-looking).
PULSAR-EC-RECON-MODEL below is a separate proof-scope disclosure (the EC
reduction no_leak_reduction), not a threshold-path safety residual.
PULSAR-EC-RECON-MODEL (HIGH — proof-scope disclosure; RE-SCOPED this pass)
Status: OPEN, but RE-SCOPED — reconstruct-then-sign is no longer the load-bearing production residual. Two distinct models now exist:
Model 1 — idealised correctness (reconstruct-then-sign). The EC
pulsar_n1_byte_equality / _extracted is machine-checked structurally (0
admits) relative to the bucket-C-idealised axioms (combine_body_axiom,
S_functional_spec, per-stage combine_body_*_spec / sign_body_*_spec,
v0.4 algebraic_aggregate_ctx_body_axiom), which assert the
extracted/aggregated code equals the centralised FIPS 204 signer applied to
the Lagrange-reconstructed master secret. This is an idealised
correctness model; it reconstructs the master key and signs with it,
intentionally NOT the production instantiation.
Model 2 — the production no-leak residual (added this pass).
proofs/easycrypt/Pulsar_N1_NoLeak.ec states the production path the way it
runs: the public Lagrange aggregate of the per-party masked responses
equals the central z without ever forming the master secret
(no_leak_z_aggregate), and the hint is recovered from the public
w' = A·z − c·t1·2^d via FIPS UseHint (public_hint_roundtrip). The ONLY
open assumption is no_leak_reduction: under Module-LWE + Module-SIS
the public transcript leaks nothing about (s1,s2,t0) beyond one
single-party FIPS 204 signature. That is a STANDARD PQ assumption — the same
hardness ML-DSA's EUF-CMA uses — not an implementation reconstruct.
What is machine-checked NOW (this host, lake build green, 0 sorry):
the CORRECTNESS core of Model 2 — Crypto.Pulsar.NoLeakAggregate
(z_aggregate_no_reconstruct, hint_is_fips_hint,
no_leak_under_standard_assumptions), Crypto.Pulsar.BoundaryClearance
(boundary_clearance, findHintCoeff_unique), Crypto.Threshold_Lagrange.
The EC side of Model 2 machine-checks on the host via easycrypt compile
(opam switch proofs), enforced every run by the gate ec-machine-check.sh.
Remaining OPEN:
- The production no-leak path is ALSO interop-tested (BCC single-key sig byte-equal under CIRCL + pq-crystals, ML-DSA-65/87); its novel ZK parts are fail-closed-pending-review — see V13-W-LEAK / V13-PARTIAL-Z-PROOF.
no_leak_reduction's full simulation-soundness proof (the v0.8 EC/paper artifact) is not written; it is disclosed as a Module-LWE/MSIS reduction.- Model 1's C-idealised cone closure is still the Jasmin/libjade byte-walk (issues #3, #4) — but Model 1 is now explicitly not the safety-relevant residual, so its closure is a correctness nicety, not a leak-freeness gate.
Resolution criteria:
- A separate (non-reconstruct) model of the PRODUCTION no-leak path is
written, with its CORRECTNESS core machine-checked (Lean, this host)
and its residual stated as a STANDARD Module-LWE/MSIS reduction
(
Pulsar_N1_NoLeak.ec+Crypto.Pulsar.NoLeakAggregate). Pulsar_N1_NoLeak.ecmachine-checks viaeasycrypt compileon the host (gateec-machine-check.sh; pulsar 14/14 theories compile).no_leak_reductiondischarged to a full M-LWE/M-SIS simulation proof (v0.8 EC/paper artifact), OR accepted by external review as a standard reduction.- Jasmin/libjade byte-walk lands ⇒ Model 1's C-idealised axioms become lemmas (correctness nicety; issues #3, #4).
- External cryptographic review signs off that (a) Model 2's standard-reduction residual is the correct production posture and (b) Model 1 is an acceptable correctness idealisation (cross-ref: the external-review gate shared with V13-HINT-LEAK below).
PULSAR-V13-HINT-LEAK (CRITICAL)
The v0.3/v0.4 AlgebraicAggregate* path broadcasts CS2 = c·λ_i·s_{2,i}
and CT0 = c·λ_i·t_{0,i} unmasked (ref/go/pkg/pulsar/threshold_v03.go
round2EmitFull, :930-963) and reconstructs :1131-1168). Both are secret-key-derived: c·s2_joint, c·t0_joint at
the aggregator (c, λ_i
public ⇒ s_{2,i} = (c·λ_i)^{-1}·CS2 (one session when c invertible;
else accumulate). Worse, c·s2_joint = c·s2_master (Shamir), so revealing
the aggregate over varying public c leaks the long-term secret-key
components s2 (and likewise t0) via a linear system, plus the secret
relation A·s1 = (t1·2^d + t0) − s2; whether or not this immediately
recovers short s1 (a lattice/preimage problem), threshold secrecy and
transcript simulation are already broken. Leaderless ⇒ every
quorum member aggregates ⇒ every corrupt validator learns it each round.
The in-code PUBLIC-BFT-SAFETY NOTE claiming (z_i,cs2_i,ct0_i) are
(t−1)-secret is false — it only covers the y_i-masked z_i.
Confirmed by adversarial audit (AUDIT-2026-06.md re-audit) + direct code
read. Masking the individual shares is necessary but not sufficient —
the aggregate reconstruction still leaks the master key. The fix must
never reconstruct c·s2/c·t0/r0.
Containment (landed, branch fix/threshold-mldsa-hint-leak, commit eda6d96):
The entire v0.3 AlgebraicAggregate* path — threshold_v03.go, attest.go,
orchestrate.go, and their tests — is DELETED forward-only. There is no
flag to re-enable it, and the secret-dependent makeHint primitive it used is
also removed (BCC recovers the hint from public data via FindHint). The
dangerously-false (t−1)-secret note is gone with the path.
Replacement design + verified math core: boundary-cleared nonces + carry
elimination (spec/threshold-mldsa-boundary-clearance.tex,
boundary.go/bcc_sign.go). The hint is computed from the public
w' = A·z − c·t1·2^d and w1 = HighBits(w) strictly via FIPS UseHint
(FindHint); boundary clearance (margin 2β) keeps the small c·s2 shift
off the boundary; c·t0 is structurally ‖c·t0‖∞ ≤ τ·2^{d-1} < γ2 for
ML-DSA-65/87 only (param-guarded, ErrBCCParamSet). Verified (all green):
FindHint↔UseHint round-trip, BoundaryClear ⇒ HighBits-stable + r0-bound,
exact off-by-one edges, offline yield ≈ 9.8 %, and a no-leak single-key
signature that verifies byte-for-byte under CIRCL + pq-crystals (ML-DSA-65/87).
Status: leak removed + no-leak core complete + cert-verification hardened;
PULSAR-V13-W-LEAK is now CLOSED semi-honest on the TALUS-MPC CSCP path (see
its CLOSED marker below), and the remaining malicious-secure / range-proof
gates are the open Residual A. [~] = structurally complete in code,
semi-honest; the malicious-secure hardening is Residual A (a deviation is
liveness-only via FindHint + TalusReleaseGate, never forge/leak).
Resolution criteria:
- v0.3
AlgebraicAggregate*path removed from the codebase (not merely gated). - Hint derived only via public
FindHint(w', w1)(FIPSUseHint); secretmakeHintdeleted. - No production code computes
c·s2/c·t0/r0/LowBits(residual). - Boundary predicate proves the hidden
r0bound; ML-DSA-65/87 scope enforced (ErrBCCParamSet). CS2/CT0+ all hint-secret wire fields deleted; reflection guard (TestNoHintSecretFieldsInProductionWireTypes) enforces it.- Full
wnever on the wire — CLOSED semi-honest on the TALUS-MPC CSCP path: no node formsw/w0/A0even transiently, andNonceCertcarries onlyw1+ a binding commitment (simulation-proven — see PULSAR-V13-W-LEAK, marked CLOSED below). The earlier debug-oracle ZK-boundary-clearance prototype (ErrClearanceProofUnsound) is superseded by the REAL CSCP secure-comparison; the malicious-secure layer is Residual A. - [~] Partial-
zcorrectness — sound linear sigma proof, FS-bound, challenge validated asSampleInBall(partial_proof.go); registered fail-closed by default; the small-norm range gate is fail-closed (L2-vs-L∞, no faithful proof exists). - Canonical, non-grindable nonce selection (
CanonicalNonceIndex). - [~] DKG never reconstructs the master key /
t0(DKGPublicOutput, not0); sound DKG linear proof; thet0-bound range gate is fail-closed pending review. - Rejected attempts coarse abort classes (
AbortClass). - Tree aggregation (z-sums + bitmaps + proof roots) for ~1000 signers.
- Two-certificate consensus artifact — ML-DSA sig + signer bitmap bound to the signature via an accountability QC (
ConsensusCert.Verify). - Final sigs verify under ≥2 independent FIPS 204 verifiers (CIRCL + pq-crystals) on the BCC path.
- External cryptographic review + the malicious-secure CSCP layer and a networked, non-simulation MPC deployment (Residual A — the remaining gate; the semi-honest leak-free property is already proven in simulation).
PULSAR-V13-W-LEAK (CLOSED — semi-honest, simulation-proven, v1.2.0; TALUS-MPC CSCP path)
Status: CLOSED on the TALUS-MPC CSCP path (commit 530c24e) — semi-honest,
honest-majority (N ≥ 2T−1), proven leak-free in an in-process N-party
SIMULATION (the harness holds all parties' shares; it is the algorithm that
never reconstructs w/w0, faithfully proven — but this is NOT yet a
networked/deployed distributed MPC). The orthogonal malicious-secure /
identifiable-abort layer (and a networked, non-simulation MPC deployment) is the
named Residual A (see ## Open); a malicious deviation is bounded to
liveness (abort/retry) by FindHint + TalusReleaseGate, never forge or leak.
Retained here with the HINT-LEAK cluster for narrative continuity; the registry
pointer lives in ## Closed. The hazard history and the closure proof follow.
The boundary-cleared nonce certificate must not publish the full
commitment w = A·y. Once z is assembled, w' = A·z − c·t1·2^d is
public, so anyone with full w computes w' − w = c·t0 − c·s2 = Δ — the
same challenge-multiplied long-term-secret residual as PULSAR-V13-HINT-LEAK,
in a different form. Production may publish only w1 = HighBits(w), a
commitment to w, and a zero-knowledge boundary-clearance proof (that a
hidden w = A·y is boundary-clear), never full w, w_i shares that
reconstruct it, LowBits(w), or w' − w. The current BoundaryClear(w)
Go predicate and spec are debug-oracle/prototype: production needs the
ZK proof machinery, which does not yet exist ⇒ the BCC/CEF signing path is
prototype, not production, even though the arithmetic tests pass.
Status update (TALUS, PULSAR-V12 item 3): leak-free realisation BUILT +
PROVEN (semi-honest honest-majority); the W-LEAK proper is CLOSED on the
TALUS-MPC path; the orthogonal malicious-secure layer is the named residual.
The leaking DealNonceMPCDebug.DebugW is gone from the output, and the
narrowed residual — realising the ideal cefIdealSecureHighBits by an ACTUAL
CarryCompare secure comparison so no node forms w0/w/A0 even transiently
— is now BUILT (talus_cscp.go, branch feat/pulsar-cscp):
- The REAL secure circuit
cscpSecureHighBitsVeccomputesw1 = HighBits(Σ g_i mod q)coefficient-wise from the per-party ADDITIVE commitment shares via a genuine secure comparison: additive→Shamir reshare to ⟨w⟩ over GF(q); a mask-open bit-decomposition (carry-save adder + a bitwise prefix less-than for the mod-q fold — the "CSA + prefix comparison" the obstruction names); and the exact boundary-count HighBits identityw1 = (Σ_{k=1..16}[w>(2k−1)γ2]) mod 16(m=16 is a power of two for ML-DSA-65/87, validated coefficient-exact against FIPS Decompose). Built on thebgwMulShares/SharedRandomBitsubstrate; enforces N ≥ 2T−1. CEFComputeW1now DRIVES this real circuit (it no longer calls the ideal);cefIdealSecureHighBitsis retained only as the test ORACLE the secure output is proven equal to.- LEAK-FREE, proven three ways: (i) transcript — the ONLY values ever
reconstructed are the random-bitwise validity bit, the per-coefficient UNIFORM
mask-open
c = (w−r) mod q, and the finalw1;w,w0,A0, and the bits ofware never opened (TestCSCP_MultiNode_LeakFree,otherCt==0); (ii) structural source guard —reconstructScalarGFqis called exactly once (insideopen()), andopen()is called with only the three sanctioned tags (TestCSCP_LeakFree_Structural); (iii) reflection — a node's persistent state (CSCPParticipant) holds only its own commitment share, no jointw/w0/A0field. Perfect masking is shown directly (TestCSCP_MaskOpen_HidesW: fresh randomness ⇒ different mask-opens, identicalw1). - CORRECT, proven exact (not probabilistic): the real CSCP
w1equals both the idealcefIdealSecureHighBitsand the ground-truthHighBits(A·ȳ)on real multi-node shares, ML-DSA-65 and -87 (TestCSCP_SecureVec_MatchesIdealOracle); the gadgets are validated bottom-up (bitwise LT exhaustive over all 64×64 pairs; bit-decompose reconstructs; secure HighBits == FIPS Decompose on boundary + random coefficients). The headlineTestTalus_MPC_EndToEnd_StockVerify/_Mode87now run the REAL CSCP and the aggregated signature still verifies byte-for-byte under the UNMODIFIEDcloudflare/circl mldsa{65,87}.Verify. Race-clean (the per-coefficient parallel driver). - The obstruction (DCF for T=2 / CSA+prefix for T≥3, N≥2T−1, round & comparison
cost, leak-if-skipped) remains COMPUTED by
assessCSCP/AssessCarryCompare.
Residual (orthogonal, semi-honest → malicious): the circuit is semi-honest
honest-majority. A malicious party could feed an inconsistent re-share, a
non-{0,1} "bit", or equivocate a mask opening — biasing w1. This is the
CSCPMaliciousResidual (AssessCSCPMalicious): each deviation is named with its
standard closing layer (Feldman/Pedersen-committed shares + verified openings,
a bit-validity proof, identifiable abort via signed share commitments — TALUS
Phase B). Crucially, even WITHOUT that layer a wrong w1 cannot forge or leak:
FindHint rejects a w1 no public hint reaches and TalusReleaseGate runs
mandatory stock FIPS-204 verification before any signature is emitted, so a
deviation is at worst a LIVENESS fault (nonce consumed, retry), never a forged
signature or a key leak (TestCSCP_WrongW1_CaughtByFindHint). KEYGEN is still
the trusted dealer DealAlgShares (dealerless byte-FIPS-204 KEY DKG is unreachable,
item 2); permissionless safety rests on the dealerless Corona leg of the AND-mode
dual-PQ cert.
PULSAR-V13-PARTIAL-Z-PROOF (HIGH — consensus robustness)
BCC/CEF removes the hint-path leakage, but leaderless consensus also needs
proof-carrying z-partials: each signer proves z_i = λ_i·y_i + c·λ_i·s_{1,i}
bound to (session_id, nonce_id, party_id, DKG share commitment, nonce commitment) without revealing y_i/s_{1,i}. Otherwise one bad partial
fails the aggregate with no clean blame path (leaderless DoS). Verify
partials without c·s2_i/c·t0_i/r0_i/hint shares (those fields must
not exist).
Status: functionally CLOSED on the new no-reconstruct signing path
(branch feat/pulsar-dealerless-v12). The sound, complete Maurer /
generalized-Schnorr linear sigma for exactly this relation already exists
(partial_proof.go ProvePartial/VerifyPartialProof, special-soundness
from invertible challenge differences in Z_q, parallel-repeated to
≈2⁻¹⁸⁶ soundness, HVZK). DistributedBCCSigner.Round2 produces it and
AggregateBCC verifies every partial against the public (λ_i,c,z_i) +
session/nonce/party binding, dropping any that fail — the clean blame path
(TestDistributedBCC_SoundPartialZProofRejectsForgery). Documented scope
(unchanged): the sigma proves the LINEAR relation + FS context binding; it
does NOT re-prove the hash-opening of the DKG/nonce commitments (SHA-3
non-linear) nor a small-norm bound on y_i (no exact ℓ∞ range proof — the
final FIPS ‖z‖<γ1−β check and the boundary-clear nonce gate cover norm).
The registry seam stays default-fail-closed; the one-line production
closure is RegisterPartialZVerifier(SoundPartialZVerifier(mode,λ,c,z)).
Forward-looking (v1.2)
These are EXTENSIONS surfaced by the 2026-06 fresh four-dimension audit
(AUDIT-2026-06.md). Both are independent of every closed finding;
both ship as decomplected hooks that do NOT touch existing wire form,
ABI, or any FIPS 204 byte-equality contract. Neither is a flaw in the
current claims — they are deferred-by-design forward-pointing items
filed for the next minor.
PULSAR-V12-TEE-BIND — TEE-quote binding helper for permissionless quorum gating
Status: SCAFFOLDED at audit time (commit pending). One pure
function AttestationContext(setup, msg) in
ref/go/pkg/pulsar/attest.go returning the canonical 32-byte TBS
digest a validator's TEE quote should bind to when the host chain
gates permissionless-quorum admission on attestation presence. Five
unit tests pin stability + nil-input safety + full input-coverage
sensitivity + customisation domain-separation
(ref/go/pkg/pulsar/attest_test.go).
Why v1.2 not v1.1.x: the audit treats the existing v1.1.1 claims (byte-equality, public-BFT safety, FIPS 204 §5.4 ctx-bound) as the single canonical home. The TEE-binding helper extends the surface without altering it; bundling under v1.2 keeps the v1.1.x cut focused on PULSAR-V04-CTX closure.
What this is NOT: it is not a TEE attestation verifier. The
chain-validating attestation verifier lives at
github.com/luxfi/mpc/cc/attest. Pulsar's role is to declare the
canonical TBS bytes; the verifier role belongs to the consensus
envelope.
Custody-mode TEE path: unchanged.
github.com/luxfi/threshold/protocols/mldsa-tee already ships the
SEV-SNP / TDX / NRAS-attested custody surface that materialises the
master seed inside an attested TEE. The permissionless v0.3 path does
NOT materialise sk at any party by construction, so attestation there
is a policy gate, not a safety primitive.
PULSAR-V12-PARALLEL-PQ — parallel-PQ AND-mode dual-lattice finality (consensus consumer)
Status: CONSUMER WIRED in luxfi/consensus; Pulsar-side
no-reconstruct threshold PRODUCTION remains gated by the V13 findings
below. Filed here so the consumer's expectations and this repo's
blockers stay one document apart, not two narratives.
luxfi/consensus/protocol/quasar (dualpq.go,
consensus_cert_dualpq_test.go) now composes a dual-lattice AND-mode
finality cert that carries a Pulsar (Module-LWE / FIPS-204 ML-DSA)
leg in parallel with a Corona (Ring-LWE) leg, both required to
finalize (config CertModeStrict + CertVariantStrict ⇒ RequiredLegs() = {Pulsar, Corona}). The Pulsar leg is verified live and byte-for-byte
by an unmodified FIPS-204 verifier (verifyPulsarLeg → wire.VerifyBytes);
that verify path is production-ready and is exercised by a real
group-key signature in the consensus multi-node test.
What is NOT yet production on the Pulsar side — the leg's no-reconstruct, single-share t-of-n SIGNING:
- The current public
KeyShare(types.go) is a GF(257) byte-wise share of the 32-byte ML-DSA SEED. ML-DSA'ss1/s2are a non-linear SHAKE expansion of the seed, so seed-shares admit only the Lagrange reconstruct-then-sign path (Combine/LargeCombine) — which materialises the master key in the aggregator (the H-1 footgun; intentionally NOT the production instantiation, see PULSAR-EC-RECON-MODEL Model 1). A no-reconstruct signer needs poly-vector secret shares of(s1, s2, t0)(the v0.3AlgebraicKeyShareshape) so the per-partyz_i = λ_i·y_i + c·λ_i·s_{1,i}aggregates Lagrange-linearly without ever forming the secret. The newRoundSigner/Partial/FlatAggregateZmodel carries the interface and the z-sum aggregation primitive for exactly this, but no concrete poly-vector share type or concreteRoundSignerimplementor exists on the current line (the v0.3 algebraic stack was removed in the b185533 consolidation). - The leaderless production path is now BUILT (TALUS, v1.2.0):
PULSAR-V13-W-LEAK is CLOSED semi-honest on the TALUS-MPC CSCP path
(marked CLOSED above) and PULSAR-V13-PARTIAL-Z-PROOF is functionally
closed on the no-reconstruct path. The remaining open work is Residual A
(the CSCP malicious-secure / identifiable-abort layer + a networked,
non-simulation MPC deployment); a malicious deviation is liveness-only via
FindHint+TalusReleaseGate, never forge or leak.
Why the consumer is permissionless-safe anyway. The consensus cert
is AND-mode and the Corona leg is genuinely dealerless and
no-reconstruct (Ring-LWE shares are linear; corona/keyera Pedersen
DKG never forms the master secret; per-node corona/threshold.NewSigner
holds exactly one share). An adversary who compromises a fenced/TEE
Pulsar genesis ceremony and forges a Pulsar leg STILL cannot finalize —
AND-mode also requires the Corona leg, whose dealerless key has no
single point of forgery. The permissionless guarantee rests on Corona;
the Pulsar leg is FIPS-204 standard + Module-LWE defense-in-depth, with
its genesis TEE-gated (see PULSAR-V12-TEE-BIND and the mldsa-tee
custody surface above).
Forward path (do NOT resurrect v0.3). Finish the new model:
(1) add a poly-vector secret-share type and a concrete single-share
RoundSigner whose Round2 emits a real Partial;
(2) close PULSAR-V13-W-LEAK and PULSAR-V13-PARTIAL-Z-PROOF (the
distributed-nonce and partial-z ZK proofs). The proven per-node custody
DECOMPOSITION to apply once the share type lands is gate C's
DistributedSigner (luxfi/threshold/docs/_gatec/distributed.go,
branch feat/distributed-signer-gatec): one validator = one share,
session/round messages on the bus, aggregator combines messages (no
share, no sk) — the same single-share boundary the Corona leg already
ships. Restoring the removed v0.3 stack is rejected: it would create a
second threshold path (violates one-way) and is a backwards move.
Status update — branch feat/pulsar-dealerless-v12 (item 1 BUILT,
item 2 RESEARCH-BLOCKED with a computed obstruction):
-
Item 1 — no-reconstruct single-share SIGNING: BUILT + PROVEN.
ref/go/pkg/pulsar/distributed_bcc.goaddsAlgShare(a GF(q) poly-vector Shamir share of the EXPANDED component s1 only — the BCC/CEF path never touches s2/t0, so sharing them would reopen PULSAR-V13-HINT-LEAK; this matches theDKGPublicOutputno-t0 invariant and thedkg_wellformed.gonote "online signing needs only s1_i, y_i and public t1") andDistributedBCCSigner, the concreteRoundSigner(var _ RoundSigner = (*DistributedBCCSigner)(nil)). Round1 binds the canonicalNonceCertand derives c; Round2 emitsz_i = λ_i·y_i + c·λ_i·s1_icarrying the sound partial-z proof; Finalize aggregatesz = Σ z_iLagrange-linearly (FlatAggregateZ), recovers the hint from PUBLICw'viaFindHint, and emits FIPS-204sigEncode. The aggregator surfaceAggregateBCCtakes[]Partialonly — no share, sk, or seed. Multi-node proof (distributed_bcc_test.go, 7 tests): t separate signers one share each over a message bus, signatures verify under unmodified FIPS-204 (VerifyBytes+ stock circlVerify), ML-DSA-65 and -87, ctx-binding real, sub-quorum refused, share carries no seed/s2/t0,ShareCount()==1. PULSAR-V13-PARTIAL-Z-PROOF is functionally CLOSED on this path: the sound Maurer/Schnorr sigma (partial_proof.go) is verified per-partial inAggregateBCC; a forged z-partial is dropped with a clean blame path (TestDistributedBCC_SoundPartialZProofRejectsForgery). The consensus-facing registry closure is the one-linerRegisterPartialZVerifier(SoundPartialZVerifier(mode,λ,c,z)). Honest residuals: KEYGEN here is the trusted dealerDealAlgShares(no-reconstruct at SIGN time, not dealerless — that is item 2), and the joint nonce is the NonceMPC stand-inDealNonceMPCDebug(it reveals w to the harness = PULSAR-V13-W-LEAK, still fail-closed; the SIGNING decomposition is independent of how the nonce was established). -
Item 2 — dealerless byte-FIPS-204 ML-DSA DKG: RESEARCH-BLOCKED, with a COMPUTED obstruction (not a stub, not a fake, no dealer/TEE fallback).
ref/go/pkg/pulsar/distributed_bcc_dkg.goassessDealerlessFIPSderives the wall from the parameters (mirroringrangeproof.go): FIPS-204 calibrates β=τη, ω, and the BCC 2β margin to ‖s1‖∞,‖s2‖∞ ≤ η; a dealerless joint secret is a sum/Lagrange-combination of N≥2 contributions ⇒ ‖s2‖∞ ≤ Nη ⇒ ‖c·s2‖∞ ≤ Nβ > β, violating the BCC boundary-clearance hypothesis ‖c·s2‖∞ ≤ β at N=2 for both ML-DSA-65 and -87; the deeper break is that a sum-of-contributions secret is not the S_η distribution ML-DSA's EUF-CMA assumes, and forcing it back into S_η needs either a dealer or a norm-reduction that changes (A,t). t0 is NOT the obstruction (joint t0 = Power2Round-low is in range for any N, so ‖c·t0‖∞ < γ2 always — pinned by computation). The Corona/Raccoon noise-flooding technique IS the right one for a dealerless lattice signature and is exactly whycorona.BootstrapPedersenis dealerless — but it produces a noise-flooded Ring-LWE / Raccoon-family signature (Threshold Raccoon, EUROCRYPT'24) that does not verify under FIPS-204; ML-DSA has fixed S_η bounds and no noise-absorbing rounding step. This is precisely why the cert is AND-mode dual-PQ.DealerlessMLDSADKGfails closed (ErrDealerlessByteFIPSUnreachable); 5 tests pin the arithmetic. -
**Item 3 — TALUS construction (dealerless NONCE DKG + CEF distributed-w1
- two profiles): BUILT to the maximal real extent; the CSCP secure
comparison is the ONE precisely-computed residual.** Pulsar now realises
the SOTA TALUS scheme (Kao, Threshold ML-DSA with One-Round Online
Signing via Boundary Clearance and Carry Elimination, arXiv:2603.22109)
on the item-1 BCC/CEF core (
talus*.go):
-
Dealerless Shamir Nonce DKG (
talus_nonce_dkg.go,NonceDKGParticipant) — REPLACES the trusted nonce dealing insideDealNonceMPCDebug. Each party samples its OWN small contributiony_h(‖·‖∞ ≤ ⌊(γ1−2β−4)/N⌋), Shamir-shares it, and sums the shares it RECEIVES intoy_i = Σ_h f_h(x_i) = F(x_i),F(0) = Σ_h y_h = ȳ. No party (and no dealer) ever forms the joint nonce ȳ; the contribution is erased after dealing; the instance is one-time-use (Consume/Aborterase the share). Proven byTestTalus_NonceDKG_Dealerless(each node holds shares at exactly its own eval point ⇒ cannot interpolate ȳ; two T-subsets reconstruct the SAME ȳ in the oracle; small-nonce bound holds). -
CEF distributed-w1 (
talus_cef.go). Each party computes its OWN additive commitment contributiong_i = A·(λ_i·y_i)locally (CEFCommitmentShare);Σ_i g_i = A·ȳ = wbut no node forms w. The carry-elimination identity (cefReconstructW1FromShares) recoversw1 = HighBits(Σ g_i mod q)from the per-party Decompose parts + the two carries (q-wrap and α-carry) — proven equal to ground truth on real shares (TestTalus_CEF_CarryEliminationIdentity, ML-DSA-65 and -87).CEFComputeW1emits a W-LEAK-cleanNonceCertcarrying ONLY w1 + a binding commitment — never w, w0, or the low sum (asserted byTestTalus_CEF_DistributedCommitment+ the forbidden-field guard). This narrows PULSAR-V13-W-LEAK: the leakingDebugWis gone from the output; the cert is provably w0-free. -
The ONE residual — CarryCompare (CSCP) — COMPUTED, not faked (
assessCSCP/AssessCarryCompare, mirroringassessDealerlessFIPS). The carry-elimination needs the aggregate low sumA0 = Σ a0_ito resolve the α-carry, and A0 is w0 up to the carry — forming it in the clear IS the W-LEAK. TALUS resolves the carry with a SECURE comparison: a Distributed Comparison Function (DCF/FSS) for T=2, or a Carry-Save-Adder reduction + prefix comparison (needs N ≥ 2T−1) for T≥3. That non-linear secure comparison is the irreducible MPC step this package does not yet build;cefIdealSecureHighBitsmodels the IDEAL functionality it realises (returns ONLY w1, so the cert stays clean) andassessCSCPCOMPUTES the obstruction: the step, the per-T primitive, the honest-majority bound (N≥2T−1), the offline roundsmax(3, ⌈log2(N/2)⌉+2), the per-signature comparison count256·K·⌈1/0.317⌉, and the leak if skipped (opening A0 ⇒ w0 ⇒w'−w = c·t0 − c·s2). Pinned byTestTalus_CSCPObstruction_Computed. -
Honest-majority MPC substrate (
talus_mpc.go) —bgwMulShares(BGW secure multiplication over GF(q) Shamir shares) +SharedRandomBit(XOR-folded). SOUND, tested, and they concretely ENFORCE TALUS Theorem 10.1's N ≥ 2T−1 barrier (the degree-2(T−1) product is unreconstructable otherwise —ErrBGWNotEnoughParties). This is the multiplication/randomness layer the CSCP comparison circuit composes from; the malicious-secure / identifiable-abort hardening (Feldman/ Pedersen-committed shares, TALUS Phase B) is the orthogonal residual. -
Two profiles (
talus.go). Pulsar-TEE = trusted coordinator/TEE holds ȳ, computes w1 directly, and CAN pre-filter BCC offline (TalusTEEComputeW1; TEE attestation binding is the OPTIONAL luxfi/tee extension viaattest.go AttestationContext, never baked into core). PulsarPC = TEE-free, fully distributed, no node forms ȳ or w; honest-majority N≥2T−1 for T≥3 (TalusProfileAllows). The online path and emitted signature are byte-identical across profiles. -
Safety gate + pool + Quasar evidence.
TalusReleaseGateruns MANDATORY stock FIPS-204 verification before any signature is emitted and NEVER releases a failed/empty signature (TestTalus_ReleaseGate_NeverReleasesFailed).TalusNoncePoolgives a refillable pool with the existing non-grindableCanonicalNonceIndexselection (TEE admits only boundary-clear nonces; MPC filters online).TalusEvidencebinds the Quasar evidence kindpulsar-talus-mldsa(distinct from Corona) + suite IDs…-65/…-87(ML-DSA-44 refused, outside BCC scope) and dispatches to the suite-pinned stock verifier so no suite string routes a Pulsar leg to the wrong verifier. -
Headline proof.
TestTalus_MPC_EndToEnd_StockVerify/_Mode87: a full multi-node PulsarPC ceremony over a message bus (dealerless DKG → per-node commitment shares → CEF w1 → one z-broadcast round → release gate) produces a signature that verifies under the UNMODIFIED stockcloudflare/circlmldsa{65,87}.Verify, with single-share custody, no joint-nonce / no-w / no-w0 / no-s1 reconstruction, sub-quorum refusal, one-time nonces, and tamper rejection. 15 TALUS tests green;go build ./...and the full package suite green.
Remaining honest work (Item 3): (a) DONE —
cefIdealSecureHighBitsis realised by the actual CSCP secure-comparison circuit (talus_cscp.go,cscpSecureHighBitsVec, driven byCEFComputeW1) on thebgwMulSharessubstrate; no node forms w0/w/A0 even transiently (proven by transcript + source-structural guard + reflection; see PULSAR-V13-W-LEAK above). (b) the malicious-secure / identifiable-abort layer (committed shares, verified openings, complaint round) over the DKG and the comparison — the scopedCSCPMaliciousResidual, orthogonal to the now-proven semi-honest leak-free property; a wrong w1 is caught downstream (liveness fault, never forgery/leak); (c) KEYGEN is still the trusted dealerDealAlgShares(item 2 proves dealerless byte-FIPS-204 KEYGEN is unreachable; permissionless safety rests on the dealerless Corona leg in the AND-mode cert). HONEST DISTINGUISHABILITY NOTE: the TALUS threshold transcript (masked CEF broadcasts + per-party z_i) may differ in DISTRIBUTION from a single-party ML-DSA transcript, even though the final signature's byte format and verify path are identical and standard. - two profiles): BUILT to the maximal real extent; the CSCP secure
comparison is the ONE precisely-computed residual.** Pulsar now realises
the SOTA TALUS scheme (Kao, Threshold ML-DSA with One-Round Online
Signing via Boundary Clearance and Carry Elimination, arXiv:2603.22109)
on the item-1 BCC/CEF core (
PULSAR-V12-GPU-NTT-WIRE — route Round-2 NTTs through gpu-kernels batched dispatch
Status: SPEC only. The substrate
(lux-private/gpu-kernels/ops/lattice/ntt_mldsa, q = 8380417, R = 2^32,
byte-equal to PQClean MLDSA65_CLEAN_ntt) ships across all five
backends (CUDA, HIP, Metal, Vulkan, WGSL). The C ABI
lux_lattice_ntt_mldsa_batch is the natural batched-NTT entry. The
existing pulsar/gpu.UseAccelerator keeps the SubRing-dispatch
threshold above pulsar's N=256 production ring so single-poly GPU
dispatch is intentionally off (it loses to pure-Go at N=256 on every
host). The batched dispatch (22 forward NTTs per Round-2-party-attempt
on independent polys) is where the GPU win lives.
Three discrete pieces:
- Substrate: lift
lux_mldsa_verify_batchandlux_lattice_ntt_mldsa_batchfromErrNotSupportedstub (luxfi/accel/internal/capi/capi.go:503-531) to a real call. - Pulsar batched NTT entry: package-private
batchNTT(polys []poly)inmldsa_lattice.gothat dispatches via accel iffpulsar/gpu.Enabled()andaccel.Available()andlen(polys) >= batchThreshold; otherwise falls back to the existing per-poly pure-Gontt(). - Round-2 batched call sites: replace per-poly loops in
threshold_v03.go:680-913withbatchNTTcalls per logical batch (yHat, s1Hat, cs2-input, ct0-input).
Byte-equality contract: enforced by the existing
TestPulsar_GPU_ByteEqual regression guard
(threshold_v03_gpu_byte_eq_test.go). Today it passes vacuously (both
legs run pure-Go); after PULSAR-V12-GPU-NTT-WIRE lands it pins the
accel-engaged leg byte-equal to the pure-Go leg.
Engine-layer batch verify: pulsar's CPU
VerifyBatch already defers GPU acceleration to the engine layer per
verify_batch.go:11-23. The substrate (MLDSAVerifyBatch) is the
forward-looking item, not pulsar code; engine wiring at
/Users/z/work/lux/consensus/engine/gpu_batch_pipeline.go adds the
MLDSA batch path once the substrate ships.
Closed
PULSAR-V13-W-LEAK — CLOSED semi-honest (v1.2.0)
Status: CLOSED (semi-honest, simulation-proven), commit 530c24e. The
REAL CSCP secure-comparison circuit (talus_cscp.go::cscpSecureHighBitsVec,
driven by CEFComputeW1) realises the ideal so that no node forms w/w0/A0
even transiently — proven leak-free by TestCSCP_MultiNode_LeakFree /
TestCSCP_LeakFree_Structural / TestCSCP_MaskOpen_HidesW in an in-process
N-party SIMULATION. The full hazard description and closure narrative are
retained in-place with the V13 threshold-path cluster above (its header is
marked CLOSED). The orthogonal malicious-secure / identifiable-abort layer + a
networked, non-simulation MPC deployment is the open Residual A (## Open);
a malicious deviation is bounded to a liveness fault (abort/retry) by FindHint
TalusReleaseGate, never forge or leak (TestCSCP_WrongW1_CaughtByFindHint).
PULSAR-V04-CTX — v0.4 ctx-bound threshold sign (FIPS 204 §5.4)
Status: CLOSED in v1.1.1 (tag pending — see CHANGELOG.md for the exact commit). Owner: cryptographer.
Root cause
OrchestrateV03Sign (and the underlying AlgebraicAggregate +
AlgebraicThresholdSigner.round2EmitFull) hardcoded the FIPS 204
§5.4 step-2 ctx prefix to the empty-ctx encoding:
// BEFORE (v1.0.x): μ derivation
h := sha3.NewShake256()
h.Write(tr[:])
h.Write([]byte{0x00, 0x00}) // ← always empty ctx
h.Write(message)
h.Read(mu[:])
ctx-bound permissionless threshold sign was therefore impossible:
operators that needed FIPS 204 §5.2 domain separation (e.g. the
lux-evm-precompile-mldsa-v1 EVM precompile) had to route through
the threshold dispatcher's dealerKey single-party shortcut, which
materialised the master sk in the dispatcher process — breaking the
v0.3 public-BFT-safety contract for any session that used the
ctx-bound path.
Fix
Decomplect μ derivation into a single helper deriveMuCtx(tr, ctx, msg, out) (threshold_v03.go) that the v0.4 path threads ctx into the
FIPS 204 §5.4 prefix:
// AFTER (v1.1.1): single source of truth
func deriveMuCtx(tr [64]byte, ctx, msg, out []byte) {
h := sha3.NewShake256()
h.Write(tr[:])
h.Write([]byte{0x00, byte(len(ctx))}) // FIPS 204 §5.4 single-byte length
if len(ctx) > 0 { h.Write(ctx) }
h.Write(msg)
h.Read(out[:64])
}
New ctx-aware API surface:
NewAlgebraicThresholdSignerCtx(..., ctx, ...)— addsCtxfield onAlgebraicThresholdSigner.AlgebraicAggregateCtx(..., ctx, ...)— companion toAlgebraicAggregate.OrchestrateV03SignCtx(..., ctx, ...)— companion toOrchestrateV03Sign.
Backwards-compatibility invariants:
OrchestrateV03Sign(msg)is now a thin wrapper that callsOrchestrateV03SignCtx(nil, msg). Output bytes are byte-identical to historical v0.3 (pinned byTestOrchestrateV03SignCtx_EmptyCtx_MatchesV03Sign).AlgebraicAggregate(...)is now a thin wrapper that callsAlgebraicAggregateCtx(..., nil, ...). Same byte-identity.NewAlgebraicThresholdSigner(...)is now a thin wrapper that callsNewAlgebraicThresholdSignerCtx(..., nil, ...). TheCtxfield is nil on the historical constructor.
ctx-length guard: ErrCtxTooLarge (alias of ErrCtxTooLong from
sign.go) at all three boundaries — constructor, aggregator, and
orchestrator.
Graduation gate
All currently TRUE on the tip of main at v1.1.1:
TestOrchestrateV03SignCtx_Mu_Includes_CtxPASS — distinct ctx yields distinct μ; the productionderiveMuCtxmatches the reference SHAKE-256 byte-for-byte; emptynilctx equals empty[]byte{}ctx (FIPS 204 §5.4 step-2 encoding).TestOrchestrateV03SignCtx_EmptyCtx_MatchesV03SignPASS — under identical deterministic RNG seeds,OrchestrateV03Sign(msg)andOrchestrateV03SignCtx(nil, msg)emit bit-identical wire bytes. Existing chain certs remain valid.TestOrchestrateV03SignCtx_CtxTooLarge_RejectedPASS — 256-byte ctx rejected withErrCtxTooLargeat constructor, aggregator, and orchestrator; 255-byte ctx accepted at the boundary.TestOrchestrateV03SignCtx_VerifyMatchesFIPS204PASS — the output verifies under cloudflare/circl's stock FIPS 204mldsa65.Verify(pub, msg, ctx, sig)and is REJECTED under different ctx or empty ctx (ctx binding is real). Aggregator- side ctx mismatch against the signers' ctx fails at MAC verification or norm rejection — never produces a valid sig under a different ctx than the signers used.TestAlgebraic_NoSkAccess/AlgebraicAggregateandTestAlgebraic_NoSkAccess/AlgebraicAggregateCtxPASS — AST guard now covers BOTH the wrapper and the ctx-bound entry point. No sk-bearing parameter, no sk-bearing call, no sk-bearing identifier.- All v1.0.22 graduation gates remain TRUE (
TestAlgebraic_FullCycle_n5_t3,TestAlgebraic_ByteValid,TestAMatrix_IsAlreadyInNTTDomain,TestCirclInternalShape_VsPulsar). - Race-clean:
cd ref/go && GOWORK=off go test -race -count=1 -short -timeout 900s ./pkg/pulsar/.
PULSAR-V03-1 — v0.3 algebraic sign: byte-equality with circl Verify
Status: CLOSED in v1.0.20 (commit 023a3ed).
Regression-guard hardening in v1.0.21 (267ec04) and v1.0.22 (29094a7).
Owner: cryptographer.
Root cause
deriveKeyMaterial in ref/go/pkg/pulsar/mldsa_keyderive.go was
applying a spurious forward NTT to the public matrix A AFTER
sampling it via polyDeriveUniform:
// BEFORE (buggy, v1.0.19 and earlier), per (i,j) over K×L:
polyDeriveUniform(&km.a[i][j], &km.rho, ...) // already NTT-domain
// ... later, separate K×L pass over the same matrix:
km.a[i][j].ntt() // EXTRA NTT — wrong
Per FIPS 204 §3.5 Algorithm 32 (ExpandA), A is sampled DIRECTLY
into the NTT representation; no separate forward-NTT step exists.
polyDeriveUniform is exactly that algorithm — byte-identical to
cloudflare/[email protected]'s PolyDeriveUniform. The post-step produced
double-NTT'd values.
Why the bug was invisible before v0.3:
- v0.1 calls
circl.SignTo, which maintains its ownA. - v0.2 emits via
circl.SignTo(setup.SkBytes, ...); the wrongAonly entered transcript-level commits, which are self-consistent across parties. - keygen consumes
km.aBEFORE the spurious NTT step (int = A·s1 + s2), so the public key matched circl byte-for-byte. Only the post-step contaminated the cachedkm.athat v0.3 sign later consumed assetup.A.
v0.3 was the first mode that propagated the wrong A all the way to
the output signature.
Fix
Drop the post-sample NTT loop in deriveKeyMaterial. The same
redundant .ntt() in manualVerifyOnce (threshold_v03_bytediff_test.go)
and in TestPrimDiff_VerifyPipeline_OnCirclSig was removed.
Regression guards pin the convention byte-for-byte against circl's
stored pk.A: TestAMatrix_IsAlreadyInNTTDomain compares km.a (the
contaminated field) at corners [0][0] and [K-1][L-1];
TestCirclInternalShape_VsPulsar mirrors circl's PublicKey via
unsafe-pointer and asserts km.a == pk.A. v1.0.22 also hardened the
AST guard in TestAlgebraic_NoSkAccess to walk *ast.SelectorExpr.Sel.Name
and *ast.Ident, so an indirect dispatch (var fn = polyDeriveUniformLeqEta; fn(...)) cannot bypass the banned-call check on AlgebraicAggregate.
Graduation gate
All currently TRUE on the tip of main at v1.0.22:
TestAlgebraic_FullCycle_n5_t3PASS — v0.3 sig verifies under stockmldsa65.Verify.TestAlgebraic_NoSkAccessPASS — public-BFT safety contract:AlgebraicAggregatehas no*PrivateKey/SkBytes/seedparameter; AST walks confirm no sk-bearing primitive is reachable from its body (including indirect dispatch).TestAMatrix_IsAlreadyInNTTDomainandTestCirclInternalShape_VsPulsarPASS — byte-equality vs circlpk.A.TestTransitional_DependsOnSkBytesPASS — v0.2 still declares its SkBytes dependency honestly. (The original gate expected this to FAIL on the assumption v0.2 would be edited in place; the actual closure shipped v0.3 as a parallel track and left v0.2 honest. Both paths now coexist.)- Class N1 byte-equality preserved:
TestN1_ByteEquality_*PASS. - Full suite green under
-race:cd ref/go && GOWORK=off go test -count=1 -short -timeout 300s ./pkg/pulsar/.