10 Commits
Author SHA1 Message Date
Antje Worring 7c102d2d14 fix(threshold): reject duplicate PartyID in Round2/Finalize signing combine (kernel-boundary uniq guard; was caller-enforced). + TestFinalize/Round2_DuplicatePartyID_Rejected 2026-06-21 20:40:00 -07:00
Antje Worring 6b4d5d529b docs: correct stale 'no EC toolchain' claims; note combine bridge discharged to lemma + jasminc available 2026-06-21 19:14:18 -07:00
Antje Worring baf2ba8c40 fix(ec): machine-check all 14 theories (R_q_xi order, w_low_t, wrapper intros, RLWE_Functional comment); discharge combine bridge C11 to a lemma via no_leak_z_aggregate keystone, residual shrunk to public w-agreement 2026-06-21 18:10:48 -07:00
Antje Worring ba9fe18360 proofs: de-misdirect the reconstruct-then-sign EC cone with a no-leak model
The EC byte-equality (corona_n1_byte_equality) proved the threshold combine
bit-equals CombineAbs, whose sign_abs_op_lifted_eq_rlwe bridge pins it to
rlwe_sign_op on the LAGRANGE-RECONSTRUCTED master secret -- exactly the path
the Boschini/Raccoon production combine must never take (CORONA-EC-RECON-MODEL).
This pass re-scopes that cone as IDEALISED CORRECTNESS and adds the HONEST
production model whose residual is a STANDARD Module-LWE/MSIS reduction.

New proofs/easycrypt/Corona_N1_NoLeak.ec (written; machine-recheck pending
EasyCrypt -- no `ec` on host, scripts/checks/ec-compile.sh is the CI gate):
  - mask_telescope_zero [B, Lean-backed]: Sum_i (maskPrime_i - mask_i) = 0 --
    the pairwise-PRF masks (z_i = R_i*u + maskPrime_i + c*lambda_i*s_i - mask_i)
    are the same double sum reindexed (Fubini), so they cancel on aggregation.
    Machine-checked in Lean as pairwise_mask_telescopes.
  - no_leak_z_aggregate: the surviving aggregate is R*u + c*s by Lagrange-at-0
    WITHOUT forming the master secret and with no per-party c*s_i ever exposed.
  - no_leak_reduction [C-standard, OPEN]: under Module-LWE + Module-SIS the
    public transcript leaks nothing about s beyond one Boschini signature. The
    honest replacement for sign_abs_op_lifted_eq_rlwe -- a reduction to the SAME
    substrate AXIOM-INVENTORY.md §1 already lists, secret NEVER reconstructed.

The CORRECTNESS CORE is machine-checked in Lean 4 + Mathlib on this host
(luxfi/proofs: Crypto.Corona.NoLeakAggregate / 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, §0 Disclosure 1),
BLOCKERS (CORONA-EC-RECON-MODEL re-scoped, first criterion now [x]), budget
AXIOM 56->58. Framework gate PASS (all 5 checks); go build + full test suite green.
2026-06-21 15:26:31 -07:00
Antje Worring 5906b09508 Revert "reshare: gate master-secret reconstruction behind corona_research [RED-2]"
This reverts commit 71110cbeeb.
2026-06-21 15:10:41 -07:00
Antje Worring 71110cbeeb reshare: gate master-secret reconstruction behind corona_research [RED-2]
reshare.Verify Lagrange-interpolates the input shares at X=0 and RETURNS the
reconstructed master secret to its caller (its own doc: "MUST NOT be used in
production"). Its only non-test caller is cmd/reshare_oracle (a KAT generator).
Left in the production package with no boundary, it is a latent master-key
footgun.

Fix (surgical split, not whole-file tag): reshare.go also defines the
production Reshare/Refresh/Share that keyera imports, so the file cannot be
tagged out. Move ONLY Verify into verify_reconstruct.go behind
//go:build corona_research; its shared interpolation helpers (selectQuorum,
lagrangeAtZero, sortedKeys) stay in reshare.go because production uses them.
Gate the sole non-test caller cmd/reshare_oracle/main.go with the same tag.

Tests: the reshare/refresh tests that reconstruct the secret (via Verify) move
into reshare_research_test.go / refresh_research_test.go / the tagged
integration_test.go and run under -tags corona_research. The production-
behaviour tests that do NOT reconstruct (determinism, arg validation, t=1
identity, fuzz, transcript) stay in the default build — no coverage lost.
Generic test helpers shared across both builds (cloneVector, runRoundsAndVerify)
move to untagged clone_test.go / signrounds_test.go.

Verification:
- default `go build ./...` exits 0; reshare.Verify ABSENT from the default
  build (proven: a Verify-calling test does not compile into the default run).
- default `go test ./...`: 0 failures; production tests run.
- `go test -tags corona_research ./...`: green; reconstruction tests + oracle
  compile and run (TestReshareSecretInvariant etc. pass).
- gofmt + vet clean in both build modes.
- security/framework/check.sh corona: PASS (no CLOSED-but-reconstructs blocker).
2026-06-21 15:02:59 -07:00
Antje Worring 83031bf331 high-assurance: repoint gate references to luxfi/security/framework (canonical home) 2026-06-21 14:22:36 -07:00
Antje Worring 988e4cc15a proofs: honest bucketed axiom inventory + reconstruct-then-sign disclosure
Reclassify (not reduce) the EasyCrypt axiom surface and correct the prior
inventory's understatement. NO axioms discharged this pass (honest): no
easycrypt toolchain on host, and every in-file-derivable axiom is already a
proved lemma; residual A/B axioms are over abstract ops/constants
(op group_pk_width : int., op sig_len : int.) and the C axioms are open.

- AXIOM-INVENTORY.md: replace the §2 table that mislabelled the wrapper
  bridges and section-local module contracts as "Discharged in the
  Wrapper". They are now correctly bucket C / OPEN: combine_body_spec hides
  the Boschini combine steps 2-6, and combine_abs_op_lifted_bridge /
  sign_abs_op_lifted_eq_rlwe pin the lifted op to rlwe_sign_op on the
  Lagrange-RECONSTRUCTED master secret (reconstruct-then-sign). Complete
  bucketed census of all 56 axioms -- A (18, 5 Lean-bridged), B (27), C
  (11) -- one row per axiom with name, file:line, justification. CT
  contracts (sign_round{1,2}_constant_time) classified C/fail-closed.
- PROOF-CLAIMS.md: add assurance vocabulary + two load-bearing disclosures
  -- (1) the EC byte-equality MODELS reconstruct-then-sign; (2) Corona has
  NO independent interop verifier (R-LWE has no NIST target), so its
  byte-equality is asserted + same-construction Go<->C++ KAT, never
  "proven/verified". Corrects the §4 claim that Pulsar is machine-checked
  "at every step" (it too rests on the same reconstruct-then-sign cone).
- BLOCKERS.md (new): CORONA-EC-RECON-MODEL, CORONA-CT-PENDING,
  CORONA-NO-INDEP-VERIFIER -- all OPEN, all cross-referenced to the shared
  external-review gate.
- .assurance/reviewed-axioms.txt: list every load-bearing / security-cone
  axiom (A: 5 Lean-bridged; C: combine_body_axiom, S_functional_spec,
  combine_body_spec, combine_abs_op_lifted_bridge, sign_abs_op_lifted_eq_rlwe)
  with bucket + justification.
- .assurance/budget.txt: correct prose (0 real admit. tactics; AXIOM=56 exact).

Framework gate (circular-proof + axiom-budget + the other three) PASS with
full disclosure. go test ./... green (no Go touched).
2026-06-21 14:20:05 -07:00
Antje Worring 9284af66c6 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
Antje Worring dc15c54a47 harden: hedged 256-bit nonce key, DRY CT comparator, honest CT/proof docs
Closes the CRIT-1 residual (D1-2) sid-entropy gap and the CT/doc hygiene
gaps to bring Corona to the no-leak/no-gap bar. EasyCrypt proofs untouched.

PRIORITY 1 — anti-nonce-reuse / no-leak durability:
- The Round-1 nonce-PRF key no longer keys on a bare 64-bit sid. It now
  derives from a 256-bit domain-separated SessionID (primitives.DeriveSessionID:
  TranscriptHash("corona.sign.session-id.v1" || be64(sid) || T)) AND a fresh
  per-signature 256-bit hedge salt drawn inside the kernel from party.Rand
  (default crypto/rand). PRNGKeyForRound = PRF(skShare, "CoronaNonceV3" ||
  sessionID || salt). Hedging restores threshold-Raccoon's fresh-per-signature
  nonce posture: reuse durability no longer rests on the external consensus
  layer never reissuing an sid — even an sid collision yields distinct R with
  prob 2^-256. A deterministic 256-bit SessionID alone is necessary but NOT
  sufficient (it repeats when sid repeats); the salt is what closes the leak.
- SignRound1 is fail-closed: rejects an all-zero derived SessionID or all-zero
  salt with ErrDegenerateSession, and surfaces a short-read error. The
  consensus slot-uniqueness invariant is documented as a HARD precondition at
  SignRound1 and Signer.Round1 (no longer a buried comment).
- KAT/oracle determinism preserved via one seam: sign.DeterministicNonceSource
  (KeyedPRNG over seed || "corona.sign.nonce-salt.v1" || partyIndex), set on
  Party.Rand / Signer.SetNonceRand only by reproducibility harnesses.
- SignRound1 / Signer.Round1 now return an error; all call sites updated.
- KAT REGEN: only sign_verify_e2e.json changes (nonce-key bytes moved);
  transcript_hash.json / MAC / legacy PRNGKey vectors are byte-stable, proving
  the consensus-agreed transcript path was left untouched. Regenerated via
  `bash scripts/regen-kats.sh`; `--verify` confirms byte-determinism (10 files).
- Regression: sign/nonce_reuse_test.go proves same-(skShare,sid) yields distinct
  D (fresh R), pinned-nonce reproduces byte-identically, and the degenerate-
  session guard fires. TestE2EKATReplayDeterminism rewritten to assert both the
  hedged-differs and pinned-reproduces properties (was a defanged no-op).

PRIORITY 2 — constant-time hygiene:
- reshare/commit.go already used a constant-time comparator; the real gap was
  the verbatim duplication of constTimePolyEqual+uint64SliceToBytes across dkg2
  and reshare. Consolidated to one canonical utils.ConstantTimePolyEqual; both
  delegate (no dkg2<->reshare dependency). Orphaned imports removed.
- FullRankCheck and the reshare commit path are now covered in the CT review
  with their public-operand justification.

PRIORITY 3 — doc accuracy:
- CONSTANT-TIME-REVIEW.md rewritten Corona-specific and file:line-accurate:
  drops the stale Pulsar/lens/warp/secp256k1 content; audits the real call
  sites (hedged nonce key, masking PRF, lattigo samplers as the residual TCB
  axiom, utils.ConstantTimePolyEqual, CheckL2Norm/Verify/FullRankCheck big.Int
  variable-time on PUBLIC operands, activation/commit-digest array equality,
  keyera/reshare zeroization).
- PROOF-CLAIMS.md §1: threshold.Combine / sign.LocalSign (nonexistent) -> the
  real sign.Party.SignFinalize exposed as threshold.Signer.Finalize.
- threshold/threshold.go package doc: Ring-LWE -> Module-LWE.
2026-06-21 08:21:58 -07:00