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
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.