Repository navigation
Conversation
Quest-Claim: e11f844db1ac1a2d
rind::kem offers ML-KEM-512 and ML-KEM-1024 beside ML-KEM-768 on every backend. Sealed marker types MlKem512, MlKem768, and MlKem1024 parameterize DecapsulationKey, EncapsulationKey, Ciphertext, and SharedSecret, so a ciphertext of one set fails to compile against a key of another. They replace kem::ML_KEM_768; Ciphertext::new checks the length, and decapsulate takes &Ciphertext and cannot fail. The FIPS 203 construction is generic over the rank, the compression widths, and eta1, using s2n-bignum's basemul_k2 and k4 and mlkem-native's AVX2 compression at 5 and 11 bits. Tests cover Wycheproof, ACVP, BoringSSL, and CCTV vectors for each set, differential tests against aws-lc-rs, and ctgrind, BINSEC, and zeroing checks. rind-aws-lc-rs gains ML_KEM_512 and ML_KEM_1024. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kixelated
marked this pull request as ready for review
November 11, 2026 10:13
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 55 minutes. View limit details
Pre-merge checks:
|
Collaborator
Author
|
Maintainer pick (2026-11-11, (Written by Claude Opus 5.5 with high) |
# Conflicts: # rind/src/mid/mlkem768.rs
Mutant runs build with `rind/wipe`, so rind/tests/zeroing.rs runs and kills a wiping `Drop` replaced with `()`. Since wiping became opt-in, every such mutant survived. The transpose loop walks the lower triangle, which leaves no equivalent `(i + 1)` bound mutant. The debug test covers `Ciphertext`, a rind-dart test the unknown KEM id, and rind-timing's case list joins the tool code mutation skips. Stale `mlkem768` entries follow the rename. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # .cargo/mutants.toml
kixelated
added a commit
that referenced
this pull request
Nov 11, 2026
Mutant runs now build with `rind/wipe`, as #606 does, so the zeroing and heap scratch tests catch ML-DSA's wiping `Drop`s. New tests check the portable `reduce` and `chknorm` against their contracts, which aarch64's backend comparison could not, and that `MlDsaPrivateKey`'s `encoded_len` matches its encoding. The rest are recorded as equivalent or unreachable in .cargo/mutants.toml, each class with why. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # ALGORITHMS.md
kixelated
disabled auto-merge
November 12, 2026 04:42
kixelated
added this pull request to the merge queue
Nov 12, 2026
Any commits made after this event will not be merged.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Completes quest/m3/parity/ml-kem.md and deletes it, removing every link to it.
Problem
rind::kemoffered only ML-KEM-768. rustls's aws-lc-rs provider shipsMLKEM1024, so rustls provider parity needs ML-KEM-1024. aws-lc-rs users ofML_KEM_512andML_KEM_1024had no rind equivalent.Approach
mid/mlkem.rs(formerlymlkem768.rs) is generic over a sealedParamstrait. The trait carries the rank K (2, 3, 4), the compression widths du/dv (10/4, or 11/5 for 1024), and eta1 (3 for 512), plus associated array types for each size, since stable Rust has nogeneric_const_exprs.mlkem_basemul_k2andk4come in throughadmin/parse-asmfor x86_64 and aarch64. mlkem-native's AVX2poly_compress_d5andd11come in throughadmin/import-aws-lc. The portable and armv7 backends get a generic base multiplication and generic division-free compression, checked exhaustively against the definition. Decompression and eta=3 CBD sampling are Rust on every backend. The matrix-index computation uses no division, so the variable-time scan passes.admin/sync-acvpwidened), BoringSSL's ML-KEM-1024 files (admin/sync-vectors, about 5 MB), and CCTV's per-set modulus vectors.ct_binsec_mlkem512/768/1024), qemu constant-time traces, zeroing and heap-scratch checks, and the fuzzer's key parsing, all per set.ML_KEM_512andML_KEM_1024, which drops the omission from its README. rind-rustls moves to the new API and keeps only X25519MLKEM768. ItsMLKEM1024group belongs to the rustls parity quest.Public API impact (breaking)
kem::ML_KEM_768andkem::Algorithmas a value are gone. The sealed marker typesMlKem512,MlKem768, andMlKem1024parameterizeDecapsulationKey<A>,EncapsulationKey<A>,Ciphertext<A>, andSharedSecret<A>, so a ciphertext of one set fails to compile against a key of another.kem::Algorithmis now the sealed trait they implement.Migration:
DecapsulationKey::generate(&ML_KEM_768)?DecapsulationKey::<MlKem768>::generate()?EncapsulationKey::new(&ML_KEM_768, bytes)?EncapsulationKey::<MlKem768>::new(bytes)?key.decapsulate(bytes)?key.decapsulate(&Ciphertext::<MlKem768>::new(bytes)?). The length check moves toCiphertext::new, anddecapsulatecannot fail.encapsulate()returning(Ciphertext, SharedSecret)(Ciphertext<A>, SharedSecret<A>). The bytes stay available throughAsRef<[u8]>.rind-aws-lc-rs's API is unchanged apart from the two new algorithms.
Measurements
These numbers come from a local x86_64 host (AVX-512) that other agents share, so they are noisy. Criterion ran with 1 s warm-up and 3 s measurement, through
quest gate. Times are medians.Matrix cache: keeping it boxed beat re-sampling the matrix each call. Re-sampling took encaps from 4.29, 4.92, and 6.36 µs to 5.08, 6.39, and 8.42 µs, and decaps from 3.58, 4.24, and 5.37 µs to 4.42, 5.61, and 7.46 µs (512, 768, and 1024).
Verification
main(head below):just check origin/mainpasses,admin/ctgrind unit --release -- kemand the adapters' KEM test pass under memcheck, and a targetedadmin/mutantsrun over every survivor CI reported catches all of them.dart-ioshit the 30 minute limit with the simulator silent for 20 minutes after a slow Xcode build (210 s, against 70 s on passing runs), while the native macOS arm64 Dart job passed the same ML-KEM code. Read as a runner hang, not rerun; this push runs it again.just check origin/mainpasses. This covers lint, the workspace build, rind's tests, the variable-time scan on every target,admin/testing,quest check, and the bench-report render.just armv7passes under qemu on all three CPU paths.just portablepasses up toheap_scratch's planted self-testdetects_a_leak_in_key_generation, which fails the same way onmainwith portable plus debug assertions. moq-dev/rind#600 fixes it withblack_box.cargo clippy -p rind --lib --target aarch64-unknown-linux-gnu -D warningspasses. The aarch64 tests, including the k2 and k4 basemul paths, were not run locally. CI's arm64 runners run them.admin/regenerate's generators reproduce the existing files unchanged and add only the new routines.Decisions made without asking
SharedSecretis generic over the set, as the quest's goal says ("one key, ciphertext, and secret type per parameter set"). The bytes are 32 in every set, so it could stay untyped. Recommend keeping it typed, for symmetry and so a future KEM with a different secret size fits.decapsulateis infallible. OnceCiphertext::newhas checked the length, FIPS 203 decapsulation has no failure (implicit rejection). Recommend keeping it.Option<Box<_>>, wiped in the decapsulation key's drop). It measured faster, as above.mlkem768→mlkem(bench.yml and bench-report updated). Historicmlkem768-*series keep their names.rind/wipe(.cargo/mutants.toml'sfeatures). Since moq-dev/rind#461 made wiping opt-in,rind/tests/zeroing.rswas compiled out of mutant runs, so every wipingDropreplaced with()survived; this PR'sDecapKeyandSharedSecretdrops did. With the feature, zeroing.rs kills them, as the existing "whose ownDropwipes all of it" exclusions already assumed. moq-dev/rind#609, which turnswipeon by default, would make the line redundant but harmless.for j in 0..i), the same swaps, which leaves no equivalent(i + 1)bound mutant to record.Follow-ups
Models
Size: M
Implementer: Claude Code, Opus 5.5 (claude-opus-5-5), medium effort
Implementer: Claude Code, claude-opus-5-5, medium effort (iterate, M)
Implementer: Claude Code, claude-opus-5-5, medium effort (iterate, XS)
(Written by Claude Opus 5.5 with medium)
🤖 Generated with Claude Code
Review
Rewritten by
quest reviewafter each round.01a1ce10-ccc7-7122-bf17-b7d2efd07b46, round 1The parameter-set generalization has substantial vector, differential, constant-time, and zeroing coverage with no actionable defects found, though builds and tests were not run as instructed.