docs(mldsa): FIPS 204 traceability — parameter sets, algorithms, KAT coverage

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).
This commit is contained in:
Hanzo AI
2026-05-28 20:30:52 -07:00
parent 14b557d98b
commit 007b383dab
+99
View File
@@ -0,0 +1,99 @@
# 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/mldsa` and 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/warp` `MLDSACertSet` (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`