Skip to content

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

Open
dghgit wants to merge 23 commits into
feature/key-rework-memoryfrom
feature/camellia
Open

dghgit wants to merge 23 commits into
feature/key-rework-memoryfrom
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. The four-mode scope (no AEAD roles) is unchanged.

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 and block role pairs only, which cover those four modes; the engines implement ModeNames for all nine, so the mode types over them are named, but a key under GCM, CCM, CMAC or ECB<Blocks> has no 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}, 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>>, and Wycheproof camellia_ccm_test.json (486 of 552 cases dispatchable, those within SP 800-38C A.1's nonce and tag sets) through the CCM mode traits over the engines.
  • 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 feature/key-rework-memory 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 and others added 16 commits October 24, 2026 23:46
…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
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
…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
@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.

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.

2 participants