Skip to content

camellia: add bouncycastle-camellia, a constant-time Camellia block cipher - #141

Open
dghgit wants to merge 73 commits into
release/0.1.4alphafrom
feature/camellia
Open

dghgit wants to merge 73 commits into
release/0.1.4alphafrom
feature/camellia

Conversation

@dghgit

@dghgit dghgit commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds bouncycastle-camellia: a constant-time, table-free, low-memory Camellia block cipher (RFC 3713), ported from Bouncy Castle Java's CamelliaEngine/CamelliaLightEngine, on the key objects of #172: Camellia128Key<M>, Camellia192Key<M> and Camellia256Key<M> over the engines Camellia128Internal and 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.

Update 2026-11-04: with the key settled as the source of the operator, the AEAD, ECB and MAC roles are back, as AESKey carries them (Camellia has GCM in RFC 6367, CCM in RFC 5528 and CMAC): Camellia*Key under GCM, CCM<N, T>, CCM_Packet<..>, ECB<Blocks>, CMAC<16> and GMAC<16> carry the matching pairs, with the Camellia_GCM_*, Camellia_CCM_*, Camellia_CMAC_* and Camellia_GMAC_* aliases and the camellia{128,192,256}-{gcm,ccm} subcommands (the runners are the AES commands' over the Camellia keys). The Wycheproof CCM suite and the new CMAC suite (camellia_cmac_test.json, 306 cases) run through the keys; no standard or vector suite publishes a Camellia-GCM answer and OpenSSL has no Camellia-GCM at all, so GCM's known answers are the Camellia authors' own cases as carried in nettle's testsuite/gcm-test.c (the AES-GCM specification's inputs under Camellia-128 and -256; the seven 12-byte-IV cases, in gcm_authors_tests.rs) and, for all three key lengths, Bouncy Castle Java's (bc-java 1.87's GCMBlockCipher over CamelliaEngine, the RFC 3713 keys, a counting nonce, AAD and 45-byte message, plus the empty-message tag), pinned at each key length through Camellia*Key<GCM> in gcm_bc_java_tests.rs and through the binary in the CLI tests.

Description

  • All four S-boxes are Boolean circuits (SBOX1 found by exhaustive search, reusing the Boyar-Peralta AES non-linear section via a field isomorphism; SBOX2-4 are bit-rotations of it, done as plane renumberings).
  • Bit-sliced over 32-bit planes, four blocks at a time.
  • CamelliaKey<P, M> mirrors AESKey: 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, block, ECB, AEAD and MAC role pairs, as AESKey does, so every one of the nine modes the engines name through ModeNames has a key with a role. Keys and engines implement PartialEq / Eq in 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.
  • CLI subcommands camellia{128,192,256}-{cbc,cfb,cfb8,ctr,gcm,ccm}, through the key objects, with the aes*-* contract: camellia*-cbc is CBC<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-camellia workspace entry, the umbrella re-export, the memory bench) are additive. No behavioural change to AES or other existing ciphers.

Validation

  • RFC 3713 Appendix A vectors; all 3840 NTT CRYPTREC t_camellia.txt vectors; BC Java's own CamelliaTest vectors, 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 the CTR keys are held to) and the CFB8 equations through the keys; Wycheproof CBC-PKCS5 (216 cases, 144 invalid) through Camellia*Key<CBC<PKCS7>>, Wycheproof camellia_ccm_test.json (486 of 552 cases dispatchable, those within SP 800-38C A.1's nonce and tag sets) through Camellia*Key<CCM<N, T>>, and camellia_cmac_test.json (306 cases) through Camellia*Key<CMAC<16>>. The CLI tests pin two CCM cases and the three bc-java GCM answers through the binary in both directions, and cross-check camellia*-gcm's generated-nonce output against the library.
  • Shared frameworks over the keys: TestFrameworkFromKeyMaterial for every mode, and the block, symmetric and stream suites.
  • cargo test --workspace: all passing; cargo test --workspace --all-targets --no-run builds the benches; cargo +nightly fmt --check clean. The CLI integration tests pin the OpenSSL CBC and CFB vectors through the binary in both directions, encryption under --iv.
  • cargo mutants -p bouncycastle-camellia after the review fixes: 577 mutants, 537 caught, 27 unviable, 13 missed (the same XOR/OR equivalences in ortho::swap, p, fl, flinv, the S-box layer and join as before).

AI Usage Statement

  • Yes, non-trivial code changes were generated by AI

Assisted-by: Claude:claude-sonnet-5
Assisted-by: Claude:claude-mythos-5-1

🤖 Generated with Claude Code

@hubot
hubot deleted the feature/camellia branch September 19, 2026 01:02
@dghgit
dghgit restored the feature/camellia branch September 19, 2026 04:26
@ounsworth

ounsworth commented Sep 19, 2026 •

Copy link
Copy Markdown
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.

@ounsworth ounsworth closed this Sep 19, 2026
@dghgit dghgit reopened this Sep 19, 2026
@hubot
hubot deleted the feature/camellia branch September 28, 2026 15:21
@hubot
hubot deleted the branch release/0.1.4alpha September 28, 2026 15:21
@hubot
hubot restored the feature/camellia branch September 28, 2026 15:45
@dghgit
dghgit changed the base branch from feature/xof-cshake to feature/simple-ciphers September 28, 2026 15:49
@dghgit
dghgit changed the base branch from feature/simple-ciphers to feature/key-rework-memory October 24, 2026 17:21
@hubot
hubot force-pushed the feature/camellia branch 2 times, most recently from 83e1b74 to 8e28ccb Compare October 24, 2026 17:46
@dghgit

dghgit commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

The review round of PR #140 applied here, in 63275706, e690b87b and c415e08c (branch head c415e08c):

  1. Key roles. as_cipher_key and the _ => arms are gone from the three constructors, and check_key_type with them: 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 four-mode scope is unchanged; the Wycheproof gap is closed on it: camellia_ccm_test.json runs through the CCM mode traits over the engines (486 of 552 cases, those within SP 800-38C A.1's nonce and tag sets at the three key lengths; the rest counted as unsupported as the AES suite does), beside the CBC-PKCS5 file the crate already ran.
  2. CLI. camellia*-cbc is CBC<PKCS7> at any length; all twelve commands take --iv/--iv-file and -d/--direction. The CLI tests pin encryption now: camellia*-cbc encrypt --iv reproduces the OpenSSL CBC chains plus the PKCS7 block (computed from the permutation of the key's length) and camellia*-cfb encrypt --iv reproduces the CFB chains exactly.
  3. Heading is # 🚨 Security Considerations 🚨, anchor updated.
  4. Memory Usage tabulates measured per-entry-point stack per key length (new 464/592/592 B, one- and four-block 96 B, two-block 112 B), by the same method and toolchain as the SM4 table, with the same caveat about the AES figures.
  5. The three public-behaviour unit tests moved to alg_name_tests.rs or went; the Sec 2.3.3 subkey-swap pin stays.
    6–13. Manifest comment, the sm4 citation in bitslice.rs, BlockPermutation attributions, ECB<PKCS7> in the key docs, "An Camellia", the CLI test citations, and every doc line within 100 columns.
  6. cargo mutants -p bouncycastle-camellia after the changes: 577 mutants, 537 caught, 27 unviable, 13 missed, the same XOR/OR equivalences as before. PR description updated.

cargo test --workspace, --all-targets --no-run, rustdoc with warnings denied and rustfmt are clean.

@roy-basmacier

Copy link
Copy Markdown

Findings

A. Memory Usage table undercounts (docs only). lib.rs:231-236 tabulates the measure closure's
frame only ("Measured as the frame of each entry point's measure closure"), exactly the SM4 round-2 finding A.
Runtime stack painting (~/.cache/bc-rust-pr141/stackprobe, calibrated: empty call = 8 B; AES-128
encrypt_block control = 264 B vs AES table 208):

Entry point PR table Runtime
Camellia128Internal::new 464 888
Camellia192/256Internal::new 592 1112
encrypt_block / decrypt_block 96 520 / 504
encrypt_2blocks 112 536
encrypt_4blocks / decrypt_4blocks 96 456

lib.rs:222-225 itself itemizes 64 + 32 + 32 B of working state, already more than the 96 B tabulated. Fix the
numbers and the methodology sentence in lib.rs and bench_camellia_mem_usage.rs:41-43.
B. CamelliaParams exposes schedule internals. kl_kr and subkeys are pub methods on a
pub trait (reachable via P: CamelliaParams inferred from Camellia128Internal). AES's AESParams carries only
constants + Schedule. Move the two fns to the pub(crate) sealed supertrait.
C. Params types unexported but in public signatures (nit). Camellia128Key<M> = CamelliaKey<Camellia128Params, M>
and Camellia128Internal expand to a type users cannot name; rustdoc shows it unlinked. AES exports
AES128Params & co. Either export them or accept.
D. KEY_TYPE vs constructor under MAC modes (same judgment call as SM4 B). Camellia128Key<CMAC<16>> compiles,
advertises MACKey, accepts only SymmetricCipherKey. key.rs:110-111 documents the assumption (SM4 option 2).
E. Nits: hazmat/camellia.rs:179,188 "See ElectronicCodeBook::new for the error cases" -> Camellia128Internal::new
lists them; ntt_cryptrec_data.rs consts could be static (clippy large_const_arrays); common/mod.rs:223 and
openssl_cbc_tests.rs:78 clippy nits.

@dghgit

dghgit commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

Roy's two follow-ups from PR #140 applied here too, head 078f1c65:

  1. Stack table. The table reported each entry point's measure closure frame alone; the disassembly of the remark build shows the closure calling encrypt_4blocks (or the schedule's expand) out of line, which calls f, which calls ortho. Summed as the deepest chain with return addresses (rustc 1.97 nightly, x86-64): new 720 B for Camellia-128 and 1120 B for Camellia-192/256, one-block calls 496 B, two-block calls 512 B, encrypt_4blocks 528 B, decrypt_4blocks 512 B. The bench's method note says to sum the chain and lists each frame (84dd6cb4).
  2. MAC-mode key type. The check against Mode::KEY_TYPE is back ahead of the permutation's own on all three key lengths, as AESKey has it; under CMAC<16> cipher material is refused for its type and MAC material by the permutation, so nothing passes and generate fails the same way. mode_key_tests pins the constant, both materials and generate at 128 and 256 bits. Scoped mutants on key.rs: 28 tested, none missed (078f1c65).

@dghgit
dghgit requested a review from roy-basmacier October 30, 2026 16:08
dghgit added a commit that referenced this pull request Oct 30, 2026
…arams types are exported

Roy's B, C and E on PR #141. kl_kr and subkeys were pub methods on the pub
CamelliaParams trait, reachable through any P: CamelliaParams, where AESParams
carries only the constants and the Schedule type; they move to the sealed
CamelliaParamsInternalTrait, which already existed with no members. The three
params structs are exported from the crate root, as AES's are, so
Camellia128Key<M> expands to a type a user can name and rustdoc links it. The
Camellia-192 and -256 engine constructors list their error cases as the
Camellia-128 one does, instead of pointing at ElectronicCodeBook::new; the
three CRYPTREC vector arrays are static rather than const; the two index loops
in the test reference engine iterate; and check_chain's explicit lifetime,
which named no worker, is elided. Clippy on the crate is clean. Scoped mutants
on schedule.rs: 117 tested, 114 caught, 2 unviable, 1 missed, the documented
| / ^ equivalence in join.

Assisted-by: Claude:claude-mythos-5-1
@dghgit

dghgit commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

Roy's B, C and E applied in 6260b012 (branch head):

  • B. kl_kr and subkeys are off the public CamelliaParams trait and on the sealed CamelliaParamsInternalTrait, which already existed with no members; the public trait now carries only the constants and the Schedule type, as AESParams does.
  • C. Camellia128Params, Camellia192Params and Camellia256Params are exported from the crate root, as AES's are, so Camellia128Key<M> expands to a type a user can name and rustdoc links it.
  • E. The Camellia-192 and -256 constructors list their error cases as the 128 one does, instead of pointing at ElectronicCodeBook::new; the three CRYPTREC vector arrays are static; the two index loops in the test reference engine iterate; and check_chain's explicit lifetime, which named no worker, is elided. Clippy on the crate is clean.

Scoped mutants on schedule.rs: 117 tested, 114 caught, 2 unviable, 1 missed, the documented |/^ equivalence in join. rustfmt, cargo test -p bouncycastle-camellia, rustdoc with warnings denied and cargo test --workspace --all-targets --no-run are clean.

dghgit added a commit that referenced this pull request Oct 30, 2026
The two that carry over from Roy's E on PR #141, the rest of B, C and E
having no counterpart here: the key-schedule reference helper in the unit
tests iterates the shift table instead of indexing it, and the two runtime
asserts on ENCRYPTION_APPROVED, which clippy flags as constant and which
key_tests and alg_name_tests both carried, are one compile-time pair in
alg_name_tests. Clippy on the crate is clean; cargo test -p bouncycastle-tdes
and the workspace all-targets build pass.

Assisted-by: Claude:claude-mythos-5-1
@dghgit dghgit added this to the 0.1.4alpha milestone Oct 31, 2026
dghgit added a commit that referenced this pull request Nov 3, 2026
…modules are public, the stack table is measured, and the doc nits

PR #142's review, and the round PR #140 and #141 had before it. ARIAKey's
three constructors carried as_cipher_key and a `_ =>` arm for MAC-mode keys,
which lost their role when the AEAD, ECB and MAC pairs went; both go, and
check_key_type stays ahead of the permutation's own check so that a key under
a MAC mode refuses cipher material for its type and MAC material by the
permutation, which mode_key_tests pins at both key lengths. The key docs name
every mode that gives a key a role -- CTR at any nonce length, ECB<PKCS7> and
ECB<NoPadding> among them -- rather than the four aliased ones.

The mode and key modules are `pub`, as in bouncycastle-aes, so their docs
render; the three params types are exported beside their trait, so the
`ARIA*Key<M>` aliases name public types. The ModeNames comment says which
modes RFC 5794 Appendix B gives an OID (CFB's parameters carry the segment
size, so CFB8 is `id-aria*-cfb` with `k = 8`; GMAC has none). 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_aria_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 deepest frame chain under each closure from the release build's
frame-layout remarks and disassembly (closure, then encrypt_4blocks or
expand, fo/fe, substitution_layer, ortho), which puts a one-block call at
416 B, not the "near 100 bytes" the Design section foregrounded for the
working state alone; that sentence now points at the table.

The three unit tests in hazmat/aria.rs that tested public behaviour only (the
engine sizes, the algorithm names, the LANES constant) move to
alg_name_tests; the Sec 2.2 decryption-order pin and the Appendix A.1
intermediate values stay. stream_mode_tests pins the CTR counter limit
through an ARIA key under CTR<15>. Nits: the manifest comment, the sibling
citations in bitslice.rs, the BlockPermutation attributions for methods that
are on BlockPermutation, two clippy suggestions in the tests, and every doc
or comment line past 100 columns.

Assisted-by: Claude:claude-mythos-5-1
dghgit added a commit that referenced this pull request Nov 3, 2026
… and -d

As for sm4 and camellia on PRs #140 and #141: aria*-cbc was CBC<NoPadding>
with no --iv while aes*-cbc on this base is PKCS7 at any length with
--iv/--iv-file, and the aria help pointed at aes128-cbc for an alignment rule
it no longer has (PR #142 review). 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: aria*-cbc encrypt --iv reproduces the KISA CBC vectors followed by
the PKCS7 block (computed from the permutation of the key's length), and
aria*-cfb, -cfb8 and -ctr encrypt --iv reproduce the KISA stream vectors
exactly, CTR under the twelve-byte zero nonce they imply. 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
@dghgit
dghgit force-pushed the feature/key-rework-memory branch from 3c170c9 to 81cef74 Compare November 3, 2026 02:36
dghgit added a commit that referenced this pull request Nov 3, 2026
The two that carry over from Roy's E on PR #141, the rest of B, C and E
having no counterpart here: the key-schedule reference helper in the unit
tests iterates the shift table instead of indexing it, and the two runtime
asserts on ENCRYPTION_APPROVED, which clippy flags as constant and which
key_tests and alg_name_tests both carried, are one compile-time pair in
alg_name_tests. Clippy on the crate is clean; cargo test -p bouncycastle-tdes
and the workspace all-targets build pass.

Assisted-by: Claude:claude-mythos-5-1
dghgit added a commit that referenced this pull request Nov 3, 2026
…arams types are exported

Roy's B, C and E on PR #141. kl_kr and subkeys were pub methods on the pub
CamelliaParams trait, reachable through any P: CamelliaParams, where AESParams
carries only the constants and the Schedule type; they move to the sealed
CamelliaParamsInternalTrait, which already existed with no members. The three
params structs are exported from the crate root, as AES's are, so
Camellia128Key<M> expands to a type a user can name and rustdoc links it. The
Camellia-192 and -256 engine constructors list their error cases as the
Camellia-128 one does, instead of pointing at ElectronicCodeBook::new; the
three CRYPTREC vector arrays are static rather than const; the two index loops
in the test reference engine iterate; and check_chain's explicit lifetime,
which named no worker, is elided. Clippy on the crate is clean. Scoped mutants
on schedule.rs: 117 tested, 114 caught, 2 unviable, 1 missed, the documented
| / ^ equivalence in join.

Assisted-by: Claude:claude-mythos-5-1
dghgit added a commit that referenced this pull request Nov 3, 2026
…modules are public, the stack table is measured, and the doc nits

PR #142's review, and the round PR #140 and #141 had before it. ARIAKey's
three constructors carried as_cipher_key and a `_ =>` arm for MAC-mode keys,
which lost their role when the AEAD, ECB and MAC pairs went; both go, and
check_key_type stays ahead of the permutation's own check so that a key under
a MAC mode refuses cipher material for its type and MAC material by the
permutation, which mode_key_tests pins at both key lengths. The key docs name
every mode that gives a key a role -- CTR at any nonce length, ECB<PKCS7> and
ECB<NoPadding> among them -- rather than the four aliased ones.

The mode and key modules are `pub`, as in bouncycastle-aes, so their docs
render; the three params types are exported beside their trait, so the
`ARIA*Key<M>` aliases name public types. The ModeNames comment says which
modes RFC 5794 Appendix B gives an OID (CFB's parameters carry the segment
size, so CFB8 is `id-aria*-cfb` with `k = 8`; GMAC has none). 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_aria_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 deepest frame chain under each closure from the release build's
frame-layout remarks and disassembly (closure, then encrypt_4blocks or
expand, fo/fe, substitution_layer, ortho), which puts a one-block call at
416 B, not the "near 100 bytes" the Design section foregrounded for the
working state alone; that sentence now points at the table.

The three unit tests in hazmat/aria.rs that tested public behaviour only (the
engine sizes, the algorithm names, the LANES constant) move to
alg_name_tests; the Sec 2.2 decryption-order pin and the Appendix A.1
intermediate values stay. stream_mode_tests pins the CTR counter limit
through an ARIA key under CTR<15>. Nits: the manifest comment, the sibling
citations in bitslice.rs, the BlockPermutation attributions for methods that
are on BlockPermutation, two clippy suggestions in the tests, and every doc
or comment line past 100 columns.

Assisted-by: Claude:claude-mythos-5-1
dghgit added 20 commits November 5, 2026 06:59
…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
The same undercount Roy found on PR #140's SM4 table: the figures were each
entry point's `measure` closure frame alone, while the disassembly of the
remark build shows the closure calling encrypt_4blocks (or the schedule's
expand) out of line, which calls f, which calls ortho. Summing the chain
with return addresses, on rustc 1.97 nightly x86-64: new 720 B for
Camellia-128 and 1120 B for the other two, 496 B for the one-block calls,
512 B for the two-block calls and decrypt_4blocks, 528 B for
encrypt_4blocks. The bench's method note says to sum the chain and lists
each frame.

Assisted-by: Claude:claude-mythos-5-1
…utation does

As for SM4 on PR #140: 6327570 dropped the check against Mode::KEY_TYPE,
leaving a key under a MAC mode declaring KEY_TYPE = MACKey while its
constructor took cipher material and refused MAC material. The check is
back on all three key lengths, as AESKey has it; mode_key_tests pins the
constant, both materials and generate at 128 and 256 bits. Scoped mutants
on key.rs: 28 tested, 5 caught, 23 unviable, none missed.

Assisted-by: Claude:claude-mythos-5-1
…arams types are exported

Roy's B, C and E on PR #141. kl_kr and subkeys were pub methods on the pub
CamelliaParams trait, reachable through any P: CamelliaParams, where AESParams
carries only the constants and the Schedule type; they move to the sealed
CamelliaParamsInternalTrait, which already existed with no members. The three
params structs are exported from the crate root, as AES's are, so
Camellia128Key<M> expands to a type a user can name and rustdoc links it. The
Camellia-192 and -256 engine constructors list their error cases as the
Camellia-128 one does, instead of pointing at ElectronicCodeBook::new; the
three CRYPTREC vector arrays are static rather than const; the two index loops
in the test reference engine iterate; and check_chain's explicit lifetime,
which named no worker, is elided. Clippy on the crate is clean. Scoped mutants
on schedule.rs: 117 tested, 114 caught, 2 unviable, 1 missed, the documented
| / ^ equivalence in join.

Assisted-by: Claude:claude-mythos-5-1
…cs sit on the items, the Wycheproof CBC suite uses the shared loaders, and the CTR limit is pinned through a key

Three of the aria review's findings hold for this crate too. The cbc, cfb,
cfb8, ctr and key modules are private, so the docs each carried never
rendered; they now sit on `Camellia_CBC_128`, `Camellia_CFB_128`,
`Camellia_CFB8_128`, `Camellia_CTR_128` and `CamelliaKey`, the one path each
has, and the module headers say so. The CAMELLIA-CBC-PKCS5 suite found its
file through its own two candidate paths and skipped silently when neither
resolved, accepted any error for an invalid case, and could not tell a
zeroized output buffer from one never written; it is now the AES suite over
the Camellia keys -- the shared `wycheproof_json` loader, the expected error
read off the case's flags, a pre-filled output buffer that a failed decrypt
must leave all zeros -- as `cbc_wycheproof.rs`, named as the suites it
copies. And no test reached `Ctr`'s counter limit through a Camellia key:
stream_mode_tests now does, under `CTR<15>`, where the 256th block is the
last and the byte after it is refused.

Assisted-by: Claude:claude-mythos-5-1
…rried over the rebase onto its release-based history

This branch took feature/key-rework-memory by merge, and the merge commits carried the
adaptations to what arrived. The rebase onto the branch's new history (key-rework-memory
rebased onto release/0.1.3alpha, which carries feature/key-rework as one squash commit)
dropped those merges; this commit restores the affected files to the branch's pre-rebase
tip, so the tree is identical to it.

Assisted-by: Claude:claude-mythos-5-1
…ey carries them -- 9accbde dropped them with the ARIA trim, and the Camellia-CCM and Camellia-CMAC Wycheproof suites now run through Camellia128Key<CCM<N, T>> and <CMAC> (486 and 306 cases; GCM has no published Camellia vector and is covered by the AEAD suite over the Gcm code the AES and ARIA suites pin); the constructor takes MAC material for a MAC mode, retagged for the permutation as AESKey does; Camellia_GCM_*, Camellia_CCM_*, Camellia_CMAC_* and Camellia_GMAC_* name the workers, with GMAC's nonce-bound pair inherent on the key; the mode-key suite adds the ECB<Blocks>, GCM and CCM_Packet keys and the MAC keys' round trips, and the docs say which modes a key now covers

Assisted-by: Claude:claude-fable-5-1
…*-gcm and aes*-ccm commands over the Camellia keys (the CCM runner and its key table are shared with the AES file), with Wycheproof CCM known answers in both directions, GCM held to the library's own key, and tag-check and round-trip tests

Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-fable-5-1
…andard or vector suite publishes one, so bc-java 1.87's GCMBlockCipher over CamelliaEngine supplies the ciphertext and tag at each key length (the RFC 3713 keys, a counting nonce, AAD and 45-byte message) and the empty-message tag, pinned through Camellia*Key<GCM> in both directions

Assisted-by: Claude:claude-fable-5-1
…gh the binary in both directions at each key length

Assisted-by: Claude:claude-fable-5-1
… testsuite/gcm-test.c carries them as "obtained from the authors": the AES-GCM specification's inputs under Camellia-128 and Camellia-256; the seven 12-byte-IV cases (1, 3, 4 and 13 to 16) run through Camellia128Key<GCM> and Camellia256Key<GCM> in both directions, the 8- and 60-byte-IV cases are outside GCM's fixed 96-bit nonce and said so; OpenSSL has no Camellia-GCM to check against

Assisted-by: Claude:claude-fable-5-1
…>> and its detached in-place one-shots rather than over the permutation; a weak-MAC-key test pins that as_cipher_key carries the MAC key's strength onto the retagged copy; the GMAC key is held to the GCM key over AAD alone at both key lengths, and the authors' empty GCM cases (1 and 13) run through Camellia*Key<GMAC> as its known answers; the CCM suite header no longer cites the AES crate's ACVP file (the same findings as PR #142's second round)

Assisted-by: Claude:claude-fable-5-1
…rule -- key, IV, nonce and AAD files are raw bytes, or hex under the global --hex-input -- the GCM paragraphs say "the other Camellia modes", and the three camellia*-gcm commands carry the clippy allowance their AES twins have (as PR #142's second round)

Assisted-by: Claude:claude-fable-5-1
…ver the rebase onto release/0.1.4alpha

This branch took release/0.1.3alpha (029a17b, the squash merge of PR #190) by merge, and
that merge commit carried the adaptations to what arrived. The rebase onto release/0.1.4alpha
dropped the merge; this commit restores the affected files to the branch's pre-rebase tip,
so the tree is identical to it apart from the 0.1.4 line's own version bump and notes file.

Assisted-by: Claude:claude-fable-5-1
dghgit added a commit that referenced this pull request Nov 4, 2026
The two that carry over from Roy's E on PR #141, the rest of B, C and E
having no counterpart here: the key-schedule reference helper in the unit
tests iterates the shift table instead of indexing it, and the two runtime
asserts on ENCRYPTION_APPROVED, which clippy flags as constant and which
key_tests and alg_name_tests both carried, are one compile-time pair in
alg_name_tests. Clippy on the crate is clean; cargo test -p bouncycastle-tdes
and the workspace all-targets build pass.

Assisted-by: Claude:claude-mythos-5-1
dghgit added a commit that referenced this pull request Nov 4, 2026
…modules are public, the stack table is measured, and the doc nits

PR #142's review, and the round PR #140 and #141 had before it. ARIAKey's
three constructors carried as_cipher_key and a `_ =>` arm for MAC-mode keys,
which lost their role when the AEAD, ECB and MAC pairs went; both go, and
check_key_type stays ahead of the permutation's own check so that a key under
a MAC mode refuses cipher material for its type and MAC material by the
permutation, which mode_key_tests pins at both key lengths. The key docs name
every mode that gives a key a role -- CTR at any nonce length, ECB<PKCS7> and
ECB<NoPadding> among them -- rather than the four aliased ones.

The mode and key modules are `pub`, as in bouncycastle-aes, so their docs
render; the three params types are exported beside their trait, so the
`ARIA*Key<M>` aliases name public types. The ModeNames comment says which
modes RFC 5794 Appendix B gives an OID (CFB's parameters carry the segment
size, so CFB8 is `id-aria*-cfb` with `k = 8`; GMAC has none). 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_aria_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 deepest frame chain under each closure from the release build's
frame-layout remarks and disassembly (closure, then encrypt_4blocks or
expand, fo/fe, substitution_layer, ortho), which puts a one-block call at
416 B, not the "near 100 bytes" the Design section foregrounded for the
working state alone; that sentence now points at the table.

The three unit tests in hazmat/aria.rs that tested public behaviour only (the
engine sizes, the algorithm names, the LANES constant) move to
alg_name_tests; the Sec 2.2 decryption-order pin and the Appendix A.1
intermediate values stay. stream_mode_tests pins the CTR counter limit
through an ARIA key under CTR<15>. Nits: the manifest comment, the sibling
citations in bitslice.rs, the BlockPermutation attributions for methods that
are on BlockPermutation, two clippy suggestions in the tests, and every doc
or comment line past 100 columns.

Assisted-by: Claude:claude-mythos-5-1
dghgit added a commit that referenced this pull request Nov 4, 2026
… and -d

As for sm4 and camellia on PRs #140 and #141: aria*-cbc was CBC<NoPadding>
with no --iv while aes*-cbc on this base is PKCS7 at any length with
--iv/--iv-file, and the aria help pointed at aes128-cbc for an alignment rule
it no longer has (PR #142 review). 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: aria*-cbc encrypt --iv reproduces the KISA CBC vectors followed by
the PKCS7 block (computed from the permutation of the key's length), and
aria*-cfb, -cfb8 and -ctr encrypt --iv reproduce the KISA stream vectors
exactly, CTR under the twelve-byte zero nonce they imply. 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
@dghgit
dghgit changed the base branch from release/0.1.3alpha to release/0.1.4alpha November 4, 2026 21:15
@dghgit

dghgit commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto release/0.1.4alpha (ac20638: the 0.1.3 tree with the version bump and the new notes file) and retargeted there: feature/camellia is now 9b22094, replayed from 637b4d5 with the merge of 029a17b dropped and the tree restored to a reference merge, so it is identical to the old tip apart from the 0.1.4 setup. Workspace suite passes on the new tip.

@hubot
hubot deleted the feature/camellia branch November 4, 2026 22:43
@hubot
hubot deleted the branch release/0.1.4alpha November 4, 2026 22:43
@hubot
hubot deleted the branch release/0.1.4alpha November 4, 2026 23:08

This branch has not been deployed

No deployments
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.

3 participants