MlKem
MlKem: ML-KEM-768 key encapsulation (FIPS 203), the NIST post-quantum KEM.
Two parties agree on a 32-byte shared secret: the receiver publishes an encapsulation (public) key, the sender encapsulates against it and sends the ciphertext, and the receiver decapsulates the ciphertext with its secret key. Use the secret as input keying material (HKDF), and combine it with a classical exchange (X25519) where you need a hybrid.
Backed by the vendored mlkem-native (runtime/pqc.c, runtime/third_party/), portable C, the same code on the compiled and interpreted backends. The builtins are deterministic: this module draws the randomness from Crypto.random_bytes, and the *_from_seed / encapsulate_with_coins variants take it explicitly (for test vectors).
Types
Functions
Ciphertext size in bytes: 1088.
The shared secret a [ciphertext] carries, recovered with [secret_key]. Err for a wrong-length argument or a corrupted secret key. A ciphertext made for a different key, or tampered with, is NOT an error: ML-KEM's implicit rejection returns an unrelated pseudorandom secret, so the parties' keys simply disagree (authenticate what you derive from it).
Encapsulate a fresh shared secret against [public_key]: Ok((ciphertext, shared_secret)). Send the ciphertext; keep the secret.
match MlKem.encapsulate(peer_public_key) do
Ok((ct, secret)) -> ...
Err(e) -> ...
endEncapsulate against [public_key] with explicit 32-byte [coins]: Ok((ciphertext, shared_secret)). Err for a wrong-length argument or a public key that fails FIPS 203's modulus check. Prefer encapsulate/1; reusing coins reuses the secret.
A fresh key pair from 64 random bytes.
let kp = MlKem.keypair()
-- kp.public_key: 1184 bytes, kp.secret_key: 2400 bytesThe key pair a 64-byte seed (d || z, FIPS 203 ML-KEM.KeyGen_internal) determines. Err for a seed of any other length.
Encapsulation (public) key size in bytes: 1184.
Decapsulation (secret) key size in bytes: 2400.