Commit Graph
135 Commits
Author SHA1 Message Date
zeekay f24f324b37 pulsar: GATE-C indirection lint + honest soundness wording (RED INFO)
The AST name call-graph follows DIRECT named calls only; it misses function-
value / closure / go:linkname indirection (RED PoC: e:=deriveKeyMaterial;
s:=bccSign; s(e(...)) not flagged). The old comment overstated 'never miss one'.

Fix: pair the reach graph with a companion lint forbidBannedPrimitiveIndirection
that forbids taking ANY banned primitive as a non-call value or aliasing it via
//go:linkname anywhere in the default build. With that lint green, every banned-
primitive use in the build IS a direct call the graph follows — so the PAIR is
complete for the banned set (neither half claimed complete alone). Wording
softened to state exactly this.

GATE: TestGATE_C_NoBannedPrimitiveValueIndirection — (a) the real build takes no
banned primitive as a value / linkname; (b) the name graph alone MISSES the
e:=deriveKeyMaterial; s:=bccSign indirection while the lint CATCHES it; (c)
go:linkname aliasing a banned primitive is caught.
2026-06-27 22:36:52 -07:00
zeekay 5a3264ab68 pulsar: authenticate partial->PartyID; gate blame on signature validity (RED MEDIUM)
AggregateBCCWithBlame consumed raw []Partial; PartyID was unauthenticated, so an
attacker could stamp a victim's slot on a forged partial and (via first-per-
PartyID + duplicate rules) get the honest victim BLAMED and front-run-EXCLUDED.
No forge/leak (capstone holds), but blame misattributed.

Fix: bind each partial to its producer's long-term identity key.
- Partial gains Author + AuthSig; Round2 signs (author ‖ slot ‖ H(PartyID,
  session,nonce,ZShare,Proof)) via an injected IdentitySigner (SetIdentity).
- AggregateBCCWithBlame gains (quorum, epoch, AbortSignatureVerifier). When a
  verifier is supplied it AUTHENTICATES each partial BEFORE attribution: accept
  only if AuthSig verifies AND Author == quorum[PartyID]; drop forged/wrong-slot/
  unsigned partials with NO blame against the slot's honest owner, BEFORE the
  first-per-PartyID/duplicate logic (so a forgery cannot evict the victim).
- Blame is emitted ONLY for authenticated partials and NEVER off a raw PartyID
  (auth==nil => no blame produced — attribution fails closed). Wraps
  protocol_auth.SignedProtocolMessage (one identity layer). Networked transport
  auth stays a flagged residual.

GATE B updated to authenticated partials (a deviator SIGNS its bad partial =>
attributable; a transport-tampered one breaks its sig => dropped, not framed).
New TestRED_PoC_MEDIUM_CannotFrameOrExcludeHonestVictim: forged victim-slot
partial is dropped (attacker can't sign as victim) -> victim NOT blamed, NOT
excluded, round still signs; contrast shows the verifier is load-bearing.
2026-06-27 22:36:52 -07:00
zeekay ef9bb41dfd pulsar: nonce dedup keys on w1 ALONE — close RED LOW cross-committee gap
The dedup key was H(committeeID‖w1). The same joint nonce (same w1) used in two
committees that share a victim validator produced DISTINCT keys, so the victim's
ledger did not dedup across committees -> victim emits a partial in each -> the
attacker collects two partials on one nonce.

Fix: key on w1 alone. This is sound precisely BECAUSE the ledger is now
per-validator-share (resolved by shareIdentityKey): within the victim's one
ledger the same w1 collapses to ONE key regardless of committee. committeeID
stays on the NonceTicket/binding for audit and on TicketID; only the MaterialKey
drops it.

GATE: TestRED_LOW_CrossCommittee_SameNonce_Deduped — two distinct committees
sharing a victim, same w1 -> equal MaterialKey -> second reserve ErrNonceReused.
2026-06-27 22:36:52 -07:00
zeekay 858872cd42 pulsar: nonce single-use SAFE BY CONSTRUCTION — close RED HIGH default-path fail-open
NewDistributedBCCSigner gave each instance its OWN empty in-memory ledger;
since a signer fixes (sid,ctx,msg) at construction, signing two messages needs
two signer objects -> two empty ledgers -> cross-message nonce reuse slipped
unless the integrator hand-threaded ONE ledger via SetNonceLedger. The
reference runBCCCeremony never did, so the shipped default was fail-open and
RED recovered the victim's full s1-share on the bare API.

Fix: resolve the single-use ledger from a process-global registry keyed by
SHARE IDENTITY (shareIdentityKey = H(mode,nodeID,evalPoint,secret-share)).
Every signer over the same key-share resolves to ONE ledger -> cross-instance
reuse refused by DEFAULT, no per-instance empty-ledger path. SetNonceLedger now
installs a persistent ledger into the same per-share slot (first-writer-wins);
the in-process default is safe NOW, persistence stays a flagged residual.

GATE A extended: TestRED_PoC_DefaultLedger_NonceReuse_Refused drives the REAL
API like runBCCCeremony (fresh signer per message, NO SetNonceLedger) and
asserts the second Round2 on the reused nonce + the relabel variant both return
ErrNonceReused -> RED's PoC flips, s1 is unrecoverable.
2026-06-27 22:36:52 -07:00
zeekay 520396ebc6 pulsar: malicious-behavior capstone + selective-abort + order-independence (item 5b)
CAPSTONE (TestMalicious_BadBehaviorNeverForgesOrLeaks): every single-member
deviation on the no-reconstruct sign path => ABORT or attributable BLAME, NEVER a
FIPS-valid forged signature. Subtests: nonce-reuse refused; invalid-sigma
blamed+abort; duplicate cannot inflate threshold; malformed no-panic+blamed;
valid-sigma wrong-z is a liveness fault (no forgery). Honest baseline asserts an
honest quorum DOES sign (so the negatives are meaningful).

SELECTIVE-ABORT (TestMalicious_SelectiveAbort_ReformProducesValidSig): the
aggregator's Lagrange is over the EXACT supplied evalPoints set, so selective
abort is orchestrator RE-FORMATION of a fresh exact-threshold quorum excluding the
blamed party -> the re-formed clean quorum produces a FIPS-valid signature.

ORDER-INDEPENDENCE (TestMalicious_AggregationOrderIndependent): identical
signature bytes regardless of partial submission order (CanonicalSignerSet
deterministic) -> no last-mover grinding of subset/output/challenge.

go vet clean; no stdlib log; full suite green (6.2s).
2026-06-27 21:21:36 -07:00
zeekay d2b4c1eb62 pulsar: nonce-ticket lifecycle + authenticated-message equivocation (item 5a)
- NonceTicket (unique TicketID = H(committeeID||w1||binding) audit handle) +
  ReserveNonceTicket: the ONE nonce-consume path. Dedup keys on MATERIAL
  (committeeID||w1), NOT TicketID, so relabel/different-message reuse of the same
  joint nonce is still ErrNonceReused. Round2 refactored to reserve via the
  ticket. Lifecycle test: unique ids, single-use, domain-bound, abort-doesn't-leak.
- protocol_auth.go: canonical to-be-signed encoding for protocol messages bound
  to (epoch,session,nonce,round); pluggable identity verifier (reuses the
  AbortSignatureVerifier shape, DRY); DetectEquivocation -> two validly-signed
  conflicting same-slot messages from one author yield ComplaintEquivocation
  evidence. Networked transport (authenticated channels) is the consensus-layer
  residual; this is the crypto primitive + detector.

Full suite green.
2026-06-27 21:19:02 -07:00
zeekay ee398080f6 pulsar: GATE-2 hardened to call-graph reachability (GATE C) + CI legacy-tag invariant (items 3-4)
RED GATE-2 bypass: the structural gate greps only distributed_bcc.go for
KeyFromSeed(/func LargeCombine, so a reconstruct-then-sign wired via
deriveKeyMaterial+bccSign elsewhere PASSES.

GATE C (gate2_reachability_test.go): stdlib go/ast name call-graph over the
default-build files. Bans {KeyFromSeed, deriveKeyMaterial, bccSign,
shamirReconstruct*, LargeCombine, DealAlgShares} from being REACHABLE from the
committee sign entrypoints (AggregateBCC[WithBlame], NewDistributedBCCSigner,
DistributedBCCSigner.{Round1,Round2,Finalize,FinalizeWithBlame,SetNonceShare}).
Callee side over-approximated by name -> sound bias (over-report, never miss).
Two tests: (1) the REAL package is clean (8 entrypoints, none reach a banned
primitive); (2) the checker CATCHES RED's deriveKeyMaterial+bccSign bypass, both
as a synthetic graph AND via the real parse->graph pipeline on rogue source;
plus a clean-path negative control (no false positive).

Item 4 (ci_build_invariant_test.go): the production (default-tag) build never
carries legacy_trusted_dealer -- asserts the tag gates real reconstruct files,
they are absent from the default build, LargeCombine is quarantined, no
default file requires the tag, and DealAlgShares (trusted-dealer keygen) is
defined ONLY in _test.go.

Full suite green.
2026-06-27 21:15:13 -07:00
zeekay 90b8ff7ddd pulsar: identifiable abort for the sign path (RED MEDIUM) + GATE B
AggregateBCC silently dropped malformed/duplicate/invalid partials (anonymous
DoS) and CanonicalSignerSet does not dedupe (a duplicate PartyID could satisfy
the threshold with < t DISTINCT signers); a short ZShare panicked the aggregator.

FIX:
- AggregateBCCWithBlame (canonical) attributes every detectable deviation to its
  PartyID (PartialBlame: malformed / duplicate / unknown-party / session-mismatch
  / invalid-proof); AggregateBCC is the back-compat wrapper (RoundSigner.Finalize
  + GATE-2 reflection + existing tests intact). FinalizeWithBlame maps PartyID ->
  NodeID -> signed-complaint AbortEvidence (ComplaintBadPartial kind, never
  self-accuses).
- Duplicate PartyID rejected: first occurrence authoritative, later ones blamed;
  duplicates can NOT inflate a sub-threshold set.
- unpackPolyVecChecked: malformed/truncated ZShare -> ErrWireLengthMismatch, no
  panic (closes a malformed-share DoS).
- shareCommitmentsFor: ONE pure fn of public inputs called by BOTH Round2 and
  AggregateBCC => the partial-z proof binds the SAME per-party DKG/nonce
  commitments on prove + verify (symmetric, no globals). nil today; the single
  BDLOP plug point.

DESIGN+SCAFFOLD+FLAG (share_commit.go, Residual A): sound valid-sigma WRONG-z
blame needs a HIDING lattice commitment (BDLOP/Ajtai under a SEPARATE matrix) to
the dealt (y_i,s1_i) + an extended linear-sigma of opening. Homomorphic A*s1_i /
A*y_i is REJECTED (reopens W-LEAK / HINT-LEAK). Until then a valid-sigma wrong-z
is a LIVENESS fault (no FIPS-valid signature, no forgery/leak), marked
ErrIdentifiableAbortResidual.

GATE B (blame_gate_test.go): B.1 duplicate attributed + cannot inflate threshold;
B.2 invalid-sigma attributed to exact PartyID as AbortEvidence; B.3 malformed
ZShare no panic + BlameMalformed; B.4 honest residual — valid-sigma wrong-z
yields no forgery and is the flagged BDLOP residual.

GATE-1/GATE-2 still green; full suite green (7.5s).
2026-06-27 21:10:55 -07:00
zeekay 789ed0adfc pulsar: nonce single-use anti-replay guard closes RED nonce-reuse key-recovery (HIGH) + GATE A
THE HIGH (RED TestRED_NonceReuse_RecoversS1): same joint nonce + 2 messages =>
public (z_A - z_B) = (c_A - c_B)*s1 solves for the WHOLE expanded key. UNGUARDED
on v0.4.0.

FIX (nonce_ledger.go + Round2 wiring):
- NonceLedger single-use store keyed on the nonce COMMITMENT
  H(committeeID || w1) -- NOT the nonceID label, so a relabeled joint nonce
  cannot bypass. Reserve() is fail-closed: ErrNonceReused on any second use,
  never rolled back (an aborted attempt leaves no reusable nonce state).
- DistributedBCCSigner reserves the nonce in Round2 BEFORE touching the secret.
  Per-validator ledger injectable via SetNonceLedger (one ledger per share across
  signer instances catches cross-instance reuse); domain binding via
  SetNonceBinding (epoch/policy/message_kind/digest, audit + tripwire).

GATE A (nonce_reuse_gate_test.go): (1) actually RECOVERS the full 5-poly s1 by
solving (c_A-c_B)*s1 = z_A-z_B over Z_q (negacyclic Gauss-Jordan) == dealer
secret bit-for-bit -- the vuln is real; (2) the real signer API refuses the
second partial (ErrNonceReused), incl. the relabel bypass -- the system can
never be assembled via honest signers.

GATE-1/GATE-2 still green; full suite green (7.2s).

Residual (flagged): in-memory ledger does not survive restart -> production must
inject a PERSISTENT ledger; dealer-side NonceMPC 'Consumed' marking is
complementary defense-in-depth (leak-free NonceMPC residual).
2026-06-27 20:58:24 -07:00
zeekay 2962fd5c15 pulsar: claim hygiene — VERSIONS.md (v0.3 removed / v0.4 no-reconstruct / keygen track) + FINAL SCOPED claim in PROOF-CLAIMS §0
v0.3 algebraic-broadcast REMOVED (HINT-LEAK); v0.4 = BCC/CSCP no-reconstruct
(current). Keygen track documented: trusted-dealer bootstrap (test-only,
quarantined) + Pedersen-VSS dealerless exploration (feat/v02 branch) +
NonceMPC leak-free residual. PROOF-CLAIMS §0 records the user-approved scoped
claim; NEVER FIPS-certified / fully-malicious-proven / 1000-validator DKG.
2026-06-27 20:52:05 -07:00
zeekay 9661ad4ac0 Pulsar v0.4: no-reconstruct BCC/CSCP committee signing is the sole production path
Red-verified (commit a0bd97e): AggregateBCC no-reconstruct signer is the only
production committee signer; LargeCombine + DealAlgShares quarantined out of the
default build; GATE-1 (circl mldsa65.Verify accepts) + GATE-2 (no KeyFromSeed/sk
in sign-combine) green. HONEST SCOPE: no-reconstruct foundation, standard-verifier
compatible; NOT yet real-key-safe (nonce single-use guard + malicious-secure CSCP
are the next layer, red HIGH). v0.3 algebraic-broadcast path was removed; v0.4 =
BCC/CSCP.
v0.4.0
2026-06-27 20:06:25 -07:00
zeekay 00afb8ec20 pulsar: no-reconstruct committee threshold sign; quarantine reconstruct+dealer
Make the committee threshold-SIGN combine genuinely no-reconstruct and remove
the centralized-trust paths from the production build.

- Quarantine the GF(q) SEED-share reconstruct family behind
  //go:build legacy_trusted_dealer: large_threshold.go (LargeCombine, the
  KeyFromSeed-at-sign H-1 footgun), large_dkg.go, large_reshare.go,
  large_types.go, largeshamir.go (+ their tests). The production committee
  sign path is now ONLY the no-reconstruct AlgShare/AggregateBCC RoundSigner
  (distributed_bcc.go): each party emits z_i = λ_i·y_i + c·λ_i·s1_i from its
  own share+nonce; the combiner Lagrange-sums to z and recovers the hint from
  public w' = A·z − c·t1·2^d — never forming s1, the seed, or sk.

- Rip out the trusted s1-share dealer DealAlgShares (+ zeroizeKeyMaterial)
  from distributed_bcc.go into bootstrap_dealer_test.go (a _test.go file,
  uncompilable into any production binary; available to tests/bootstrap only).

- Add the two hard gates (no_reconstruct_committee_test.go):
  GATE 1 (standard-verifier): a (t,n)=(4,7) committee no-reconstruct signature
  verifies under independent cloudflare/circl mldsa65.Verify; tamper rejected.
  GATE 2 (no-reconstruct invariant): structural — the production build has no
  KeyFromSeed call in any sign-combine file and no LargeCombine; behavioural —
  Partial and AggregateBCC carry no share/sk/seed, and t-1 partials cannot sign.

Residual (flagged, NOT claimed fixed): a dealerless s1-share KEYGEN is the
research-blocked Part-2 problem (naive_additive_seta_obstruction.go computes the
obstruction; Mithril short-replicated shares is the adoption target). Keygen-side
KeyFromSeed in dkg.go (group-pubkey derivation) is a separate keygen residual.
Honest claim: no-reconstruct committee threshold signing whose output verifies
under the standard ML-DSA verifier — NOT FIPS-204 KeyGen distribution-equivalence,
NOT FIPS-validated.
2026-06-27 19:30:56 -07:00
zeekay 6667462663 Merge: scope dealerless-keygen claim correctly (Phase 0) v1.2.1 2026-06-27 18:28:28 -07:00
zeekay 11d490a015 pulsar: scope the dealerless-keygen claim correctly (Phase 0 claim cleanup)
The obstruction file over-claimed: "a genuinely dealerless DKG ... is NOT
achievable with known techniques." That is too strong and contradicted by
published work. Corrected to the NARROW, true statement and renamed the file to
say what it actually proves.

- distributed_bcc_dkg.go -> naive_additive_seta_obstruction.go (+ test). The file
  computes the obstruction to the NAIVE additive (Pedersen/Gennaro) lift: a summed
  joint secret has ‖s2‖∞ ≤ Nη, breaking the BCC boundary-clearance hypothesis and
  ML-DSA's S_η-calibrated EUF-CMA. That computed barrier is correct and unchanged
  (assessDealerlessFIPS, errors.Is sentinel — both intact, test green).
- Removed the general-impossibility framing. Short replicated-share constructions
  (Mithril, ia.cr/2026/013, USENIX Sec 2026) achieve dealerless byte-FIPS-204
  threshold ML-DSA at small N — a known, adoptable technique, not yet implemented
  here; cited as the candidate path.
- Fixed a re-introduced mislabel: Corona is Module-LWE (Ringtail/Raccoon), not
  Ring-LWE (2 comment sites).

What stays true and proven (separate concern): Pulsar's no-leak BCC/CEF threshold
SIGNING produces a STANDARD ML-DSA-verifiable signature (TestBCCSignRoundTripVerifiesCIRCL,
independent circl verifier). The keygen is trusted-dealer; genuinely-dealerless
byte-FIPS keygen is the open item the corrected file scopes.

Comments + file rename only; no logic, no symbol rename. Package builds, test green.
2026-06-27 18:28:28 -07:00
zeekay c469bf602b pulsar: TALUS docs to v1.2.0 — PULSAR-V13-W-LEAK closed (semi-honest), residuals scoped
TALUS threshold ML-DSA built: dealerless nonce DKG + CEF + REAL CSCP CarryCompare secure-comparison closes PULSAR-V13-W-LEAK (semi-honest, simulation-proven) — no node forms w0/w even transiently. FindHint + ReleaseGate bound malicious deviation to liveness (never forge/leak). Open items narrowed to Residual A (malicious-secure CSCP + networked non-simulation MPC) and Residual B (dealerless byte-FIPS-204 key DKG proven unreachable via S_eta bound -> trusted-dealer keygen; Corona carries permissionless). BLOCKERS reconciled, README/LLM/CHANGELOG/PROOF-CLAIMS refreshed; tag refs -> v1.2.0.
2026-06-27 14:14:46 -07:00
zeekay bdbd9a346a pulsar: REAL CSCP secure-comparison circuit closes PULSAR-V13-W-LEAK (semi-honest)
Builds the CarryCompare (CSCP) secure-comparison MPC circuit that realises the
ideal cefIdealSecureHighBits with an ACTUAL secure comparison, so no node (and no
process) ever forms the aggregate low sum A0 = Sum a0_i, the low part
w0 = LowBits(w), or the full commitment w — even transiently. This is the closing
move for PULSAR-V13-W-LEAK on the TALUS-MPC path.

talus_cscp.go — the real circuit, composing from the bgwMulShares / SharedRandomBit
substrate (talus_mpc.go):
  - cscpSecureHighBitsVec: additive commitment shares -> additive->Shamir reshare to
    <w> over GF(q) -> secure HighBits -> opened w1 only. Parallel over the 256*K
    independent coefficients; race-clean.
  - secure HighBits via the exact boundary-count identity
    w1 = (Sum_{k=1..16}[w > (2k-1)*gamma2]) mod 16 (m=16 power-of-two buckets for
    ML-DSA-65/87), proven coefficient-exact against FIPS Decompose over ALL q
    residues.
  - bit-decomposition by mask-open (carry-save adder + bitwise prefix less-than for
    the mod-q fold = the "CSA + prefix comparison" the obstruction names);
    bitLTPubShared / bitLTSharedPub / bitAdd / bitSubBetaQ / randomBitwise gadgets.
  - CSCPParticipant: per-node state holds ONLY its own commitment share (no joint
    w/w0/A0 field). CSCPMaliciousResidual / AssessCSCPMalicious: the scoped,
    orthogonal malicious-secure / identifiable-abort layer (TALUS Phase B).
  - enforces N >= 2T-1 (TALUS Thm 10.1).

talus_cef.go — CEFComputeW1 now DRIVES the real circuit (cscpSecureHighBitsVec)
instead of the ideal; cefIdealSecureHighBits retained as the test ORACLE.

Proven: gadgets bottom-up (bitwise LT exhaustive over all 64x64 pairs; bit-decompose
reconstructs; secure HighBits == FIPS Decompose on boundary + random coeffs);
multi-node leak-free ceremony (separate per-node state + bus) with w1 == ground-truth
HighBits(A*ybar), transcript opening ONLY {validity bit, uniform mask-open, w1}
(otherCt==0), source-structural guard (reconstruct only inside open(), sanctioned
tags only), reflection (no joint field), perfect masking; real CSCP == ideal
F_HighBits, ML-DSA-65 and -87; a wrong w1 is caught downstream by FindHint + the
mandatory stock-FIPS release gate (liveness fault, never forgery/leak). The headline
TestTalus_MPC_EndToEnd_StockVerify / _Mode87 now run the REAL CSCP and the aggregated
signature still verifies under unmodified cloudflare/circl mldsa{65,87}.Verify.

27 TALUS+CSCP tests green; full pkg suite green; race-clean.

Residual (honest): the circuit is semi-honest honest-majority; the malicious-secure
identifiable-abort layer is scoped (CSCPMaliciousResidual), not faked. KEYGEN stays
trusted-dealer (item 2 obstruction); permissionless safety rests on the dealerless
Corona leg of the AND-mode dual-PQ cert.
v1.2.0
2026-06-27 12:34:56 -07:00
zeekay a18093496d pulsar: TALUS-TEE w1 source + nonce pool + BLOCKERS V12-item-3 (CSCP obstruction)
- talus_cef.go: TalusTEEComputeW1 — the Pulsar-TEE coordinator w1 source
  that (unlike MPC) CAN pre-filter BCC offline; returns a W-LEAK-clean cert
  (only w1 leaves the TEE). Cross-checked vs the coordinator nonce path.
- talus_sign.go: TalusNoncePool — refillable pool with the existing
  non-grindable CanonicalNonceIndex selection (TEE admits only
  boundary-clear; MPC filters online), one-time consume, fail-closed empty.
- talus_test.go: TestTalus_TEE_ComputeW1_BCCPrefilter +
  TestTalus_NoncePool_CanonicalSelection (15 TALUS tests total, all green).
- BLOCKERS.md: PULSAR-V12 item-3 documents the TALUS build + the COMPUTED
  CSCP residual; PULSAR-V13-W-LEAK marked NARROWED (DebugW gone; only the
  secure-comparison realisation of cefIdealSecureHighBits remains).
2026-06-27 11:52:08 -07:00
zeekay 532a00c0bb pulsar: TALUS threshold ML-DSA — dealerless nonce DKG + CEF distributed-w1 + 2 profiles (PULSAR-V12)
Implements the TALUS construction (arXiv:2603.22109) on the existing
no-reconstruct BCC/CEF signing core:

- talus_nonce_dkg.go: dealerless Shamir Nonce DKG. No party/dealer ever
  forms the joint one-time nonce y; each party sums received shares to its
  own y_i. Replaces the trusted nonce dealing inside DealNonceMPCDebug.
- talus_cef.go: CEF distributed-w1. Per-party additive commitment
  g_i=A*(lambda_i*y_i) (no y/w reconstruct) + the proven carry-elimination
  identity (w1 recovered from per-party Decompose parts + carries) + the
  ideal secure-HighBits functionality whose OUTPUT is W-LEAK-clean (only
  w1, never w/w0). assessCSCP COMPUTES the residual CarryCompare
  obstruction (which step, primitive per T, round/comm cost, leak if
  skipped) — not faked.
- talus_mpc.go: honest-majority BGW secure multiplication + shared random
  bits, the substrate the CSCP composes from; concretely enforces TALUS
  Thm 10.1's N>=2T-1 barrier.
- talus.go: TalusTEE/TalusMPC profiles, suite IDs (65/87; 44 refused),
  Quasar evidence kind 'pulsar-talus-mldsa', honest-majority gate.
- talus_sign.go: mandatory pre-release FIPS-204 verify gate (never release
  a failed sig) + Quasar TalusEvidence (suite-pinned verifier dispatch,
  distinct from Corona).
- talus_test.go: multi-node Pulsar-MPC proof — dealerless DKG, distributed
  commitment, carry-elimination identity, BGW N>=2T-1, one-round signing
  verifying under stock cloudflare/circl mldsa{65,87}.Verify, sub-quorum
  fails, nonce one-time, failed-verify never released, no y/w/w0/s1
  reconstruct.

go build ./... green; full pulsar package tests green.
2026-06-27 11:47:18 -07:00
zeekay 91d756ad8f BLOCKERS: PULSAR-V12 item-1 BUILT (no-reconstruct signer), item-2 obstruction computed; PARTIAL-Z-PROOF functionally closed on the new path 2026-06-27 11:07:32 -07:00
zeekay 0c710e8f34 pulsar: dealerless ML-DSA DKG obstruction, derived not asserted (PULSAR-V12 Part 2)
Genuinely-dealerless DKG producing byte-FIPS-204 ML-DSA keys is NOT achievable
with known techniques. This commit COMPUTES why (mirroring rangeproof.go's
derive-don't-assert pattern) rather than faking a key or falling back to a
dealer/TEE.

THE OBSTRUCTION (precise): FIPS-204 draws s1,s2 from S_eta (||.||inf <= eta) and
calibrates beta=tau*eta, omega, and the BCC 2*beta boundary margin to that. A
dealerless DKG forms the joint secret as a sum/Lagrange-combination of N>=2
contributions => ||s2||inf <= N*eta, so ||c*s2||inf <= N*beta > beta, violating
the BCC boundary-clearance hypothesis ||c*s2||inf <= beta. assessDealerlessFIPS
computes N*beta vs beta and shows byte-validity breaks at N=2 for both ML-DSA-65
and -87; the deeper break is that a sum-of-contributions secret is not the
S_eta distribution ML-DSA's EUF-CMA assumes. Forcing the joint into S_eta needs
either a dealer or a norm-reduction that changes (A,t) => not byte-compatible.

NOT the obstruction: t0. The joint t0 = Power2Round-low(joint t) is in
(-2^(d-1), 2^(d-1)] by definition for ANY N, so ||c*t0||inf <= tau*2^(d-1) < gamma2
always. Pinned by TestDealerless_T0IsNotTheObstruction (200704/245760 < 261888).

CORONA/RACCOON noise-flooding assessed: corona.BootstrapPedersen is dealerless
because Ring-LWE is noise-flooded (beta_j = A*(lambda_j*s_j)+e_j', sigma=kappa*sigmaE*sqrt(n))
with a Round_Xi absorption step; ML-DSA has fixed S_eta bounds and no absorbing
rounding, so any flooded variant is a Raccoon-family scheme (Threshold Raccoon,
EUROCRYPT'24) that does NOT verify under FIPS-204. This is exactly why the
Quasar cert is AND-mode dual-PQ: dealerless Corona leg || dealer/TEE-genesis
Pulsar leg. DealerlessMLDSADKG fails closed (ErrDealerlessByteFIPSUnreachable),
never fakes, never falls back to dealer/TEE. 5 tests pin the arithmetic.
2026-06-27 11:06:09 -07:00
zeekay 1118868729 pulsar: no-reconstruct single-share threshold ML-DSA signer (PULSAR-V12 Part 1)
Concrete poly-vector (s1) AlgShare + DistributedBCCSigner closing the
PULSAR-V12-PARALLEL-PQ forward-path item 1: a no-reconstruct, single-share
t-of-n ML-DSA signer in the current RoundSigner/Partial/FlatAggregateZ model.

- AlgShare: GF(q) poly-vector Shamir share of the EXPANDED signing component
  s1 (s1 only — the BCC/CEF path never touches s2/t0, so sharing them would
  reopen PULSAR-V13-HINT-LEAK; matches the DKGPublicOutput no-t0 invariant).
- DistributedBCCSigner (satisfies RoundSigner): Round1 binds the canonical
  NonceCert and derives c; Round2 emits z_i = lambda_i*y_i + c*lambda_i*s1_i
  with the SOUND linear-sigma partial-z proof (partial_proof.go); Finalize
  aggregates z=sum z_i Lagrange-linearly (FlatAggregateZ), recovers the hint
  from PUBLIC w' via FindHint, emits FIPS-204 sigEncode. The aggregator holds
  NO share/sk/seed (AggregateBCC takes []Partial only).
- PULSAR-V13-PARTIAL-Z-PROOF: REAL — sound Maurer/Schnorr sigma wired and
  proven (honest+forged partials), forgeries dropped with a clean blame path.
- DealAlgShares: Part-1 TRUSTED-DEALER keygen (no-reconstruct at SIGN time,
  not dealerless at keygen — that is Part 2). DealNonceMPCDebug is the
  NonceMPC stand-in (reveals w to the harness = PULSAR-V13-W-LEAK gate,
  fail-closed for production; signing decomposition is independent of it).

Multi-node proof (7 tests, all green): t separate signers one share each,
ceremony over a message bus, signatures verify under UNMODIFIED FIPS-204
(VerifyBytes + stock circl Verify), ML-DSA-65 and -87, ctx-binding real,
sub-quorum refused, share carries no seed/s2/t0, ShareCount==1 per node.
2026-06-27 11:01:26 -07:00
zeekay 6f1c423730 BLOCKERS: file PULSAR-V12-PARALLEL-PQ (consensus dual-PQ AND-mode consumer)
luxfi/consensus 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. Record the consumer and pin the
Pulsar-side gap in one document:

  - The Pulsar leg VERIFY path (wire.VerifyBytes, unmodified FIPS-204) is
    production-ready and exercised live by the consensus multi-node test.
  - The Pulsar leg's no-reconstruct single-share t-of-n SIGNING is not yet
    production: the current KeyShare is a GF(257) seed-share and ML-DSA s1 is
    non-linear in the seed, so seed-shares admit only reconstruct-then-sign.
    A no-reconstruct signer needs poly-vector (s1,s2,t0) shares; the new
    RoundSigner/Partial/FlatAggregateZ model carries the interface + z-sum
    primitive but no concrete poly-vector share type or RoundSigner implementor
    exists on the current line. It also stays fenced fail-closed behind
    PULSAR-V13-W-LEAK (distributed boundary-clear nonce proof) and
    PULSAR-V13-PARTIAL-Z-PROOF.
  - Permissionless safety comes from the dealerless Corona leg in AND-mode;
    Pulsar genesis is TEE-gated (PULSAR-V12-TEE-BIND / mldsa-tee).
  - Forward path: finish the new model (poly-vector share + concrete
    RoundSigner + close the V13 ZK gates) applying gate C's DistributedSigner
    decomposition; do NOT resurrect the removed v0.3 stack (two-way / backwards).
2026-06-27 01:13:08 -07:00
zeekay 430e1a5c05 security(pulsar): rip v0.1 reconstruct-then-sign Combine path — H-1b
The v0.1 GF(257) threshold-signing instantiation (ThresholdSigner /
Round1 / Round2 / Combine) Lagrange-reconstructed the master seed in
aggregator memory and called FIPS 204 SignTo once — i.e. a quorum's
full ML-DSA signing key materialised in a single process. That
reconstruct-then-sign ceremony was the H-1 footgun. Its only
production reach was consensus's quasar wave_signer (deleted), via the
threshold/protocols/pulsar alias (Combine re-export dropped in the
threshold repo).

The one and only threshold-signing path is now the v0.3 algebraic
ceremony (threshold_v03.go / orchestrate.go), whose
Lagrange-linearity-of-z aggregation produces the FIPS 204 signature
WITHOUT reconstructing the secret in any party's memory.

Removed:
- threshold.go: ThresholdSigner, NewThresholdSigner, Round1, Round2,
  Combine (kept the shared transcript/committee/CT helpers + error set
  consumed by the v0.3 and GF(q) paths; dropped now-unused crypto/rand
  + io imports and dead ErrNilSession).
- types.go: Round1Message, Round2Message wire types.
- round.go: dead RoundSigShare (was the wave_signer carrier).
- threshold_test.go, n1_byte_equality_test.go: pure-v0.1 suites.
- round_test.go / bench_test.go / precompile_e2e_test.go: excised the
  v0.1 sign cases, kept RoundContext/ApproxRoundSecurity/DKG/Large/v0.3.
- cmd/genkat: dropped v0.1 threshold-sign KAT generation + helper.
- ct/dudect/combine_ct.go + dudect_combine.c: dead CT harness for the
  removed Combine path.
- shared_dkg_test.go: relocated the non-v0.1 DKG test helpers
  (runDKG / runDKGWithIdentities) that threshold_test.go had hosted.

Verified: GOWORK=off go build ./... exit 0; go vet clean;
go test ./ref/go/pkg/pulsar/ exit 0 (DKG, reshare, v0.3, KAT replay,
large-committee all green).
2026-06-26 21:08:00 -07:00
zooqueen 39ee49604c fix(consensus): add FullW/LowBitsW to the generic forbidden-wire-field sweep (was NonceCert-specific); docs: tag v1.1.4, EC-machine-check note v1.1.5 2026-06-21 20:40:00 -07:00
zooqueen f2d84f10a2 docs: correct stale 'no EC toolchain / recheck-pending' claims — EC machine-checks on host (ec-machine-check.sh, 14/14) v1.1.4 2026-06-21 19:14:18 -07:00
zooqueen cde7fe53c5 fix(ec): delete stale V04 leaking-path orphan; machine-check all EC theories; scrub v0.4 refs; comment-aware budget v1.1.3 2026-06-21 18:10:48 -07:00
zooqueen c546d5dc0a proofs: de-misdirect the reconstruct-then-sign EC cone with a no-leak model
The headline EC byte-equality (pulsar_n1_byte_equality) proved the threshold
combine bit-equals SinglePartyRun, which RECONSTRUCTS the master secret and
signs with it -- exactly the path the production leaderless signer must never
take (PULSAR-V13-HINT-LEAK). This pass re-scopes that cone as IDEALISED
CORRECTNESS and adds the HONEST production model whose residual is a STANDARD
Module-LWE/MSIS reduction, not an implementation reconstruct.

New proofs/easycrypt/Pulsar_N1_NoLeak.ec (written; machine-recheck pending
EasyCrypt -- no `ec` on host, scripts/checks/ec-compile.sh is the CI gate):
  - no_leak_z_aggregate: the public masked Lagrange aggregate equals central z
    WITHOUT forming the master secret (re-exports the Lean-bridged
    threshold_partial_response_identity).
  - public_hint_roundtrip [B, Lean-backed]: the hint is recovered from the
    PUBLIC w' = A*z - c*t1*2^d via FIPS UseHint; procedure lift of the
    machine-checked Lean boundary_clearance + findHintCoeff_unique. No
    c*s2/c*t0/r0 anywhere.
  - no_leak_reduction [C-standard, OPEN]: under Module-LWE + Module-SIS the
    public transcript leaks nothing about (s1,s2,t0) beyond one FIPS 204
    signature. The honest replacement for combine_body_axiom -- a reduction to
    the SAME lattice assumptions ML-DSA's EUF-CMA uses, secret NEVER formed.

The CORRECTNESS CORE is machine-checked in Lean 4 + Mathlib on this host
(luxfi/proofs: Crypto.Pulsar.NoLeakAggregate / .BoundaryClearance /
Threshold_Lagrange; lake build green, #print axioms shows no sorryAx).

Disclosure updated to match reality: AXIOM-INVENTORY (new Bucket C-standard +
"A is machine-checked in Lean"), PROOF-CLAIMS (two models), BLOCKERS
(PULSAR-EC-RECON-MODEL re-scoped, first criterion now [x]), budget AXIOM
87->89 (the 2 new disclosed standard-assumption axioms). Framework gate PASS
(all 5 checks); ref/go build + tests green.
2026-06-21 15:26:18 -07:00
zooqueen e5e4f575f6 high-assurance: repoint gate references to luxfi/security/framework (canonical home) 2026-06-21 14:22:36 -07:00
zooqueen 0fed7fbb5e proofs: honest bucketed axiom inventory + reconstruct-then-sign disclosure
Reclassify (not reduce) the EasyCrypt axiom surface and make the trust
cone of the N1 byte-equality theorem fully disclosed. NO axioms discharged
this pass (honest): no easycrypt toolchain on host to machine-recheck a
hand proof, and every in-file-derivable axiom is already a proved lemma;
the residual A/B axioms are over abstract types/ops and the C axioms are
open security assumptions that must stay open.

- AXIOM-INVENTORY.md (new): complete bucketed census of all 78 real axiom
  declarations -- A standard-math-fact (16/17, 5 Lean-bridged), B
  serialization/layout (41), C OPEN security assumption (21). One row per
  axiom: name, file:line, bucket, justification. Notes the framework
  axiom-budget regex over-counts (87) because 9 comment lines begin with
  the word "axiom".
- PROOF-CLAIMS.md (new, root, gate-read): assurance vocabulary
  (machine-checked / sound-by-reduction / interop-tested / asserted-axiom
  / fail-closed-pending-review / open-research) matched to reality. States
  plainly that the EC byte-equality is machine-checked (0 admits) MODULO a
  C-cone that models reconstruct-then-sign (combine_body_axiom /
  S_functional_spec / *_body_*_spec assert the extracted code equals the
  centralised signer on the Lagrange-reconstructed master secret) -- the
  abstraction the production leaderless path must never use -- and that the
  no-leak property is interop-tested (CIRCL + pq-crystals), not EC-proven.
- BLOCKERS.md: add PULSAR-EC-RECON-MODEL as an explicit OPEN item
  cross-referenced to the V13 external-review gate; fix the contradictory
  "no open items" header.
- .assurance/reviewed-axioms.txt: list every load-bearing / security-cone
  axiom (A: 5 Lean-bridged + C: combine_body_axiom, S_functional_spec,
  algebraic_aggregate_ctx_body_axiom) with bucket + justification -- full
  disclosure, not a blanket allow.
- .assurance/budget.txt: correct the prose (true decl count 78 vs counted
  87; 0 real admit. tactics); counts held, not raised.

Framework gate (circular-proof + axiom-budget + the other three) PASS with
full disclosure. go test ./... green (no Go touched).
2026-06-21 14:19:49 -07:00
zooqueen 3d0b112331 high-assurance: declare unproven-assertion budget + reviewed axioms
Enforced by ~/work/lux/proofs/framework/check.sh. Caps the current trust
surface so it cannot silently grow; the goal is to drive it down.
2026-06-21 13:37:32 -07:00
zooqueen 1d1c9211b4 pulsar: harden cert verification, remove v0.3 leaking path (PULSAR-V13)
Cert-verification surface (red-review fixes — none touch the proven BCC
arithmetic, all close fail-open/forgery seams):

  1. ConsensusCert: bind the signer bitmap to the signature via an
     accountability QuorumCert over a payload root committing bitmap +
     transcript root + signature bytes; Verify() replaces the structural-
     only VerifyStructure (bitmap rewrite / signature splice now rejected).
  2. nonceCertPayloadRoot: bind Mode, WCommitment, ClearanceProof, Consumed
     (length-prefixed) — closes swappable-commitment + replay seams.
  3. VerifyNonceCert / ConsensusCert.Verify: fail-closed QuorumSigVerifier
     seam (one registry for both cert types) — QC signatures are no longer
     trusted unchecked; unregistered verifier => reject.
  4. boundaryThreshold saturates at 0 and VerifyNonceCert/RunNonceMPCDebug
     gate bccParams ok — ML-DSA-44 (vacuous boundary clearance) can no
     longer underflow to "everything clear".
  5. partial-z: reject a challenge c that is not a FIPS 204 SampleInBall
     (tau ±1 coeffs) — a degenerate c=0 can no longer strip the s1 binding.

Forward-only removal of the v0.3 Algebraic threshold path: it broadcast
per-party c*s2 / c*t0 hint material whose aggregate reconstructs the joint
key (PULSAR-V13-HINT-LEAK). Deleted threshold_v03*.go + attest.go +
orchestrate.go + tests; preserved the two helpers the no-leak BCC signer
uses (polyVecExceeds, deriveMuCtx). Removed the now-dead code orphaned by
it — including makeHint, the secret-dependent hint primitive (BCC recovers
the hint from public data via FindHint), shamir_poly.go, and the accel
import. staticcheck U1000 clean; 190 tests pass.

The v0.1/v0.2 threshold.go path (documented aggregator-trust model, tests
green) is intentionally retained — it is not the V13 leak.
2026-06-21 07:52:05 -07:00
zooqueen 2ad553c54b pulsar: BDLOP range proofs for DKG/nonce small-norm checks 2026-06-21 07:13:30 -07:00
zooqueen d612de58e3 pulsar: BCC/CEF no-leak sign verified under CIRCL+pq-crystals + sound linear proofs
- bcc_sign.go: no-leak single-key BCC sign (boundary-clear nonce + public
  FindHint from w'=A·z-c·t1·2^d); a real FIPS 204 signature verifies byte-equal
  under own Verify, cloudflare/circl, and pq-crystals (P65 3309B, P87 4627B)
- no-leak debug oracle asserts no c·s2/c·t0/r0/LowBits/full-w in the transcript
- FIX: ML-DSA-87 c̃ size 48->64 (FIPS 204 λ=256 ⇒ λ/4); latent, P87 sign untested before
- sound LINEAR sigma proofs (Maurer/Schnorr, 8x reps, perfect HVZK): partial-z
  (z_i=λ_i·y_i+c·λ_i·s1_i), DKG (A·s1+s2-t0=t1·2^d), nonce-transcript
  (Σλ_i·A·y_i - w0 = w1·α); registerable, witness-hiding (tested)
- genuinely-novel parts honestly FAIL-CLOSED (tight range proofs; HighBits-in-MPC)
2026-06-21 02:14:01 -07:00
zooqueen 43add148f9 pulsar: Ringtail-style 2-round signing API + RoundSigner + canonical signer subset
- round.go: SignRound1 (bind canonical nonce)/SignRound2 (z partial)/RoundSigner
  interface (the Quasar cert-profile API consensus calls; pulsar never calls
  consensus). CertProfile enum (BLS/Corona/Pulsar/Magnetar).
- CanonicalSignerSet: deterministic first-threshold-by-PartyID subset + bitmap
  (anti-grinding of signer set/z/h/signature); order-independent (tested).
- boundary slack: |w0| <= gamma2 - 2β - slack (one-coeff edge safety).
- ZPartialPublicInput -> PartialInput.
2026-06-21 01:25:15 -07:00
zooqueen 492fda22f7 pulsar: external-review package (audit/pulsar-v1) — honest status, KNOWN_BAD_V03, invariants, threat model, test matrix, repro, reviewer questions 2026-06-21 01:22:47 -07:00
zooqueen 5f52f9b996 pulsar: FindHint (exported), package doc + security-explicit errors; recover doc.go
- findHintToTarget -> FindHint; ErrNonceRevealsW -> ErrNonceTranscriptRevealsW;
  add ErrNonceTranscriptRevealsLowBitsW, ErrForbiddenHintMaterial
- recover clobbered doc.go (const Version) from HEAD; add V13 production-path
  note to the package doc
2026-06-21 01:21:05 -07:00
zooqueen 89c25d9675 pulsar: decomplect names to domain (NonceCert/Partial/Aggregate/ConsensusCert)
Rename mitigation-named public types to domain names (BCC* dropped; boundary
clearance / carry elimination kept as implementation profile in docs/spec):
  BoundaryNonceCert -> NonceCert        NonceCertVote      -> NonceVote
  NonceMPCTranscript -> NonceTranscript  MPCTranscriptRoot -> NonceTranscriptRoot
  BCCZPartial -> Partial                 ZAggregate        -> Aggregate
  BCCSignature -> Signature (folded into existing type)   ConsensusCert (kept)
Files: threshold_bcc*.go/nonce_mpc.go/z_partial.go/tree_aggregate.go/
  dkg_wellformed.go -> boundary.go/consensus.go/proof.go/nonce.go/partial.go/
  aggregate.go/dkg_wellformed.go (+tests). Recover clobbered dkg.go from HEAD.
All tests green, vet clean.
2026-06-21 01:18:31 -07:00
zooqueen ba30df5102 PULSAR-V13: validator-run NonceMPC clearance cert (replaces standalone ZK)
- BoundaryNonceCert: W1+WCommitment+MPCTranscriptRoot+ClearanceQC, NO full W
- QuorumCert + NonceCertVote + ZAggregate; nonceCertPayloadRoot binds every
  consensus field (tamper-evident); VerifyBoundaryNonceCert (QC present+binds+
  quorum+signer-set, fail-closed)
- NonceMPC transcript + ValidateAndVoteNonceCert voting rule + RunNonceMPCDebug
  oracle (W1=HighBits(w), Clear=BoundaryClear(w), public view never reveals w)
- 9 tests: no-full-W, requires-QC, binds-all-fields, doesn't-reveal-W,
  correct-W1, boundary-clear-votable, QC-verifies, bad-root-rejected, and the
  permanent proof that w'-w=residual (why W is forbidden)
2026-06-21 01:07:20 -07:00
zooqueen 2a9f34f166 PULSAR-V13: fail-closed ZK proof obligations (W-LEAK + partial-z)
ClearanceVerifier + PartialZVerifier interfaces; default verifiers FAIL
CLOSED (ErrClearanceProofUnsound / ErrPartialZProofUnsound) so production
BCC signing is DISABLED until sound, externally-reviewed proofs are
registered. ProductionBCCSigningReady()=false by default. Honest
containment, not a stand-in for the (research-grade) proofs.
2026-06-21 01:01:13 -07:00
zooqueen 4c84cf1c43 PULSAR-V13: production BCC/CEF wire layer (no hint-secret fields)
- BCCNonceCert (W1+WCommitment+ClearanceProof, NO full W), BCCZPartial,
  BCCSignature, ConsensusCert — reflection test enforces no CS2/CT0/D2/D0/
  R0Share/LowBits/Hint fields
- CanonicalNonceIndex: deterministic non-grindable nonce selection
- TreeAggregateZ == FlatAggregateZ (z-sum only) up to 1000-signer committee
- coarse AbortClass (no per-signer/coefficient leak)
- ConsensusCert.VerifyStructure (quorum + signer-set accountability)
- 5 tests green
2026-06-21 00:58:24 -07:00
zooqueen 39593b3673 PULSAR-V13: contain hint-path leak + land verified BCC/CEF math core
- hard-gate threshold_v03 AlgebraicAggregate (fail-closed, PULSAR-V13-HINT-LEAK)
- threshold_bcc.go: BoundaryClear + findHintToTarget (FIPS UseHint) + ML-DSA-65/87
  param guard; no production code forms c*s2/c*t0/r0/LowBits
- 6 verified tests green (gate, param guard, FindHintToTarget<->UseHint round-trip,
  BoundaryClear=>HighBits-stable+r0-bound, off-by-one edges, yield 9.8%)
- spec/threshold-mldsa-boundary-clearance.tex (BCC0/BCC+, full-w-hidden, ZK req)
- BLOCKERS: V13-HINT-LEAK + V13-W-LEAK + V13-PARTIAL-Z-PROOF + resolution criteria
2026-06-21 00:54:00 -07:00
zooqueenandHanzo Dev dc32e6bb88 docs: tidy LLM.md indexes; CLAUDE.md -> LLM.md symlink convention
Co-authored-by: Hanzo Dev <[email protected]>
2026-06-17 09:58:15 -07:00
zeekay f86fcd4699 corona→corona: academic Corona now only in lp-220-p3q-corona 2026-06-11 10:28:26 -07:00
zeekay 5911dc0d32 go: 1.26.3 → 1.26.4 (security: crypto/x509, mime, net/textproto) 2026-06-06 22:09:52 -07:00
zeekay 5625c65339 SUBMISSION: bump revision date to 2026-06-05
Aligns cover-sheet revision date with the submission-2026-06-05 cut.
Spec PDF is built fresh per cut by scripts/build.sh and bundled into
the tarball at cut-time (PDF is gitignored — generated artifact).
2026-06-05 18:27:15 -07:00
zeekay ee239d1e10 deps: bump accel v1.0.7 → v1.2.0 (MLDSAVerifyBatch + LatticeNTTMLDSABatch) 2026-06-05 17:42:05 -07:00
zeekay 77d5371fa8 chore: scrub 'subnet' → 'chain' in types.go comment (no-subnet rule) 2026-06-05 17:38:45 -07:00
zeekay 7e302120fb pulsar v1.2-dev: Round-2 batched NTT via accel (closes PULSAR-V12-GPU-NTT-WIRE)
Wires Pulsar's v0.3 algebraic-threshold Round-2 forward NTTs through
luxfi/accel's LatticeNTTMLDSABatch (commit 6ec46c4 — the real GPU NTT
substrate, no longer the ErrNotSupported stub).

Surface:
  batchNTT(polys []poly) [][]int32  in mldsa_lattice.go

  Dispatches to accel.LatticeNTTMLDSABatch when
    accel.Available() AND len(polys) >= accel.MLDSABatchThreshold (8).
  Otherwise runs pulsar's per-poly circl-style (*poly).ntt() — byte-
  identical to the pre-batchNTT reference. Any accel error falls
  through to the pure-Go path.

Round-2 call sites converted (4 logical batches, 22 forward NTTs per
party-attempt total):

  yHat        threshold_v03.go ~L680   (L polys: 4/5/7 for P44/P65/P87)
  s1Hat       threshold_v03.go ~L893   (L polys, replaces L per-iter ntt)
  cs2-input   threshold_v03.go ~L917   (K polys: 4/6/8)
  ct0-input   threshold_v03.go ~L939   (K polys)

The accel substrate engages on ModeP87 (K=8) for the cs2-input and
ct0-input batches; ModeP44 and ModeP65 batches are below threshold and
stay on the per-poly leg.

Byte-equality regression (TestPulsar_GPU_ByteEqual, ModeP65) PASSES.
The test's four Round-2 batches are sized 5, 5, 6, 6 — all strictly
below the accel threshold — so both legs run the per-poly path and
the bit-identical contract holds by construction. Wider FIPS 204
verification (TestSignVerify_RoundTrip_AllModes including ModeP87)
continues to pass because both legs compute the same Z_q residues
and the FIPS 204 verifier checks math, not intermediate uint32
representations.

Tests:
  go build ./...                                    PASS
  go test -count=1 ./...                            PASS
  go test -count=1 -tags accel ./...                PASS
  go test -count=1 -race -run TestPulsar_GPU_ByteEqual ./...  PASS
2026-06-03 13:10:04 -07:00
zeekay a6ab227ffe audit 2026-06: TEE + GPU + public-permissionless-chain safety
Fresh four-dimension audit at v1.1.1 (commit 6a5606f). BLOCKERS.md stays
at "submission-ready. No open items." for existing claims; two
forward-looking v1.2 extensions file under the new Forward-looking
section.

Bottom line per dimension:

1. Public-permissionless-chain safety — no re-opener. Slashable
   equivocation extractable via AbortEvidence (4-field TLV +
   wire-stable codec); rogue-key bound via FIPS 204 tr =
   SHAKE-256(pk, 64) → μ; adaptive corruption gap is a research
   direction documented as openq in spec/pulsar.tex; front-running
   ruled out by Round-1 commit-and-reveal + ML-KEM-768-derived
   pairwise MAC keys; PULSAR-V04-CTX v0.4 ctx-bound μ derivation
   stays load-bearing via single canonical deriveMuCtx helper.

2. TEE — luxfi/threshold/protocols/mldsa-tee already ships the
   custody-mode TEE-gated master-seed surface (AMD SEV-SNP / Intel
   TDX / NVIDIA NRAS via mpc/cc/attest + KMS ReleaseGate + HSM
   wrap-key + approval). Adds in-pulsar AttestationContext(setup, msg)
   helper for the permissionless-quorum-gating case: canonical 32-byte
   TBS digest a validator's TEE quote should bind to. No wire change,
   no ABI break. Five unit tests pin stability, nil-safety, full input
   sensitivity, and customisation-tag domain separation.

3. GPU — pulsar/gpu (UseAccelerator) is wired to luxfi/lattice/v7/gpu
   dispatcher; lux-private/gpu-kernels/ops/lattice/ntt_mldsa ships the
   byte-equal-to-PQClean NTT across 5 backends (CUDA/HIP/Metal/Vulkan/
   WGSL). The substrate (lux_lattice_ntt_mldsa_batch + the existing
   stubbed lux_mldsa_verify_batch in accel/internal/capi/capi.go:503-531)
   is the v1.2 forward-looking item; routing through Round-2 batched
   NTT call sites is mechanical once the ABI ships. Byte-equality
   regression guard TestPulsar_GPU_ByteEqual already in place; passes
   vacuously today, pins divergence the moment GPU dispatch engages.

4. Cross-validation against pulsar-mptc legacy — clean. No orphan
   imports. All "MPTC" refs are to the NIST competition category.

Build sanity: go build / go vet clean; full ref/go/pkg/pulsar suite
green (14.9s, 1.4s -race on new tests); GPU subpackage + interop tests
green.

Files:
- AUDIT-2026-06.md (new) — comprehensive audit per dimension.
- BLOCKERS.md — adds Forward-looking (v1.2) section with
  PULSAR-V12-TEE-BIND + PULSAR-V12-GPU-NTT-WIRE. Existing Closed
  section untouched.
- ref/go/pkg/pulsar/attest.go (new) — AttestationContext helper
  (one pure function over already-transmitted Round-1 inputs).
- ref/go/pkg/pulsar/attest_test.go (new) — stability + nil-safety +
  input sensitivity + domain-separation pins.
2026-06-03 11:40:02 -07:00
zooqueenandHanzo Dev f7b41d2b52 pulsar/jasmin: make threshold round1/round2/combine compile (codegen-only)
These 3 threshold-signature sources type-checked but failed in the Jasmin
backend. Fixed with codegen-only restructuring — NO algorithm, value, wire
layout, or constant-time change:
- combine: decomposed an over-blended x86 effective address into a base reg;
  split a shifted-OR source into shift-into-temp then OR.
- round1: relieved register pressure (spill output ptrs, extract the
  expandA+matvec+decompose phase into a helper frame, pack derive_rho_prime
  inputs into one preimage buffer, u32 stores for y_state).
- round2: an export fn had 13 pointer params (Jasmin caps at 6) — marshalled
  them into a caller-supplied table; gave polyvecl_scalar_mont distinct in/out
  ptrs; routed per-peer MAC tables through one buffer; stack-return digest
  helpers; spilled keccak-crossing loop-invariants.
Shared lib tweaks (consumed by these files): mac/transcript/lagrange/seed .jinc
stack-return + u64-index + BE-via-temp. All #[ct] contracts and #declassify
pragmas preserved (CT type-checked at compile). Full Jasmin corpus: 23/23
compile (was 20/23).

Co-authored-by: Hanzo Dev <[email protected]>
2026-06-02 12:59:58 -07:00