Repository navigation
Conversation
Contributor
|
We had agreed not to add more ciphers until we get through reviewing and locking in the overall architecture via the AES work. Closing this PR for now. |
dghgit
force-pushed
the
feature/camellia
branch
from
September 28, 2026 10:36
482b254 to
caab3e9
Compare
dghgit
changed the base branch from
feature/xof-cshake
to
feature/simple-ciphers
September 28, 2026 15:49
…llia ported from bc-java New crate `crypto/camellia` (`bouncycastle::camellia`): the Camellia block cipher (RFC 3713) with 128-, 192- and 256-bit keys as a raw keyed permutation implementing ElectronicCodeBook -- Camellia_128 / Camellia_192 / Camellia_256 over a sealed CamelliaParams -- ported from BC Java's CamelliaEngine and CamelliaLightEngine and commented line by line against the RFC. The S-boxes are a 121-gate Boolean circuit (32 AND, 74 XOR, 9 XNOR, 6 NOT) over eight u32 bit-planes rather than the Java engines' tables (4 KiB, or 256 B in the light engine), so there is no secret-indexed memory access in the cipher or the key schedule. SBOX1 is GF(2^8) inversion between two affine maps -- a decomposition found by exhaustive search against the RFC's table: of the 256 input constants exactly one (0xc5) admits it, unique up to the inverse's own symmetries -- so the non-linear section of the Boyar-Peralta AES circuit (copied from aes) does the inversion, with generated affine layers chosen among the 2040 equivalent forms for the fewest gates. SBOX2/3/4 are one-bit byte rotations of SBOX1, which on bit-planes are plane renumberings under compile-time position masks, so one circuit serves all four. The u32 planes hold four blocks' F-inputs per pass: encrypt_4blocks/decrypt_4blocks are the natural unit, the trait's blocks8 is two passes and blocks2 uses two lanes. The four-lane u32 design keeps the per-call working set near 160 B (half the u64 alternative), which is the "lowmemory" in the name. One stored schedule (208 B / 272 B, in a Secret) serves both directions via the Sec 2.3.3 subkey swap. Also: Camellia_CBC_128/192/256<Dir> aliases over bouncycastle-modes; camellia128-cbc / camellia192-cbc / camellia256-cbc CLI subcommands sharing cbc_cmd.rs; criterion bench; mem_usage_benches harness; umbrella re-export; release notes. Verified against RFC 3713 Appendix A (all three key lengths, every lane and slot of the four-, eight- and two-block paths, both directions); all 3840 vectors of NTT's CRYPTREC test-vector file t_camellia.txt (ten keys per key length, 128 single-bit plaintexts each, both directions, transcribed mechanically); the nine vectors of BC Java's CamelliaTest (RFC 3713 and NESSIE); the CAMELLIA-*-CBC vectors of OpenSSL's evpciph_camellia.txt through the CBC aliases; a transcription of CamelliaLightEngine kept in the tests, which the engine must agree with on thousands of keys and blocks of every length in every lane and both directions; ElectronicCodeBook conformance for all three types; and the CLI against the OpenSSL vectors. cargo mutants: 552 mutants, 533 caught, 6 unviable, 13 missed -- all thirteen proven |/^ equivalences on disjoint bits or the documented Boyar-Peralta t37 gate, commented at the site. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ddedMode projection, and the block-aligned vectors move onto modes::Cbc
…e invalid, driving the padding crate's constant-time unpad with adversarial input
…e permutation, and Block and the concrete params types are no longer exported
Doc comments scattered per-file citations to BC Java's CamelliaEngine and CamelliaLightEngine (their table-driven S-boxes, the camelliaF2 rotation trick, per-direction subkey layout, the SIGMA array) throughout lib.rs, round.rs, schedule.rs and camellia.rs. The crate's Provenance section already names both as the source engines this crate is ported from and describes what it reproduces; the scattered comparisons are replaced with self-contained descriptions of the same points that don't depend on the reader having BC Java's source open. Test files that cross-check against BC Java's own vectors (tests/bc_java_tests.rs, tests/common/mod.rs) are untouched, since BC Java is literally their subject. No behavioural change; cargo fmt --check is clean; cargo test -p bouncycastle-camellia passes (13 passed). Assisted-by: Claude:claude-sonnet-5 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…```text Same issue as PR #139 (tdes): mem_usage_benches/src/lib.rs makes every bench source a module of a lib target, so its //! header is rustdoc'd and an indented block compiles as a Rust doctest by default. Fenced as ```text like the other bench binaries. Assisted-by: Claude:claude-sonnet-5 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…aliases and their camellia{128,192,256}-{cfb,cfb8,ctr} CLI commands, so Camellia covers the same four modes AES does rather than CBC alone -- `bouncycastle-modes` is cipher-agnostic and its Cfb, Cfb8 and Ctr already work over any ElectronicCodeBook, so each alias is one line of type plus the const parameters Camellia fills in (16/24/32-byte keys, a 16-byte block, and a 12-byte CTR nonce leaving the 4-byte counter the mode caps at, the same split bouncycastle-aes chooses for its 16-byte block). RFC 3713 specifies only the permutation and assigns identifiers for CBC (Sec 3), so each of the three new modes is pinned against the best published source there is, and the three sources need different handling. CFB128: the CAMELLIA-*-CFB entries of OpenSSL's evpciph_camellia.txt (3.6.2) chain into one four-block message per key length under the IV 000102..0f, over SP 800-38A Appendix F's plaintext and keys, and are straight known-answer tests through the aliases, driven under the vector's own IV via a FixedSeedRNG exactly as the existing CBC vectors are. CTR: RFC 5528's nine Camellia-CTR vectors build the counter block as a 4-octet nonce, an 8-octet IV and a block counter starting at one, which is the IPsec convention and not one the nonce/counter split can produce, so those vectors pin a reference CTR written from the SP 800-38A Sec 6.5 equations over the permutation and the aliases are then required to agree with that reference on the counter blocks they do produce; the CTR docs and the camellia*-ctr help both say ciphertexts do not interoperate with an RFC 5528 implementation. CFB8: there is no published vector -- the OpenSSL file says in as many words that it does not carry CFB{1,8}-CAMELLIAxxx -- so the aliases are held to the Sec 6.3 equations at s = 8 evaluated over the permutation. stream_mode_alias_tests.rs covers the wiring the vectors do not: that each of the nine aliases names the mode it claims to, round-trips at any length with no padding, gives the same answer whatever the chunking, draws fresh init data per encryption, and that CFB128, CFB8 and CTR are mutually distinct. The nine CLI commands are thin dispatchers over the existing stream_mode_cmd plumbing, so they inherit the IV-in-the-ciphertext convention, the 1 KiB streaming chunk and the key loader unchanged; their tests pin the OpenSSL CFB vectors end to end through the pipe and hold camellia*-cfb8 and camellia*-ctr to the library for the two modes without usable vectors. No new mutants: `cargo mutants -p bouncycastle-camellia --list` reports the same 550 before and after, because the three new source files are type aliases and documentation with no executable code of their own. quality_stats.sh's "unwraps in core code" for camellia goes 0 -> 44, all of it `.unwrap()` inside the new doctests, which the script counts from src/ without distinguishing doc comments; the doctests are written in the same style as crypto/aes/src/{cfb,cfb8,ctr}.rs, which is why aes reports 58.
Assisted-by: Claude:claude-opus-5
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…en pipe on the error paths -- the identical harness on feature/sm4 failed the Rust Tests workflow, and these three suites carry the same latent race. `a_key_of_the_wrong_length_is_rejected` writes its stdin payload from the test thread and `.expect()`s the result, but the command it invokes rejects the key and `exit`s before reading a byte, so the write races the child's exit and gets EPIPE; it happened to win the race on this branch's CI run and lose on sm4's. The assertion the test actually makes -- non-zero status, and the algorithm named in stderr -- is unaffected, because `wait_with_output` still returns both, so the fix is to match on the write result and ignore `ErrorKind::BrokenPipe` while still panicking on every other write error. That is the same treatment, and the same reasoning, that aes_ctr_cli_tests.rs already documents for its threaded harness; the harness is copied per file, so all three new suites (cfb, cfb8, ctr) get it. Because the race is timing-dependent, camellia_cfb8_cli_tests.rs also gains a deterministic guard: a 4 MiB payload to `camellia128-cfb8` with a rejected key cannot fit in a pipe buffer, so the write is certain to get EPIPE rather than merely likely to. No behaviour outside the test harness changes. Assisted-by: Claude:claude-opus-5 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ce the stream-mode suites got in a2d4b66, closing the last copy of that race in this crate's CLI tests -- `a_key_of_the_wrong_length_is_rejected` writes its stdin payload from the test thread and `.expect()`s the result, but `camellia128-cbc` rejects the key and `exit`s before reading a byte, so the write races the child's exit and gets EPIPE. This file predates the stream modes and has never failed CI, but the defect is identical and was demonstrated here rather than assumed: dropping a 4 MiB error-path payload into the unpatched harness reproduces exactly the panic that failed the Rust Tests workflow on the cfb8 suite. The write result is now matched on, `ErrorKind::BrokenPipe` ignored and every other write error still a panic, which is what the five aes_*_cli_tests.rs suites have always done; an audit of cli/tests confirms no suite in the tree still `.expect()`s that write. The new `a_large_payload_on_an_error_path_does_not_break_the_harness` is the deterministic guard for it -- a payload that cannot fit in a pipe buffer makes EPIPE certain rather than merely likely, so the harness cannot silently regress to the flaky form. Also reflows the over-width comment lines this series left in camellia_cfb8_cli_tests.rs: rustfmt does not wrap comments, so they passed `cargo fmt --check` while sitting past the 100-column max_width every other comment in the tree respects. Nothing the existing tests assert on changes: `wait_with_output` still returns the exit status and the stderr they match against, and no non-test code is touched. Assisted-by: Claude:claude-opus-5 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ts, which no longer exist since 334cd2b made the methods required Assisted-by: Claude:claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nch absorbed through its merges (SymmetricCipher/BlockCipherPadding renames, the ElectronicCodeBook batch methods, AES*Internal, core::security_strength, PaddedBlockCipher* adapters and the rest), restored in one commit after the linear rebase dropped those merges; the tree is identical to merging 482b254 with 2d4d038 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…alias tests, stream-mode tests, OpenSSL raw-Cbc tests, the CLI CFB8/CTR tests and the crate's doc examples take the renamed in-place one-shots (encrypt_in_place/decrypt_in_place), renamed only where the call is in place (the padded Camellia_CBC_* Vec one-shots are unchanged), and import the SymmetricCipher* supertraits their do_*_init calls now come from Assisted-by: Claude:claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Camellia and its three key-length aliases move to bouncycastle_camellia::hazmat with BLOCK_LEN and LANES defined at the crate root; everything else is the path in use lines and doc links. No logic change, no mutation run owed. Assisted-by: Claude Code:claude-fable-5-1 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rection::Select Follows aes 160ac18; the padding crate's PaddedMode copy goes with it. Type aliases only, no behaviour change, no mutation run owed. Assisted-by: Claude Code:claude-fable-5-1 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ions and the workspace wiring The replay of this branch onto feature/key-rework-memory drops its merges from feature/simple-ciphers, and the move of bouncycastle-modes and bouncycastle-padding into bouncycastle-cipher, with Direction and ElectronicCodeBook's new homes, was resolved only in those merges. This is the camellia crate, its CLI commands and tests and its memory bench exactly as the branch tip 83e1b74 had them, with the crate's workspace entry, umbrella re-export, memory-bench manifest entries and the twelve camellia subcommands in main.rs restored, whose conflicts the replay resolved to the base. Assisted-by: Claude:claude-mythos-5-1
…e workers, the engines become Camellia128Internal / Camellia192Internal / Camellia256Internal The engines are renamed for what they are under the key objects of feature/key-rework-memory: Camellia<P> -> CamelliaInternal<P> with Camellia128Internal, Camellia192Internal and Camellia256Internal for the three key lengths, Clone, each implementing ElectronicCodeBook (new) and BlockPermutation (the block methods) separately, and ModeNames for all nine modes, since Camellia has published modes beyond the four aliased here (RFC 5528 CTR and CCM, RFC 6367 GCM). CamelliaKey<P: CamelliaParams, M: Mode<CamelliaInternal<P>>> mirrors AESKey: the key holds the mode's key state, FromKeyMaterial<16> / <24> / <32> build it per key length, and the role impls -- symmetric, block, ECB, AEAD and MAC pairs -- forward to the mode traits, so which roles a key carries is decided by its mode. Camellia128Key<M> and friends name the key lengths. The crate aliases CBC, CFB, CFB8 and CTR as before, now with the key-state lifetime (Camellia_CBC_128<'k, Dir, Pad>, ...); the other modes are reached by naming them, and GCM is exercised through the AEAD framework. Tests: cbc_alias_tests and stream_mode_alias_tests become padded_alias_tests, alg_name_tests and a key-side stream_mode_alias_tests; mode_key_tests runs the FromKeyMaterial, block, symmetric, stream and AEAD frameworks over the keys; the OpenSSL CBC and CFB128 vectors, the RFC 5528 CTR reference, the CFB8 equations and Wycheproof drive the keys, and the RFC 3713, NTT CRYPTREC, bc-java and reference suites the engines. CLI: the twelve camellia commands load a Camellia*Key and keep their contract -- whole blocks under NoPadding for CBC, the IV or nonce in band, no --iv -- and their integration tests replay the OpenSSL vectors through the binary and check the stream commands against the keys' in-place decryption. Assisted-by: Claude:claude-mythos-5-1
dghgit
changed the base branch from
feature/simple-ciphers
to
feature/key-rework-memory
October 24, 2026 17:21
dghgit
force-pushed
the
feature/camellia
branch
from
October 24, 2026 17:21
83e1b74 to
8e28ccb
Compare
hubot
force-pushed
the
feature/camellia
branch
2 times, most recently
from
October 24, 2026 17:46
83e1b74 to
8e28ccb
Compare
…ECB and MAC pairs go CamelliaKey<P, M> carried the full AESKey role set: the AEAD and declared-AEAD pairs (GCM, CCM), the hazmat ECB pair (ECB<Blocks>) and the MAC pair (CMAC), none of which this crate aliases, checks against a published vector or exposes in the CLI. They were there for parity with AESKey only. The symmetric and block pairs remain; between them they cover CBC, CFB, CFB8 and CTR, the four modes the Camellia_* aliases name, and a key under any other mode has no role. mode_key_tests drops the ECB<Blocks> and GCM construction and framework runs. ModeNames keeps all nine names, since the mode types over the engine name themselves by them. Assisted-by: Claude:claude-mythos-5-1
Lifted onto this branch from feature/key-rework-memory (5607ba9), where AESKey and AESInternal gained the same: the engine compares the schedule through Secret's byte-wise equality, which inspects every byte so the time taken does not say where two differ, and a key is equal when its mode state is, bounded on the state rather than on Mode::KeyState. The key objects never hand the material back, so this is the only way two keys can be compared. mode_key_tests: equality follows the material for a clone, the same bytes and a single flipped bit. Assisted-by: Claude:claude-mythos-5-1
…tack table is measured, and the doc nits The same round as PR #140's review, applied here. CamelliaKey's three constructors carried as_cipher_key and a `_ =>` arm for MAC-mode keys, which lost their role in 922236e; both go, and with them check_key_type, since the permutation's own validation is the same check for every mode that has a role (a scoped `cargo mutants` on key.rs is 0 missed; the crate lists 577 mutants). The key docs name ECB<PKCS7> among the symmetric-pair modes. The Security Considerations heading takes the style guide's form and the anchor follows it. The Memory Usage section tabulates the measured stack per entry point and key length: bench_camellia_mem_usage takes the AES bench's measure-closure shape for new and the six block entry points at each key length, and the figures are the closure frames from the release build's frame-layout remarks plus the return address. The three unit tests in hazmat/camellia.rs that tested public behaviour only (the engine sizes, the algorithm names, the LANES constant) move to alg_name_tests or go; the Sec 2.3.3 subkey-swap pin stays. Nits: the manifest comment, the sm4 citation in bitslice.rs, the ElectronicCodeBook attributions for methods that are on BlockPermutation, "An Camellia", and every doc or comment line past 100 columns, including the two rustfmt could not fit. Assisted-by: Claude:claude-mythos-5-1
…file and -d As for sm4 on PR #140: camellia*-cbc was CBC<NoPadding> with no --iv while aes*-cbc on this base is PKCS7 at any length with --iv/--iv-file, and the camellia help pointed at aes128-cbc for an alignment rule it no longer has. The three CBC commands are now CBC<PKCS7> over the same block-mode helpers; the nine stream commands take --iv/--iv-file through load_iv as the aes ones do; and all twelve take the direction as -d/--direction, which every other cipher command already does. The CLI tests pin encryption as well as decryption now that the IV can be supplied: camellia*-cbc encrypt --iv reproduces the OpenSSL evpciph_camellia CBC chains followed by the PKCS7 block (computed from the permutation of the key's length), camellia*-cfb encrypt --iv reproduces the CFB chains exactly, and camellia128-cfb8 and -ctr under --iv are held to the library. The alignment test becomes an any-length test plus a rejected unpadded ciphertext. Their module docs cite the files that exist. Assisted-by: Claude:claude-mythos-5-1
…its over the engines Wycheproof carries camellia_ccm_test.json beside the camellia_cbc_pkcs5 file this crate already runs; the four-mode scope left it unrun. It runs now the way the AES CCM suite does, over the hazmat mode traits and the permutation directly, since the keys carry no AEAD role: 486 of the 552 cases are within SP 800-38C A.1's nonce and tag sets at the three key lengths (405 valid, 81 invalid) and the other 66 are counted as unsupported. All pass. The crate docs' provenance list names both Wycheproof files. Assisted-by: Claude:claude-mythos-5-1
Contributor
Author
|
The review round of PR #140 applied here, in
|
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.
Summary
Adds
bouncycastle-camellia: a constant-time, table-free, low-memory Camellia block cipher (RFC 3713), ported from Bouncy Castle Java'sCamelliaEngine/CamelliaLightEngine, on the key objects of #172:Camellia128Key<M>,Camellia192Key<M>andCamellia256Key<M>over the enginesCamellia128Internaland friends.Rebased onto
feature/key-rework-memory(#172) on 2026-10-25 and ported to its key-object design; the base is now that branch. The review round of PR #140 is applied here in the last three commits: the keys' leftover MAC-key path is gone, the CLI matches the AES commands, the Memory Usage table is measured, the style and nit items are fixed, and the Wycheproof CAMELLIA-CCM suite runs through the mode traits. The four-mode scope (no AEAD roles) is unchanged.Description
CamelliaKey<P, M>mirrorsAESKey: the key holds the mode's state, its workers borrow it, and which role pair a key carries is decided by its mode. The crate aliases CBC, CFB, CFB8 and CTR (Camellia_CBC_128<'k, Dir, Pad>,Camellia_CFB_128<'k, Dir>, ...); the keys carry the symmetric and block role pairs only, which cover those four modes; the engines implementModeNamesfor all nine, so the mode types over them are named, but a key under GCM, CCM, CMAC orECB<Blocks>has no role. Keys and engines implementPartialEq/Eqin constant time over the expanded schedule, as on Key object rework: the traits lose their constructors, every mode gets a key, and workers borrow the key #172.camellia{128,192,256}-{cbc,cfb,cfb8,ctr}, through the key objects, with theaes*-*contract:camellia*-cbcisCBC<PKCS7>at any length, every command takes--iv/--iv-file(the IV or nonce is in band otherwise) and-d/--direction.Scope and Risk
New crate only; the shared changes it carries (the
bouncycastle-camelliaworkspace entry, the umbrella re-export, the memory bench) are additive. No behavioural change to AES or other existing ciphers.Validation
t_camellia.txtvectors; BC Java's ownCamelliaTestvectors, through the engines. OpenSSL CBC and CFB128 vectors, RFC 5528's nine CTR vectors (through a reference built from the SP 800-38A equations, which theCTRkeys are held to) and the CFB8 equations through the keys; Wycheproof CBC-PKCS5 (216 cases, 144 invalid) throughCamellia*Key<CBC<PKCS7>>, and Wycheproofcamellia_ccm_test.json(486 of 552 cases dispatchable, those within SP 800-38C A.1's nonce and tag sets) through theCCMmode traits over the engines.TestFrameworkFromKeyMaterialfor every mode, and the block, symmetric and stream suites.cargo test --workspace: all passing;cargo test --workspace --all-targets --no-runbuilds the benches;cargo +nightly fmt --checkclean. The CLI integration tests pin the OpenSSL CBC and CFB vectors through the binary in both directions, encryption under--iv.cargo mutants -p bouncycastle-camelliaafter the review fixes: 577 mutants, 537 caught, 27 unviable, 13 missed (the same XOR/OR equivalences inortho::swap,p,fl,flinv, the S-box layer andjoinas before).AI Usage Statement
Assisted-by: Claude:claude-sonnet-5
Assisted-by: Claude:claude-mythos-5-1
🤖 Generated with Claude Code