Maps every parameter set + entry point in luxfi/crypto/mldsa to the
matching FIPS 204 section (§4 Table 1 sizes, §5 KeyGen/Sign/Verify
algorithms, §7 wire encodings). Surfaces the gap that today's KATs
are self-pinned (fixed-seed determinism) rather than the published
NIST CAVP .rsp vectors — the C generator at c/ref/nistkat exists
upstream but the Go side never consumes its emitted vectors.
Pairs with the research-preview banner just added to
luxfi/threshold/protocols/mldsa to give the full picture:
luxfi/crypto/mldsa — production, FIPS 204 conformant
(per-validator single-party path)
luxfi/threshold/protocols/mldsa — research-preview scaffold; no
threshold signer yet, not
FIPS-conformant
The two are complementary: per-validator ML-DSA is the production
identity-proof lane used by Warp 2.0 MLDSACertSet + bridge admin
schemes today. Threshold ML-DSA is the future MPC-aggregated lane,
paper-port today.
Tests untouched, still pass (0.6s).
5.0 KiB
FIPS 204 Traceability — luxfi/crypto/mldsa
This document maps every parameter set, function, and wire structure in
github.com/luxfi/crypto/mldsa to the corresponding section of
FIPS 204 (Module-Lattice-Based Digital Signature Standard), published
by NIST in August 2024.
Status: all three parameter sets (ML-DSA-44/65/87) are FIPS-204- conformant in the per-validator (single-party) sign+verify path. The threshold variant lives in
luxfi/threshold/protocols/mldsaand is research-preview, not FIPS-conformant (no signer yet).
Parameter sets — FIPS 204 §4 (Table 1)
| Lux constant | FIPS 204 name | Security category | pk size | sk size | sig size |
|---|---|---|---|---|---|
MLDSA44 |
ML-DSA-44 | Category 2 (~128-bit classical) | 1312 B | 2560 B | 2420 B |
MLDSA65 |
ML-DSA-65 | Category 3 (~192-bit classical) | 1952 B | 4032 B | 3309 B |
MLDSA87 |
ML-DSA-87 | Category 5 (~256-bit classical) | 2592 B | 4896 B | 4627 B |
Size constants in mldsa.go (MLDSA44PublicKeySize, …) re-export the
CIRCL upstream values verbatim. The values are pinned in
TestSizeConstants_FIPS204 (KAT-replay suite) — any drift fails the
test.
Algorithm map — FIPS 204 §5
| FIPS 204 algorithm | Section | Lux entry point | Backend |
|---|---|---|---|
ML-DSA.KeyGen |
§5.1, Algorithm 1 | mldsa.GenerateKey(mode, rand) |
CIRCL mldsa{44,65,87}.GenerateKey (pure Go) or pq-crystals C ref (CGO) |
ML-DSA.Sign |
§5.2, Algorithm 2 | PrivateKey.Sign(rand, msg, opts) (implements crypto.Signer) |
CIRCL mldsa{44,65,87}.SignTo |
ML-DSA.Verify |
§5.3, Algorithm 3 | Verify(pk, msg, sig) / PublicKey.Verify(msg, sig) |
CIRCL mldsa{44,65,87}.Verify |
The "hash variant" path of FIPS 204 §5.4 (HashML-DSA) is not exposed by this package today. Callers that need pre-hash sign should compute the hash and call the standard Sign over the digest — Lux's bridge and warp paths do this explicitly so the externally-visible domain separation is auditable.
Wire encoding — FIPS 204 §7
All keys and signatures use FIPS 204 byte encodings verbatim (no
length prefix, no version byte) — crypto.Signer.Sign returns
[]byte of MLDSAxxSignatureSize. Cross-implementation
byte-compatibility is verified by TestMLDSA*_KATReplay against
fixed-seed reference vectors.
KAT (Known-Answer Test) coverage
| Test | Vector source | What it pins |
|---|---|---|
TestMLDSA44_KATReplay |
self-generated, fixed seed | keygen-determinism + sign-determinism |
TestMLDSA65_KATReplay |
self-generated, fixed seed | same, level 3 |
TestMLDSA87_KATReplay |
self-generated, fixed seed | same, level 5 |
TestMLDSA65KAT_VerifyKnownGood |
hard-coded katSigPrefixHex |
reference signature prefix matches CIRCL output |
TestMLDSA65KAT_VerifyRejectsWrongMessage |
hard-coded | unforgeability sanity |
TestMLDSA65KAT_VerifyRejectsTamperedSig |
hard-coded | sig-bit-flip detection |
TestMLDSA65KAT_SeedStability |
hard-coded | seed→keypair stability across releases |
TestMLDSA65KAT_AllModes (subtests for 44/65/87) |
hard-coded | all three parameter sets tested |
Gap. The above tests pin self-generated determinism. They do
not load NIST CAVP .rsp reference vectors. The C generator at
c/ref/nistkat/PQCgenKAT_sign.c exists upstream from pq-crystals but
its emitted .rsp vectors are not checked into this repo and the Go
side never consumes them.
Plan: land NIST CAVP vectors for ML-DSA-44 / 65 / 87 under
c/ref/nistkat/responses/ (run the C generator, commit the .rsp),
add a nist_kat_test.go that parses the format and asserts every
keygen + sign matches. Tracked as a 1-day fix in
luxfi/threshold/protocols/mldsa/README.md § "Gap to solid and done".
Constant-time considerations — FIPS 204 §3.3.1
CIRCL's ML-DSA implementation runs in constant time for the secret-key
path; pq-crystals C reference does the same for the CGO path. We
do not currently run dudect against either path inside Lux CI —
add this as part of the multi-week hardening when the threshold signer
lands and needs CT validation under its own per-party sign path.
Test entrypoints
| File | Purpose |
|---|---|
kat_test.go |
KAT-replay suite (above) |
mldsa_test.go |
functional sign / verify / round-trip / cross-mode rejection |
fuzz_test.go |
sign + verify malformed inputs, randomized API surface |
provenance_test.go |
wire-format provenance + CGO/pure-Go dispatch determinism |
batch_test.go |
batched verify path determinism |
gpu_44_test.go / gpu_87_test.go |
optional GPU backend regression |
Cross-references
- FIPS 204: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf
- Per-validator usage:
luxfi/warpMLDSACertSet(one signature per validator, no aggregation primitive) - Bridge profile constants:
luxfi/bridge/profile.go(SchemeMLDSA65,SchemeMLDSA87,AuthMLDSA87,AuthMultisigMLDSA) - Research-preview threshold scaffold:
luxfi/threshold/protocols/mldsa - Magnetar (FIPS 205 SLH-DSA) sibling for hash-based PQ:
luxfi/magnetar - ML-KEM (FIPS 203, transport) sibling:
luxfi/crypto/mlkem