From a5fa9034e42226571637bc2db1f5a43d0387ed59 Mon Sep 17 00:00:00 2001 From: Yoav Haimov Date: Fri, 30 Oct 2026 16:42:46 +0200 Subject: [PATCH] docs: record the WP-4 vector setup in CLAUDE.md Co-Authored-By: Claude Sonnet 5.5 --- CLAUDE.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 92c33a1..27948c8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -29,7 +29,7 @@ pytest python/tests/test_kyber.py::test_kyber768_new_api `make clean` deletes `target/`, the built `.so`, and the `.pyi`; rebuild afterwards. -Known baseline (2026-10-30, after WP-5 / #13 merged): `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, `cargo test` and `pytest python/tests` all pass on `dev-v2`, and the legacy golden vectors (#6) are in. CI (`.github/workflows/CI.yml`) has a `test` job (Linux/macOS/Windows, Python 3.8 and newest) and an `every commit passes` job that runs `scripts/check.sh` over each commit of a PR via `git rebase --exec`; making them required checks on `dev-v2` is a branch-protection setting only the maintainer can change (#7). The clippy lints `needless_range_loop`, `identity_op` and `explicit_counter_loop` are allowed per module in `src/kyber/` because the legacy loops mirror the reference C code; don't add new code that needs them. CI installs the latest stable toolchain, which can be newer than the one on your machine and bring new clippy lints (rustc 1.99 added `chunks_exact_to_as_chunks`, which failed PR #28 although 1.95 was clean), so run clippy with a recent stable before pushing: `rustup toolchain install stable` and `cargo +stable clippy --all-targets -- -D warnings`. +Known baseline (2026-10-30, after WP-4 / #12 and WP-5 / #13 merged): `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, `cargo test` and `pytest python/tests` all pass on `dev-v2`, and the legacy golden vectors (#6) are in. CI (`.github/workflows/CI.yml`) has a `test` job (Linux/macOS/Windows, Python 3.8 and newest) and an `every commit passes` job that runs `scripts/check.sh` over each commit of a PR via `git rebase --exec`; making them required checks on `dev-v2` is a branch-protection setting only the maintainer can change (#7). The clippy lints `needless_range_loop`, `identity_op` and `explicit_counter_loop` are allowed per module in `src/kyber/` because the legacy loops mirror the reference C code; don't add new code that needs them. CI installs the latest stable toolchain, which can be newer than the one on your machine and bring new clippy lints (rustc 1.99 added `chunks_exact_to_as_chunks`, which failed PR #28 although 1.95 was clean), so run clippy with a recent stable before pushing: `rustup toolchain install stable` and `cargo +stable clippy --all-targets -- -D warnings`. ## Architecture @@ -45,6 +45,8 @@ Three layers (the legacy Kyber path; ML-KEM sits beside it, see below): ML-KEM (WP-3 to WP-5, merged): `src/mlkem/` is the FIPS 203 core, generic over `K` (`params.rs`, `kpke.rs`, `kem.rs`, `check.rs` for the section 7.2/7.3 checks, `ct.rs` for the constant-time reject select); it shares only audited primitives with `src/kyber/` (the list is in the module docs of `src/mlkem/mod.rs`). `src/pymlkem.rs` holds the private PyO3 functions `_mlkem_{512,768,1024}_{keygen,encaps,decaps}`; it calls only the public functions of `mlkem::kem`, never `kem::acvp` or the `acvp` feature, and raises the `KyberError` subclasses defined in `python/pykyber/_error.py` (looked up by name at raise time). `python/pykyber/_mlkem.py` has `ML_KEM_512/768/1024` (one base class, three thin subclasses); `MlKemKeypair` and `MlKemEncapsulationResult` in `_types.py` are deliberately not subclasses of the Kyber types, and `_validation.py` refuses Kyber objects in ML-KEM methods by type. Tests: `python/tests/test_mlkem*.py`; the ACVP files come from `scripts/fetch_vectors.py` and a missing file fails the run. +Official vectors (WP-4, merged): the manifest pins ACVP, C2SP CCTV and Wycheproof files by commit and SHA-256 (`tests/vectors/manifest.json`); the Rust side is `src/mlkem/{acvp,cctv,wycheproof,differential}_tests.rs` and the Python side `python/tests/test_mlkem_{acvp,cctv,wycheproof}.py`. Two things to know. The CCTV `unluckysample` files and accumulated hashes were made with the pre-final `G(d)` (no `k` byte), so `cctv_tests.rs` builds those keys with `kpke::keygen_expanded` and the old derivation; the final one is covered by ACVP, and the CCTV tests are not evidence about `G(d || k)`. The differential test compares against the dev-only `ml-kem` 0.3.3 crate (needs rustc 1.87+); `flate2` is a dev-dependency for the gzip modulus files. `cargo test` takes about a minute because the 10 000-run CCTV hashes run in the dev profile; `PYKYBER_CCTV_RUNS=1000000 cargo test --release --lib accumulated` runs the million-run hashes (about 8 minutes). + Other locations: docs are in `docs/` (`api.md`, `index.md`), the benchmark is in `performance-tests/`, and `CHANGELOG.md` is maintained by hand. `.opencode/` (another agent tool's notes, including a `SECURITY.md` log of past fixes: constant-time division removal, Kyber-512 η1=3) is **gitignored**, so other contributors don't have it. PLAN-2.0 WP-0 migrates that log to a root `SECURITY.md`.