FIPS 204 quick reference
A memory aid for ML-DSA — the post-quantum signature scheme used throughout this stack. This is not a substitute for FIPS 204.
What it is
ML-DSA ("Module-Lattice-Based Digital Signature Algorithm") is the NIST-standardized PQ successor to ECDSA / EdDSA. It is a lattice-based signature scheme whose security rests on the hardness of Module-LWE and Module-SIS, not on integer factorization or elliptic-curve discrete log. Finalized in FIPS 204 (August 2024).
Historical name: Dilithium. The NIST-selected variant is now formally ML-DSA.
Parameter sets
| Parameter set | NIST security category | ~Classical security | Public key | Secret key | Signature |
|---|---|---|---|---|---|
| ML-DSA-44 | II | ~128 bits | 1,312 B | 2,560 B | 2,420 B |
| ML-DSA-65 | III | ~192 bits | 1,952 B | 4,032 B | 3,309 B |
| ML-DSA-87 | V | ~256 bits | 2,592 B | 4,896 B | 4,627 B |
The number ("44", "65", "87") encodes internal matrix dimensions; it is not a security level. Compare against AES-128 / AES-192 / AES-256 using the NIST category, not the parameter-set number.
OIDs
ML-DSA-44 2.16.840.1.101.3.4.3.17
ML-DSA-65 2.16.840.1.101.3.4.3.18
ML-DSA-87 2.16.840.1.101.3.4.3.19
When to use which
- ML-DSA-65 — default. Level 3, best balance of security and size for most deployments including on-chain verification where signature size is paid in calldata cost.
- ML-DSA-44 — when signature size and signing latency dominate (client-side signing on constrained devices). Use only when Level 2 is acceptable in your threat model.
- ML-DSA-87 — when Level 5 (256-bit equivalent) is required. Larger keys and signatures; rarely needed for transactional use cases.
Comparison with ECDSA / EdDSA
| Property | ECDSA-P256 / Ed25519 | ML-DSA-65 |
|---|---|---|
| Hardness assumption | Elliptic-curve discrete log | Module-LWE / Module-SIS |
| Quantum-vulnerable | Yes (Shor's algorithm) | No |
| Public key size | 32–64 B | 1,952 B |
| Signature size | 64–72 B | 3,309 B |
| Verification gas (EVM) | ~3K (ecrecover) | Millions in pure EVM; ~374K on Arbitrum Stylus |
| Deterministic | EdDSA yes; ECDSA no by default | Deterministic ("hedged" optional) |
PQ signatures are larger by one to two orders of magnitude. That size appears at every layer: bandwidth, storage, calldata, certificate chains.
Test vectors
Implementations in this stack are validated against NIST ACVP test vectors (official keygen, siggen, sigver vectors from usnistgov/ACVP-Server) and the Wycheproof corpus. Any implementation change that affects ACVP outputs is treated as a regression.
Common mistakes
- Mixing raw and hashed inputs. Sign a digest, not the raw message. In the smart-account stack, the signed input is
userOpHash(a 32-byte keccak-256). Always be explicit about what is signed. - Omitting domain separation. When signing across multiple chains or sessions, include a domain separator (e.g.
chainId,nonce) to prevent cross-context replay. - Confusing raw and encoded key sizes. The 1,952-byte ML-DSA-65 public key is the raw key. SPKI-wrapped or PKCS#8-wrapped versions are larger.
pq-key-encoderhandles this. - Rolling your own implementation. Use an audited library (
ml-dsain Rust,@noble/post-quantumin TypeScript). Side-channel-resistant lattice arithmetic is difficult to get right.
Related
- FIPS 204 final standard
- Supported algorithms — sizes and OIDs for all NIST PQ algorithms
- Threat model — what the signature actually protects in context