ML-KEM-768 Encapsulation Design

Overview

ML-KEM-768 in MetaMUI Crypto Primitives is FIPS 203 ML-KEM, and nothing else. Encapsulation is ML-KEM.Encaps (FIPS 203 Algorithm 20): 32 bytes m from a cryptographically secure RNG, then Encaps_internal. No binding mixes a timestamp, a domain string or any other input into m.

Entry points (Rust, metamui_mlkem::mlkem768)

Function FIPS 203 Use
encapsulate(pk, rng) Alg 20 ML-KEM.Encaps every application
decapsulate(sk, ct) Alg 21 ML-KEM.Decaps (implicit rejection) every application
generate_keypair(rng) Alg 19 ML-KEM.KeyGen every application
encapsulate_deterministic(pk, m) Alg 17 Encaps_internal known-answer tests only
generate_keypair_from_dz(d, z) Alg 16 KeyGen_internal known-answer tests only
generate_keypair_from_seed(seed) none — MetaMUI single-seed convention, d := seed, z := SHA3-256(seed ‖ "z_derivation") cross-language fixtures only

FIPS 203 §6 describes the _internal functions as a testing interface, not as an application’s source of keys or shared secrets; the seeded convention above inherits the same limit. The release facade (metamui-crypto) offers none of them; its tests reproduce the NIST ACVP answers by passing a scripted CryptoRng to encapsulate and generate_keypair.

The last three rows, on mlkem512 and mlkem1024 as well, are compiled only with the crate’s fips203-internal feature. A dependant that does not name the feature cannot call them. The crate’s own tests enable it on themselves through a path = "." dev-dependency, so the ACVP and KAT gates are always built and nothing published carries the feature. generate_keypair and encapsulate draw (d, z) and m and then run the same KeyGen_internal and Encaps_internal bodies. Before 2026-09-16 they were copies of those bodies, and the vectors verified the copies.

Feature fips203-internal (2026-09-16)

Who enables it Why
metamui-mlkem’s own tests, examples and benches ACVP keyGen/encapDecap, the upstream KAT gate, emit_kat_fixtures
metamui-crypto-wasm/mlkem the KAT exports behind @metamui/mlkem/testing
nothing else the facade, metamui-hybrid, metamui-pqc, the interop driver and metamui-did-pqc call only the randomized functions

cargo test never skips the gates when the feature is off. A required-features entry on the test targets would do that, so crate_metadata.py --check refuses one on any exported crate. The crate’s test internal_entry_points_are_gated fails if any public function or re-export named *from_dz*, *from_seed* or *deterministic* is compiled without the feature. It also fails if the self-dependency disappears. Evidence: documents/public-release/evidence/202-api-tests.md §7.

What was removed, and why

Until 2026-09-15 the Rust mlkem768 module also exported encapsulate_production, encapsulate_test and encapsulate_raw_compatibility, and an earlier version of this page described them as a “three-tier” design:

None of the three had a caller in this repository, in any other language binding, or in metamui-did-pqc (which uses the MLKem768 type’s encapsulate). The Python module that once carried the same names is gone. Evidence: documents/public-release/evidence/202-api-tests.md §6.