Threshold ML-DSA
Status — research preview, NOT production.
Lane What's here Status Per-validator ML-DSA N independent FIPS 204 signatures, aggregated at the consensus layer as MLDSACertSetProduction. Lives at luxfi/crypto/mldsa(CIRCL-backed) +luxfi/warpMLDSACertSet. This is the PQ identity-proof lane used by Warp 2.0 + bridge admin/pause schemes today.Threshold ML-DSA (this package) RSS partitions, parameter tables, structural cert-set fuzz seed Research preview. keygen.go/sign.go/combine.go/a_posteriori.godo not ship yet.hrej.go::HRejreturns"not yet wired to CIRCL ring". Do NOT depend on this package for live signing — there is no working signer to depend on.The pattern mirrors
luxfi/magnetar(FIPS 205 SLH-DSA): per-validator standalone primitive is production; true threshold without trusted dealer is research-grade and not yet deployed. The vocabulary distinction matters — seemagnetar/README.md§ "Why per-validator instead of threshold?" for the architectural reasoning.
First practical threshold signature scheme fully compatible with NIST FIPS 204 ML-DSA. Outputs standard ML-DSA signatures (drop-in verification) — once the signer lands. The current tree is the paper-port scaffold up to that point.
Paper: Celi, del Pino, Espitau, Niot, Prest — Efficient Threshold ML-DSA,
USENIX Security 2026. The full LaTeX source is being prepared at
papers/threshold-mldsa.tex and is not yet checked in (the hrej.go
reference to that path will become live when the paper lands).
Configurations
- Security levels: ML-DSA-44 / 65 / 87 (NIST I / III / V)
- Threshold range:
2 ≤ T ≤ N ≤ 6(hard upper bound in this release) - Typical:
2-of-3,3-of-5 - Security model: static dishonest majority in the ROM
Rounds
3 rounds per signing attempt, K parallel instances (see params.go):
- Commit — each party publishes
H(vk, i, wᵢ)withwᵢ = A·rᵢ - Reveal — open
wᵢ, derive challengec - Respond — each party publishes
zᵢafter local hyperball rejection
Combiner verifies the aggregated z meets ML-DSA bounds and emits a
standard signature.
Bandwidth (per party, per successful attempt, ML-DSA-44)
| N\T | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|
| 2 | 10.5 kB | ||||
| 3 | 15.8 kB | 21.0 kB | |||
| 4 | 15.8 kB | 36.8 kB | 42.0 kB | ||
| 5 | 15.8 kB | 73.5 kB | 157.4 kB | 84.0 kB | |
| 6 | 21.0 kB | 99.8 kB | 388.4 kB | 524.8 kB | 194.2 kB |
Files (current tree)
| File | Status | Role |
|---|---|---|
doc.go |
✅ shipped | package doc |
params.go |
✅ shipped | (T,N) × level parameter sets (Tables 3, 10, 11) |
rss.go |
✅ shipped | replicated secret sharing, hardcoded optimal partitions (Appendix B, Algorithm 6) |
hrej.go |
⚠ stub | HRej() returns "not yet wired to CIRCL ring" |
rss_test.go |
✅ shipped | RSS partition correctness + subset count + recovery |
fuzz_certset_test.go |
✅ shipped | wire-format parser fuzz seed |
keygen.go |
❌ not written | Algorithm 1 — paper port pending CIRCL ring integration |
sign.go |
❌ not written | Algorithms 2–4 (commit / reveal / respond) |
combine.go |
❌ not written | aggregate z + emit FIPS-204-byte-compat sig |
a_posteriori.go |
❌ not written | Section 6.2 acceptance check + retry |
Gap to "solid and done"
This list is mirrored in the parent threshold/CLAUDE.md.
1-day fixes (mostly docs / wiring):
- Land
papers/threshold-mldsa.texor remove the citation fromhrej.go. - NIST CAVP
.rspKAT vector ingestion inluxfi/crypto/mldsa(generator C exists atc/ref/nistkat/PQCgenKAT_sign.c; the Go side never consumes published vectors). FIPS-TRACEABILITY.mdinluxfi/crypto/mldsamapping parameter sets → FIPS 204 sections.- Profile-level scheme pin in
luxfi/bridge/cmd/bridge/so the daemon refuses an inbound non-PQ signing request when the operator profile namesml-dsa-65.
Multi-week (real research / engineering):
- Implement
keygen.go/sign.go/combine.go/a_posteriori.go. Paper claims 3-round protocol; none of the round transitions are coded. - End-to-end round-protocol test (2-of-3 keygen → sign → verify-via-CIRCL byte-compat). Without it the "byte-compatible with FIPS 204" claim in
doc.gois unverified. dudectconstant-time validation on the per-party sign path once it exists.- External cryptographer sign-off (Tier A submission shape, mirroring
magnetar/CRYPTOGRAPHER-SIGN-OFF.md). - Benchmark harness (
mldsa_bench_test.go.brokenalready exists incrypto/mldsaas a broken artifact — repair + add a threshold bench).