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
2026-05-12 09:21:09 -07:00

Pulsar

Threshold ML-DSA — a 2-round threshold signing and DKG system whose generated signatures are verifiable by unmodified FIPS 204 ML-DSA verification. Targeting NIST MPTC Class N1 (signing) + N4 (ML keygen / DKG).

Pulsar is the Lux Module-LWE post-quantum threshold signature library. Its 2-round threshold protocol structure operates on ML-DSA-65's polynomial- vector-over-R_q algebra so the per-party-aggregated signature is bit- identical to a single-party FIPS 204 signature on the same message + public key. The Ring-LWE sibling library is luxfi/corona.

Quasar composition

Both libraries are independently complete; luxfi/consensus/protocol/quasar consumes them as parallel kernels selected per-chain via FinalitySchemeID.

Status: Research / Reference (not production hardened, not FIPS validated). NIST-profile vectors use SHAKE / cSHAKE / KMAC. Any BLAKE3 deltas are experimental and out-of-scope for the MPTC submission.

Why

NIST FIPS 204 (ML-DSA) is the only NIST-approved post-quantum digital signature in 2026. Threshold variants of ML-DSA are not yet standardized — NIST's Multi-Party Threshold Cryptography project is collecting them now (IR 8214C, January 2026; first call package deadline expected 2026-Nov-16).

Pulsar aims to enter that process with a credible, output-interchangeable threshold ML-DSA candidate — built from the production-tested protocol machinery shipping in luxfi/corona (Ring-LWE), retargeted to the Module-LWE primitives ML-DSA itself uses.

The win, if Pulsar's Sign output is byte-equal to FIPS 204 Sign:

  • Threshold-produced signatures verify under unmodified FIPS 204 verifiers.
  • Existing FIPS-validated ML-DSA modules (BoringSSL FIPS, AWS-LC, OpenSSL 3.0 PQ provider) consume Pulsar certs without code changes.
  • The threshold layer can be Class-N-claimed at NIST without a parallel algorithm standardization track.

Repository layout

pulsar/
├── docs/                     human-readable design notes
│   ├── threat-model.md
│   ├── nist-mptc-category.md
│   ├── design-decisions.md
│   ├── BLOCKERS.md
│   └── patent-notes-draft.md
├── spec/                     LaTeX technical specification (MPTC package)
│   ├── pulsar.tex          main spec
│   ├── security-games.tex    EUF-CMA / TS-UF / robustness / adaptive corr.
│   ├── system-model.tex      network / setup / abort / preprocessing
│   ├── parameters.tex        concrete parameter sets, lattice-estimator
│   └── references.bib
├── ref/
│   ├── go/                   reference implementation (Go, no assembly)
│   │   ├── cmd/              CLI entry points
│   │   ├── internal/         private helpers
│   │   └── pkg/              public API (sign/, dkg/, primitives/, hash/, fmt/)
│   └── c/                    conformance implementation (post-encoding-freeze)
├── vectors/                  Known Answer Tests (KATs)
│   ├── kat-v1.json           input/output vectors per MPTC §IO-Testing
│   ├── kat-v1.rsp            CAVS-style response file (compatibility)
│   └── transcripts/          full-protocol KATs (n,t sweeps)
├── bench/                    reproducible benchmark harness
├── test/                     fuzz / negative / interoperability tests
├── ct/dudect/                constant-time analysis harness
├── estimator/                lattice-estimator parameter scripts
├── scripts/                  build.sh / test.sh / bench.sh / gen_vectors.sh / sbom.sh
└── go.mod

Quickstart

Pulsar is in pre-spec stage. Reference impl, vectors, and bench harness ship after the spec freezes. Track BLOCKERS.md for what's stable vs in-flight.

git clone https://github.com/luxfi/pulsar
cd pulsar
./scripts/build.sh       # checks spec compile + Go build
./scripts/test.sh        # runs unit + KAT suite (when available)
./scripts/bench.sh       # reproduces bench/results/ (when available)
./scripts/gen_vectors.sh # regenerates KATs from reference impl (when available)

NIST MPTC submission

package element location status
Technical Specification spec/pulsar.pdf (built from spec/pulsar.tex) draft
Reference Implementation ref/go/ skeleton
Report on Experimental Evaluation bench/results/REPORT.md TBD
Notes on Patent Claims spec/patent-notes.tex TBD
Open-source license LICENSE (Apache-2.0) ✓
Build/test/benchmark scripts scripts/ skeleton
I/O test vectors vectors/kat-v1.{json,rsp} TBD

Target dates:

  • 2026-Jul-20 preview writeup (NIST third preview deadline)
  • 2026-Nov-16 package submission (NIST first call deadline)

Relationship to upstream and siblings

Pulsar is independent of its sibling and academic predecessor — no import line, no shared types. The relationship table is provenance, not dependency.

repo role lattice basis hash family status
luxfi/corona production R-LWE threshold ML-DSA — Pedersen DKG over R_q + proactive resharing Ring-LWE (R_q) SHA-3 / cSHAKE256 (SP 800-185) production library
luxfi/pulsar (this repo) production Module-LWE threshold ML-DSA; output byte-equal to FIPS 204 ML-DSA Module-LWE (R_q^k) SHA-3 / cSHAKE256 (SP 800-185) production library
luxfi/pulsar-mptc NIST MPTC submission package (frozen artifact for review) Module-LWE (R_q^k) SHA-3 / SHAKE256 (NIST profile) active submission package

Composition with Corona as optional layered PQ defense

Pulsar and Corona are independently usable: a chain can pick either as its sole PQ threshold layer, no cross-dependency. Lux primary-network QuasarCert combines them as a Double Lattice layered defence — Module-LWE plus Ring-LWE — so a break in one lattice family does not break finality:

QuasarCert {
    BLS         — optional classical fast-path (BLS-12-381 aggregate)
    Corona      — Ring-LWE threshold ML-DSA   (luxfi/corona)
    Pulsar      — Module-LWE threshold ML-DSA (this repo)
    MLDSARollup — per-validator ML-DSA-65 rolled up via STARK/FRI (P3Q)
}

Each layer is checkable independently with no shared code; selecting the layer happens at chain-construction time via the FinalitySchemeID axis on the chain's ChainSecurityProfile. The pure-PQ profile drops BLS entirely and runs on Corona + Pulsar.

Security

SECURITY.md describes how to disclose vulnerabilities and what's in-scope for bug bounty.

License

Apache-2.0 — same as luxfi/corona. See LICENSE.

S
Description
Pulsar — lattice threshold signatures with dynamic resharing for Lux Quasar consensus
Readme
16 MiB
Languages
Go 65.2%
eC 20%
TeX 9.8%
Shell 3.9%
C 0.9%
Other 0.2%