pulsar: claim hygiene — nonce safe-by-construction, authenticated blame, honest GATE-C wording

Update VERSIONS.md + PROOF-CLAIMS.md so no claim overstates:
- nonce single-use is now claimed ENFORCED BY DEFAULT (per-share registry on the
  real API), not opt-in; w1-only dedup closes cross-committee reuse.
- authenticated-PartyID blame: blame gated on identity-signature validity; an
  attacker cannot frame/exclude an honest victim; never blame off a raw PartyID.
- GATE-C: 'complete for DIRECT calls' + companion indirection lint — drop the
  'never miss one' overstatement; the pair (not either half) closes the banned set.
- residuals restated honestly: persistent ledger (in-process default safe now),
  networked transport auth, BDLOP valid-sigma-wrong-z.
This commit is contained in:
zeekay
2026-06-27 22:36:52 -07:00
parent 5f2722f987
commit 287c3d9446
2 changed files with 57 additions and 21 deletions
+13 -3
View File
@@ -34,9 +34,19 @@ This is the single sentence the project stands behind. Its honest decomposition:
release-gate to a **liveness fault, never a forge/leak**.
- **malicious-CSCP + networked-MPC are gated residuals** — UNBUILT, fail-closed,
tracked (Residual A). The `harden/malicious-security` branch advances this:
nonce single-use, identifiable-abort plumbing, reachability GATE-2; the **sound
valid-sigma wrong-`z` blame** (needs BDLOP lattice commitments) remains residual.
See `ref/go/pkg/pulsar/VERSIONS.md`.
**nonce single-use safe by construction** (per-share registry enforces it on the
DEFAULT API, not opt-in; `w1`-only dedup closes cross-committee reuse),
**authenticated-PartyID blame** (blame is gated on identity-signature validity —
an attacker cannot frame or front-run-exclude an honest victim; no blame is ever
emitted off a raw unauthenticated PartyID), identifiable-abort plumbing, and
GATE-2 reachability **paired with an indirection lint** (the name call-graph is
complete for DIRECT calls only — the lint forbids function-value/closure/
`go:linkname` indirection of the banned primitives, so the pair is complete).
Still residual: the **sound valid-sigma wrong-`z` blame** (needs BDLOP lattice
commitments), a **persistent (crash-safe) nonce ledger** (the in-process default
is safe now), and **networked transport authentication** (the partial→producer
crypto binding is in place; authenticated delivery is consensus-owned). See
`ref/go/pkg/pulsar/VERSIONS.md`.
**NEVER claim:** FIPS/NIST-certified threshold ML-DSA · fully-malicious-secure-proven
· global-1000-validator DKG. (Any artifact asserting these is wrong — fix the
+44 -18
View File
@@ -10,7 +10,7 @@
|---|---|---|---|
| **v0.3 — algebraic broadcast** | **REMOVED** | The `AlgebraicAggregate` path broadcast per-party `c·s2` / `c·t0` residual shares and reconstructed the leaking `MakeHint` residual at the aggregator. | Closed as **PULSAR-V13-HINT-LEAK** — broadcasting those shares leaks the long-term key. Ripped out (commit `b185533`); **no backward-compatible re-entry**. |
| **v0.4 — BCC/CSCP no-reconstruct** | **CURRENT (production sign path)** | Boundary-Cleared Carry-elimination (BCC/CEF) + Comparison-Secure-Comparison-Protocol (CSCP). Each validator holds exactly one poly-vector Shamir share of `s1`; signing aggregates only masked `z`-partials; the hint is recovered from the **public** `w' = A·z c·t1·2^d` and `w1`. No process forms `s1`, the seed, `sk`, `c·s2`, `c·t0`, `r0`, or full `w`. Output verifies under unmodified FIPS 204 ML-DSA (`mldsa{65,87}.Verify`). | Base `main` @ `v0.4.0` (commit `b652893`). The sole production path. |
| **v0.4.x — `harden/malicious-security`** | **THIS BRANCH (in review, NOT merged)** | Hardens v0.4 from semi-honest/no-leak toward **malicious** security: nonce single-use / anti-replay ledger (closes the nonce-reuse key-recovery vector), identifiable-abort plumbing (duplicate-PartyID rejection, invalid-proof blame attribution, per-party commitment binding), GATE-2 hardened to call-graph reachability, CI invariant against `legacy_trusted_dealer` in the prod build. | Branch off `origin/main`; **a RED agent re-verifies before any merge.** See "Malicious-hardening status" below for implemented-vs-residual. |
| **v0.4.x — `harden/malicious-security`** | **THIS BRANCH (in review, NOT merged)** | Hardens v0.4 from semi-honest/no-leak toward **malicious** security: nonce single-use **safe by construction** (per-share registry, default-path enforced; `w1`-only dedup closes cross-committee reuse), **authenticated-PartyID blame** (forged victim-slot partials dropped before attribution; blame gated on identity-signature validity — an attacker cannot frame/exclude an honest victim), identifiable-abort plumbing (duplicate-PartyID rejection, invalid/malformed blame, per-party commitment binding), GATE-2 reachability **+ indirection lint**, CI invariant against `legacy_trusted_dealer` in the prod build. | Branch off `origin/main`; **a RED agent re-verifies before any merge.** See "Malicious-hardening status" below for implemented-vs-residual. |
## Keygen / nonce-gen track (separate from the sign path)
@@ -28,21 +28,42 @@ The no-reconstruct property above is a **SIGN-time** property. Key and nonce
## Malicious-hardening status (this branch — honest implemented-vs-residual)
**Implemented, with a passing gate:**
- **Nonce single-use / anti-replay** (`nonce_ledger.go`) — per-signer ledger keyed on
the nonce commitment `(committeeID ‖ w1)`; `Round2` reserves before emitting the
secret `z`-partial; reuse (even relabeled under a new `nonceID`) is rejected
fail-closed. GATE A (`TestRED_NonceReuse_RecoversS1`) demonstrates the
key-recovery math is real **and** that the guard blocks obtaining the second
partial.
- **Duplicate-PartyID rejection** + **invalid/malformed-proof blame attribution** in
`AggregateBCC` — a deviating partial is attributed to its `PartyID` (structured
`AbortEvidence`), not silently dropped. GATE B covers these.
- **Nonce single-use / anti-replay — SAFE BY CONSTRUCTION** (`nonce_ledger.go`). The
single-use store is resolved from a **process-global registry keyed by SHARE
IDENTITY** (`shareIdentityKey`), so EVERY signer instance over the same key-share
shares ONE ledger by DEFAULT — there is **no opt-in and no per-instance
empty-ledger fail-open**. The dedup key is the nonce commitment **`w1` ALONE**
(committee-independent), so reuse is refused even when relabeled under a new
`nonceID` AND when the same joint nonce is presented across two committees that
share a victim. `Round2` reserves before emitting the secret `z`-partial.
- GATE A `TestRED_NonceReuse_RecoversS1` (key-recovery math is real + injected-
ledger guard), `TestRED_PoC_DefaultLedger_NonceReuse_Refused` (the **DEFAULT**
API — fresh signer per message, **no** `SetNonceLedger` — refuses the second
partial + relabel), `TestRED_LOW_CrossCommittee_SameNonce_Deduped` (same nonce
across committees deduped).
- **Authenticated PartyID → blame gated on signature validity** (RED MEDIUM,
`distributed_bcc.go` / `protocol_auth.go`). Each `Partial` carries `Author +
AuthSig` (the producer's identity-key signature over slot ‖ content);
`AggregateBCCWithBlame` AUTHENTICATES each partial (valid signature **and**
`Author == quorum[PartyID]`) BEFORE attribution, dropping forged/wrong-slot
partials with **no blame against the slot's honest owner**, before the
first-per-PartyID/duplicate logic. Blame is **never** emitted off a raw
unauthenticated PartyID (with no verifier wired, no blame is produced at all).
- GATE B (duplicate / invalid-proof / malformed all attributed to the SIGNING
deviator) + `TestRED_PoC_MEDIUM_CannotFrameOrExcludeHonestVictim` (a forged
victim-slot partial cannot blame or exclude the victim; the verifier is shown
load-bearing).
- **Per-party DKG/nonce commitment binding** — `AggregateBCC` populates and verifies
the commitments the sigma proof is bound to (non-transferability).
- **GATE-2 → reachability** (`gate2_reachability_test.go`) — stdlib AST call-graph;
the reconstruct primitives (`KeyFromSeed`, `deriveKeyMaterial`, `bccSign`,
`shamirReconstruct*`, `LargeCombine`) must be **unreachable** from the committee
sign entrypoints. GATE C catches the `deriveKeyMaterial`+`bccSign` bypass.
- **GATE-2 → reachability + indirection lint** (`gate2_reachability_test.go`) — a
stdlib AST name call-graph proves the reconstruct primitives (`KeyFromSeed`,
`deriveKeyMaterial`, `bccSign`, `shamirReconstruct*`, `LargeCombine`) are
**unreachable from the committee sign entrypoints via direct calls** (GATE C
catches a `deriveKeyMaterial`+`bccSign` bypass), **paired** with a companion lint
that forbids taking any banned primitive as a non-call **value** or aliasing it
via `//go:linkname`. The graph is complete for DIRECT calls; the lint closes
function-value / closure / linkname indirection — the pair (not either half) is
complete for the banned set.
- **CI invariant** — the production (default-tag) build never carries
`legacy_trusted_dealer`.
@@ -52,10 +73,15 @@ The no-reconstruct property above is a **SIGN-time** property. Key and nonce
A homomorphic `A·s1_i` / `A·y_i` commitment is **rejected** because it reopens
PULSAR-V13-W-LEAK / HINT-LEAK. Until then, a valid-sigma wrong-`z` is a
**liveness fault (unattributed abort), never a forgery or leak**.
- **Malicious-secure CSCP**, **networked MPC transcript**, **authenticated /
signed protocol channels**, **leak-free NonceMPC**, **persistent nonce ledger**
(crash-restart safety), **last-mover-bias controls**. See `BLOCKERS.md`
Residual A and the branch report.
- **Persistent nonce ledger (crash-restart safety).** The in-process default is
safe NOW (registry, above); the persistent per-share ledger that survives a
restart is the residual — install one at startup via `SetNonceLedger` (writes the
same per-share registry slot, first-writer-wins).
- **Networked / authenticated transport.** The partial→producer crypto binding is
in place (above); the networked channel that authenticates message DELIVERY is
owned by the consensus layer and remains a flagged residual.
- **Malicious-secure CSCP**, **networked MPC transcript**, **leak-free NonceMPC**,
**last-mover-bias controls**. See `BLOCKERS.md` Residual A and the branch report.
## The honest one-line scope (canonical)