6. Private Key Format
この節では PKIX における ML-KEM の RFC 原文を保持し, algorithm identifiers, SubjectPublicKeyInfo, private key formats, ASN.1 objects, security considerations, examples を含めます.
6. Private Key Format
[FIPS203] specifies two formats for an ML-KEM private key: a 64-octet
seed and an (expanded) private key, which is referred to as the
decapsulation key. The expanded private key (and public key) is
computed from the seed using ML-KEM.KeyGen_internal(d,z) (algorithm
16) using the first 32 octets as _d_ and the remaining 32 octets as
_z_. If the expanded private key is generated without exporting the
seed, ML-KEM.KeyGen() (algorithm 19) is used; it combines seed
generation with ML-KEM.KeyGen_internal(d,z).
A key pair is generated by sampling 64 octets uniformly at random for
the seed (private key) from a cryptographically secure pseudorandom
number generator (CSPRNG). The public key can then be computed using
ML-KEM.KeyGen_internal(d,z) as described earlier.
"Asymmetric Key Packages" [RFC5958] describes how to encode a private
key in a structure that both identifies which algorithm the private
key is for and allows for the public key and additional attributes
about the key to be included as well. For illustration, the ASN.1
structure OneAsymmetricKey is replicated below.
OneAsymmetricKey ::= SEQUENCE {
version Version,
privateKeyAlgorithm SEQUENCE {
algorithm PUBLIC-KEY.&id({PublicKeySet}),
parameters PUBLIC-KEY.&Params({PublicKeySet}
{@privateKeyAlgorithm.algorithm})
OPTIONAL}
privateKey OCTET STRING (CONTAINING
PUBLIC-KEY.&PrivateKey({PublicKeySet}
{@privateKeyAlgorithm.algorithm})),
attributes [0] Attributes OPTIONAL,
...,
[[2: publicKey [1] BIT STRING (CONTAINING
PUBLIC-KEY.&Params({PublicKeySet}
{@privateKeyAlgorithm.algorithm})
OPTIONAL ]],
...
}
For ML-KEM private keys, the privateKey field in OneAsymmetricKey
contains one of the following DER-encoded CHOICE structures. The
seed format is a fixed 64-byte OCTET STRING (66 bytes total with the
0x8040 tag and length) for all security levels, while the expandedKey
and both formats vary in size by security level:
ML-KEM-512-PrivateKey ::= CHOICE {
seed [0] OCTET STRING (SIZE (64)),
expandedKey OCTET STRING (SIZE (1632)),
both SEQUENCE {
seed OCTET STRING (SIZE (64)),
expandedKey OCTET STRING (SIZE (1632))
}
}
ML-KEM-768-PrivateKey ::= CHOICE {
seed [0] OCTET STRING (SIZE (64)),
expandedKey OCTET STRING (SIZE (2400)),
both SEQUENCE {
seed OCTET STRING (SIZE (64)),
expandedKey OCTET STRING (SIZE (2400))
}
}
ML-KEM-1024-PrivateKey ::= CHOICE {
seed [0] OCTET STRING (SIZE (64)),
expandedKey OCTET STRING (SIZE (3168)),
both SEQUENCE {
seed OCTET STRING (SIZE (64)),
expandedKey OCTET STRING (SIZE (3168))
}
}
The CHOICE allows three representations of the private key:
* The seed format (tag [0]) contains just the 64-byte seed value
from which both the expanded private key and public key can be
derived using ML-KEM.KeyGen_internal(d,z) (algorithm 16) using the
first 32 octets as _d_ and the remaining 32 octets as _z_.
* The expandedKey format contains the expanded private key that was
derived from the seed. If the seed is not exported, both the
expanded private key and public key can be derived using ML-
KEM.KeyGen() (algorithm 16).
* The both format contains both the seed and expanded private key,
allowing for interoperability; some may want to use and retain the
seed and others may only support expanded private keys.
The privateKeyAlgorithm field uses the AlgorithmIdentifier structure
with the appropriate OID as defined in Section 3.
The publicKey field contains the byte stream of the public key. If
present, the publicKey field will hold the encoded public key as
defined in Section 4.
Note that while the private key can be stored in multiple formats,
the seed-only format is RECOMMENDED, as it is the most compact
representation. Both the expanded private key and the public key can
be deterministically derived from the seed using ML-
KEM.KeyGen_internal(d,z) (algorithm 16) using the first 32 octets as
_d_ and the remaining 32 octets as _z_. Alternatively, the public
key can be extracted from the expanded private key. While the
publicKey field and expandedKey format are technically redundant when
using the seed-only format, they MAY be included to enable key pair
consistency checks during import operations.
When parsing the private key, the ASN.1 tag explicitly indicates
which variant of CHOICE is present. Implementations should use the
context-specific tag IMPLICIT [0] (raw value 0x80) for seed, OCTET
STRING (0x04) for expandedKey, and SEQUENCE (0x30) for both to parse
the private key, rather than any other heuristic like length of the
enclosing OCTET STRING.
Appendix C.1 contains examples for ML-KEM private keys encoded using
the textual encoding defined in [RFC7468].