You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ML-KEM: K-PKE key generation, encryption and decryption #9
Notes for whoever picks this up, from the WP-2 audit (#8, merged in #28). Read the module docs at the top of src/mlkem/mod.rs first; this is the short list of what you will run into.
What exists in src/mlkem/ (crate-private, unused until now, so drop the #[allow(dead_code)] on the module in src/lib.rs once something uses it):
params.rs: ParamSet with K, ETA1, ETA2, DU, DV and the Table 3 sizes, plus MlKem512/768/1024 aliases. Stable Rust cannot use these constants as array lengths in generic code, so byte buffers are slices or Vec and only [Poly; K] is a plain array.
polyvec.rs: PolyVec with ntt, invntt_tomont, reduce, add, basemul_acc, to_bytes and from_bytes. from_bytes reduces mod q like ByteDecode12.
sample.rs: sample_ntt (Algorithm 7). Its input is rho || j || i, so Algorithm 13's A[i][j] is sample_ntt(rho, j, i).
compress.rs: an exact Compress_11 + ByteEncode_11 for du = 11.
Things that will bite:
The legacy ntt carries Montgomery factors. ntt_inverse is Algorithm 10 times 2^16 and poly_base_multiply is Algorithm 11 times 2^-16, so compose them the way the legacy indcpa does and the factors cancel. poly_add and poly_sub are plain i16 operations, so reduce between steps.
Compression for du has a gap. The legacy d = 10 and d = 11 code exists only inside the per-level polyvec_compress*/polyvec_decompress* functions, so PolyVec cannot call it. You either extract poly-level helpers from the legacy loops (a pure move, golden vectors must stay green) or write generic ones in src/mlkem. Do not reuse the legacy d = 11 compression: it is wrong at two residues. The d = 4, 5 and 1 paths (poly_compress, poly_compress_1024, poly_tomsg) and the decompress functions are fine to call.
Do not reuse poly_frommsg, verify, cmov or poly_getnoise_*. frommsg builds its mask with wrapping_neg() on a message bit (the Clangover pattern; it was not turned into a branch on rustc 1.95, but nothing guarantees that), verify/cmov have no optimization barrier, and getnoise hard-codes eta. Use the PRF (shake256 over seed || nonce, 64 * eta bytes) with cbd2 or cbd3 and ParamSet::ETA1/ETA2.
poly_frombytes does not reduce mod q. Use PolyVec::from_bytes, otherwise the section 7.2 modulus check will always pass.
Keygen is (rho, sigma) = G(d || k): the single k byte is the difference from Kyber.
Process reminders: a new section in AGENTS.md asks for named constants instead of magic numbers. CI runs clippy on the latest stable toolchain (1.99.1 when I checked), which has lints your local one may not, so run cargo +stable clippy --all-targets -- -D warnings before pushing. scripts/check.sh is the local gate for every commit.
Known gap that belongs to #18 and #16, not to this issue: the Keccak permutation spills temporaries to its own stack frame and the zeroize of the state cannot clear them.
Done in #29, merged into dev-v2. K-PKE KeyGen, Encrypt and Decrypt (Algorithms 13 to 15) are in src/mlkem/kpke.rs, generic over K. ek_PKE and dk_PKE match all 75 ACVP keyGen cases, and Encrypt and Decrypt match the ACVP encapsulation and decapsulation vectors for all three sets. Notes for #10 are in a comment there.
Activity
Zikithezikit commentedon Oct 30, 2026
Notes for whoever picks this up, from the WP-2 audit (#8, merged in #28). Read the module docs at the top of src/mlkem/mod.rs first; this is the short list of what you will run into.
What exists in src/mlkem/ (crate-private, unused until now, so drop the #[allow(dead_code)] on the module in src/lib.rs once something uses it):
Things that will bite:
Process reminders: a new section in AGENTS.md asks for named constants instead of magic numbers. CI runs clippy on the latest stable toolchain (1.99.1 when I checked), which has lints your local one may not, so run cargo +stable clippy --all-targets -- -D warnings before pushing. scripts/check.sh is the local gate for every commit.
Known gap that belongs to #18 and #16, not to this issue: the Keccak permutation spills temporaries to its own stack frame and the zeroize of the state cannot clear them.
Zikithezikit commentedon Oct 30, 2026
Done in #29, merged into dev-v2. K-PKE KeyGen, Encrypt and Decrypt (Algorithms 13 to 15) are in src/mlkem/kpke.rs, generic over K. ek_PKE and dk_PKE match all 75 ACVP keyGen cases, and Encrypt and Decrypt match the ACVP encapsulation and decapsulation vectors for all three sets. Notes for #10 are in a comment there.