zeekay 44b38e2496 pulsar-m: threshold sign (2-round commit + reveal)
Two-round threshold signing producing FIPS 204 ML-DSA signatures
byte-equal to what a single-party FIPS 204 signer would emit. This
is the Class N1 (signing) deliverable.

Protocol shape (v0.1 reconstruction-aggregator instantiation):

  Round 1 (party i): sample per-round mask r_i ← {0,1}^512.
    Compute masked share s'_i = share_i ⊕ r_i. Commit
    D_i = cSHAKE256(r_i || s'_i || tau_1)
    where tau_1 = (sid, kappa, T, i, pk, mu). Note: binding BOTH
    halves under D_i closes the masked-half-rotation gap a v0.1
    audit would otherwise expose.
    MAC D_i to every peer j ∈ T\{i} under the long-lived MAC key
    K_{i,j} via KMAC256 (PULSAR-M-SIGN-R1-MAC-V1). Broadcast
    (D_i, {MAC_{i,j}}).

  Round 2 (party i): verify every received MAC in constant time
    against the locally-known K_{i,j}. On MAC mismatch, emit
    ComplaintMACFailure. On success, reveal (r_i, s'_i) so peers
    can re-derive D_i and combine.

  Combine: aggregator gathers t Round-2 reveals, re-derives each
    D_i = cSHAKE256(mask || masked || tau_1) and checks it equals
    the Round-1 commit. Lagrange-interpolates the byte-sum at x=0
    in GF(257), reduces it via the same cSHAKE256 mix the DKG
    used, calls mldsa.SignTo on the recovered seed. Returns the
    FIPS 204 signature.

The resulting signature satisfies pulsarm.Verify (which is FIPS 204
ML-DSA.Verify verbatim). The v0.2 path replaces the
reconstruction-aggregator step with the Lagrange-linearity sign of
spec/pulsar-m.tex §4.2, where the master secret is never
reconstructed in any party's memory; output bytes are identical.

Tests (vs. n,t ∈ {(5,3),(7,4),(10,7)}):
  - RoundTrip: threshold-produced sig passes FIPS 204 Verify
  - BadMAC: tampered Round-1 MAC triggers ComplaintMACFailure
  - DifferentAttempt: kappa mismatch rejected at Round 2
  - TamperedReveal: any byte-flip in Round-2 reveal caught at
    Combine via commit-mismatch (both mask and masked are bound)
  - DifferentQuorum_SameMessage: two disjoint quorums both produce
    valid FIPS 204 sigs on the same message under the same pk
  - QuorumTooSmall: empty / non-member rejection

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

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.

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%