21 Commits
Author SHA1 Message Date
zeekay ff80ae6038 chore: sync working tree
Commits 1 outstanding change(s) that were sitting uncommitted.
No build artifacts and no secrets in the changeset (both checked).
2026-07-26 10:13:03 -07:00
zeekay 1a154ee9e8 fix(deps): correct moved-tag hashes for luxfi modules in go.sum
Several luxfi versions carry TWO different contents across this workspace,
because published tags were moved instead of a new patch being cut:
age@v1.5.0, pq@v1.0.3, threshold@v1.9.4, zap@v0.6.0, zap@v0.8.1.

Adjudicated before editing, since "checksum mismatch / SECURITY ERROR" is also
what a real supply-chain attack looks like. It is not one here: sum.golang.org
holds the OLD hash while proxy.golang.org and a direct fetch BOTH serve the same
NEW bytes. Two independent transports agreeing means nothing is rewriting
content in flight — the tag moved at source. The sumdb entry is a fossil:
GOPRIVATE covers github.com/luxfi/* with GOSUMDB=off, so our own modules never
consult the checksum DB and a moved tag splits consumers silently.

The old bytes are served by nothing now, so a stale pin can never build.
Corrected to the only content that exists, in BOTH line forms (h1: and
/go.mod h1:) — Go reports these one at a time, so a partial fix just relocates
the error.

Deliberately no `go mod tidy`: this changes no selected version, only the
recorded hash of versions already chosen.

Verified: `go list -m all` resolves with no checksum error.

The durable fix is upstream: never move a published tag, cut x.y.z+1 instead.
2026-07-26 02:42:49 -07:00
zeekay d76abdca36 chore(deps): bump geth v1.20.1 + luxfi deps — stack unification 2026-07-15 11:12:40 -07:00
zeekay 65dbf7891e bump: dealerless pulsar/corona/dkg/mlwe (no trusted dealer, no-reconstruct)
Move to the dealerless threshold-signature stack: corona v0.10.2 (Module-LWE
Ringtail, dealerless Pedersen-VSS) + pulsar v1.7.1 (dealerless Mithril RSS keygen
+ no-reconstruct signing, trusted dealer ripped) + dkg v0.3.5 + mlwe v0.2.1.
2026-06-28 19:39:51 -07:00
zeekay 40186f01f9 docs(LLM): record v0.10.2 — Phase-2 SP 800-185 + Lagrange routed onto luxfi/mlwe (byte-preserving) 2026-06-28 13:11:59 -07:00
zeekay c85b5cf2ba merge refactor/onto-mlwe (v0.10.2): route SP 800-185 + Lagrange onto luxfi/mlwe — byte-preserving de-dup
One-and-one-way completion: Pulsar AND Corona now both consume the single
github.com/luxfi/mlwe base (v0.2.1) for the shared Module-LWE primitives.
Corona remains Module-LWE (Ringtail/Raccoon line).

WHAT THIS MERGES (transcript + Lagrange routing ONLY — no scope creep):
  - hash/sha3.go: cSHAKE256 / KMAC256 / TupleHash256 / EncodeString now
    vend from mlwe/transcript (the single SP 800-185 surface). Corona keeps
    ONLY its domain-separation tags. hash/sp800_185.go (the local primitive
    copy) is deleted; its NIST primitive vectors now live in mlwe/transcript.
  - primitives/shamir.go: ComputeLagrangeCoefficients delegates field
    arithmetic + interpolation to mlwe/share (NewPrimeField + Lagrange@0);
    Corona keeps the adapter lifting each scalar into the R_q ring.Poly.

DELIBERATELY NOT ROUTED (kept byte-incompatible / audited):
  - Lattigo 48-bit ring stays Lattigo (re-rolling audited Lattigo forbidden).
  - The seeded Shamir deal (ShamirSecretSharing) stays Corona/Pulsar-specific
    (its sampler is byte-incompatible with mlwe.Split).

CORRECTNESS GATE — Go byte-parity (PROVEN, this is the gate):
  Every Corona KAT oracle was run on the pre-refactor baseline (main 17ac4f3,
  Corona-local impls) and on this branch (mlwe v0.2.1 routed), and every
  emitted byte is identical: 19/19 KAT files byte-identical old==new
  (recursive diff clean + sha256 manifest match), covering the exact files
  this change touches (corona_oracle_v2 transcript_hash, shamir_share,
  sign_verify_e2e) plus the full oracle surface (reshare, activation, dkg,
  sign, shamir_general, shamir_tk, transcripts_byte, m4_* samplers).
  e2e threshold variants (3,2),(5,3),(7,4),(10,7) pass; go build ./... and
  go test ./... green across all packages.

  mlwe v0.2.0 -> v0.2.1 is byte-safe by source inspection: the only delta
  between those tags is added *_bench_test.go files (test-only, never
  compiled into the consuming binary); zero production bytes changed in
  mlwe/transcript or mlwe/share. The oracle parity above confirms this
  empirically.

CI-GATE NOTE — C++ cross-runtime byte gate is a POST-MERGE CONFIRMATION,
not a merge blocker:
  cmd/cross_runtime_verify (requires luxcpp cmake/conan/blst) runs in CI as
  a post-merge confirmation. The Go byte-parity above is the correctness
  gate and is sufficient to merge, by this transitivity argument:
    - Old Go bytes == New Go bytes (proven: 19/19 byte-identical).
    - The C++ runtime and the Go runtime share NO build inputs — the C++
      port does not depend on go.mod / luxfi/mlwe at all.
    - Therefore this dependency change CANNOT shift any C++ byte, and the
      C++<->Go KAT relationship is INVARIANT under this change: whatever
      C++==Go (or C++!=Go) held before, holds identically after.
  So the post-merge C++ run can only re-confirm the pre-existing C++<->Go
  state; it cannot regress as a result of this Go-only de-dup.

PRE-EXISTING DRIFT (documented, NOT introduced here, NOT a crypto-byte diff):
  The sign_verify_e2e KAT's prose "description" field references
  threshold.GenerateKeysTrustedDealer (a ~13-byte wording difference vs a
  plain "GenerateKeys" phrasing) — a Go<->C++ description-string mismatch in
  the cross-runtime comparison, orthogonal to cryptographic bytes. It
  pre-dates this branch; sign_verify_e2e.json is sha256-identical old==new
  here, so this change leaves it exactly as it was.

Tag: v0.10.2
2026-06-28 13:09:07 -07:00
zeekay 9e6a6cab8c refactor(hash,primitives): route SP 800-185 + Lagrange onto luxfi/mlwe v0.2.1
Byte-preserving de-dup: Corona's SP 800-185 transcript surface
(hash/sha3.go; deletes the local hash/sp800_185.go) and
ComputeLagrangeCoefficients (primitives/shamir.go) now consume the
shared github.com/luxfi/mlwe base — the single Module-LWE primitive
surface for the Lux stack (Corona + Pulsar).

Routed onto mlwe:
  - hash/sha3.go: cSHAKE256 / KMAC256 / TupleHash256 / EncodeString
    -> github.com/luxfi/mlwe/transcript. Corona retains ONLY its
    domain-separation tags; the byte encodings live in mlwe/transcript.
  - primitives/shamir.go: ComputeLagrangeCoefficients delegates the
    field arithmetic + interpolation to github.com/luxfi/mlwe/share
    (NewPrimeField + Lagrange at point 0); Corona keeps the adapter
    that lifts each scalar into the R_q constant-term ring.Poly.

Deliberately NOT routed (byte-incompatible / audited):
  - Lattigo 48-bit ring stays Lattigo (re-rolling audited Lattigo forbidden).
  - The seeded Shamir deal (ShamirSecretSharing) stays Corona-specific
    (its sampler is byte-incompatible with mlwe.Split).

Corona remains Module-LWE (Ringtail/Raccoon line).

Byte-parity gate: every Corona KAT oracle emits byte-identical output
old (Corona-local impls) == new (mlwe-routed). Go byte-parity is the
correctness gate; the C++ cross-runtime byte gate is a post-merge CI
confirmation (see merge commit CI-GATE note).
2026-06-28 13:02:56 -07:00
zeekay 17ac4f350e merge Corona no-reconstruct-signing audit (v0.10.0): STRICT trustless lane certified — sign path proven no-reconstruct 2026-06-28 01:21:23 -07:00
zeekay 1367e9bb97 docs: certify Corona a STRICT trustless lane (no-reconstruct signing, gate 5)
- LLM.md: Latest Tag -> v0.10.0; record the no-reconstruct signing gate +
  v0.9.0 DKG cutover in the recent-commits table.
- PROOF-CLAIMS.md: catalogue the new code-level conformance gate alongside
  the Lean-4 secret_aggregate_no_reconstruct proof, framed honestly as a
  TEST gate (not a proof-assistant artifact).

Audit verdict (branch audit/no-reconstruct-signing): Corona threshold signing
is no-reconstruct — each party emits z_i = R_i*u + maskPrime_i + c*lambda_i*s_i
- mask_i from its OWN share; SignFinalize sums the masked partials z_sum = Sum
z_j = R*u + c*s; the secret s = Sum lambda_j*s_j appears only as the coefficient
of the public challenge c inside the masked aggregate and is never materialised.
Dealerless keygen (keyera.Bootstrap) + no-reconstruct signing => strict
trustless lane for STRICT_DUAL_PQ / POLARIS_MAX.
2026-06-28 00:57:18 -07:00
zeekay 500d319328 test(threshold): pin Corona no-reconstruct signing (gate 5, trustless-by-default)
Structural + behavioural proof that the Corona threshold SIGNING path never
forms the full secret s, even transiently at sign time:

  GATE A (structural, go/ast): every signing/verify function body is scanned;
    none calls an across-party reconstruction primitive (reconstruct /
    interpolate / combineShares / recover* / ShamirSecretSharing /
    lagrangeAtZero / selectQuorum) and none invokes the trusted-dealer keygen
    (Gen / GenerateKeysTrustedDealer). Per-party Lagrange (party.Lambda on the
    party's OWN share) is the legitimate no-reconstruct mechanism and is NOT
    forbidden. Negative-control verified: injecting a reconstruct call into
    SignFinalize trips GATE A.

  GATE B (behavioural, reflect): Round1Data/Round2Data/Signature carry no
    share/sk/seed/lambda; Finalize ingests only map[int]*Round2Data (masked z
    partials) — the aggregator never holds a second party's secret.

  GATE C (independent verifier): a real (3,5) no-reconstruct ceremony, each
    Signer from exactly ONE share, verifies under the bare Corona verifier
    (public data only) and the stateless wire verifier; tamper rejected.

Verdict: Corona is a STRICT trustless lane — dealerless keygen (keyera.Bootstrap)
+ no-reconstruct signing. Sub-quorum-cannot-forge is pinned separately by
TestThresholdSubQuorumCannotForge.
2026-06-28 00:53:54 -07:00
zeekay 7996ad7a75 merge Phase-3a: corona onto luxfi/dkg v0.2.0 — dealerless no-reconstruct DKG
keyera.Bootstrap drives luxfi/dkg vss share-dealing + blame; keeps corona's own
Path-(a) noise-flooded Round_Xi finalize (the vss Pedersen T is discarded — Ring-LWE
tolerates large blinding). Deployed group key byte-identical (golden KAT). dkg2 deleted.
2026-06-27 22:29:52 -07:00
zeekay 2cecc08c63 refactor(corona): delete the dkg2 package — superseded by luxfi/dkg vss
The Pedersen-VSS DKG share-dealing now runs entirely on github.com/luxfi/dkg
(proven byte-identical at cutover); corona's own copy is dead. Remove it and its
now-orphaned tooling, keeping only corona-specific code (Ringtail signing, β
rounding, Path (a) finalize — all in sign/, utils/, keyera/, untouched).

Deleted:
  - dkg2/ (the whole package: Round1/Round2/commits/complaint/GPU dispatch).
  - cmd/dkg2_oracle/ (the dkg2 KAT generator; the DKG KAT now lives in
    luxfi/dkg's own ring/vss vectors).
  - keyera/cutover_gate_test.go (the transitional dkg2-vs-vss equality gate; its
    job is done — permanent byte-stability is pinned by the golden KAT, and the
    PIN-4 convention assertion is preserved dkg2-free in pin4_convention_test.go).

Updated:
  - cmd/cross_runtime_oracle drops the dkg2 manifest leg (the luxcpp C++ dkg2
    cross-runtime gate migrates to luxfi/dkg separately — flagged, not silently
    broken).
  - keyera/reanchor doc comments + threshold bench comment point at luxfi/dkg.

go build ./... + go test ./... -count=1 green (13 ok / 0 fail), go vet + gofmt
clean. The golden byte-stability KAT + Bootstrap→sign→verify + dishonest-dealer
abort all still pass on the vss path.
2026-06-27 22:03:55 -07:00
zeekay 259a1a2cae feat(keyera): drive the dealerless DKG through luxfi/dkg vss
Rewire BootstrapPedersen's no-reconstruct share-dealing onto the shared
github.com/luxfi/dkg library (vss + blame + ring.Ringtail()), dropping the
in-keyera dependence on corona/dkg2. corona keeps ONLY its scheme-specific
finalize: Path (a) noise flooding + Round_Xi, which turns the per-party secret
shares s_j into the LWE-shaped Ringtail public key bTilde = Round_Xi(A·s+e'').
The vss Pedersen aggregate T = A·s1+B·u is NOT corona's group key (its B·u term
is not a small LWE error), so vss is used purely for the no-reconstruct share
distribution + identifiable blame.

Mechanism:
  - BootstrapPedersen draws per-party sampling seeds from the ceremony entropy
    (same sequencing as before) and threads each into vss.Party.Round1, so the
    χ draws — hence the Pedersen commits and the secret shares — are byte-
    identical to the prior dkg2 path (cutover gates B/C/E).
  - DealPedersen runs Round 1 + opens every sealed envelope; FinishBootstrapPedersen
    runs Round 3 (Pedersen verify + aggregate) then Path (a) + KeyShare assembly.
    The two-phase split is the test seam for identifiable abort (tamper an opened
    share, observe ErrBootstrapPedersenAbort + re-checkable blame).
  - Commit digests are recomputed under the corona HashSuite over the lattigo
    wire bytes of vss's commits — byte-identical to dkg2's CommitDigest — so the
    noise seed and transcript hash are preserved.
  - AbortEvidence now carries luxfi/dkg blame.Complaint (accused-by-NodeID,
    third-party re-checkable via vss.RecheckBadDelivery); the in-process channel
    identities are derived deterministically and affect only the (immediately-
    opened) envelope ciphertext, never any byte-stable output.

Proof: the frozen golden KAT (bTilde / transcript / shares digests for 5/3 and
3/2) PASSES against the vss path — the group key, transcript, and shares are
preserved byte-for-byte. Determinism, Bootstrap→sign→verify, dishonest-dealer
abort (+ RecheckBadDelivery), reanchor round-trip/abort, and the no-master-secret
structural checks all green. Public API (Bootstrap/KeyEra/EpochShareState/
BootstrapTranscript/GroupKey/KeyShare) unchanged.
2026-06-27 21:55:51 -07:00
zeekay aaa666de29 test(keyera): cutover gate E — vss Round3 aggregateShare+verifyPedersen byte-identical to dkg2 Round2Identify
Completes the share-dealing byte-equality proof (gates A-E): vss's real
Round3 (verifyPedersen + aggregateShare) accepts dkg2's contributions
cross-implementation and produces s_j = Sigma_i f_i(j) byte-identical to
dkg2.Round2Identify. With A-E green the BootstrapPedersen swap onto
vss (Round1 -> OpenDealerShare -> Round3.ShareResult.Share) preserves the
group key + per-party shares byte-for-byte; corona's Path-(a) noise-flood
finalize is unchanged. PIN 4 resolved: no R^{-1} scaling adapter needed.
2026-06-27 21:49:21 -07:00
zeekay 1c6cf6166f test(keyera): freeze BootstrapPedersen golden byte-stability KAT
Capture the group key (bTilde), transcript hash, and per-validator shares from
the dkg2-backed BootstrapPedersen at the cutover point, as frozen SHA-256
digests for two committee shapes (5/3, 3/2). This is the permanent byte-for-byte
target the luxfi/dkg rewire must reproduce — proving the group-key convention,
transcript, and shares are PRESERVED (not re-baselined) when the no-reconstruct
share-dealing moves to vss while corona keeps its own Path-(a) finalize.
2026-06-27 21:44:03 -07:00
zeekay 374e600952 test(keyera): luxfi/dkg v0.2.0 cutover gate — Ringtail byte-identical to dkg2
Phase 3a step 1: require github.com/luxfi/dkg v0.2.0 and prove, before any
rewire, that the shared library's ring.Ringtail() binding reproduces
corona/dkg2's KAT-pinned arithmetic byte-for-byte.

Gate (cutover_gate_test.go), all green:
  (A) ring.Ringtail() A,B == dkg2.DeriveA/DeriveB over all 8x7 slots.
  (B) vss's REAL Party.Round1 commits == dkg2.Round1WithSeed commits for the
      same 32-byte sampling seed (exercises vss computeCommits, not a re-impl).
  (C) vss Horner shares (ring.ScalarMulVec/VecAdd) == dkg2 big.Int Horner shares
      for every recipient — the Barrett-vs-bigint paths agree on the canonical
      representative in [0,q).
  (D) PIN 4 pinned to ground truth: dkg2.Round2 b_ped (IMForm+INTT) = vss group
      commit T (INTT-only) scaled by R^{-1}; the two differ by EXACTLY the
      Montgomery factor R (MForm(b_ped)==T). corona's PRODUCTION key is NEITHER:
      keyera Path-(a) noise flooding multiplies NTT-Mont operands so the R is
      correctly cancelled, yielding the TRUE A·s+e'' — convention-aligned with
      vss's TRUE T. dkg2's R^{-1}-scaled b_ped is an internal Round2 value the
      production path discards, so the rewire (keep corona's finalize, use vss
      for share-dealing) preserves the group key with NO convention change.
2026-06-27 21:39:39 -07:00
zeekay 321f5968b8 docs: state the dual-leg diversity claim accurately (not an over-correction)
The prior pass swung too far: it answered "does running both give diversity?"
with a flat "No, both are Module-LWE." That under-credits the real security.

Accurate, layered claim now installed in design-decisions / README / SUBMISSION /
nist-mptc-category:
- Pulsar and Corona are distinct SCHEMES at different PARAMETER regimes
  (Pulsar = FIPS-204 ML-DSA deterministic FS-with-aborts, q=8380417; Corona =
  Ringtail/Raccoon masked threshold, q=0x1000000004A01, params tuned for
  threshold). In AND-mode an adversary must forge BOTH; a cryptanalytic,
  parameter-specific, or implementation flaw in one does not transfer — the pair
  is strictly stronger than either leg alone ("both have to be cracked").
- What it is NOT: hardness-ASSUMPTION diversity. Both rest on Module-LWE/SIS, so a
  fundamental Module-LWE break threatens both lattice legs; assumption-disjoint
  diversity is the hash-based Magnetar (SLH-DSA) leg.

Docs-only; go build green; no shims.
2026-06-27 17:02:21 -07:00
zeekay df1db68bd0 docs/comments: correct lattice-family label Ring-LWE -> Module-LWE (Corona is Module-LWE)
Corona is Module-LWE (threshold-Raccoon/Ringtail), NOT Ring-LWE. Confirmed in code: sign/sign.go samples A in R_q^{8x7} (sign.go:87 SamplePolyMatrix M=8,N=7), secret s a rank-7 ring vector, b=A*s+e (sign.go:106-107) over R_q=Z_q[X]/(X^256+1) (LogN=8), q=0x1000000004A01 -- rank>1 module structure, not rank-1 ring-LWE. threshold/threshold.go:4-5 already said Module-LWE.

Fixed the family label across README, SPEC, SUBMISSION, NIST-SUBMISSION, PATENTS, LLM, CONTRIBUTING, SECURITY, CHANGELOG, DEPLOYMENT-RUNBOOK, Makefile, AXIOM-INVENTORY, PROOF-CLAIMS, BLOCKERS, CRYPTOGRAPHER-SIGN-OFF, FIPS-TRACEABILITY, TRUSTED-COMPUTING-BASE, AUDIT-2026-05/06, docs/mptc/*, jasmin/README, 3 Go comments + cli help string.

Also corrected the downstream false claim that Corona (Ring-LWE) and Pulsar (Module-LWE) are 'different lattice families' giving 'structural/family diversity': both are Module-LWE, so the Double-Lattice defense is construction/implementation diversity (threshold-Raccoon vs ML-DSA), not hardness-family diversity; a Module-LWE break affects both legs (hash-based Magnetar is the assumption-diversifier). Fixed companion R-SIS -> Module-SIS where it was the module scheme's SIS assumption; added the Langlois-Stehle (DCC 2015) Module-LWE citation alongside LPR 2010.

Delicate artifacts: proof identifiers (rlwe_sign_op, RLWE_Functional theory/file, *_eq_rlwe bridges, CentralRLWESign, RLWESign, rlwe_compute_*) were NOT renamed -- EasyCrypt/jasmin toolchains are absent here so a rename cannot be compile-verified, and .assurance/ gates parse those names. Added clarifying naming notes to the 5 prominent .ec files, proofs/easycrypt/README.md, AXIOM-INVENTORY.md, and jasmin/rlwe/sign.jazz. .assurance/*.txt left untouched (already say Module-LWE/Module-SIS; rlwe tokens are gate-parsed identifiers). Left AUDIT-2026-06.md:463 historical rename-log and the ProtoStar-LWE paper-title substring untouched.

go build ./... and go test ./... green (GOWORK=off; all packages ok).
2026-06-27 16:12:24 -07:00
zeekay 26eb3f35b7 corona: docs to v0.8.0 — dealerless Pedersen DKG is the production keygen default
dkg2/BootstrapPedersen (dealerless Pedersen DKG over R_q = Z_q[X]/(X^256+1)) is the production keygen default since v0.7.5; signing never reconstructs the master secret (SignFinalize sums partials). Corona carries the permissionless / no-trusted-dealer guarantee in the Quasar AND-mode dual-PQ cert that Pulsar's byte-FIPS-204 keygen cannot (a dealerless sum of FIPS secrets breaks ML-DSA's S_eta bound). README/LLM/BLOCKERS refreshed; stale v0.7.4 / WIP -> v0.8.0 / Production. Not FIPS byte-equal; no fabricated cert-size figure.
2026-06-27 14:15:00 -07:00
zeekay f08e2b57aa threshold: make trusted-dealer keygen explicit, drop dead ReconstructSecret, pin sub-quorum soundness
Part of the Lux threshold-crypto security rip (killing trusted-dealer /
full-key-reconstruction footguns).

- Rename threshold.GenerateKeys -> threshold.GenerateKeysTrustedDealer.
  The function samples the full secret and sets sign.K / sign.Threshold in
  one process: it IS the trusted dealer. The new name mirrors
  keyera.BootstrapTrustedDealer so the trust model is explicit and
  greppable. Doc comment now states it is for test/KAT/CT/CLI/oracle use
  only, and that production chain keygen uses keyera.Bootstrap (dealerless
  Pedersen DKG). Stays exported; every caller updated (cli, ct/dudect,
  same-package tests) plus stale comment refs in cmd, keyera, wire,
  reshare.

- Delete utils.ReconstructSecret. It Lagrange-interpolates the full secret
  from shares and had zero callers anywhere in the repo: a
  reconstruction-shaped footgun left dead. CompareSecrets and the section
  retained.

- Include threshold/minority_soundness_test.go: an adversarial negative
  pinning that a strict sub-quorum cannot assemble a signature that
  verifies under the group key (uncancelled PRF mask fails the L2-norm
  gate). A sub-quorum forgery would be a catastrophic finality break.
2026-06-26 21:13:45 -07:00
zeekay 4d9334ee94 corona→corona: academic Corona now only in lp-220-p3q-corona 2026-06-11 10:27:40 -07:00