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.
Pulsar-M
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-M is the Module-LWE sibling of Pulsar
(Ring-LWE). Pulsar's 2-round threshold protocol structure is transplanted onto
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.
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-M aims to enter that process with a credible, output-interchangeable
threshold ML-DSA candidate — built from the production-tested protocol
machinery already shipping in luxfi/pulsar (R-LWE), retargeted to the
M-LWE primitives ML-DSA itself uses.
The win, if Pulsar-M'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-M certs without code changes.
- The threshold layer can be Class-N-claimed at NIST without a parallel algorithm standardization track.
Repository layout
pulsar-m/
├── docs/ human-readable design notes
│ ├── threat-model.md
│ ├── nist-mptc-category.md
│ ├── design-decisions.md
│ ├── known-limitations.md
│ └── patent-notes-draft.md
├── spec/ LaTeX technical specification (MPTC package)
│ ├── pulsar-m.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-M is in pre-spec stage. Reference impl, vectors, and bench harness ship after the spec freezes. Track docs/known-limitations.md for what's stable vs in-flight.
git clone https://github.com/luxfi/pulsar-m
cd pulsar-m
./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-m.pdf (built from spec/pulsar-m.tex) |
draft |
| Reference Implementation | ref/go/ |
skeleton |
| Report on Experimental Evaluation | bench/results/REPORT.md |
TBD |
| Notes on Patent Claims | docs/patent-notes-draft.md |
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
| repo | what | hash family |
|---|---|---|
| luxfi/corona | academic R-LWE 2-round threshold sig (Boschini–Kaviani–Lai–Malavolta–Takahashi–Tibouchi, ePrint 2024/1113) | BLAKE3 |
| luxfi/pulsar | production fork of Corona with Pedersen DKG + proactive resharing | SHA-3 / cSHAKE256 (canonical), BLAKE3 (legacy) |
| luxfi/pulsar-m (this repo) | Module-LWE sibling: threshold ML-DSA | SHA-3 / SHAKE256 (NIST profile) only |
Security
SECURITY.md describes how to disclose vulnerabilities and what's in-scope for
bug bounty.
License
Apache-2.0 — same as luxfi/pulsar and luxfi/corona. See LICENSE.