Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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`.
Expand Down
Loading