Internet X.509 Public Key Infrastructure -- Algorithm Identifiers for the Module-Lattice-Based Digital Signature Algorithm (ML-DSA)
Extracted elements (25)
A secondary security reason for disallowing HashML-DSA is that pure ML-DSA prepends SHAKE256(public_key) to the message before hashing, requiring a public-key-specific collision search rather than a generic hash collision; HashML-DSA removes this enhanced targeted-collision protection.
HashML-DSA is disallowed primarily to increase interoperability: ML-DSA and HashML-DSA require different Verify() routines, and since the same OIDs identify both public keys and signature algorithms, an implementation would need to commit a key to pure or pre-hashed mode at certificate creation time — creating operational problems when the use case is unknown at key-generation time.
The seed format (32-byte ξ) is the RECOMMENDED private-key storage format because it is the most compact representation (32 bytes vs. up to 4896 bytes expanded) and both the expanded private key and public key can be deterministically derived from it via ML-DSA.KeyGen_internal(ξ).
Only the pure variant of ML-DSA (not the pre-hash HashML-DSA variant) is specified for use in PKIX certificates and CRLs. The pure variant does support a typical pre-hash flow via the External μ-ML-DSA mechanism described in Appendix D.
Prior to standardization, ML-DSA was known as Dilithium (CRYSTALS-Dilithium). ML-DSA and Dilithium are not compatible with each other.
Conforming CA implementations MUST specify ML-DSA algorithms explicitly using the OIDs from Section 2 when encoding ML-DSA signatures in certificates and CRLs. Conforming client implementations that process such certificates and CRLs MUST recognize the corresponding OIDs.
If the keyUsage extension is present in a certificate with an ML-DSA subject public key, at least one of digitalSignature, nonRepudiation, keyCertSign, or cRLSign MUST be set.
It is RECOMMENDED that implementations retain and export the seed even when also exporting the expanded private key, because expanding a seed is a one-way function — once the seed is discarded, it cannot be recovered from the expanded private key.
ML-DSA public keys cannot be used to establish keys or encrypt data; therefore the keyUsage extension MUST NOT have keyEncipherment, dataEncipherment, keyAgreement, encipherOnly, or decipherOnly set.
The HashML-DSA mode (Section 5.4 of FIPS 204) MUST NOT be used; public keys identified by id-hash-ml-dsa-44-with-sha512, id-hash-ml-dsa-65-with-sha512, and id-hash-ml-dsa-87-with-sha512 MUST NOT appear in X.509 certificates used for CRLs, OCSP, certificate issuance, and related PKIX protocols.
The parameters component of the AlgorithmIdentifier for all three ML-DSA OIDs MUST be absent; the AlgorithmIdentifier SHALL be a SEQUENCE of one component (the OID only).
When encoding an ML-DSA private key in a OneAsymmetricKey object, any of the three private-key formats (seed, expandedKey, both) may be used, though the seed format is RECOMMENDED for storage efficiency.
When parsing a private key, implementations MUST use the ASN.1 tag to determine which CHOICE variant is present: context-specific IMPLICIT [0] (0x80) for seed, OCTET STRING (0x04) for expandedKey, and SEQUENCE (0x30) for both, rather than length-based heuristics.
When receiving a private key that contains both the seed and the expandedKey, the recipient SHOULD perform a seed consistency check by regenerating the expanded key via ML-DSA.KeyGen_internal and comparing bytewise. If the check is performed and fails, the recipient MUST reject the private key as malformed.
SIGNATURE-ALGORITHM ASN.1 classes sa-ml-dsa-44, sa-ml-dsa-65, and sa-ml-dsa-87 are defined; each specifies its identifier OID, that parameters are absent, the associated public key type, and an S/MIME capability.
Three NIST-registered OIDs identify the ML-DSA parameter sets: id-ml-dsa-44 (2.16.840.1.101.3.4.3.17), id-ml-dsa-65 (2.16.840.1.101.3.4.3.18), and id-ml-dsa-87 (2.16.840.1.101.3.4.3.19), corresponding to NIST PQC security categories 2, 3, and 5 respectively.
IANA has assigned OID decimal 119 (id-mod-x509-ml-dsa-2025) in the 'SMI Security for PKIX Module Identifier' registry (1.3.6.1.5.5.7.0) for the ASN.1 module defined in this document.
Beyond unforgeability, ML-DSA possesses exclusive ownership, message-bound signatures, and non-resignability properties relevant to non-repudiation, all grounded in the collision resistance of SHAKE-256.
ML-DSA is strongly unforgeable under chosen message attacks (SUF-CMA), assuming an attacker has access to signatures for no more than 2^64 chosen messages. Security strength levels map to NIST PQC categories 2, 3, and 5 (equivalent to AES-128, AES-192, and AES-256 key search resistance).
ML-DSA requires high-quality random numbers for key generation; use of inadequate PRNGs can allow efficient private key recovery. Implementations must follow FIPS 204 Section 3.6.1 guidance for cryptographic random number generation.
ML-DSA supports both deterministic and randomized signing; a verifier cannot distinguish the two. Randomized signing mixes in a 256-bit random string from an approved RBG and provides greater resistance to fault and hardware side-channel attacks; deterministic signing simplifies testing and needs no randomness source at signing time.
ML-DSA was designed to ease side-channel resilience (e.g., it avoids Gaussian sampling), but implementations must still guard against side-channel leakage. Key recovery has been demonstrated from the bit-unpacking function in the signing algorithm over large signature samples; masking countermeasures exist but carry performance overhead.
An ML-DSA signature in an X.509 certificate is carried in the signatureValue BIT STRING, containing the raw ML-DSA signature computed over the ASN.1 DER-encoded TBSCertificate. The optional context string (ctx) parameter is left to its default value: the empty string.
ML-DSA public keys are encoded as raw byte strings (per FIPS 204 Algorithm 22) within the subjectPublicKey BIT STRING of SubjectPublicKeyInfo, with no ASN.1 wrapping. When appearing outside SubjectPublicKeyInfo, they may be encoded as typed OCTET STRINGs: ML-DSA-44-PublicKey (SIZE 1312), ML-DSA-65-PublicKey (SIZE 1952), ML-DSA-87-PublicKey (SIZE 2592).
The ML-DSA private key in a OneAsymmetricKey structure uses a DER-encoded CHOICE with three alternatives: seed ([0] OCTET STRING SIZE 32 for all levels), expandedKey (OCTET STRING SIZE 2560/4032/4896 for levels 44/65/87), or both (SEQUENCE containing seed and expandedKey). The seed format is a fixed 34 bytes total including tag and length.