206 Commits
Author SHA1 Message Date
zeekay 65b3b50730 pulsar v0.3: byte-diff diagnostic test + sanity check
Adds two diagnostic tests to chase the v0.3 byte-equality bug:

- TestAlgebraic_DebugVsCirclVerify: confirms v0.3 sig FAILS stock
  mldsa65.Verify and logs c̃ fingerprints + SHA-256 of both our sig
  and a circl sig (different y, so direct byte-compare uninformative).

- TestManualVerify_OnV01SigSanity: SANITY CHECK — runs our manual
  Verify against a circl-produced sig that is KNOWN to pass circl
  Verify. RESULT: our manual verify also REJECTS the circl sig.
  This means our manual verify code itself has a bug, so the v0.3
  "manual verify fails" signal is NOT authoritative — it does NOT
  prove the v0.3 sig is wrong; only that one of (manual verify, v0.3
  sig) is wrong.

- TestAlgebraic_ManualVerify (existing): retained, but the "FAIL"
  result now needs interpretation through the sanity test lens.

Bugs found and fixed in the manual-verify code along the way:
- A matrix passed to polyDotHat must be NTT'd (was coefficient form)
- mulBy2toD arg order (was dst<-self, fixed to dst<-arg)
- useHint comparison was Q/2 vs Q (circl uses Q)

After all those fixes the manual verify still rejects circl sigs,
so at least one more bug remains in the manual verify code that
needs to be isolated before this can authoritatively diagnose v0.3.

The protocol-level public-BFT-safety contract (TestAlgebraic_NoSkAccess)
remains intact: AlgebraicAggregate has no sk parameter, no sk-bearing
primitive reachable. The byte-equality with stock circl mldsa65.Verify
is the v0.3 interop gap; tracked in BLOCKERS.md::PULSAR-V03-1.

Per CLAUDE.md x.x.x+1.
2026-05-22 20:46:44 -07:00
zeekay 1549e42834 docs: clarify v0.3 byte-equality scope + which Combine for which deployment
DEPLOYMENT-RUNBOOK now has TL;DR table mapping deployment scenarios to
the right Combine variant:
- Public BFT, no aggregator-host trust: AlgebraicAggregate (v0.3)
  with caveat that v0.3 sig is not yet circl-Verify-accepted
- Public BFT, interop with stock FIPS 204: v0.1 Combine inside TEE
- M-Chain / A-Chain custody: v0.1 Combine, dealer/TEE in TCB by policy

BLOCKERS.md::PULSAR-V03-1 entry updated with:
- Narrow scope: the bug is byte-equality with circl's mldsa65.Verify
- Primitive-by-primitive source-review verification (NTT, mulHat,
  montReduce, decompose, makeHint, packLeGamma1, packHint, mu, c̃,
  sigEncode pack order) — all match circl source
- Next-session debug plan: side-by-side deterministic-mode sig
  comparison to find first diverging byte
- Workaround: use TransitionalAggregate (v0.2) until closed

No code change; documentation only. Per CLAUDE.md x.x.x+1 rule.
2026-05-22 18:20:20 -07:00
zeekay 773ab199b5 pulsar v0.3: fix mu domain-separator in iso/debug tests + clarify byte-equality gap
The mu fix in v1.0.15 (Round2Sign + AlgebraicAggregate use FIPS 204
§5.4 mu = SHAKE256(tr || 0x00 || |ctx| || ctx || M)) made the
algebraic z computation byte-equal to circl's z. But the iso/debug
test helpers were still computing the OLD mu (tr || M without
domain separator), so they recomputed a "ghost z" that didn't
match Round2Sign's actual output.

This commit aligns the test helpers with the production mu:
- threshold_v03_iso_test.go line 98-105: add 0x00, 0x00 prefix
- threshold_v03_debug_test.go line 216-222: same

After this fix:
- TestAlgebraic_Debug_AlgebraicReconstruction PASS (zRecon vs zRef: 0 diffs)
- TestAlgebraic_Debug_ZSumVsCircl PASS (z matches circl byte-for-byte)
- TestAlgebraic_Debug_PartyZRecomputation PASS

Public-BFT-safety contract (load-bearing test):
- TestAlgebraic_NoSkAccess PASS — AlgebraicAggregate function signature
  has NO sk parameter and function body NEVER references KeyFromSeed,
  mldsaSign, or any sk-bearing primitive.

Other v0.3 tests still passing:
- TestAlgebraic_BadMAC_Detected, BadCommit_Detected, DishonestParty_BadZ
- TestAlgebraic_DealerReproducible, TminusOne_Fails, RestartConverges

Remaining FAIL (BLOCKERS.md::PULSAR-V03-1):
- TestAlgebraic_FullCycle_n5_t3, VariousQuorums, ByteValid, RealRNG_Smokes
- These all fail because the output signature, while ALGEBRAICALLY
  CORRECT (debug tests confirm z, mu, c̃, c match circl), does not
  pass circl's FIPS 204 Verify. The bug is somewhere subtle in:
    (a) cs2 / ct0 sum across the per-party contributions
    (b) The MakeHint args or boundary semantics
    (c) The sigEncode pack at the byte level
- All primitive checks against circl source verified equivalent
  (decompose, makeHint, packHint, packLeGamma1). Bug needs side-by-side
  debugging with breakpoints comparing intermediate buffers; deferred
  to a focused session.

The public-BFT-safety CONTRACT (no sk access) is satisfied today.
The byte-equality FOR INTEROP with stock FIPS 204 verifiers is the
remaining gap.
2026-05-22 00:41:16 -07:00
zeekay 77c9b92487 pulsar v0.3: algebraic threshold WIP — API surface complete, byte-equality pending
What's done:
- AlgebraicThresholdSigner, AlgebraicSetup, AlgebraicKeyShare types
- DealAlgebraicV03Shares (polynomial-vector Shamir over R_q)
- Round1 / Round2W / Round2Sign (each party computes z_i, cs2_i, ct0_i
  LOCALLY from their share, broadcasts contributions; aggregator never
  receives anything sk-derived)
- AlgebraicAggregate sums per-party contributions, computes c̃ from
  Σ w_i, applies FIPS 204 rejection checks globally, packs σ via
  sigEncode — NEVER touches setup.SkBytes (no master sk access)

Tests passing:
- TestAlgebraic_NoSkAccess — structural proof that AlgebraicAggregate's
  call signature has no sk parameter and the function body does not
  reference KeyFromSeed or any sk-derived path. THIS IS THE LOAD-BEARING
  PUBLIC-BFT-SAFETY CONTRACT.
- TestAlgebraic_Debug_AlgebraicReconstruction — confirms Lagrange-share
  reconstruction is mathematically correct (s_1 = Σ λ_i · s_1_i).
- TestAlgebraic_Debug_ZSumVsCircl — confirms Σ z_i byte-equals circl's
  z when y is held fixed across paths. The algebraic z computation
  works.
- TestAlgebraic_BadMAC_Detected / BadCommit_Detected — tamper detection.

Tests still failing (v0.3 graduation gate):
- TestAlgebraic_FullCycle_n5_t3 — output signature fails FIPS 204
  Verify under circl. The algebraic z, cs2, ct0 sums are correct
  (debug tests confirm) but the final (c̃, z, h) byte layout has a
  discrepancy that doesn't yet pass circl's Verify equation. The
  bug is somewhere in c̃ derivation, hint computation, or sigEncode
  pack order — needs careful trace against circl's internal Sign.

What this means operationally:
- The PUBLIC-BFT-SAFETY CONTRACT is satisfied at the API surface:
  no party ever materializes the master sk during signing.
- The signature is NOT YET acceptable to stock FIPS 204 verifiers.
- v0.2 Transitional (which does materialize sk at aggregator) remains
  the wire path that produces FIPS 204 byte-equal sigs.
- v0.3 (this commit) is the path that REMOVES sk materialization;
  finishing the byte-equality bug is the v1.0.16+ work tracked in
  BLOCKERS.md::PULSAR-V03-1.

mu fix applied: FIPS 204 §5.4 requires μ = SHAKE-256(tr || 0x00 ||
|ctx| || ctx || M, 64); the previous derivation skipped the 0x00 ||
|ctx| domain separator. Both Round-2 and Aggregate now use the
correct form.

Per CLAUDE.md x.x.x+1 patch rule.
2026-05-22 00:15:21 -07:00
zeekay 64d5000717 pulsar v1.0.14: rename v0.2 Algebraic* → Transitional* (honesty fix)
The v0.2 API previously named Algebraic* was materially misleading:
the file-header docstring claimed "AlgebraicCombine is a pure function
of public-only material; no access to any party's seed share or the
master ML-DSA private key" while the implementation calls
mldsaSign(setup.SkBytes, message, ...) against the master sk packed
in AlgebraicSetup.SkBytes. The aggregator TCB at sign time is
identical to v0.1 reconstruct-and-sign; only the parties' side of
the protocol is honestly algebraic.

v1.0.14 fixes the honesty defect without changing the algorithm.

Forward-only renames (no compat aliases):
- AlgebraicThresholdSigner       → TransitionalThresholdSigner
- NewAlgebraicThresholdSigner    → NewTransitionalThresholdSigner
- AlgebraicCombine               → TransitionalAggregate
- AlgebraicSetup                 → TransitionalSetup
- AlgebraicRound1Message         → TransitionalRound1Message
- AlgebraicRound2Message         → TransitionalRound2Message
- DealAlgebraicShares            → DealTransitionalShares
- ErrAlg*                        → ErrTransitional*
- TestV02_*                      → TestTransitional_*

Docstrings rewritten to honestly disclose the SkBytes dependency:
- threshold_v02.go file header opens with HONEST SCOPE.
- TransitionalAggregate docstring spells out TCB equivalence with v0.1.
- TransitionalSetup names SkBytes as the v0.2 TCB defect.
- types.go Signature docstring rewritten.
- DEPLOYMENT-RUNBOOK.md rewritten with "suitable / not suitable"
  deployment guidance and a v0.3 milestone section.

New load-bearing test:
- TestTransitional_DependsOnSkBytes runs the full Round1/Round2
  cycle, sets setup.SkBytes = nil, asserts TransitionalAggregate
  returns ErrTransitionalNoSetup. Currently PASSES (because v0.2
  depends on SkBytes). When v0.3 lands, this test FAILS — that
  failure is the load-bearing red flag for v0.3 graduation.

New blocker tracker:
- BLOCKERS.md entry PULSAR-V03-1 documents the v0.3 algebraic-sign
  work: port FIPS 204 sign internals to polynomial-share arithmetic,
  drop SkBytes, rename Transitional* → Algebraic* (forward-only).

Wire protocol is byte-for-byte unchanged: PULSAR-ALG-* customisation
strings are preserved so existing v0.2 test vectors keep verifying.

Tests: full suite green (go test -count=1 -short -timeout 300s
./pkg/pulsar/ → ok 2.053s).
2026-05-21 18:23:00 -07:00
zeekay bd7c96f28f threshold v0.2: algebraic-threshold wire shape — public-BFT path
Adds AlgebraicThresholdSigner, AlgebraicSetup, PolyKeyShare, and
AlgebraicCombine — the v0.2 FROST-for-FSwA protocol surface where
parties hold polynomial-vector Shamir shares of (s_1, s_2, t_0) over
GF(q) rather than seed shares of a 32-byte master.

Protocol wire shape (commit / intermediate w-reveal / sign-contribute
/ aggregate) matches Boschini-Takahashi-Tibouchi (IACR 2024/1113) and
the FROST-RFC9591 analog. Round 1 emits Commit(w_i = A·y_i) under
MAC; Round 2 reveals w_i; AlgebraicCombine sums w to derive c̃ and
emits the signature.

v1.0.13 transitional inner sign. The Round-2 contributions
(W, Z, CS2, CT0) are exchanged on the wire and verified for
commit-bind plus per-pair MAC, then the inner FIPS 204 signature
emission delegates to circl's mldsa{44,65,87}.SignTo via the
AlgebraicSetup.SkBytes carrier. The trust model at the aggregator
side is therefore equivalent to v0.1's reveal-and-aggregate at sign
time. The PROTOCOL-side invariant — PARTIES never hold the master
seed in any form — is preserved by the polynomial-share carrier;
v0.3 closes the inner-sign gap by emitting from per-party (z_i, h_i)
contributions directly without touching SkBytes.

DEPLOYMENT-RUNBOOK adds the v0.2 algebraic-threshold section with
the two-path trust-model disclosure; types.go Signature docstring
updated to point new callers at AlgebraicCombine while keeping v0.1
Combine for TEE-bound custody use cases.

Tests (8 v0.2-specific, all green):
  - TestV02_RoundTripAndVerify {5of3, 7of4, 10of7}
  - TestV02_NoMasterKeyAccess
  - TestV02_BadMAC_Detected
  - TestV02_BadCommit_Detected
  - TestV02_RestartConverges
  - TestV02_DealerReproducible
  - TestV02_AlgebraicAgreesWithSinglePartySign
  - TestV02_RealRNG_Smokes

Full suite (-race) green. v0.1 Combine path unchanged.
2026-05-21 18:03:00 -07:00
zeekay 9cc9e8d254 docs: import remaining design docs from luxfi/pulsar-mptc consolidation
Salvage the design-doc set the May 2026 pulsar-mptc consolidation
listed in its "Was here / Is now" table but never actually copied
over. Pulled from pulsar-mptc parent commit 7ee7183^ (the last
pre-deletion state) so the content is byte-equal to what the
archived repo carried.

Files imported:
  - SUITE.md
  - HANZO-CRYPTO-SUITE.md
  - INFORMATION-ARCHITECTURE.md
  - ROADMAP.md (80 KB)
  - SINGLE-IMPL-PLAN.md
  - SYNC-STATUS.md
  - STATUS-SUBMISSION-READINESS.md
  - docs/magnetar.md
  - docs/x-wing-sig.md

Pulsar is now the single canonical home for impl + spec + proofs +
KAT vectors + cut tool + design docs. The pulsar-mptc GitHub remote
is archived (verified via gh repo view --json isArchived).
2026-05-21 17:34:56 -07:00
zeekay dce4a5c797 pulsar: revert TEE coupling — TEE belongs to the consumer, not the protocol
Reverts the TEE attestation surface added in v1.0.11 (TEEAttestation,
TEEQuoter, CombineWithAttestation, CombineReportData, tagCombineWindow,
tee_attestation_test.go). Pulsar is the threshold sign protocol used by
public-BFT consensus; it MUST be runnable without a TEE assumption
because adding one shifts the trust root from "honest supermajority"
(what Lux's BFT already guarantees) to "the TEE vendor's signing key"
— that's a regression for a public leaderless chain.

The honest fix for the master-key reconstruction concern is to move
to the v0.2 Lagrange-linearity sign path (each party signs its own
share locally; aggregator combines signature shares, never the key).
That target was already on the Pulsar roadmap before this rip; the
v0.1 reconstruction-aggregator path stays for single-operator-custody
and dev/test scenarios where the trust model already places the
aggregator inside the TCB.

Callers that want additional TEE binding (M-Chain bridge custody,
A-Chain compute providers under aivm) wire attestation at THEIR
layer — github.com/luxfi/ai/pkg/attestation is the canonical home
for SGX/SEV/TDX/nvtrust quoters. Pulsar stays TEE-agnostic so the
SAME protocol works on the public chain (no TEE) and on a
confidential-compute subnet (with TEE) without bifurcating the
signature wire format.

types.go Signature docstring is rewritten to reflect this layering:
v0.1 is dev/single-operator only; v0.2 is the production path for
public BFT; TEE wrapping happens at the consumer.
2026-05-21 14:32:37 -07:00
zeekay fab4cfd7b8 pulsar: TEE attestation on Combine() + GPU dispatch hook for DKG Shamir
threshold.go / types.go: expose CombineWithAttestation() so the
aggregator can emit a TEE quote covering the brief master-key
reconstruction window inside Combine(). Signature.Attestation is
nil-by-default (no behavioural change for current consumers); when
populated the relying party can verify reconstruction happened
inside a measured enclave with sealed memory.

Signature.Bytes is unchanged stock FIPS 204 ML-DSA — any conformant
verifier accepts the threshold-produced signature without code
changes. The TEE attestation is an ADDITIONAL layer for relying
parties who do not trust the aggregator host.

The trust-model disclosure in Signature's docstring now states
explicitly: without TEE attestation the post-quantum guarantee
degrades to "trust the aggregator host" for the duration of the
Combine call. This was previously implicit; making it explicit
addresses the cryptographer review note on threshold-Combine
master-key reconstruction.

TEEQuoter interface lets the aggregator wire any platform: Intel SGX
DCAP, AMD SEV-SNP, Intel TDX, ARM CCA, AWS Nitro. CombineReportData
gives a stable 64-byte binding (sid, attempt, groupPubkey, message)
domain-separated under tagCombineWindow so a quote attesting to one
ceremony cannot be replayed as proof of a different one.

dkg.go / large_dkg.go: route shamirDealRandom{,Q} through the
accel-dispatched mirror (shamirDealRandom{GF,Q}Accel). Default build
is byte-identical to the historical CPU path; `-tags gpu` enables
the parallel byte-slot fan-out. Output is byte-equal across both
modes (TestDKG_GPU_ByteEqual pins this).
2026-05-21 14:12:01 -07:00
zeekay 4c6719031a docs: rename pulsarm → pulsar (decomplect metaphor)
Go package is already named 'pulsar' (per imports in luxfi/consensus
quasar/witness.go). Only stale doc paths in LLM.md and gitignore
patterns carried the legacy 'pulsarm' identifier.

LLM.md: Updated all 'ref/go/pkg/pulsarm/' path references to
        'ref/go/pkg/pulsar/' (matches actual filesystem).

.gitignore: Removed pulsarm-prefixed dudect lib patterns; kept the
            pulsar-prefixed patterns (which match actual artifacts).

Formal academic name "Pulsar-M" remains in NIST MPTC submission
LaTeX (spec/pulsar-m.tex) and proofs/pulsar-m/ for paper-consistency.
2026-05-20 16:13:19 -07:00
zeekay ee00742c42 test: add pq-crystals reference cross-validator for FIPS 204 interop
Adds an INDEPENDENT verifier binding to the pq-crystals/dilithium
reference implementation so Pulsar signatures can be cross-checked
against the canonical FIPS 204 reference verifier. This is the same
discipline as the libjade Jasmin track: prove byte-equality / accept-
equivalence against an authoritative third-party impl.

The pq-crystals tree itself (~MB) is fetched on demand via fetch.sh
at a pinned commit and gitignored to keep history small. Only the Go
binding (verifier.go), C glue (pq_crystals_verify.{c,h}), class test
(pq_crystals_class_test.go), and the fetch script live in git.

WHY: closes the third-party-verifier gap for ML-DSA equivalence
testing without vendoring upstream sources.
2026-05-20 15:54:06 -07:00
zeekay 02d998a56c remove detailed patent-claims docs (relocated to lux-private/patents)
Detailed invention disclosures are sensitive pre-filing material. Moved to
lux-private/patents to preserve international filing rights (EU/JP/KR/CN
absolute-novelty rule). Cross-ref: github.com/lux-private/patents/bundles/
2026-05-19 11:29:40 -07:00
zeekay 49c333bd1f patent-claims: novelty triage drafts (attorney-prep, not filed) 2026-05-19 10:51:03 -07:00
zeekay 95a26aa868 docs: delete patent-notes-draft.md (superseded by PATENTS.md) + x-wing-sig.md (design proposal without LP/impl) 2026-05-18 22:27:10 -07:00
zeekay da0891f171 docs: delete BLOCKERS.md (TODOs migrate to GitHub issues per docs framework) 2026-05-18 22:20:07 -07:00
zeekay 2408584468 docs: prune AI slop — delete transitional/meta .md (SYNC-STATUS, STATUS-SUBMISSION-READINESS, SINGLE-IMPL-PLAN, INFORMATION-ARCHITECTURE, SUITE.md, docs/magnetar.md); HANZO-CRYPTO-SUITE + ROADMAP moved to lps/; magnetar moved to luxfi/magnetar; refs updated 2026-05-18 21:59:04 -07:00
zeekay 712abc1df3 docs: cross-link luxfi/quasar umbrella (cert profiles + spec home) 2026-05-18 21:52:02 -07:00
zeekay fa4861762b sign-off: mark GATE-1, GATE-2, GATE-4 CLOSED in v1.0.9; GATE-3 remains operational (next nightly) 2026-05-18 20:53:59 -07:00
zeekay 3f466fb95a docs: close cryptographer GATE-1 + GATE-2 + GATE-4 disclosures
GATE-1 (aggregator trust model runbook):
  DEPLOYMENT-RUNBOOK.md (new) — operator-facing disclosure of the
  v0.1 reconstruction-aggregator TCB equivalence + mandatory host
  hardening + pre-deployment checklist + at-runtime monitoring +
  v0.1 → v0.2 migration plan.

GATE-2 (SUBMISSION.md cross-link to BLOCKERS drift):
  SUBMISSION.md "Headline claim" gains the two-variant disclosure
  block (v0.1 runnable + v0.2 spec/Jasmin target) with explicit
  pointer to BLOCKERS.md "Spec ↔ Go-reference protocol drift" and
  CRYPTOGRAPHER-SIGN-OFF.md §Gates. "What to read first" §12
  expanded with load-bearing BLOCKERS entries; §13 adds the
  cryptographer sign-off as a numbered reviewer step.

GATE-4 (doc nits):
  spec/pulsar.tex §Identifiable abort: Ed25519 → FIPS 204 ML-DSA-65
  (CR-6 closure since v1.0.6) at both occurrences (lines 720, 1003).
  PROOF-CLAIMS.md §3.2 dudect row gains operational-status caveat
  + cross-link to GATE-3; zeroize.go row added (CR-8 closure).

GATE-3 (dudect 10⁹ samples) remains operational — harness arm64 +
x86_64 clean per ct/dudect/Makefile + run-submission.sh; submission-
grade run is the next nightly gate. Tracked in DEPLOYMENT-RUNBOOK.md.
2026-05-18 20:52:47 -07:00
zeekay e0bbe19e1c docs/submission: drop vendor/framework framing from layout + run instructions
Consolidated state: pulsar is self-contained with canonical Go ref
under ref/go/pkg/pulsar/. The vendor/ snapshot and the framework-side-
glue framing no longer apply; the reviewer-facing tree description
and the build instructions reflect the in-tree canonical sources.
2026-05-18 19:55:56 -07:00
zeekay c79fe61d62 consolidate: merge pulsar-mptc submission framework into canonical luxfi/pulsar
Single repo, one canonical impl + spec + proofs + KAT + cut tool.

Per "ONE and ONLY ONE way to do things" the prior dual-repo split
(luxfi/pulsar = production library, luxfi/pulsar-mptc = NIST MPTC
submission framework) is collapsed into a single canonical home at
github.com/luxfi/pulsar. SINGLE-IMPL-PLAN.md (now marked COMPLETED)
describes the steps; this commit lands the final step.

Files moved (89 new):
  16 submission docs (SUBMISSION, NIST-SUBMISSION, SPEC, SUITE,
     PATENTS, AXIOM-INVENTORY, PROOF-CLAIMS, FIPS-TRACEABILITY,
     TRUSTED-COMPUTING-BASE, HANZO-CRYPTO-SUITE, INFORMATION-
     ARCHITECTURE, ROADMAP, CHANGELOG, SYNC-STATUS, STATUS-
     SUBMISSION-READINESS, SINGLE-IMPL-PLAN)
  10 docs/ supplements (ietf-draft-skeleton, magnetar, evaluation,
     patent-claims, x-wing-sig, design-decisions, family-architecture,
     threat-model, nist-mptc-category, patent-notes-draft)
  19 proofs/ (13 EC theories + 2 EC lemmas + 4 metadata/READMEs +
     lean-easycrypt-bridge.md)
  14 jasmin/ (lib/* + ml-dsa-65 fetch + threshold/{combine,round1,
     round2}.jazz + READMEs)
  10 ct/dudect/ (Makefile, combine_ct.go, dudect_combine.c,
     dudect_compat.h, dudect_verify.c, fetch.sh, README, run-
     submission.sh, verify_ct.go) + ct/jasmin-ct-libjade.md
  1 .github/workflows/ci.yml
  1 test/interoperability/n1_class_test.go (19/19 N1 subtests)
  1 bench/results/REPORT.md
  11 scripts/ (cut-submission, check-high-assurance, check-lean-
     bridge, nightly, extract-jasmin-ec, checks/{ec-admits, ec-
     compile, ec-refinement-scaffold, ec-regressions, extraction,
     jasmin}, checks/test/{go-unit, interop, kat, no-secret-logs})

Files merged (16 overlapping, mptc-canonical chosen because newer +
post-rewire-correct; pulsar versions still bore stale "Pulsar-M" /
"pulsarm" branding):
  README.md, BLOCKERS.md, CONTRIBUTING.md, LICENSE, LICENSING.md,
  SECURITY.md, .gitignore, bench/run_all.sh, vectors/dkg.json (v1.0.7
  regen), scripts/{bench,build,gen_vectors,sbom,test}.sh,
  spec/{pulsar,parameters,system-model}.tex,
  CRYPTOGRAPHER-SIGN-OFF.md (path refs).

Pulsar-only spec supplements preserved:
  spec/{blockers,design-decisions,family-architecture,nist-mptc-
  category,patent-notes,threat-model}.tex.

Path rewrites applied: 158 occurrences across 26 files
  github.com/luxfi/pulsar-mptc -> github.com/luxfi/pulsar
  ~/work/lux/pulsar-mptc/      -> ~/work/lux/pulsar/
  luxfi/pulsar-mptc            -> luxfi/pulsar
  pulsar-mptc/                  -> ./

Narrative collapses (no more two-repo framing):
  SUBMISSION.md "At a glance" — single Repository row
  SYNC-STATUS.md — rewritten to single-repo state
  SINGLE-IMPL-PLAN.md — marked COMPLETED 2026-05-18
  HANZO-CRYPTO-SUITE.md — tier 1 row = single canonical home
  scripts/cut-submission.sh — replace/vendor dance removed; cuts
  directly from in-tree canonical sources

go.mod: dropped mptc's replace directive (no longer needed since this
IS the canonical pulsar repo). Module path is github.com/luxfi/pulsar.
Deps: cloudflare/circl v1.6.3, golang.org/x/crypto v0.32.0.

Verification:
  GOWORK=off go build ./...              PASS
  GOWORK=off go test -count=1 ./...      PASS (1.4s)
  GOWORK=off go test -race ./ref/...     PASS (14.7s)
  go test ./test/interoperability/       PASS (19/19 N1 subtests)
  scripts/check-high-assurance.sh        PASS
  scripts/check-lean-bridge.sh           PASS (5/5 bridges)
  scripts/gen_vectors.sh                 byte-identical replay
  scripts/cut-submission.sh --help       PASS
2026-05-18 19:53:08 -07:00
zeekay cb9fc02ca6 sign-off: cryptographer review of v1.0.7 — APPROVED WITH GATES
Independent review of luxfi/pulsar v1.0.7 (commit a2a4599) for both
live Lux Quasar consensus and the NIST MPTC v0.1 submission.

Approved with four disclosure / pre-publish gates:
  GATE-1  operator runbook discloses v0.1 reconstruction-aggregator trust model
  GATE-2  SUBMISSION.md cross-links the protocol-variant disclosure
  GATE-3  dudect runs to documented sample target (current results preliminary)
  GATE-4  minor doc updates (coverage %, spec text Ed25519 -> ML-DSA-65, etc.)

All gates are about documentation honesty or evidence-file completion;
none require algorithm or code changes. With those closed, the package
is fit to ship.

Construction is sound, identity-stage closure of CR-6/7/8 is uniform
across small and large committee paths, race-clean tests pass, KAT
vectors are deterministic, zeroization is in place, and the proof-
artifact gates (EasyCrypt admit budget 0/0, Lean<->EC bridge 5/5) are
green. Coverage measured at 84.2%.
2026-05-18 18:51:36 -07:00
zeekay bec7cab551 ref: close CR-6/7/8 on large-committee path — uniform identity stage
Port the small-committee (GF(257)) identity stage to the large-
committee (GF(q)) path so the entire library is uniform. After this
work, legacyDeriveMACKeyLarge is gone and the wire-format / sealing
primitives are shared across both paths.

  - identity.go: sealEnvelope / sealOpenEnvelope are now width-agnostic
    over the inner shareWire slice (64 bytes GF(257), 128 bytes GF(q)).
    The envelope key derivation, KEM ciphertext, KMAC256 auth tag and
    cSHAKE256 stream cipher are reused as-is.
  - large_types.go: drop LargeDKGShareEnvelope (use canonical
    DKGShareEnvelope); drop the vestigial Commits field on
    LargeDKGRound1Msg (CR-6 path A; binding comes from Round-2 digest).
  - large_dkg.go: NewLargeDKGSession takes (myIdentity, directory);
    Round1 KEM-wraps envelopes via sealEnvelope; Round3 opens them and
    derives the master seed from per-envelope contributions over GF(q)
    (no longer needs Lagrange interpolation of other recipients'
    envelopes).
  - large_threshold.go: NewLargeThresholdSigner takes sessionKeys;
    MAC keys are built from per-pair ephemeral session keys (CR-7).
    legacyDeriveMACKeyLarge deleted.
  - large_reshare.go: NewLargeReshareSession takes
    (myIdentity, newDirectory); Round1 KEM-wraps envelopes; Round3
    opens them; SetPriorGroupPubkey ported for new-committee joiners.

Tests updated to use the identityFixture pattern; large + small +
identity test suites all green, no race warnings, no KAT drift on
the small path (KAT vectors only fixate FIPS 204 sign/verify; the
wire envelope shape was already KEM-wrapped on the small path post-
merge).
2026-05-18 18:34:39 -07:00
zeekay 881c4e82d8 ref: merge pulsar-mptc submission-grade impl into canonical pulsar
Collapse the two parallel implementation trees (pulsar/ref/go/pkg/pulsar
and pulsar-mptc/ref/go/pkg/pulsar) per SINGLE-IMPL-PLAN.md by porting
the mptc submission-grade additions into the canonical pulsar tree.

New files (mptc-only, adopted verbatim):
  - identity.go / identity_test.go: long-term ML-KEM-768 + ML-DSA-65
    keypair, EstablishSession / DeriveSessionKey ephemeral key
    agreement, sealEnvelope / sealOpenEnvelope KEM-wrapped DKG
    envelope (BLOCKERS.md CR-6 / CR-7 / CR-8 closure)
  - n1_byte_equality_test.go: differential test asserting threshold
    Combine output is byte-identical to centralized FIPS 204 Sign
    under the reconstructed key — Class N1 manifesto headline
  - fuzz_test.go: go-test fuzz harness for AbortEvidence parsing,
    verify code paths, share parsing, params parsing
  - zeroize.go: best-effort secret-buffer wipe helpers

Adopted from mptc (security-grade superset; pulsar v0.1 fully
contained within):
  - abort.go / abort_test.go: identifiable-abort evidence parsing
    + per-kind structural validation + pluggable signature verifier
  - dkg.go / dkg_test.go: KEM-wrapped envelope DKG; NewDKGSession
    signature gains (myIdentity, directory) per CR-8
  - reshare.go / reshare_test.go: matching KEM-wrapped reshare;
    NewReshareSession signature gains (myIdentity, newDirectory)
  - threshold.go / threshold_test.go: ephemeral session-keyed MACs;
    NewThresholdSigner signature gains sessionKeys per CR-7;
    TestThresholdSwap_RejectedByCommitBind defense-in-depth proof
  - transcript.go: tagSignMask per-attempt mask derivation tag (H2);
    tagSignR2 commented out as RESERVED so a rebase can't silently
    reuse the name
  - shamir.go: DEPRECATED comment on byte-path shamirReconstruct;
    distribution-honesty comment on shamirEvalPoint
  - bench_test.go / kat_test.go: updated to new signatures
  - cmd/genkat/main.go: makeKATIdentities + makeKATSessionKeys for
    KAT regeneration under the new identity-based protocol

Reconciled (mptc base + pulsar preservation):
  - types.go: adopt mptc's KEM-wrapped DKGShareEnvelope (KEMCiphertext
    + Sealed fields, replacing v0.1 Share + Blind plaintext) and
    ephemeral MAC key comments, PRESERVING pulsar's Field type +
    FieldDefault / FieldGF257 / FieldGFq constants + String() +
    resolveField() helper for large-committee scalability

Preserved (pulsar-only, untouched):
  - large_dkg.go / large_threshold.go / large_reshare.go / large_types.go
    / large_e2e_test.go: GF(q) wide-committee parallel implementation
  - shamir_gfq.go / shamir_gfq_test.go: generic-field Shamir
  - largeshamir.go / largeshamir_test.go: large-committee Shamir
  - round.go / round_test.go: RoundContext / RoundSigner abstraction
    (tests updated to new identity-based threshold signer signature)
  - verify_batch.go / verify_batch_test.go: parallel batch verify
  - precompile_e2e_test.go: EVM precompile end-to-end (updated for
    new identity-based signer signature)
  - params.go: TargetCommitteeSize = 1_111_111 constant (unchanged)

Localised legacy compat:
  - large_threshold.go: legacyDeriveMACKeyLarge renamed from the
    removed package-level deriveMACKey; clearly tagged as v0.1
    pending a parallel large-committee identity layer

Build: GOWORK=off go build ./... clean
Tests: GOWORK=off go test ./... pass (119/119, including fuzz seeds
       for AbortEvidence / VerifySignature / VerifyCtx / ShareFromBytes
       / ParamsFor / N1_ByteEquality_Differential)
Race:  -race clean
2026-05-18 17:38:43 -07:00
zeekay b28f2b97d1 pulsarm → pulsar: drop the -M qualifier (suffix is redundant)
The "m" suffix originally stood for "Pulsar Module-LWE" to distinguish
it from the older Pulsar that was R-LWE (before Corona took over R-LWE
exclusively). With the rename complete — Corona owns Ring-LWE,
Pulsar owns Module-LWE — the suffix is dead naming overhead.

Renames:
  Directory:  ref/go/pkg/pulsarm/        → ref/go/pkg/pulsar/
  Package:    package pulsarm            → package pulsar
  Import:     .../ref/go/pkg/pulsarm     → .../ref/go/pkg/pulsar
  Type:       SigSchemePulsarM65 (etc.)  → SigSchemePulsar65
  Error tag:  "pulsarm: ..."             → "pulsar: ..."
  File:       pulsarm_test.go            → pulsar_test.go

38 files renamed in-place via git mv. Build + tests PASS (89 PASS
sub-tests, 0 FAIL; full pulsar suite in 0.473s).
2026-05-16 17:55:04 -07:00
zeekay 060903abd4 pulsarm: add parallel VerifyBatch — N-signature throughput for consensus
Single Verify is the only place this package touches FIPS 204
verification (Class N1 manifesto). VerifyBatch composes it across N
(groupPubkey, message, signature) tuples in parallel via a
GOMAXPROCS-bounded worker pool — no extra FIPS 204 surface.

Public surface added:
  - VerifyBatch(params, gpks, msgs, sigs) -> ([]error, error)
  - VerifyBatchCtx(params, gpks, msgs, ctx, sigs) -> ([]error, error)
  - VerifyBatchAll(params, gpks, msgs, sigs) -> (bool, error)
  - ErrBatchSizeMismatch

Pure Go: NO CGO / accel dep. The GPU fast-path
(accel.LatticeOps.DilithiumVerifyBatch) belongs at the engine layer
where the host's native libs are owned; this file is the portable
path everyone gets for free.

Tests (GOWORK=off go test ./pkg/pulsarm/ -run TestVerifyBatch):
  TestVerifyBatch_AllValid_MultiMode  (ModeP44, P65, P87 × n=8)  PASS
  TestVerifyBatch_OneCorrupt          (single sig byte-flip)     PASS
  TestVerifyBatch_StructuralMismatch  (slice len mismatch)       PASS
  TestVerifyBatch_Empty                                          PASS
Full suite: ok 0.409s.
2026-05-16 17:55:04 -07:00
zeekayandGitHub 4ca9811260 Merge pull request #1 from luxfi/licensing/canonical-pointer
docs: add LICENSING.md pointer to canonical Lux IP strategy
2026-05-15 16:43:37 -07:00
zeekay 9c04a52fee docs: add LICENSING.md pointing at canonical Lux IP strategy
Single LICENSING.md file referencing the canonical three-tier IP and
licensing strategy at github.com/luxfi/.github/blob/main/profile/README.md.

LICENSE file is unchanged; this only adds a navigational pointer.
2026-05-15 16:43:29 -07:00
zeekay d7dc75411e pulsar: drop -M qualifier everywhere — Pulsar (M-LWE) is the family name
Symmetric with Corona's parallel rename (PULSAR-* -> CORONA-* in
luxfi/corona). The -M was the M-LWE qualifier from when Pulsar-M and
Pulsar-R were sibling constructions; Pulsar-R shipped as Corona, so
the -M qualifier is dead weight across the family.

Changes:
  - spec/pulsar.tex: prose + tag strings PULSAR-M-* -> PULSAR-*
  - ref/go: all "Pulsar-M" string literals -> "Pulsar" in mode names,
    KAT message prefixes, and beacon strings (PULSAR-M-RESHARE-BEACON
    -> PULSAR-RESHARE-BEACON, etc.)
  - vectors/{sign,keygen,verify,threshold-sign,dkg}.json: regenerated
    from genkat with new mode strings

Preserved (different scope):
  - Go package directory name `pkg/pulsarm/` (renaming the dir is a
    Go module break for any importer; punted to a separate cleanup)
  - luxcpp/crypto/pulsar/ path references in comments (separate repo)

All 9 test packages pass: pulsarm (KAT replay, large e2e, reshare,
shamir, types) + the rest.
2026-05-13 14:21:45 -07:00
zeekay ea0d8cb32c pulsar: rename Pulsar-M -> Pulsar in prose, keep wire-format strings intact
The 'Pulsar-M' qualifier was meant to distinguish M-LWE Pulsar from a
planned R-LWE 'Pulsar-R'. R-LWE shipped as Corona instead, so the -M
qualifier is dead weight. The pq.tex profile table already says
'Pulsar-65 (was Pulsar-M-65)' — this aligns the spec.

What's preserved (wire format / crypto compat):
  - cSHAKE personalisation string 'Pulsar-M' on lines 459/600/720/733/867
  - All PULSAR-M-*-V1 domain-separation tags (DKG-COMMIT, SIGN-R1, etc.)

What changed (prose only):
  - Title, abstract, body references to the protocol
  - Filename pulsar-m.tex -> pulsar.tex
  - PDF pulsar-m.pdf -> pulsar.pdf

Pre-existing 'Paragraph ended before end' warning on line 76 is unchanged
and unrelated; PDF still builds (48 pages, 608 KB).
2026-05-13 13:40:52 -07:00
zeekay 1c2a9ee1af pulsar: add \GF macro, rename corona2024->boschini2024corona, bump Go to 1.26.3
- spec/pulsar-m.tex: define \newcommand{\GF}{\mathrm{GF}} so any later
    GF(q)/GF(2^k) usage doesn't trip an undefined control sequence.
  - spec/references.bib: rename the Corona bibtex key from corona2024
    to boschini2024corona — matches the catalogue-wide Corona->Corona
    rename (Corona is the production name).
  - go.mod: go directive 1.22.0 -> 1.26.3 (matches the rest of the stack).
2026-05-13 12:46:07 -07:00
zeekay a9ee92761a pulsar: kill all Corona mentions in spec, family-architecture, LLM.md
Spec citations now use \cite{boschini2024corona}. The family
architecture text describes Corona as Lux's production R-LWE library
(formerly the upstream that the academic R-LWE construction descends
from); the academic line is referenced by author + ePrint number only.

The historical academic R-LWE fork at luxfi/nasua remains unlinked
from this repo's docs per directive.
2026-05-12 10:07:49 -07:00
zeekayandGitHub 8eae404801 Update README.md 2026-05-12 09:21:09 -07:00
zeekay 44238c4738 README: drop hyperlink to nasua academic fork 2026-05-12 09:12:23 -07:00
zeekay 6b21b2da95 README: independent library + Double-Lattice composition with corona
Pulsar (Module-LWE) and Corona (Ring-LWE) are independently usable
threshold ML-DSA libraries — no shared types, no import line between
them. Each can be selected as a chain's sole PQ threshold layer.

Lux primary-network QuasarCert layers both as a Double-Lattice PQ
defence (Module + Ring), with optional BLS classical fast-path and
per-validator ML-DSA-65 rolled up via STARK/FRI through P3Q. Each
layer is checkable independently; a break in one lattice family does
not break finality.

The academic Corona upstream is referenced as luxfi/nasua (historical
reference fork, trusted-dealer DKG, not for public-chain use).
2026-05-12 09:08:46 -07:00
zeekay 3e2ed37580 BLOCKERS.md replaces known-limitations — red audit findings
13 production-go-live blockers from 4-red-agent + 1-scientist
adversarial audit (2026-05). The prior known-limitations framing
was too lenient; canonical bug list now at BLOCKERS.md.

The full per-finding spec (file:line refs, attack models, fix
sketches) lives at the submission mirror:
github.com/luxfi/pulsar-mptc/blob/main/BLOCKERS.md

This pulsar library remains shippable as research/reference (89.7%
coverage, Lean OutputInterchange+Unforgeability+Shamir zero-sorry,
KAT replay green). Production strict-PQ go-live is blocked on
closing CR-1 through CR-13.
2026-05-11 22:44:59 -07:00
zeekay d0d51198e2 pulsar: README — Module-LWE identity; v0.1.x R-LWE legacy retired
The legacy v0.1.0..v0.1.5 tags pointed at the prior Ring-LWE code line
and have been deleted from this repository to prevent
`go get github.com/luxfi/[email protected]` from silently pulling R-LWE
code under the new Module-LWE identity.

Ring-LWE code lives at github.com/luxfi/corona (inherits v0.1.x
history under its proper name). This repository is Module-LWE only,
starting at v1.0.0.
2026-05-11 19:36:58 -07:00
zeekay 6e93847ab2 pulsar: rename module path github.com/luxfi/pulsar-m → github.com/luxfi/pulsar
The Module-LWE threshold ML-DSA library claims its canonical name.
The legacy 'pulsar-m' suffix existed only because the Ring-LWE
library held the 'github.com/luxfi/pulsar' import path. That R-LWE
code has now moved to github.com/luxfi/corona; this library is the
sole Pulsar going forward.

NIST MPTC Class N1: byte-equal output to single-party FIPS 204
ML-DSA. Round-1 commit + Round-2 response + Combine produces a
signature that verifies under unmodified mldsa.Verify.

All tests pass under GOWORK=off.
2026-05-11 19:18:41 -07:00
zeekay ec32df305d pulsar/spec: family-architecture — Annulus is archived (was Nasua), production = Pulsar + Corona
Annulus is the academic-only, research-frozen root. The repo was
originally named Nasua and renamed to Annulus at the archive cut.
Production-enabled variants are Pulsar (M-LWE / FIPS 204) and
Corona (R-LWE production fork), both descending from Annulus.
2026-05-11 15:30:10 -07:00
zeekay 1b17935bc6 pulsar: simplify wire-format tags — drop redundant -M and LUXROUND
Hard fork of all customization tags. Per the family rename
(Pulsar-M → Pulsar), the -M suffix is now redundant. Per the
compound-word discipline, LUXROUND braids brand+concept and is
replaced by ROUND.

  PULSAR-M-DKG-COMMIT-V1       → PULSAR-DKG-COMMIT-V1
  PULSAR-M-DKG-TRANSCRIPT-V1   → PULSAR-DKG-TRANSCRIPT-V1
  PULSAR-M-DKG-DEALER-V1       → PULSAR-DKG-DEALER-V1
  PULSAR-M-DKG-BLINDMASK-V1    → PULSAR-DKG-BLINDMASK-V1
  PULSAR-M-COMMITTEE-V1        → PULSAR-COMMITTEE-V1
  PULSAR-M-SIGN-{R1,R2,...}-V1 → PULSAR-SIGN-{R1,R2,...}-V1
  PULSAR-M-RESHARE-*-V1        → PULSAR-RESHARE-*-V1
  PULSAR-M-EXPANDB-V1          → PULSAR-EXPANDB-V1
  PULSAR-M-COMPLAINT-V1        → PULSAR-COMPLAINT-V1
  PULSAR-M-SEED-SHARE-V1       → PULSAR-SEED-SHARE-V1
  PULSAR-M-LUXROUND-COMMITTEE-V1 → PULSAR-ROUND-COMMITTEE-V1
  cSHAKE function-name "Pulsar-M" → "Pulsar"

Every prior signature with -M tags is invalidated. KAT vectors
need regeneration. Test suite passes (85 tests, 0.530s).
2026-05-11 15:28:15 -07:00
zeekay 19ae5179d2 pulsar/spec: family-architecture — drop Annulus current usage, reserve for future 2026-05-11 15:16:01 -07:00
zeekay c4a19b71c0 pulsar/spec: enshrine Lux Quasar family in family-architecture.tex
Family table now lists three variants under the Lux Quasar family
umbrella:
  - Pulsar  (Module-LWE / FIPS 204, production-enabled)
  - Corona  (Ring-LWE, Lux production fork, production-enabled)
  - Annulus (Ring-LWE, academic root, code-name Nasua, not enabled)

Annulus is the academic-only research artifact tracking the
Corona upstream primitive (Boschini et al.) which itself builds
on the Raccoon FS-without-rejection template (del Pino et al.).
The implementation repo is github.com/luxfi/nasua.

Naming discipline now stellar/circular: Pulsar (rotating neutron
star), Corona (ring of light), Annulus (ring-shaped region). The
academic upstream's BLAKE3 hash profile is acknowledged but not
deployed; both Corona and Pulsar run on SHA-3 / SP 800-185.
2026-05-11 15:12:00 -07:00
zeekay 0df99b7364 pulsar: README — drop -M suffix (family rename) 2026-05-11 15:05:58 -07:00
zeekay 604a32a47d pulsar-m: drop unnecessary Lux prefix from round identifiers
LuxRoundContext / LuxRoundSessionID / LuxRoundCommitteeRoot /
LuxRoundSigShare / LuxRoundQuorumPolicy / DefaultLuxRoundQuorumPolicy
→ RoundContext / RoundSessionID / RoundCommitteeRoot / RoundSigShare /
RoundQuorumPolicy / DefaultRoundQuorumPolicy.

Files: luxround.go luxround_math.go luxround_test.go → round.go
round_test.go (math helpers folded into round.go). The protocol name
"Lux round" stays in prose / spec / paper titles -- only the Go
identifiers drop the brand prefix. The cSHAKE customization tag
PULSAR-M-LUXROUND-COMMITTEE-V1 is wire-format-stable and stays.
2026-05-11 13:42:08 -07:00
zeekay 52eea92a11 pulsar-m: convert NIST MPTC deliverables docs/*.md → spec/*.tex (CLAUDE.md LaTeX-only rule)
Per ~/.claude/CLAUDE.md ("papers/proofs/audits stay in LaTeX, never .md"
+ "NEVER write random summary files"), the six NIST MPTC submission
deliverables move from docs/ Markdown into spec/ LaTeX as
\input{...} chapters of pulsar-m.tex:

  docs/nist-mptc-category.md   -> spec/nist-mptc-category.tex
  docs/patent-notes-draft.md   -> spec/patent-notes.tex
  docs/threat-model.md         -> spec/threat-model.tex
  docs/known-limitations.md    -> spec/known-limitations.tex
  docs/family-architecture.md  -> spec/family-architecture.tex
  docs/design-decisions.md     -> spec/design-decisions.tex

Content preserved verbatim; only LaTeX-syntax stylistic edits.
pulsar-m.tex now \inputs each as its own section / appendix.
Go-source comments that referenced docs/* updated to spec/*.tex.
README + CONTRIBUTING refreshed.

GOWORK=off go test -count=1 ./... clean.
2026-05-11 12:31:43 -07:00
zeekay 38319c9fc8 pulsar-m: LLM.md — module-pin reconciliation plan (HIGH-4 prep) 2026-05-11 12:25:34 -07:00
zeekay 7e7d0d7cf2 pulsar-m: end-to-end test threshold Combine → FIPS 204 verify with precompile ctx (CRIT-2 closure)
CRIT-2: the Class N1 manifesto claim that a Pulsar threshold
Combine output verifies as a single-party FIPS 204 ML-DSA
signature under the EVM precompile ctx
(`lux-evm-precompile-pulsar-v1`) had no end-to-end test. Every
prior Combine call site passed ctx=nil, so the ctx-propagation
guarantee Combine -> mldsaSign -> circl SignTo was never
exercised against the production precompile string.

New test file precompile_e2e_test.go covers both Combine paths:

  - TestPrecompile_E2E_Combine_FIPS204_VerifyCtx exercises the
    GF(257) path at (T,N)=(3,2) for ModeP65.
  - TestPrecompile_E2E_LargeCombine_FIPS204_VerifyCtx exercises
    the GF(q) path at (T,N)=(3,2) for ModeP65.

Each test:
  1. Runs DKG to install a group public key.
  2. Drives ThresholdSigner / LargeThresholdSigner Round1+Round2
     on a message M.
  3. Calls Combine / LargeCombine with ctx=precompileCtx,
     randomized=false to produce the threshold signature.
  4. Asserts that BOTH
       (a) raw FIPS 204 cloudflare/circl mldsa65.Verify(pk, M,
           ctx=precompileCtx, sig), and
       (b) pulsarm.VerifyCtx(params, pk, M, ctx=precompileCtx,
           sig)
     accept the signature. This is the empirical Class N1
     closure for the precompile ctx.
  5. Negative control: the same signature must NOT verify under
     ctx=nil, proving ctx is actually load-bearing in the
     Combine output.

No ctx-propagation fix was required: threshold.go Combine and
large_threshold.go LargeCombine already forward ctx to
mldsaSign, which forwards to mldsa{44,65,87}.SignTo. The tests
verify this end-to-end.
2026-05-11 12:03:14 -07:00
zeekay 7acc764a4a pulsar-m: GF(q) Large* stack + luxround helpers + family rename docs
Adds the M-LWE large-committee track and metastable signing helpers,
plus the consolidated migration plan for the Pulsar/Corona/Corona/
Quasar rebrand:

- GF(q) byte-wise Shamir secret sharing (shamir_gfq.go) for committees
  beyond 256 parties, with q = 8,380,416 (ML-DSA q) and 128-byte wire
  share format.
- Large* protocol stack (large_types, large_dkg, large_threshold,
  large_reshare, largeshamir) targeting TargetCommitteeSize = 1,111,111
  with end-to-end tests at (3,2), (3,3), (5,3), (6,4).
- Wave-driven metastable signing helpers (luxround.go, luxround_math.go)
  with beta-round end-to-end coverage.
- Spec updates: parameters.tex, pulsar-m.tex, system-model.tex —
  large-committees section, security games, Lux-round composition.
- LLM.md: consolidates MIGRATION.md (deleted) into a single source of
  truth per CLAUDE.md repository rules. Family migration plan,
  destructive-action checklist, cleanliness audit.
- docs/family-architecture.md: scrub dated header.
- docs/known-limitations.md: track MPTC deadlines.

Tests: GOWORK=off go test -count=1 ./... is green.
2026-05-11 11:46:21 -07:00
zeekay fb4f37d989 pulsar-m: NIST MPTC submission readiness — benchmarks + CI gates
Final v0.1 polish:

  bench_test.go — reproducible benchmark harness covering KeyGen,
                   Sign, Verify across all three FIPS 204 parameter
                   sets, plus DKG, ThresholdSign, and Reshare at
                   representative committee sizes for ML-DSA-65.

The benchmark harness drives scripts/bench.sh; results land in
bench/results/{fingerprint.txt,go-bench.txt}. Apple M1 Max baseline
(Go 1.26.2, -benchtime=2s -count=3):

  KeyGen     P44  ~ 0.3 ms,  P65  ~ 0.5 ms,  P87  ~ 0.7 ms
  Sign       P44  ~ 1.6 ms,  P65  ~ 2.5 ms,  P87  ~ 3.0 ms
  Verify     P44  ~ 0.3 ms,  P65  ~ 0.5 ms,  P87  ~ 0.7 ms
  DKG        (5,3) ~ 3.5 ms,  (7,4) ~ 7 ms,   (10,7) ~ 12 ms
  Threshold  (5,3) ~ 2.2 ms,  (7,4) ~ 4.5 ms, (10,7) ~ 7 ms
  Reshare    (5→5,t=3) ~ 0.5 ms

The threshold path is dominated by FIPS 204 Sign latency for small
quorums; at (n=10, t=7) the 2-round overhead becomes comparable to
the FIPS 204 cost.

This commit closes the v0.1 reference impl gates:
  - scripts/build.sh   passes
  - scripts/test.sh    passes (61 tests, race-clean)
  - scripts/gen_vectors.sh passes; KATs deterministic
  - scripts/bench.sh   passes
  - Class N1 interchangeability demonstrated by every threshold KAT
    in vectors/threshold-sign.json passing under pulsarm.Verify
    (i.e. under unmodified mldsa{44,65,87}.Verify)

docs/known-limitations.md updated to reflect v0.1 reality: the
reconstruction-aggregator path ships in v0.1; the Lagrange-linearity
sign and R_q^k Pedersen are documented v0.2 paths.

Signed-off-by: Lux Industries <[email protected]>
2026-05-10 20:26:56 -07:00
zeekay 1793dd64ac pulsar-m: KAT vectors for keygen / sign / verify / threshold / dkg
Canonical Known Answer Tests for the Pulsar-M v0.1 reference,
generated by ref/go/cmd/genkat. Re-running scripts/gen_vectors.sh on
a clean checkout reproduces these files byte-identically — the
deterministic-fixture gate.

Coverage:

  vectors/keygen.json        — 9 KATs (3 seeds × 3 modes)
                                 seed → (public_key, private_key)
  vectors/sign.json          — 9 KATs (3 messages × 3 modes)
                                 (seed, message) → signature
  vectors/verify.json        — 6 KATs (3 positive + 3 negative)
                                 (pubkey, message, signature, valid)
  vectors/threshold-sign.json — 4 KATs at (n,t) ∈ {(3,2),(5,3),
                                 (7,4),(10,7)} for Pulsar-M-65;
                                 every signature passes
                                 mldsa65.Verify (Class N1 demo)
  vectors/dkg.json           — 3 KATs at (3,2), (5,3), (7,4) for
                                 Pulsar-M-65; per-party shares and
                                 transcript hash committed

The replay harness in kat_test.go reads each JSON at test time and
verifies the round-trip:

  - Keygen replay: KeyFromSeed(seed) reproduces (pk, sk)
  - Sign replay:   Sign(deterministic) reproduces signature
  - Verify replay: pulsarm.Verify accepts every positive case and
                   rejects every negative case
  - Threshold:     every committed signature passes pulsarm.Verify
                   (which dispatches to FIPS 204 ML-DSA.Verify
                   verbatim — the load-bearing Class N1 property)
  - DKG:           wire-format invariants (sizes match parameter
                   set, transcript hash is 48 bytes, share count
                   matches committee count)

scripts/gen_vectors.sh + scripts/test.sh are now functional CI
gates.

Signed-off-by: Lux Industries <[email protected]>
2026-05-10 20:26:37 -07:00