Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
249 commits
Select commit Hold shift + click to select a range
31affff
sha2: partial-bit messages, compile-time IVs, CAVP SHAVS tests (PR #88)
dghgit Sep 6, 2026
aec1ae4
sha3: partial-byte fixes, CAVP SHA3VS tests, mem-usage bench, release…
dghgit Sep 6, 2026
d604906
sha2, hmac: add SHA-512/224 and SHA-512/256 (FIPS 180-4 s. 5.3.6) and…
dghgit Sep 6, 2026
a57d508
rng: use core::fmt in hash_drbg80090a.rs; the only part of PRs #92-#9…
dghgit Sep 6, 2026
fa0be5d
sm3: add bouncycastle-sm3 (GB/T 32905-2016) and HMAC-SM3 with factory…
dghgit Sep 6, 2026
34d7953
Partial bytes follow ASN.1 BIT STRING order (X.690 s. 8.6.2): message…
dghgit Sep 6, 2026
1140a61
release notes: SM3 partial bytes follow the ASN.1 BIT STRING order li…
dghgit Sep 6, 2026
1ad97fd
sha2, sm3: document the surviving cargo-mutants equivalences at their…
dghgit Sep 6, 2026
fe6fd58
core: split BlockCipher into block-aligned BlockCipherEncryptor/Decry…
dghgit Sep 6, 2026
58a1fed
aes-lowmemory: add bouncycastle-aes-lowmemory, a constant-time, table…
dghgit Sep 6, 2026
aa9454d
modes: add BlockPermutation trait, bouncycastle-modes with AES CBC, a…
dghgit Sep 6, 2026
f56802e
padding: add Padding trait and bouncycastle-padding (PKCS7, PaddedEnc…
dghgit Sep 6, 2026
78a4021
core, modes, aes-lowmemory: in-place block cipher API with compile-ti…
dghgit Sep 6, 2026
c5f60fb
modes: add AES CFB128 mode with AES_CFB_* aliases, aes*-cfb CLI subco…
dghgit Sep 6, 2026
2c0567e
core: ElectronicCodeBook (was BlockPermutation), slice block hooks, b…
dghgit Sep 6, 2026
157b1c8
modes: add Ecb (SP 800-38A Sec 6.1) with AES_ECB_* aliases and aes*-e…
dghgit Sep 6, 2026
f6cb787
padding: add NoPadding (errors when asked to pad) with Padding::ALWAY…
dghgit Sep 6, 2026
a1c4e41
skills: add commit-range-report, a Markdown report of a commit range …
dghgit Sep 6, 2026
9c65521
mldsa, mlkem: replace the const-generic turbofish with sealed MLDSAPa…
ounsworth Sep 7, 2026
57dd3d0
core: replace StreamCipher with the split StreamCipherEncryptor / Str…
dghgit Sep 6, 2026
97ac6e3
modes: Cfb becomes a stream cipher taking any length with no padding,…
dghgit Sep 6, 2026
5c73617
release notes: CFB becomes a stream cipher with a short final segment…
dghgit Sep 6, 2026
e2b534d
modes: pin the single-call vs chunked equivalence of Cfb and Cfb8 aga…
dghgit Sep 6, 2026
f72bfe6
modes: add Ctr (SP 800-38A Sec 6.5), a stream cipher whose nonce leng…
dghgit Sep 6, 2026
0404ab9
modes: cross-check Ctr against BC Java's SICBlockCipher, which shares…
dghgit Sep 6, 2026
921e2b5
sha2: partial-bit messages, compile-time IVs, CAVP SHAVS tests (PR #88)
dghgit Sep 6, 2026
7b4e7fc
sha3: partial-byte fixes, CAVP SHA3VS tests, mem-usage bench, release…
dghgit Sep 6, 2026
c34c2f9
sha2, hmac: add SHA-512/224 and SHA-512/256 (FIPS 180-4 s. 5.3.6) and…
dghgit Sep 6, 2026
7df74a6
rng: use core::fmt in hash_drbg80090a.rs; the only part of PRs #92-#9…
dghgit Sep 6, 2026
ac896e2
sm3: add bouncycastle-sm3 (GB/T 32905-2016) and HMAC-SM3 with factory…
dghgit Sep 6, 2026
f34858d
Partial bytes follow ASN.1 BIT STRING order (X.690 s. 8.6.2): message…
dghgit Sep 6, 2026
46e2e79
release notes: SM3 partial bytes follow the ASN.1 BIT STRING order li…
dghgit Sep 6, 2026
607cfa7
sha2, sm3: document the surviving cargo-mutants equivalences at their…
dghgit Sep 6, 2026
4ca1274
core: split BlockCipher into block-aligned BlockCipherEncryptor/Decry…
dghgit Sep 6, 2026
a9627f6
aes-lowmemory: add bouncycastle-aes-lowmemory, a constant-time, table…
dghgit Sep 6, 2026
f403921
modes: add BlockPermutation trait, bouncycastle-modes with AES CBC, a…
dghgit Sep 6, 2026
e018929
padding: add Padding trait and bouncycastle-padding (PKCS7, PaddedEnc…
dghgit Sep 6, 2026
17372c9
core, modes, aes-lowmemory: in-place block cipher API with compile-ti…
dghgit Sep 6, 2026
d1bee58
modes: add AES CFB128 mode with AES_CFB_* aliases, aes*-cfb CLI subco…
dghgit Sep 6, 2026
ca53601
core: ElectronicCodeBook (was BlockPermutation), slice block hooks, b…
dghgit Sep 6, 2026
891669b
modes: add Ecb (SP 800-38A Sec 6.1) with AES_ECB_* aliases and aes*-e…
dghgit Sep 6, 2026
45941d1
padding: add NoPadding (errors when asked to pad) with Padding::ALWAY…
dghgit Sep 6, 2026
74e0100
skills: add commit-range-report, a Markdown report of a commit range …
dghgit Sep 6, 2026
37d0b3b
core: replace StreamCipher with the split StreamCipherEncryptor / Str…
dghgit Sep 6, 2026
c158860
modes: Cfb becomes a stream cipher taking any length with no padding,…
dghgit Sep 6, 2026
8c7ec71
release notes: CFB becomes a stream cipher with a short final segment…
dghgit Sep 6, 2026
9c1b9b7
modes: pin the single-call vs chunked equivalence of Cfb and Cfb8 aga…
dghgit Sep 6, 2026
5cec55d
modes: add Ctr (SP 800-38A Sec 6.5), a stream cipher whose nonce leng…
dghgit Sep 6, 2026
4adbebb
modes: cross-check Ctr against BC Java's SICBlockCipher, which shares…
dghgit Sep 6, 2026
0b06214
aes-lowmemory: the AES_CBC_* and AES_ECB_* aliases take a padding sch…
dghgit Sep 6, 2026
5e43a9d
core: stream ciphers also implement SymmetricCipherEncryptor / Symmet…
dghgit Sep 7, 2026
fe5c291
core: delete the SymmetricCipher trait and move its four one-shots on…
dghgit Sep 7, 2026
0986629
aes: rename bouncycastle-aes-lowmemory to bouncycastle-aes
dghgit Sep 7, 2026
fed518b
aes: drop Block, PaddedMode and the AesParams types from the public API
dghgit Sep 7, 2026
8f932ca
aes: the ElectronicCodeBook trait is the only public route to the per…
dghgit Sep 7, 2026
41ce203
aes: the permutation types keep the spec's capitalisation, AES / AES_…
dghgit Sep 9, 2026
d98f703
core: ElectronicCodeBook's pair methods are encrypt_2blocks / decrypt…
dghgit Sep 9, 2026
2845101
aes: cipher2 / inv_cipher2 after FIPS 197's CIPHER() and INVCIPHER(),…
dghgit Sep 9, 2026
69cfe5b
core: ElectronicCodeBook's eight-block methods are encrypt_8blocks / …
dghgit Sep 9, 2026
ab7b948
core: ElectronicCodeBook batches four blocks, encrypt_4blocks / decry…
dghgit Sep 9, 2026
c534f3b
release notes: the block-cipher trait section names the four-block me…
dghgit Sep 9, 2026
16552e9
core: SymmetricCipherEncryptor / SymmetricCipherDecryptor are SimpleC…
dghgit Sep 9, 2026
4c7eec7
gitignore: ignore editor swap and backup files, and drop the .fred.sw…
dghgit Sep 9, 2026
4bac3b3
Reverting the SKILL.md changes about producing a report since this se…
ounsworth Sep 9, 2026
fc2fcb7
Merge branch 'feature/stream-cipher' of git.bouncycastle.org:bc-rust …
ounsworth Sep 9, 2026
d66cd0b
Restructured the mem_usage_benchmarks sub-crate
ounsworth Sep 9, 2026
dc248f9
Reverting the SKILL.md changes about producing a report since this se…
ounsworth Sep 9, 2026
7539532
Moves sha512t_h0 tests out of unit tests and into integration tests. …
ounsworth Sep 9, 2026
b0bd491
rename sha2/tests/cavc_tests.rs to bc-test-data.rs to match other crates
ounsworth Sep 9, 2026
097c09b
Renaming / readability of some of the SHA2 internal traits.
ounsworth Sep 9, 2026
55f53f7
mem_usage_benches: fence the valgrind and ms_print snippets as text, …
dghgit Sep 9, 2026
0156990
sha2: the partial-byte example's three bits are message bits, not pad…
dghgit Sep 9, 2026
213473c
sha2: quote the SHA-512/t IV Generation Function as FIPS 180-4 s. 5.3…
dghgit Sep 9, 2026
5fc1370
CLAUDE.md: the build and test gates need --workspace, the mem_usage_b…
dghgit Sep 9, 2026
b11f8f6
sha2: sha512t_h0 asserts three-digit t and formats it as three digits…
dghgit Sep 9, 2026
5825050
Removing summary.md files
ounsworth Sep 12, 2026
0cc2799
minor tweaks to sha2
ounsworth Sep 12, 2026
b282942
Gave a massive hair-cut to Claude's massive release note
ounsworth Sep 12, 2026
8b48d93
Rename sha3/tasts/cavp_tests.rs to bc-test-data.rs for consistency wi…
ounsworth Sep 12, 2026
6cc74c2
small tweaks to sm3
ounsworth Sep 12, 2026
0558f26
doc change to the mem bench scripts
ounsworth Sep 12, 2026
b77f8a4
sha2: the SHA-224/256 message limit is 2^61 bytes rather than the 2^6…
dghgit Sep 13, 2026
cb0429c
sm3: the message limit is 2^61 bytes, GB/T 32905-2016 s. 5.1 allowing…
dghgit Sep 13, 2026
9c9861c
CLAUDE.md: add a scope-of-changes section, since an unrequested refac…
dghgit Sep 13, 2026
21b375c
Merge release/0.1.3alpha: HMAC and HKDF become generic utility crates…
dghgit Sep 13, 2026
91b3054
sm3: reinstate HMAC-SM3 under the per-crate layout the merge introduc…
dghgit Sep 13, 2026
3b8da02
Merge feature/stream-cipher: the HMAC and HKDF rework reaches this br…
dghgit Sep 13, 2026
3912434
core: SecurityStrength::from_bits and from_bytes become const fn, so …
dghgit Sep 16, 2026
785dbef
sha2: SHA512t becomes usable for every t FIPS 180-4 s. 5.3.6 defines …
dghgit Sep 16, 2026
4053f21
core, sha3: XOF extends Hash, so SHAKE128 and SHAKE256 are hashes; sq…
dghgit Sep 7, 2026
86819d7
sha3: pin the SHAKE block_bitlen and output_len values, which three m…
dghgit Sep 7, 2026
24ae9b4
core: XofOutput gains do_final and do_final_out, matching BC Java's d…
dghgit Sep 7, 2026
517cd59
sha3: add cSHAKE128 and cSHAKE256 (SP 800-185 Sec 3) with the Sec 2.3…
dghgit Sep 7, 2026
61d3d8e
docs: record the cargo mutants scoping flags, the bc-test-data conven…
dghgit Sep 7, 2026
63ca433
sha3: add KMAC128 and KMAC256 (SP 800-185 Sec 4) with KMACXOF, MACFac…
dghgit Sep 7, 2026
3adbfc1
core: drop the Default supertrait from Hash, so keyed constructions c…
dghgit Sep 7, 2026
b1fff3c
sha3: KMACXOF128 and KMACXOF256 as keyed XOFs, now that Hash no longe…
dghgit Sep 7, 2026
9efbf5f
core-test-framework: the XOF suite takes a constructor closure, so ke…
dghgit Sep 7, 2026
3913b55
sha3: add TupleHash and TupleHashXOF (SP 800-185 Sec 5), where each u…
dghgit Sep 7, 2026
90bd179
sha3: add ParallelHash and ParallelHashXOF (SP 800-185 Sec 6), comple…
dghgit Sep 7, 2026
5c6302a
cli: add tuplehash and parallelhash subcommands, completing SP 800-18…
dghgit Sep 7, 2026
68a3dbc
sha3: pin the Hash and XOF trait views of TupleHash, ParallelHash and…
dghgit Sep 7, 2026
50c125b
factory: replace the todo stub in xof_factory_tests with a differenti…
dghgit Sep 7, 2026
b95dd0c
core: Hash gains Clone as a supertrait, so a hash mid-stream can be f…
dghgit Sep 9, 2026
6707002
core: XOF gains default hash_xof and hash_xof_out bodies so only SHAK…
dghgit Sep 10, 2026
b466d95
core-test-framework: add test_hash_output_buffers, a closure-built Ha…
dghgit Sep 10, 2026
0e8b2f7
sha3: TupleHash and ParallelHash panicked on an output buffer shorter…
dghgit Sep 10, 2026
ad3fa52
core: drop XOFOutput::do_final and do_final_out, which no implementor…
dghgit Sep 10, 2026
8810ae7
core, core-test-framework, sha3, factory, mldsa, mlkem, cli: rename t…
dghgit Sep 14, 2026
0a2bb8f
core, core-test-framework, sha3: a final read of a XOF binds its outp…
dghgit Sep 14, 2026
8a46683
CLAUDE.md: record the cargo mutants mechanics this repo needs, since …
dghgit Sep 14, 2026
b5fcf99
core, core-test-framework: AEADCipherEncryptor/AEADCipherDecryptor ga…
officialfrancismendoza Sep 9, 2026
120b2fe
ascon, cli: add bouncycastle-ascon (SP 800-232 Ascon-AEAD128/Hash256/…
officialfrancismendoza Sep 9, 2026
2c479f4
Rebased #120 onto #118. Ported ASCON XOF/CXOF to new Hash/XOF/XOFSque…
officialfrancismendoza Sep 17, 2026
465e684
Minor doc fix to lib.rs given new XOF api (#119)
officialfrancismendoza Sep 17, 2026
7d8165b
sha2: SHA512t drops its FIPS-approval gate, per review on #133 -- SHA…
dghgit Sep 18, 2026
8e84dee
hmac: drop the stale dev-dependency comment block from Cargo.toml, wh…
dghgit Sep 18, 2026
386bbe3
Remediated documentation and test concerns (#119)
officialfrancismendoza Sep 18, 2026
61a0623
Merge remote-tracking branch 'origin/feature/simple-ciphers' into fea…
dghgit Sep 19, 2026
0161af2
Merge remote-tracking branch 'origin/release/0.1.3alpha' into feature…
dghgit Sep 19, 2026
76bb967
Merge remote-tracking branch 'origin/feature/simple-ciphers' into fea…
dghgit Sep 19, 2026
f28c388
Minor adjustment to the SHA512t docs.
ounsworth Sep 19, 2026
d64ed7c
sha2: address ounsworth's SHA512t re-review comments on #133 (SHA-384…
dghgit Sep 19, 2026
e59229d
Merge remote-tracking branch 'origin/feature/simple-ciphers' into fea…
dghgit Sep 19, 2026
631282c
Tweaks to docs for the new symmetric cipher traits.
ounsworth Sep 20, 2026
33576fc
modes: StreamCipherEncryptor::do_encrypt/encrypt/encrypt_rng and Stre…
dghgit Sep 20, 2026
86b2ed0
modes: BlockCipherEncryptor::do_encrypt_blocks/do_encrypt/encrypt/enc…
dghgit Sep 20, 2026
8beef64
core, padding: rename the trait bouncycastle_core::traits::Padding to…
dghgit Sep 20, 2026
4568928
Merge remote-tracking branch 'origin/feature/simple-ciphers' into fea…
dghgit Sep 20, 2026
3d265ad
Merge remote-tracking branch 'origin/feature/xof-cshake' into feature…
dghgit Sep 20, 2026
6d849a1
cli, ascon: document the generated-nonce stream layout and the 8 MiB …
dghgit Sep 20, 2026
bbc04e3
release notes: the current bouncycastle-ascon mutation figures (#119)
dghgit Sep 20, 2026
2f7c32a
core, core-test-framework, ascon: delete the AEADCipher trait, supers…
dghgit Sep 20, 2026
80098c4
release notes: record the AEADCipher removal and re-measure the mutat…
dghgit Sep 20, 2026
702246a
core, core-test-framework, ascon, cli: carry the inline ciphertext||t…
dghgit Sep 20, 2026
c8190be
release notes: re-measure bouncycastle-ascon after the AEAD trait cha…
dghgit Sep 20, 2026
f376c14
core, core-test-framework: close the mutation gaps a scoped run found…
dghgit Sep 20, 2026
a1468a9
release notes: record the scoped mutation figures for the AEAD trait …
dghgit Sep 20, 2026
7357e86
core, modes, aes, padding: rename SimpleCipherEncryptor / SimpleCiphe…
dghgit Sep 21, 2026
f99bf72
core, padding, modes: rename SymmetricCipherError::IncorrectOutputBuf…
dghgit Sep 21, 2026
8a13369
Merge branch 'feature/simple-ciphers' into feature/xof-cshake
dghgit Sep 21, 2026
ac72292
Merge branch 'feature/xof-cshake' into feature/officialfrancismendoza…
dghgit Sep 21, 2026
62e6a2b
docs: fix contributing typos
officialfrancismendoza Sep 21, 2026
7535274
Re-adding the changes I had committed on this branch a few days ago, …
ounsworth Sep 22, 2026
dcec6b8
Some docs tweaks
ounsworth Sep 22, 2026
df43a87
aes, core: restore the FIPS 197 Appendix B known-answer values in the…
dghgit Sep 22, 2026
ed09ae0
Merge branch 'feature/simple-ciphers' into feature/xof-cshake
dghgit Sep 22, 2026
e18dd46
core, modes, aes, core-test-framework: make do_encrypt_init_rng panic…
dghgit Sep 22, 2026
cf78449
Merge branch 'feature/simple-ciphers' into feature/xof-cshake
dghgit Sep 22, 2026
336f9cb
core, core-test-framework, ascon, cli: make AEADCipherEncryptor/AEADC…
dghgit Sep 24, 2026
2eb7a99
ascon: add Ascon_AEAD128<Dir>, naming the AEAD pair by direction
dghgit Sep 24, 2026
c89663a
Merge remote-tracking branch 'origin/feature/xof-cshake' into trial/c…
dghgit Sep 24, 2026
570ae03
Initial add of AES lightweight CCM mode (#125)
officialfrancismendoza Sep 10, 2026
5d5cf5c
core, modes: document why AEADCipherEncryptor/Decryptor were not resh…
officialfrancismendoza Sep 14, 2026
3dd3266
cli: --nonce-file for CCM reads raw bytes only, never hex-decodes
officialfrancismendoza Sep 15, 2026
3be43fb
modes, core: zeroize CCM's CBC-MAC state, and make BUFFER_LEN vs the …
officialfrancismendoza Sep 15, 2026
e95a25b
modes: batch CCM's CTR half, and fix docs that claimed it was impossible
officialfrancismendoza Sep 15, 2026
9f437ab
cli: stop BlockModeAction's shared help from describing behaviour CCM…
officialfrancismendoza Sep 15, 2026
4282833
cli: process CCM input in place instead of allocating a second buffer
officialfrancismendoza Sep 15, 2026
ac13ce0
modes: dedupe CcmEncryptor/CcmDecryptor over a shared CcmBuffer, drop…
officialfrancismendoza Sep 15, 2026
e877a32
modes: add a Wycheproof AES-CCM suite, move/drop CCM unit tests that …
officialfrancismendoza Sep 15, 2026
1b593c5
modes: close the mutation-testing gaps the batching and buffer-bounda…
officialfrancismendoza Sep 15, 2026
afa2b3c
modes: adapt CCM buffer errors to the #120 API
officialfrancismendoza Sep 21, 2026
8a24373
Fixed formatting with cargo fmt (#125)
officialfrancismendoza Sep 21, 2026
24a646c
Remediated concerns. F1-F10 fixed except F9 (optional), which was lef…
officialfrancismendoza Sep 23, 2026
b8a217f
Style / docs refactors: renamed AES, AES_128, AES_192, AES_256 to AES…
ounsworth Sep 24, 2026
67a7b45
modes, aes, core-test-framework: port CcmEncryptor/CcmDecryptor to th…
dghgit Sep 24, 2026
7a6e2a4
Initial add of AES lightengine GCM mode (#124)
officialfrancismendoza Sep 14, 2026
6bd4ed7
modes, aes, cli: follow the base branch's API renames in AES-GCM (#124)
dghgit Sep 24, 2026
788fd06
modes, aes, cli: implement AEADCipherEncryptor/AEADCipherDecryptor fo…
dghgit Sep 24, 2026
9da20d3
cli, modes, mem_usage_benches, aes: finish the AES_128 / AES_192 / AE…
ounsworth Sep 24, 2026
334cd2b
core, aes, modes, core-test-framework: make ElectronicCodeBook's encr…
dghgit Sep 25, 2026
15c2fa5
Merge branch 'feature/simple-ciphers' into feature/xof-cshake
dghgit Sep 25, 2026
52e63bc
Merge branch 'feature/xof-cshake' into feature/officialfrancismendoza…
dghgit Sep 25, 2026
e691aed
Merge the updated CCM branch into feature/officialfrancismendoza/124-…
dghgit Sep 25, 2026
127dddf
* BIG CHANGE: refactored this from Pornin's 32-bit bitsliced impl to …
ounsworth Sep 25, 2026
a559934
Applied skills/memory-hygiene-in-rust/SKILL.md and shaved the AES imp…
ounsworth Sep 25, 2026
a57d7dd
Applied skills/memory-hygiene-in-rust/SKILL.md and shaved the AES imp…
ounsworth Sep 25, 2026
627f619
docs tweaks
ounsworth Sep 26, 2026
8823c7b
Refactor core: removed SecurityStrength and impls from traits.rs
ounsworth Sep 26, 2026
7002d4a
core: fix the three do_hazardous_operations doctests broken by 8823c7…
dghgit Sep 26, 2026
a06b83a
Merge PR #137 (secbug/mldsa87_wycheproof: ML-DSA missing reduce32 lea…
dghgit Sep 26, 2026
77edc43
Merge branch 'feature/simple-ciphers' into feature/xof-cshake
dghgit Sep 26, 2026
d05e50e
Merge remote-tracking branch 'bcgit/feature/xof-cshake' into feature/…
officialfrancismendoza Sep 27, 2026
dd4e5f6
Merge remote-tracking branch 'origin/feature/officialfrancismendoza/1…
officialfrancismendoza Sep 27, 2026
2161a04
Fix batched keystream left on stack (#125)
officialfrancismendoza Sep 27, 2026
16a4ba5
Merge remote-tracking branch 'bcgit/feature/xof-cshake' into feature/…
officialfrancismendoza Sep 27, 2026
8e23ced
Merge the CCM branch (2161a04) into feature/officialfrancismendoza/12…
dghgit Sep 27, 2026
985eb94
modes: zeroize CTR's batched and single-block keystream, as 2161a04 d…
dghgit Sep 27, 2026
6a061ed
modes: CCM review fixes -- decryptor nonce floor, one error variant f…
dghgit Sep 27, 2026
f527ac9
aes: AES_CCM_*_Encryptor docs -- the nonce floor applies to the decry…
dghgit Sep 27, 2026
5de0f7d
cli: aes*-ccm -- warn on a nonce file ending in a newline, and explai…
dghgit Sep 27, 2026
30b871b
mem_usage_benches: make the CCM harness measure the streaming path it…
dghgit Sep 27, 2026
68a8934
aes: drop the redundant explicit link targets in the CCM module docs
dghgit Sep 27, 2026
174563c
mem_usage_benches: state the CCM streaming figures against the baseli…
dghgit Sep 27, 2026
62afc19
Intermediate add for CI fix changes
officialfrancismendoza Sep 27, 2026
2c32883
Merge remote-tracking branch 'origin/feature/officialfrancismendoza/1…
officialfrancismendoza Sep 27, 2026
3cee19b
Remove .claude/settings.json (#124)
dghgit Sep 27, 2026
2ed6768
modes: update the crate docs for GCM (#124)
dghgit Sep 27, 2026
01d725e
modes: keep GCM's H, tag mask and computed tag out of unzeroized stac…
dghgit Sep 27, 2026
117f06b
cli: --aad-file for GCM reads raw bytes only, never hex-decodes (#124)
dghgit Sep 27, 2026
f8f7a2e
modes: Ctr keeps its keystream out of unzeroized stack arrays, refill…
dghgit Sep 27, 2026
8575ea7
Merge branch 'feature/simple-ciphers' into feature/xof-cshake
dghgit Sep 27, 2026
7e83f10
Merge remote-tracking branch 'origin/feature/xof-cshake' into feature…
dghgit Sep 27, 2026
840bf42
Merge remote-tracking branch 'origin/feature/xof-cshake' into feature…
dghgit Sep 27, 2026
7aa826d
Merge the CCM branch (840bf42) into feature/officialfrancismendoza/12…
dghgit Sep 27, 2026
013d806
Aesthetic changes to padded_block_cipher
ounsworth Sep 27, 2026
3d7c5a7
Removed an uncessary turbofish from test code
ounsworth Sep 27, 2026
3ecabfd
Merge PR #126 (feature/officialfrancismendoza/125-AES-lightengine-CCM…
dghgit Sep 28, 2026
f8400c3
Merge PR #132 (feature/officialfrancismendoza/124-AES-lightengine-GCM…
dghgit Sep 28, 2026
6705a3f
Merge branch 'feature/xof-cshake' into feature/simple-ciphers
dghgit Sep 28, 2026
793c7f1
docs tweaks to modes
ounsworth Sep 28, 2026
1689005
modes, padding, core: follow-ups to 793c7f1's modes docs restructure …
dghgit Sep 28, 2026
f62f107
Restructuring of the cipher modes docs
ounsworth Sep 28, 2026
67a6f65
modes: Ccm's inherent one-shots take the library's _out names -- encr…
dghgit Sep 28, 2026
2d4d038
modes: fix the two doctests f62f107 left failing -- cbc.rs's streamin…
dghgit Sep 28, 2026
5946992
gitignore: stop un-ignoring .claude/settings.json, so a contributor's…
dghgit Sep 28, 2026
eaff5a5
Renaming the acvp_gcm helper file to indicate that it's a helper.
ounsworth Sep 28, 2026
085d1d9
Adding tests for ccm mode, specifically one that demonstrates that th…
ounsworth Sep 28, 2026
baf16b9
Adding tests for ccm mode, specifically one that demonstrates that th…
ounsworth Sep 28, 2026
9d7b354
Renamed SymmetricCipher from do_update to do_encrypt / do_decrypt.
ounsworth Sep 28, 2026
603d1cd
core, core-test-framework, modes: rename BlockCipherEncryptor::encryp…
dghgit Sep 28, 2026
bd6b8c1
core, core-test-framework, modes, aes, cli, mem_usage_benches: Stream…
dghgit Sep 28, 2026
d32af54
cli: aes{128,192,256}-ccm take --aad-file, raw bytes and never hex-de…
dghgit Sep 28, 2026
93eb292
modes: remove test_large_payload_symmetric_cipher, which still fails …
dghgit Sep 29, 2026
0fb4e79
modes: pin CCM_MAX_BUFFER_LEN at 512 KiB and CcmKeyStream's absolute …
dghgit Sep 29, 2026
ee3d2f3
Did a pass over CFB and CFB8 docs.
ounsworth Sep 29, 2026
305e7f1
Adjusted memory footprint benches
ounsworth Sep 16, 2026
90afcc4
Re-ran mem benches to get new values.
ounsworth Sep 16, 2026
74595a9
Claude found some sloppy pass-by-values that resulted in 2 extra copi…
ounsworth Sep 16, 2026
66893c9
Claude found reconstruction of pk from sk lead to unintentional copie…
ounsworth Sep 16, 2026
5433b65
Claude optimized pass-by-reference function signatures
ounsworth Sep 17, 2026
9614bc0
Claude optimized placing a short-lived value into its own scope.
ounsworth Sep 17, 2026
362ff35
Claude optimized variable usage to avoid duplicate copies
ounsworth Sep 17, 2026
fbbea01
Claude found an insidious .try_into() that made a silent copy
ounsworth Sep 17, 2026
f12e1a4
Claude optimized the Hint, which is one bit per coeff -- instead of b…
ounsworth Sep 17, 2026
d333337
Avoiding a .try_into() that makes a silent copy.
ounsworth Sep 17, 2026
cb48a99
Optimized buffer reuse.
ounsworth Sep 17, 2026
4831203
Misc cleanup.
ounsworth Sep 17, 2026
37d0ecf
Updated bench tables.
ounsworth Sep 17, 2026
f587491
Tweaked the SHAKE buffering to match the SHAKE internal block size.
ounsworth Sep 17, 2026
1f08985
Minor aesthetic cleanup of the new packed make_hint.
ounsworth Sep 17, 2026
e25aaf8
Fable adjusted the memory benchmarking harnesses to account for how L…
ounsworth Sep 18, 2026
95ad2d1
Fixed a bug in memory benches where mldsa verify had the public key a…
ounsworth Sep 18, 2026
0c52a6b
Fable optimized away some uneccessary copies in the non-lowmemory imp…
ounsworth Sep 18, 2026
ecc4466
Fable optimization to put #[inline(never)] guards around the A_hat ex…
ounsworth Sep 18, 2026
c05869b
Saving the Fable lessons-learned from memory hygiene into a claude sk…
ounsworth Sep 18, 2026
2cb124f
QUALITY_AND_STYLE: drop the duplicated pointer to the memory-hygiene …
ounsworth Sep 18, 2026
681ead7
Claude pointed out comments that were now out of alignment with the c…
ounsworth Sep 19, 2026
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
246 changes: 246 additions & 0 deletions .claude/skills/memory-hygiene-in-rust/SKILL.md

Large diffs are not rendered by default.

120 changes: 120 additions & 0 deletions .claude/skills/memory-hygiene-in-rust/references/case-studies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Case studies behind the rules (bc-rust, September 2026)

Every number is a massif peak in bytes on the `mem_usage_benches` harness, release build, x86_64,
measured before and after a single change. "Full" is `bouncycastle-mldsa` / `-mlkem`; "lowmem" is
the `-lowmemory` crate.

## 1. "Only 32 bytes" was not free

`make_hint_row` in mldsa-lowmemory took `out: &mut HintRow` (32 bytes) and returned the weight.
Changing it to return `(HintRow, i32)` by value, on the argument that 32 bytes cannot matter, added
exactly **+16 bytes** of peak on all three lowmem sign benches. Returning just `HintRow` and computing
the weight with popcount: also +16. Reverted. The sibling `unpack_h_row` on the verify path went to
`Option<HintRow>` at measured **0** bytes, because it was already the deepest frame there. Same
type, same size, opposite results: the frame context decides, not the type.

## 2. Decaps benches were measuring keygen

Every ML-KEM decaps bench called `keygen_from_seed` inside the measured binary. Hard-coding the
encoded private key instead:

| | old | in-main decode | helper decode |
|---|---|---|---|
| ML-KEM-512 decaps | 24136 | 28408 | 21592 |
| ML-KEM-768 decaps | 39800 | 44072 | 33416 |
| ML-KEM-1024 decaps | 63800 | 62792 | 49224 |

The "in-main" column is the first attempt, with the key byte array and `from_bytes` in the bench
body: worse than keygen for 512 and 768, because the array and the `Result` temporary stayed live
under decaps. Moving the load into an `#[inline(never)]` helper gave the third column. The old table
had over-reported decaps by up to 14.6 kB.

## 3. Sign 44 went up 8.7 kB with no code change in sign

After item 2's helper pattern was applied to ML-DSA, `Sign/ML-DSA-44` rose 93720 → 102456 with
identical instruction counts. Frame remarks: the bench `main` was 73608 bytes in both builds with
sign fully inlined into it. The key-load helper (12.5 kB) and `from_bytes` (14.6 kB) were being
called from that `main`, so they stacked on top of the already-allocated 73.6 kB frame. Fix: run the
operation in a separate non-inlined, non-returning closure so load and op are sibling frames.
Residual after the fix: **+2.1 kB**, the boundary's own spills. A wrapper that *returned* the
signature cost 4.6 kB instead: the 2.4 kB result was copied across the boundary.

## 4. Plain/expanded pairs reporting identical peaks

Before the harness rework, every `Encaps`/`Encaps_expanded_pk` pair and every
`Sign`/`Sign_expanded_sk` pair reported byte-identical peaks. That only happens when the key decode
in the bench body, not the operation, sets the peak. Treat identical numbers across variants that
do different work as a harness bug, not a coincidence.

## 5. A heap `Vec` deleted 3 to 5 kB from two table rows

`bench_mldsa65_lowmemory_verify` and the 87 variant decoded their signature with `hex::decode` into
a `Vec<u8>`. Massif `--heap=no` ignores the heap, so those rows under-reported by one signature
each (3309 and 4627 bytes) relative to the 44 row, which used a stack array. Converting them moved
the rows 15864 → 19096 and 17784 → 22328.

## 6. `sig_decode` returned an 11 kB tuple

`fn sig_decode(sig) -> Result<(SigCTilde, VecL, VecK), ()>`. When LLVM inlined it, fine. When fed a
runtime-length slice it did not inline it, and the remarks showed three copies of the 11.3 kB tuple
live at once (local, return slot, destructured bindings) plus `sig_decode`'s own 23.6 kB frame under
verify: **+18 to +24 kB** depending on caller shape. Out-parameters (`c_tilde: &mut, z: &mut,
h: &mut`, returning `Result<(), ()>`) removed it structurally: full-crate verify −6 to −20 kB across
parameter sets, 44 sign −9 to −12 kB.

## 7. `Matrix::new()` built a 56 kB temporary through `array::map`

`Self { elems: [[(); l]; k].map(|_| [(); l].map(|_| Polynomial::new())) }` goes through
`core::array::drain::drain_array_with`, which materialises the full matrix before copying it. It was
invisible until the fix in item 6 changed inlining and a **57368-byte** `drain_array_with` frame
appeared under `expandA`, adding 47 kB to one bench. Repeat expression `[[Polynomial::new(); l]; k]`
(elements are `Copy`, `new` is `const`) removed it. The same pattern in the full `mlkem` crate was
*not* being materialised (its matrix is 4 to 16 kB and LLVM folded it); changing it there moved
three table rows up 2 to 3 kB from inlining alone, so it was reverted. Structural correctness did
not win over measurement.

## 8. An unused `match` arm cost 57 kB

```rust
match a_hat {
Some(a) => sign_internal(sk, a, ...),
None => { let mut a = Matrix::new(); sk.expand_into(&mut a); sign_internal(sk, &a, ...) }
}
```
The `None` arm's local is allocated in the frame on both paths, so every expanded-key caller paid
for a matrix it never used (`sign_mu_deterministic` frame 62 kB). Fix: the arm calls an
`#[inline(never)]` helper that owns the local. Cost: 5 to 6 kB on the plain paths for the extra
boundary, which was accepted.

## 9. Converting a return to an out-parameter added a copy

`fn A_hat(&self) -> M { expandA(&self.rho) }` was a tail call; LLVM forwarded the return slot into
`expandA`, so only `expandA`'s own local existed. After `expandA` took `&mut M`, `A_hat` became
`let mut m = M::new(); expandA(&self.rho, &mut m); m`, and LLVM did not elide the move: the by-value
`A_hat()` path gained a full extra matrix. Keygen and plain verify improved by 13 to 49 kB and 12 to
50 kB from the same change, expanded-key construction regressed by 10 to 53 kB. Constructors of the
form `let mut s = Self { big: M::new(), .. }; fill(&mut s.big); s` showed three copies; returning a
struct literal built from locals showed two. Getting to one copy for a by-value constructor was not
achievable in safe Rust without an out-parameter API; that became a follow-up.

## 10. The deleted reduction

Not a memory case, but found with the same tools and worth keeping next to them. A plain `reduce32`
before `inv_ntt` existed from the first ML-DSA commits, was commented out on 2026-03-20 because
`cargo mutants` and the full bc-test-data set passed without it, and was deleted the next day. In
September 2026 Wycheproof's `MissingReduction` vectors showed the 8-level inverse-NTT butterflies
overflow `i32` when fed an unreduced sum of `l+1` Montgomery products: a valid signature rejected and
a forgery accepted in release. Restored at all nine accumulation sites in both crates; Criterion
showed the cost below the noise floor (median −0.7 % across 30 benches, one +5 % outlier that
re-ran at −1.3 %). Bound-keeping steps are dead code to every test that uses honest inputs.

## Measured noise floors on this harness

| Crate family | Layout noise between builds |
|---|---|
| lowmem (ML-KEM, ML-DSA) | ≤ 0.2 kB |
| full ML-KEM | 1 to 4 kB |
| full ML-DSA | 2 to 9 kB |

Massif itself is deterministic: identical binaries give identical peaks. The noise is in what the
compiler does with a differently shaped caller, not in the measurement.
69 changes: 69 additions & 0 deletions .claude/skills/memory-hygiene-in-rust/scripts/frame_layout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""Summarise rustc/LLVM stack-frame remarks: per-function frame sizes and large stack objects.

Build with (stable toolchain is fine):
RUSTFLAGS="-C remark=stack-frame-layout -C remark=prologepilog -C debuginfo=1" \
CARGO_TARGET_DIR=/tmp/remarks cargo build --release -p <crate> --bin <bin> 2> remarks.txt
then:
frame_layout.py remarks.txt [name-regex] [--min-object BYTES] [--top N]

Prints the largest frames ('N stack bytes in function' from the prologepilog remark) and, for each
matching function, its stack objects at or above --min-object (from the stack-frame-layout remark).
Names are demangled crudely from the v0 scheme. Start with NO name filter: the copy you are looking
for is often in a std/core frame such as core::array::drain::drain_array_with.
"""
import re, sys

def demangle(sym):
parts = []
for m in re.finditer(r"(\d+)(_?)([A-Za-z_][A-Za-z0-9_]*)", sym):
n = int(m.group(1)); ident = m.group(3)[:n]
if len(ident) == n and not ident.startswith("Cs"):
parts.append(ident)
return "::".join(parts) if parts else sym

def main():
args = sys.argv[1:]
if not args:
print(__doc__); sys.exit(1)
path = args.pop(0)
min_obj = 4096; top = 20; pattern = None
while args:
a = args.pop(0)
if a == "--min-object": min_obj = int(args.pop(0))
elif a == "--top": top = int(args.pop(0))
else: pattern = re.compile(a)
text = open(path, errors="replace").read()
text = re.sub(r"_R[A-Za-z0-9_]+", lambda m: demangle(m.group(0)), text)
text = re.sub(r"_ZN[0-9]+_?", "", text)
text = re.sub(r"17h[0-9a-f]{16}E", "", text)
for a, b in (("$LT$", "<"), ("$GT$", ">"), ("$u20$", " "), ("$C$", ","), ("$RF$", "&"), ("..", "::")):
text = text.replace(a, b)

frames = {}
for m in re.finditer(r"(\d+) stack bytes in function '([^']+)'", text):
frames[m.group(2)] = max(frames.get(m.group(2), 0), int(m.group(1)))
objects = {}
cur = None
for line in text.splitlines():
m = re.match(r"\s*Function: (.*)", line)
if m: cur = m.group(1).strip(); objects.setdefault(cur, []); continue
m = re.match(r"\s*Offset: \[SP[-+]\d+\], Type: (\w+), Align: \d+, Size: (\d+)", line)
if m and cur is not None:
objects[cur].append((int(m.group(2)), m.group(1)))

noise = re.compile(r"backtrace|gimli|driftsort|panicking|rustc_demangle|std::sys|addr2line|miniz")
rows = sorted(((sz, n) for n, sz in frames.items() if not noise.search(n) and (pattern is None or pattern.search(n))), reverse=True)
print(f"largest frames (top {top}):")
for sz, n in rows[:top]:
print(f"{sz:9d} {n[:140]}")
print(f"\nstack objects >= {min_obj} bytes:")
for sz, n in rows[:top]:
big = sorted((o for o in objects.get(n, []) if o[0] >= min_obj), reverse=True)
if big:
print(f" {n[:120]}")
for osz, kind in big:
print(f" {osz:8d} {kind}")

if __name__ == "__main__":
main()
38 changes: 38 additions & 0 deletions .claude/skills/memory-hygiene-in-rust/scripts/massif_peak.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Peak stack of one or more mem_usage_benches functions, via valgrind massif.
#
# massif_peak.sh <bin> <label> <bench_fn>...
# e.g. massif_peak.sh bench_mldsa_mem_usage after bench_mldsa44_sign bench_mldsa44_verify
#
# For each function it rewrites main() of mem_usage_benches/<bin>.rs to call only that function,
# builds --release, runs the binary under massif with --heap=no --stacks=yes, and prints
# "<label> <fn> <peak_bytes>". The bench source is restored afterwards (also on failure).
# Per-run artifacts go to $MASSIF_OUT (default /tmp/massif_peak): the massif file, stdout and stderr
# of the bench, so outputs can be diffed between labels (signatures must be identical, verifies
# must succeed) and the massif time series can be inspected:
# awk -F= '/^time=/{t=$2} /^mem_stacks_B=/{print t, $2}' $MASSIF_OUT/massif_<label>_<fn>.out
#
# Run from the repository root. Do not edit the bench source while this is running.
set -euo pipefail
BIN=$1; LABEL=$2; shift 2
OUT=${MASSIF_OUT:-/tmp/massif_peak}; mkdir -p "$OUT"
F="mem_usage_benches/$BIN.rs"
SAVED="$OUT/${BIN}_saved_${LABEL}.rs"
cp "$F" "$SAVED"
trap 'cp "$SAVED" "$F"' EXIT
for fn in "$@"; do
cp "$SAVED" "$F"
python3 - "$F" "$fn" <<'PY'
import sys
path, fn = sys.argv[1], sys.argv[2]
src = open(path).read()
i = src.index("fn main() {")
open(path, "w").write(src[:i] + "fn main() {\n " + fn + "()\n}\n")
PY
cargo build -q --release -p mem_usage_benches --bin "$BIN"
massif="$OUT/massif_${LABEL}_${fn}.out"
valgrind --tool=massif --heap=no --stacks=yes --massif-out-file="$massif" \
-- "target/release/$BIN" >"$OUT/out_${LABEL}_${fn}.txt" 2>"$OUT/err_${LABEL}_${fn}.txt" || true
peak=$(grep '^mem_stacks_B=' "$massif" | cut -d= -f2 | sort -n | tail -1)
echo "$LABEL $fn $peak"
done
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
Cargo.lock
**/target
mutants.out*/
custom_mutants_output/


.idea/
.vscode/

# editor swap / backup files
*.swp
*.swo
*~

# Claude Code: ignore personal/local state, but share team tooling
# (skills, slash commands and subagents). settings.json stays local, so personal permission
# allowlists cannot ride along in a PR.
.claude/*
!.claude/skills/
!.claude/commands/
!.claude/agents/
.claude/settings.local.json
.claude 2/
Loading