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. |
…from bc-java
New crate `crypto/aria` (`bouncycastle::aria`): the ARIA
block cipher (RFC 5794, KS X 1213) with 128-, 192- and 256-bit keys as a raw
keyed permutation implementing ElectronicCodeBook -- ARIA_128 / ARIA_192 /
ARIA_256 over a sealed ARIAParams -- ported from BC Java's ARIAEngine and
commented line by line against the RFC.
The four S-boxes are Boolean circuits over eight u16 bit-planes rather than
the Java engine's 256-byte tables, so there is no secret-indexed memory access
in the cipher or the key schedule. SB1 is the AES S-box and uses the 113-gate
Boyar-Peralta program verbatim from aes; SB2 (119 gates), SB3 (124)
and SB4 (122) are GF(2^8) inversion between affine maps -- decompositions found
by exhaustive search against the RFC's tables, each with exactly one admissible
input constant (0x00, 0x63, 0xe2) -- around the same Boyar-Peralta non-linear
section, with generated affine layers chosen among the 2040 equivalent forms
for the fewest gates. A substitution layer sends four bytes of each block
through each S-box (one column of the 4x4 byte matrix, transposed out with two
masked-swap stages) and each circuit substitutes 16 bytes, so four blocks fill
the four passes exactly: encrypt_4blocks/decrypt_4blocks are the natural unit,
the trait's blocks8 is two passes and blocks2 uses two lanes. The per-call
working state is about 100 B, which is the "lowmemory" in the name.
The diffusion layer A is computed in the word-level form of the 32-bit
implementations (per-word byte parity, six word XORs, three byte permutations,
six word XORs), a decomposition verified against the RFC's sixteen equations on
every unit vector and 1000 random blocks rather than recalled. One stored
schedule (13/15/17 round keys, 208/240/272 B, in a Secret) serves both
directions: the Sec 2.2 decryption keys dk_i = A(ek_{n+2-i}) are derived from
the stored encryption keys as each round needs them.
Also: ARIA_CBC_128/192/256<Dir> aliases over bouncycastle-modes; aria128-cbc /
aria192-cbc / aria256-cbc CLI subcommands sharing cbc_cmd.rs; criterion bench;
mem_usage_benches harness; umbrella re-export; release notes.
Verified against RFC 5794 Appendix A (the three ciphertexts in every lane of
the four-block path, every slot of the eight-block path and both pair slots;
for the 128-bit key all thirteen round keys ek1..ek13 and all eleven
intermediate values P1..P11 against a literal round-by-round transcription of
Sec 2.3.1.1); KISA's published test vectors as carried in OpenSSL's
evpciph_aria.txt (a 10-block message per key length, ECB through every batching
and CBC through the aliases, both directions); the vector, round-trip and
S-box-inverse checks of BC Java's ARIATest; a transcription of ARIAEngine kept
in the tests (byte arrays, 64-bit halves, table S-boxes fused with the
diffusion layer by multiply-broadcast), 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
KISA vectors.
cargo mutants: 1213 mutants, 1191 caught, 6 unviable, 16 missed -- all sixteen
proven |/^ equivalences on disjoint bits or the documented Boyar-Peralta t37
gate in each of the four circuits, commented at the site.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…N as a parameter, so every block cipher crate can write its <Dir, Pad> CBC and ECB aliases over the one projection
…Mode projection, and the block-aligned vectors move onto modes::Cbc
…valid, driving the padding crate's constant-time unpad with adversarial input
…rmutation, and Block and the concrete params types are no longer exported
Doc comments scattered per-file citations to BC Java's ARIAEngine (its table-driven S-boxes, its per-direction key layout, the C constant array) throughout lib.rs, schedule.rs, aria.rs and sbox.rs. The crate's Provenance section already names it as the source engine 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-aria passes (16 passed). Assisted-by: Claude:claude-sonnet-5 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
…r aria{128,192,256}-{cfb,cfb8,ctr} CLI commands, so ARIA 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 ARIA 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 5794 publishes only single-block values (Appendix A), but KISA's own mode vectors -- the ARIA-*-CFB, ARIA-*-CFB8 and ARIA-*-CTR entries of OpenSSL's evpciph_aria.txt (3.6.2), which the existing ECB and CBC tests already draw on -- cover all three new modes at all three key lengths, and unlike Camellia's and SM4's they line up with these aliases exactly: the CFB128 and CFB8 vectors share the IV 0f1e2d3c..f0 that the CBC vectors use, and the CTR vectors start from an all-zero counter block whose NextIV is ..0a after the ten-block message, which is precisely what a twelve-byte zero nonce and a counter starting at zero produce. All nine are therefore straight known-answer tests through the aliases, each encrypted under the vector's own init data via a FixedSeedRNG (there is no API for supplying one, and the test asserts what came back before comparing any ciphertext), in one call, block by block, and decrypted back seven bytes at a time. 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, and their tests replay the same KISA vectors end to end through the pipe. No new mutants: `cargo mutants -p bouncycastle-aria --list` reports the same 1211 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 aria goes 2 -> 46, 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>
…ipe 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, aria_cfb8_cli_tests.rs also gains a deterministic guard: a 4 MiB payload to `aria128-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>
…tream-mode suites got in 3ee8c7b, 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 `aria128-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 aria_cfb_cli_tests.rs, aria_cfb8_cli_tests.rs and aria_ctr_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>
…ibed a repo that no longer exists -- this file's own preamble asks for stale lines to be reported and fixed, and these two were found the hard way, by a PR failing a workflow the file says does not exist. CI: it claimed `publish_doc_benches_to_ghpages.yaml` was the only workflow and that "there is no separate CI test/lint job -- local `cargo test --workspace` is the gate". There are five workflows, four of them real PR gates (`rust-build.yml`, `rust-test.yml`, `rust-docs.yml`, `rust-style.yml`), and `Rust Tests` fails PRs; the section is now a table of what each one runs, so the local commands that mirror the gate are in one place. Three further details are recorded because each has already cost time: the pages workflow only publishes on a push to `main` (its last two jobs are gated on `github.ref`), it does not run benchmarks at all despite the file name (the `run_benches` job is commented out, "the benches run crazy slow on the github agent") so the old claim that it "publishes docs, code stats, and benchmark results" was wrong on the third, and its `concurrency: group: "pages"` is global rather than per branch, so pushing several branches at once leaves all but the last reporting "cancelled" -- a result that looks like a failure and is not. Toolchain: it claimed the workspace uses nightly pinned in `rust-toolchain.toml` because `core/src/lib.rs` enables `#![feature(adt_const_params)]`. No `rust-toolchain.toml` exists anywhere in the tree, `core` has no feature gate, and the only `adt_const_params` line in the workspace is commented out in `crypto/mldsa/src/lib.rs` beside a commented `unsized_const_params`; CI builds and tests on stable (1.98.1 as installed by `dtolnay/rust-toolchain@stable`) and passes, so the workspace is stable-clean and the note now says so, and warns that a nightly default toolchain locally will hide nightly-only code until CI catches it. The one place nightly is genuinely required is `rust-style.yml`, which does `rustup override set nightly` before `cargo fmt --all --check` while every other job stays on stable; that is now stated rather than implied. Documentation only -- no code, tests or build files are touched. Assisted-by: Claude:claude-opus-5 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…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>
…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 814cc36 with 2d4d038 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dghgit
force-pushed
the
feature/aria
branch
from
September 28, 2026 10:36
814cc36 to
d51a3d3
Compare
dghgit
changed the base branch from
feature/xof-cshake
to
feature/simple-ciphers
September 28, 2026 15:49
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s tests, stream-mode tests, KISA raw-Cbc vector 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 ARIA_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>
# Conflicts: # alpha_0.1.3_release_notes.md # crypto/aes/src/cbc.rs # crypto/aes/src/ecb.rs # crypto/aes/src/lib.rs # crypto/padding/src/padded_mode.rs
ARIA and its three key-length aliases move to bouncycastle_aria::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>
# Conflicts: # crypto/aes/src/cbc.rs # crypto/aes/src/hazmat/ecb.rs # crypto/padding/src/padded_mode.rs
…: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>
Brings in 8dff255 (bouncycastle-modes and bouncycastle-padding folded into the new bouncycastle-cipher crate) and a27d9e6 (StreamCipher and the direction markers moved out of core), so the ARIA crate, its CLI commands and tests are rewritten onto the new paths: bouncycastle_cipher::modes::*, bouncycastle_cipher::padding::*, and bouncycastle_cipher::{Direction, Encrypting, Decrypting}. Import rewrite only, no behaviour change. Assisted-by: Claude Code:claude-fable-5-1 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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-aria: a constant-time, table-free, low-memory ARIA block cipher (RFC 5794), ported from Bouncy Castle Java'sARIAEngine.Description
ARIA_CBC_{128,192,256}aliases plus a CBC CLI subcommand.Scope and Risk
New crate only, sharing the
<Dir, Pad>/PaddedModeprojection already introduced for sm4 (#140) -- additive.Validation
evpciph_aria.txt(KISA's published vectors); BC Java's ownARIATestvectors; Wycheproof CBC-PKCS5 (216 cases, 144 invalid).cargo test -p bouncycastle-aria: all passing.cargo mutants -p bouncycastle-aria: 1211 mutants, 1189 caught, 6 unviable, 16 missed (XOR/OR equivalences).AI Usage Statement
Assisted-by: Claude:claude-sonnet-5
🤖 Generated with Claude Code