Module-Lattice-Based Digital Signature Standard

draft 1.0.0 fips
idschema-atoms/fips/fips-204
created2026-05-24

FIPS 204 — Module-Lattice-Based Digital Signature Standard (ML-DSA)

FIPS Number: 204
Status: FINAL
Published: August 2024
Algorithm: ML-DSA (Module-Lattice-Based Digital Signature Algorithm)
Predecessor: CRYSTALS-Dilithium
DOI: 10.6028/NIST.FIPS.204


Abstract

FIPS 204 specifies the Module-Lattice-Based Digital Signature Algorithm (ML-DSA), a post-quantum digital signature scheme whose security rests on the hardness of the Module Learning With Errors (MLWE) problem. ML-DSA is derived from CRYSTALS-Dilithium, selected by NIST following a multi-round public evaluation of post-quantum cryptographic candidates.

The standard defines three parameter sets — ML-DSA-44, ML-DSA-65, and ML-DSA-87 — targeting NIST security levels 2, 3, and 5 respectively. It specifies key generation, signing (in both deterministic and hedged modes), and verification operations.


Background: Post-Quantum Cryptography

Classical digital signature algorithms (RSA, ECDSA) rely on the hardness of integer factorization and discrete logarithm problems. A sufficiently powerful quantum computer running Shor's algorithm can solve both in polynomial time, rendering these algorithms insecure against quantum adversaries.

NIST launched the Post-Quantum Cryptography (PQC) Standardization Project in 2016 to evaluate and standardize quantum-resistant algorithms. FIPS 204 (ML-DSA) is one of the first three standards published, alongside:

ML-DSA's security relies on the MLWE problem over rings of polynomials modulo a prime q = 8380417. This problem is widely believed to resist attacks by quantum computers. The module structure balances security strength against key and signature sizes across multiple parameter sets.


Algorithm Overview

ML-DSA follows the Fiat-Shamir with Aborts paradigm adapted for the module lattice setting. The design achieves:

Context strings (0–255 bytes) bind a signature to a specific application domain. A signature produced with context string A cannot be used in a context expecting string B — the verification will fail.


Parameter Sets

Parameter Set Security Level Comparable To Public Key Secret Key Signature
ML-DSA-44 NIST Level 2 AES-128 1312 bytes 2528 bytes 2420 bytes
ML-DSA-65 NIST Level 3 AES-192 1952 bytes 4000 bytes 3293 bytes
ML-DSA-87 NIST Level 5 AES-256 2592 bytes 4864 bytes 4595 bytes

All three parameter sets share the same algorithmic structure. Differences lie in the module dimensions (k, l), the challenge weight parameter, and the rejection sampling bounds.


Key Operations

KeyGen()

Generates a public-private key pair (pk, sk).

Sign(sk, message, context_string)

Produces a signature over an arbitrary-length message using the secret key.

Deterministic mode: The nonce is derived from the secret key and the message. Signing is reproducible given identical inputs. SHOULD be used when high-quality randomness is unavailable.

Hedged mode (RECOMMENDED): The nonce is derived from the secret key, a 256-bit random value, and the message. Hedged signing provides resilience against fault attacks and offers additional protection if the secret key is partially compromised.

The signing loop uses rejection sampling (Fiat-Shamir with Aborts): if a candidate signature fails statistical bounds, the loop restarts. This is expected behavior and is essential to the zero-knowledge property of the scheme.

Verify(pk, message, signature, context_string)

Verifies a signature against a public key and message. Returns a boolean.

A signature is accepted only when:

  1. The hint vector h has no more than omega non-zero entries.
  2. The response vector z has coefficients within the required bound.
  3. The recomputed challenge matches the challenge carried in the signature.

The context string supplied to Verify() MUST be identical to the one supplied to Sign(); a mismatch causes verification to return false.

Implementations MUST call Verify() before acting on any data protected by the signature.


Use in schema-atoms

ML-DSA-65 is the required signing algorithm for atom signatures in the schema-atoms catalog (ATOMS.yml: signing.required_algorithms: ["ml-dsa-65"]).

Why ML-DSA-65:

All three parameter sets are accepted (signing.accepted_algorithms), but new atom signatures MUST use ML-DSA-65 unless the catalog maintainer approves an exception.

Atom signing quorum for the fips class: 1 of role:catalog-maintainer (see ATOMS.yml signing.quorum_rules.fips).


Security Considerations

EUF-CMA: ML-DSA achieves existential unforgeability under chosen message attack. An adversary with signing oracle access cannot forge a valid signature on a new message except with negligible probability.

Context binding: The context string is hashed into the message representative during signing, cryptographically binding the signature to its intended domain. Applications MUST use distinct context strings for distinct protocols.

Secret key protection: Secret keys MUST NOT be embedded in artifacts, source code, or version control. They MUST be stored in a secure key management facility (hardware security module, OS keychain, or secrets vault) and rotated when compromise is suspected.

Randomness quality: The security of hedged signing and of key generation depends on the quality of the random bit generator. Implementations MUST use an approved DRBG (NIST SP 800-90A) seeded from a high-entropy source.

Quantum resistance: ML-DSA is designed to resist attacks by both classical and quantum computers. The best known quantum attacks against MLWE (for ML-DSA-65 parameters) require resources comparable to breaking AES-192.


References


atom.toml
# atom.toml — FIPS 204: Module-Lattice-Based Digital Signature Standard (ML-DSA)
id          = "schema-atoms/fips/fips-204"
version     = "1.0.0"
content_hash = "a40aaa9598b94589267046b3ae07355d9c1f79b8af92ac42d41f432623444778"
lifecycle   = "draft"
created_at  = "2026-05-24T00:00:00Z"

[fips]
fips_number    = 204
title          = "Module-Lattice-Based Digital Signature Standard"
short_name     = "ML-DSA"
published_date = "2024-08"
status         = "FINAL"
algorithm      = "ML-DSA"
parameter_sets = ["ML-DSA-44", "ML-DSA-65", "ML-DSA-87"]
asset          = "fips204.md"
asset_source   = "fips204.txt"

[protocol]
provenance = "https://doi.org/10.6028/NIST.FIPS.204 — NIST FIPS 204, August 2024. Module-Lattice-Based Digital Signature Standard."
license    = "public-domain"