Skip to content

Dev - #45

Merged
Zikithezikit merged 121 commits into
mainfrom
dev
Oct 31, 2026
Merged

Dev#45
Zikithezikit merged 121 commits into
mainfrom
dev

Conversation

@Zikithezikit

Copy link
Copy Markdown
Owner

No description provided.

Zikithezikit and others added 30 commits February 20, 2026 10:04
You can now decapsulate with your own custom private key.

```python
shared_secret = pykyber.Kyber768.decapsulate(ciphertext, secret_key)
```
In the new versions I added the dataclass to make the usage of the lib
more verbose. This broke the usage of lower versions, so I made it such
that even if you use it like the older versions it will still work.

```python
public_key, secret_key = pykyber.Kyber1024()

ciphertext, shared_secret = keypair.encapsulate()
```
Zikithezikit and others added 28 commits October 31, 2026 11:08
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
All four file kinds (seed decapsulation, encapsulation, key generation
from a seed, semi-expanded decapsulation) for the three parameter sets,
pinned to a commit and a SHA-256 per file in the manifest. The result
rule of the schema is applied as written.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A dev-only differential test (ml-kem 0.3.3, FIPS 203 final) over a
fixed-seed generator: keygen from a seed, encaps with a given m, decaps
of valid, bit-flipped and random ciphertexts, decaps under a changed
dk_PKE or z, and the modulus and hash checks after random byte changes.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The mask built from a message bit in the legacy poly_frommsg is the pattern
behind CVE-2024-37880 (Clangover), where a compiler turned it into a branch.
Route the bit and the mask through core::hint::black_box. Output is
unchanged; the golden vectors pass.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Route the accumulated difference, the flag and the select mask through
core::hint::black_box, the same idea as mlkem::ct, so the compiler cannot
prove the mask is 0 or 0xff and turn the select into a branch. The release
disassembly shows setne/cset and a vector select with no branch on the
compare result. Output is unchanged; the golden vectors pass.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Key generation and encapsulation in the Python bindings used thread_rng().
Use rand::rngs::OsRng, call try_fill_bytes in the legacy KEM functions, and
return KyberError::RandomBytesGeneration when the generator fails instead of
panicking. Wipe the half-built secret key when the second draw (z) fails and
hold the partly filled seed in Zeroizing. The Python wrappers keep the
RandomnessError subclass instead of re-wrapping it. Seeded paths and the
golden vectors are unchanged; the random-fill order and sizes are as before.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Hold m', the KDF input and the re-encrypted ciphertext of crypto_kem_dec*
in Zeroizing so they are wiped on every exit, unwinding included, and keep
the implicit-rejection flag in Zeroizing<u8>. The PRF output buffers in
poly_getnoise_* are the secret noise (the key in key generation, r in
encryption) and were never wiped; wipe them too. The release disassembly
shows the wipe of the flag and the buffers on both the normal and the
cleanup path. Add a test for the implicit-rejection output, derived from z
and H(c), for all three levels; it also passes on the commit before this
series. Output is unchanged and the golden vectors pass.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…the secret key

Kyber512/768/1024.from_keys accepted any public key and secret key of the
right sizes, so a pair from two different key pairs built a keypair whose
decapsulate silently returned a different secret than encapsulate had
produced. The round-3 secret key embeds the public key (sk_pke || pk ||
H(pk) || z), so compare the two (both are public) and raise KyberError on a
mismatch. The offset comes from named constants. A wrong-size secret key
keeps its existing size error at use. Approved by the maintainer in the
discussion on issue #18; ML_KEM_*.from_keys is not changed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The legacy bindings returned secret keys and shared secrets as Vec<u8>, which
PyO3 turns into bytes and then frees with the secret still in the allocation.
Hand them over as a SecretBytes wrapper that builds the bytes object and then
wipes the Rust buffer, and wipe the fixed-size copy from the safe API. The
Python object itself cannot be wiped. Output is unchanged.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The seeded derive path hands the KEM code a stand-in generator that is never
asked for bytes. Now that the legacy code draws randomness through
try_fill_bytes, make that method return an error, so a future change that
reaches it gets RandomBytesGeneration and not a panic. No path from Python
reaches it today.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ation functions

crypto_kem_keypair* and crypto_kem_enc* indexed caller-supplied pk, sk, ct,
ss and seed slices without checking their lengths, unlike decapsulation, so a
Rust caller with a short buffer panicked. Return InvalidInput instead. The
Python bindings already size every buffer, so no Python path reaches this.
Output is unchanged; the golden vectors pass.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Lockfile-only patch bump of an existing dependency. The advisory needs the
log feature, which pykyber does not enable, so it was not reachable here;
the legacy bindings no longer use thread_rng at all.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The old benchmark parsed the Kyber performance tests only and its figures came
from a debug build. benchmark.py now times ML_KEM_* and Kyber* directly (median
of 7 rounds of 500 calls), writes results.json, and draws two charts that replace
the four old ones. make benchmark builds the release extension first. The chart
dependency is in performance-tests/requirements.txt, not in requirements-dev.txt.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXWjkNs3Htog36snV9FcXb
Same facts, fewer words: install, quick start, a shorter class tour, sizes,
errors, the Kyber deprecation, security status and the new benchmark table and
charts. Every Python block in it was run, and the error message it shows is the
real one. The performance section now says what was measured and on what.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXWjkNs3Htog36snV9FcXb
Adds LICENSE-MIT and LICENSE-APACHE (the Apache text is the apache.org file,
11358 bytes, SHA-256 cfc7749b...523d30) and removes LICENSE. Sets license =
"MIT OR Apache-2.0" in Cargo.toml and pyproject.toml, with license-files, and
drops the Public Domain classifier. The built wheel's METADATA has
License-Expression: MIT OR Apache-2.0 and ships both files. Releases up to 1.0.5
stay under the Unlicense; the README, CONTRIBUTING.md, the changelog and the
agent notes say so.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CXWjkNs3Htog36snV9FcXb
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ents file

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
main holds the 1.0.x release history; dev already contains all of its
content (including the Android CI fixes) plus the 2.0 work, so the tree
is unchanged. This only joins the histories so the dev -> main PR merges
cleanly.
@Zikithezikit
Zikithezikit merged commit 1874716 into main Oct 31, 2026
45 checks passed
@Zikithezikit
Zikithezikit deleted the dev branch October 31, 2026 09:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant