diff --git a/.github/workflows/aes.yml b/.github/workflows/aes.yml index d7f72efd..a65c7c0e 100644 --- a/.github/workflows/aes.yml +++ b/.github/workflows/aes.yml @@ -232,6 +232,25 @@ jobs: - run: cargo test --target ${{ matrix.target }} - run: cargo test --target ${{ matrix.target }} --all-features + # Test for the portable software backend with a 16-bit word size + soft-16-bit: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - rust: 1.89.0 # MSRV + - rust: stable + env: + RUSTFLAGS: '-Dwarnings --cfg aes_backend="soft" --cfg cpubits="16"' + steps: + - uses: actions/checkout@v7 + - uses: RustCrypto/actions/cargo-cache@master + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + - run: cargo test + - run: cargo test --all-features + # Cross-compiled tests cross: strategy: diff --git a/aes/CHANGELOG.md b/aes/CHANGELOG.md index c161d673..802c0392 100644 --- a/aes/CHANGELOG.md +++ b/aes/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.9.4 (UNRELEASED) +### Changed +- Reduce size of `Aes128/192/256` structs by using compact round key representation + for software backend ([#594]) + +[#594]: https://github.com/RustCrypto/block-ciphers/pull/594 + ## 0.9.3 (2026-08-28) ### Changed - MSRV bumped to 1.89 ([#580]) diff --git a/aes/src/backends/fixslice/aes192.rs b/aes/src/backends/fixslice/aes192.rs index 0edf37f1..d1bb0117 100644 --- a/aes/src/backends/fixslice/aes192.rs +++ b/aes/src/backends/fixslice/aes192.rs @@ -16,8 +16,8 @@ pub(crate) fn key_schedule(key: &[u8; 24]) -> RoundKeys { loop { for i in 0..8 { - rkeys[rk_off + i] = (W::uniform_row(0x0f) & (tmp[i] >> W::HALF_ROW)) - | (W::uniform_row(0xf0) & (rkeys[(rk_off - 8) + i] << W::HALF_ROW)); + rkeys[rk_off + i] = (W::uniform_row(0x3) & (tmp[i] >> W::HALF_ROW)) + | (W::uniform_row(0xc) & (rkeys[(rk_off - 8) + i] << W::HALF_ROW)); } sub_bytes(&mut tmp); @@ -28,8 +28,8 @@ pub(crate) fn key_schedule(key: &[u8; 24]) -> RoundKeys { for i in 0..8 { let mut ti = rkeys[rk_off + i]; - ti ^= W::uniform_row(0x30) & tmp[i].ror(W::ror_distance(1, 1)); - ti ^= W::uniform_row(0xc0) & (ti << W::QUARTER_ROW); + ti ^= W::uniform_row(0x4) & tmp[i].ror(W::ror_distance(1, 1)); + ti ^= W::uniform_row(0x8) & (ti << W::QUARTER_ROW); tmp[i] = ti; } rkeys[rk_off..(rk_off + 8)].copy_from_slice(&tmp); @@ -37,13 +37,13 @@ pub(crate) fn key_schedule(key: &[u8; 24]) -> RoundKeys { for i in 0..8 { let ui = tmp[i]; - let mut ti = (W::uniform_row(0x0f) & (rkeys[(rk_off - 16) + i] >> W::HALF_ROW)) - | (W::uniform_row(0xf0) & (ui << W::HALF_ROW)); - ti ^= W::uniform_row(0x03) & (ui >> (3 * W::QUARTER_ROW)); + let mut ti = (W::uniform_row(0x3) & (rkeys[(rk_off - 16) + i] >> W::HALF_ROW)) + | (W::uniform_row(0xc) & (ui << W::HALF_ROW)); + ti ^= W::uniform_row(0x1) & (ui >> (3 * W::QUARTER_ROW)); tmp[i] = ti - ^ (W::uniform_row(0xfc) & (ti << W::QUARTER_ROW)) - ^ (W::uniform_row(0xf0) & (ti << W::HALF_ROW)) - ^ (W::uniform_row(0xc0) & (ti << (3 * W::QUARTER_ROW))); + ^ (W::uniform_row(0xe) & (ti << W::QUARTER_ROW)) + ^ (W::uniform_row(0xc) & (ti << W::HALF_ROW)) + ^ (W::uniform_row(0x8) & (ti << (3 * W::QUARTER_ROW))); } rkeys[rk_off..(rk_off + 8)].copy_from_slice(&tmp); rk_off += 8; @@ -55,13 +55,13 @@ pub(crate) fn key_schedule(key: &[u8; 24]) -> RoundKeys { rcon += 1; for i in 0..8 { - let mut ti = (W::uniform_row(0x0f) & (rkeys[(rk_off - 16) + i] >> W::HALF_ROW)) - | (W::uniform_row(0xf0) & (rkeys[(rk_off - 8) + i] << W::HALF_ROW)); - ti ^= W::uniform_row(0x03) & tmp[i].ror(W::ror_distance(1, 3)); + let mut ti = (W::uniform_row(0x3) & (rkeys[(rk_off - 16) + i] >> W::HALF_ROW)) + | (W::uniform_row(0xc) & (rkeys[(rk_off - 8) + i] << W::HALF_ROW)); + ti ^= W::uniform_row(0x1) & tmp[i].ror(W::ror_distance(1, 3)); rkeys[rk_off + i] = ti - ^ (W::uniform_row(0xfc) & (ti << W::QUARTER_ROW)) - ^ (W::uniform_row(0xf0) & (ti << W::HALF_ROW)) - ^ (W::uniform_row(0xc0) & (ti << (3 * W::QUARTER_ROW))); + ^ (W::uniform_row(0xe) & (ti << W::QUARTER_ROW)) + ^ (W::uniform_row(0xc) & (ti << W::HALF_ROW)) + ^ (W::uniform_row(0x8) & (ti << (3 * W::QUARTER_ROW))); } rk_off += 8; @@ -72,8 +72,8 @@ pub(crate) fn key_schedule(key: &[u8; 24]) -> RoundKeys { for i in 0..8 { let ui = rkeys[(rk_off - 8) + i]; let mut ti = rkeys[(rk_off - 16) + i]; - ti ^= W::uniform_row(0x30) & (ui >> W::QUARTER_ROW); - ti ^= W::uniform_row(0xc0) & (ti << W::QUARTER_ROW); + ti ^= W::uniform_row(0x4) & (ui >> W::QUARTER_ROW); + ti ^= W::uniform_row(0x8) & (ti << W::QUARTER_ROW); tmp[i] = ti; } } diff --git a/aes/src/backends/fixslice/mix_columns.rs b/aes/src/backends/fixslice/mix_columns.rs index fdffa023..60aad2da 100644 --- a/aes/src/backends/fixslice/mix_columns.rs +++ b/aes/src/backends/fixslice/mix_columns.rs @@ -145,30 +145,30 @@ fn rotate_rows_2(x: W) -> W { #[inline(always)] fn rotate_rows_and_columns_1_1(x: W) -> W { - let a = x.ror(W::ror_distance(1, 1)) & W::uniform_row(0x3f); - let b = x.ror(W::ror_distance(0, 1)) & W::uniform_row(0xc0); + let a = x.ror(W::ror_distance(1, 1)) & W::uniform_row(0x7); + let b = x.ror(W::ror_distance(0, 1)) & W::uniform_row(0x8); a | b } #[cfg(not(aes_backend_soft = "compact"))] #[inline(always)] fn rotate_rows_and_columns_1_2(x: W) -> W { - let a = x.ror(W::ror_distance(1, 2)) & W::uniform_row(0x0f); - let b = x.ror(W::ror_distance(0, 2)) & W::uniform_row(0xf0); + let a = x.ror(W::ror_distance(1, 2)) & W::uniform_row(0x3); + let b = x.ror(W::ror_distance(0, 2)) & W::uniform_row(0xc); a | b } #[cfg(not(aes_backend_soft = "compact"))] #[inline(always)] fn rotate_rows_and_columns_1_3(x: W) -> W { - let a = x.ror(W::ror_distance(1, 3)) & W::uniform_row(0x03); - let b = x.ror(W::ror_distance(0, 3)) & W::uniform_row(0xfc); + let a = x.ror(W::ror_distance(1, 3)) & W::uniform_row(0x1); + let b = x.ror(W::ror_distance(0, 3)) & W::uniform_row(0xe); a | b } #[inline(always)] fn rotate_rows_and_columns_2_2(x: W) -> W { - let a = x.ror(W::ror_distance(2, 2)) & W::uniform_row(0x0f); - let b = x.ror(W::ror_distance(1, 2)) & W::uniform_row(0xf0); + let a = x.ror(W::ror_distance(2, 2)) & W::uniform_row(0x3); + let b = x.ror(W::ror_distance(1, 2)) & W::uniform_row(0xc); a | b } diff --git a/aes/src/backends/fixslice/mod.rs b/aes/src/backends/fixslice/mod.rs index f5d29d83..b9ace40a 100644 --- a/aes/src/backends/fixslice/mod.rs +++ b/aes/src/backends/fixslice/mod.rs @@ -26,12 +26,15 @@ mod sbox; mod utils; mod word; -use word::Word; +pub(super) use word::Word; type State = [W; 8]; cpubits::cpubits! { - 16 | 32 => { + 16 => { + pub(super) type NativeWord = u16; + } + 32 => { pub(super) type NativeWord = u32; } 64 => { @@ -41,3 +44,4 @@ cpubits::cpubits! { pub(super) type NativeBatchSize = ::Blocks; pub(super) type BatchBlocks = Array::Blocks>; +pub(super) type MinWord = u16; diff --git a/aes/src/backends/fixslice/utils.rs b/aes/src/backends/fixslice/utils.rs index 698225ef..fe38f495 100644 --- a/aes/src/backends/fixslice/utils.rs +++ b/aes/src/backends/fixslice/utils.rs @@ -32,8 +32,8 @@ pub(super) fn delta_swap_2(a: &mut W, b: &mut W, shift: u32, mask: W) { pub(super) fn shift_rows_1(state: &mut [W]) { debug_assert_eq!(state.len(), 8); for x in state.iter_mut() { - delta_swap_1(x, W::HALF_ROW, W::pack_rows(0x00, 0x03, 0x0f, 0x0c)); - delta_swap_1(x, W::QUARTER_ROW, W::pack_rows(0x00, 0x33, 0x00, 0x33)); + delta_swap_1(x, W::HALF_ROW, W::pack_rows(0x0, 0x1, 0x3, 0x2)); + delta_swap_1(x, W::QUARTER_ROW, W::pack_rows(0x0, 0x5, 0x0, 0x5)); } } @@ -42,7 +42,7 @@ pub(super) fn shift_rows_1(state: &mut [W]) { pub(super) fn shift_rows_2(state: &mut [W]) { debug_assert_eq!(state.len(), 8); for x in state.iter_mut() { - delta_swap_1(x, W::HALF_ROW, W::pack_rows(0x00, 0x0f, 0x00, 0x0f)); + delta_swap_1(x, W::HALF_ROW, W::pack_rows(0x0, 0x3, 0x0, 0x3)); } } @@ -51,8 +51,8 @@ pub(super) fn shift_rows_2(state: &mut [W]) { pub(super) fn shift_rows_3(state: &mut [W]) { debug_assert_eq!(state.len(), 8); for x in state.iter_mut() { - delta_swap_1(x, W::HALF_ROW, W::pack_rows(0x00, 0x0c, 0x0f, 0x03)); - delta_swap_1(x, W::QUARTER_ROW, W::pack_rows(0x00, 0x33, 0x00, 0x33)); + delta_swap_1(x, W::HALF_ROW, W::pack_rows(0x0, 0x2, 0x3, 0x1)); + delta_swap_1(x, W::QUARTER_ROW, W::pack_rows(0x0, 0x5, 0x0, 0x5)); } } @@ -83,11 +83,11 @@ pub(super) fn inv_shift_rows_3(state: &mut [W]) { pub(super) fn xor_columns(rkeys: &mut [W], offset: usize, idx_xor: usize, idx_ror: u32) { for i in 0..8 { let off_i = offset + i; - let rk = rkeys[off_i - idx_xor] ^ (W::uniform_row(0x03) & rkeys[off_i].ror(idx_ror)); + let rk = rkeys[off_i - idx_xor] ^ (W::uniform_row(0x1) & rkeys[off_i].ror(idx_ror)); rkeys[off_i] = rk - ^ (W::uniform_row(0xfc) & (rk << W::QUARTER_ROW)) - ^ (W::uniform_row(0xf0) & (rk << W::HALF_ROW)) - ^ (W::uniform_row(0xc0) & (rk << (3 * W::QUARTER_ROW))); + ^ (W::uniform_row(0xe) & (rk << W::QUARTER_ROW)) + ^ (W::uniform_row(0xc) & (rk << W::HALF_ROW)) + ^ (W::uniform_row(0x8) & (rk << (3 * W::QUARTER_ROW))); } } @@ -115,5 +115,5 @@ pub(super) fn add_round_key(state: &mut State, rkey: &[W]) { #[inline(always)] pub(super) fn add_round_constant_bit(state: &mut [W], bit: usize) { - state[bit] ^= W::pack_rows(0x00, 0xc0, 0x00, 0x00); + state[bit] ^= W::pack_rows(0x0, 0x8, 0x0, 0x0); } diff --git a/aes/src/backends/fixslice/word.rs b/aes/src/backends/fixslice/word.rs index e24abc81..696edc6c 100644 --- a/aes/src/backends/fixslice/word.rs +++ b/aes/src/backends/fixslice/word.rs @@ -1,8 +1,8 @@ -use crate::Block; +use crate::{Block, backends::soft::MinWord}; use cipher::{ Array, array::ArraySize, - consts::{U2, U4}, + consts::{U1, U2, U4}, }; use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, Shr}; @@ -25,7 +25,8 @@ pub(crate) trait Word: /// Number of 128-bit blocks bitsliced together in one state. type Blocks: ArraySize; - /// Width in bits of one row of the bitsliced state (8 for `u32`, 16 for `u64`). + /// Width in bits of one row of the bitsliced state (4 for `u16`, 8 for + /// `u32`, 16 for `u64`). const ROW_BITS: u32 = (size_of::() * 2) as u32; /// Half of `ROW_BITS`. @@ -42,10 +43,10 @@ pub(crate) trait Word: /// Rotate right by `n` bits. fn ror(self, n: u32) -> Self; - /// Pack the same byte across all 4 rows of the word. + /// Pack the same nibble across all 4 rows of the word. fn uniform_row(b: u8) -> Self; - /// Place one byte at each of the 4 row positions of the word (row 0 = LSB). + /// Place one nibble at each of the 4 row positions of the word (row 0 = LSB). fn pack_rows(r0: u8, r1: u8, r2: u8, r3: u8) -> Self; /// Replicate byte `b` across every byte of the word. @@ -56,6 +57,163 @@ pub(crate) trait Word: /// Unpack a bitsliced 8-row state slice into `Self::Blocks` output blocks. fn inv_bitslice(input: &[Self]) -> Array; + + /// Broadcast the round key into all lanes. + fn broadcast(rkey: MinWord) -> Self; +} + +impl Word for u16 { + type Blocks = U1; + + #[inline(always)] + fn ror(self, n: u32) -> u16 { + self.rotate_right(n) + } + + #[inline(always)] + fn uniform_row(b: u8) -> u16 { + (b as u16) * 0x1111 + } + + #[inline(always)] + fn pack_rows(r0: u8, r1: u8, r2: u8, r3: u8) -> u16 { + (r0 as u16) | ((r1 as u16) << 4) | ((r2 as u16) << 8) | ((r3 as u16) << 12) + } + + #[inline(always)] + fn byte_repeat(b: u8) -> u16 { + (b as u16) * 0x0101 + } + + /// Bitslice one 128-bit input block into a 128-bit internal state. + fn bitslice(output: &mut [u16], input: &Array) { + debug_assert_eq!(output.len(), 8); + let b = input[0].as_slice(); + + // Bitslicing is a bit index manipulation. 128 bits of data means each bit is positioned at + // a 7-bit index. AES data is a single 4x4 column-major matrix of bytes, so the index is + // initially ([c]olumn, [r]ow, [p]osition): + // c1 c0 r1 r0 p2 p1 p0 + // + // The desired bitsliced data groups first by bit position, then row, then column: + // p2 p1 p0 r1 r0 c1 c0 + + fn read_reordered(input: &[u8]) -> u16 { + (u16::from(input[0x0])) | (u16::from(input[0x2]) << 8) + } + + // Reorder each block's bytes on input + // c1 c0 r1 r0 __ __ __ => c1 c0 r0 r1 __ __ __ + // Reorder by relabeling (note the order of input) + // c1 c0 r0 __ __ __ __ => r0 c1 c0 __ __ __ __ + let mut t = [ + read_reordered(&b[0x00..0x03]), + read_reordered(&b[0x04..0x07]), + read_reordered(&b[0x08..0x0b]), + read_reordered(&b[0x0c..0x0f]), + read_reordered(&b[0x01..0x04]), + read_reordered(&b[0x05..0x08]), + read_reordered(&b[0x09..0x0c]), + read_reordered(&b[0x0d..0x10]), + ]; + + bitslice_swaps(&mut t); + + // Final bitsliced bit index, as desired: + // p2 p1 p0 r1 r0 c1 c0 + output[..8].copy_from_slice(&t); + } + + /// Un-bitslice a 128-bit internal state into one 128-bit block. + fn inv_bitslice(input: &[u16]) -> Array { + debug_assert_eq!(input.len(), 8); + + // Unbitslicing is a bit index manipulation. 128 bits of data means each bit is positioned + // at a 7-bit index. AES data is a single 4x4 column-major matrix of bytes, so the desired + // index for the output is ([c]olumn, [r]ow, [p]osition): + // c1 c0 r1 r0 p2 p1 p0 + // + // The initially bitsliced data groups first by bit position, then row, then column: + // p2 p1 p0 r1 r0 c1 c0 + + let mut t = [ + input[0], input[1], input[2], input[3], input[4], input[5], input[6], input[7], + ]; + + bitslice_swaps(&mut t); + + fn write_reordered(rows: u16, output: &mut [u8]) { + output[0x0] = rows as u8; + output[0x2] = (rows >> 8) as u8; + } + + let mut output = Array::::default(); + // Reorder by relabeling (note the order of output) + // r0 c1 c0 __ __ __ __ => c1 c0 r0 __ __ __ __ + // Reorder each block's bytes on output + // c1 c0 r0 r1 __ __ __ => c1 c0 r1 r0 __ __ __ + write_reordered(t[0], &mut output[0][0x00..0x03]); + write_reordered(t[1], &mut output[0][0x04..0x07]); + write_reordered(t[2], &mut output[0][0x08..0x0b]); + write_reordered(t[3], &mut output[0][0x0c..0x0f]); + write_reordered(t[4], &mut output[0][0x01..0x04]); + write_reordered(t[5], &mut output[0][0x05..0x08]); + write_reordered(t[6], &mut output[0][0x09..0x0c]); + write_reordered(t[7], &mut output[0][0x0d..0x10]); + + // Final AES bit index, as desired: + // c1 c0 r1 r0 p2 p1 p0 + output + } + + fn broadcast(rkey: MinWord) -> u16 { + rkey + } +} + +/// Expand an 8-bit row pattern to a 16-bit row pattern by doubling each bit: +/// input bit `i` becomes output bits `2i` and `2i+1`. Branchless SWAR so LLVM +/// folds it to a single 16-bit immediate when `b` is a constant. +#[inline(always)] +const fn double_bits_8_to_16(b: u8) -> u16 { + let x = b as u16; + // Spread the 8 bits of x to even positions 0,2,4,6,8,10,12,14. + let x = (x | (x << 4)) & 0x0f0f; + let x = (x | (x << 2)) & 0x3333; + let x = (x | (x << 1)) & 0x5555; + // Duplicate each spread bit to its adjacent odd position. + x | (x << 1) +} + +/// Expand a 16-bit row pattern to a 32-bit row pattern by doubling each bit: +/// input bit `i` becomes output bits `2i` and `2i+1`. Branchless SWAR so LLVM +/// folds it to a single 32-bit immediate when `b` is a constant. +#[inline(always)] +const fn double_bits_16_to_32(b: u16) -> u32 { + let x = b as u32; + // Spread the 16 bits of x to even positions 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30. + let x = (x | (x << 8)) & 0x00FF00FF; + let x = (x | (x << 4)) & 0x0F0F0F0F; + let x = (x | (x << 2)) & 0x33333333; + let x = (x | (x << 1)) & 0x55555555; + // Duplicate each spread bit to its adjacent odd position. + x | (x << 1) +} + +/// Expand a 16-bit row pattern to a 64-bit row pattern by quadrupling each bit: +/// input bit `i` becomes output bits `4i`, `4i+1`, `4i+2`, and `4i+3`. +/// Branchless SWAR so LLVM folds it to a single 64-bit immediate when `b` is +/// a constant. +#[inline(always)] +const fn quad_bits_16_to_64(b: u16) -> u64 { + let x = b as u64; + // Spread the 16 bits of x to positions 0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60. + let x = (x | (x << 24)) & 0x000000FF000000FF; + let x = (x | (x << 12)) & 0x000F000F000F000F; + let x = (x | (x << 6)) & 0x0303030303030303; + let x = (x | (x << 3)) & 0x1111111111111111; + // Duplicate each spread bit to its adjacent odd position. + x | (x << 1) | (x << 2) | (x << 3) } impl Word for u32 { @@ -68,12 +226,15 @@ impl Word for u32 { #[inline(always)] fn uniform_row(b: u8) -> u32 { - (b as u32) * 0x01010101 + double_bits_8_to_16(b) as u32 * 0x01010101 } #[inline(always)] fn pack_rows(r0: u8, r1: u8, r2: u8, r3: u8) -> u32 { - (r0 as u32) | ((r1 as u32) << 8) | ((r2 as u32) << 16) | ((r3 as u32) << 24) + (double_bits_8_to_16(r0) as u32) + | ((double_bits_8_to_16(r1) as u32) << 8) + | ((double_bits_8_to_16(r2) as u32) << 16) + | ((double_bits_8_to_16(r3) as u32) << 24) } #[inline(always)] @@ -149,20 +310,10 @@ impl Word for u32 { // b0 c1 c0 r1 r0 p2 p1 p0 output } -} -/// Expand an 8-bit row pattern to a 16-bit row pattern by doubling each bit: -/// input bit `i` becomes output bits `2i` and `2i+1`. Branchless SWAR so LLVM -/// folds it to a single 16-bit immediate when `b` is a constant. -#[inline(always)] -const fn double_bits(b: u8) -> u16 { - let x = b as u16; - // Spread the 8 bits of x to even positions 0,2,4,6,8,10,12,14. - let x = (x | (x << 4)) & 0x0f0f; - let x = (x | (x << 2)) & 0x3333; - let x = (x | (x << 1)) & 0x5555; - // Duplicate each spread bit to its adjacent odd position. - x | (x << 1) + fn broadcast(rkey: MinWord) -> Self { + double_bits_16_to_32(rkey) + } } impl Word for u64 { @@ -175,15 +326,15 @@ impl Word for u64 { #[inline(always)] fn uniform_row(b: u8) -> u64 { - (double_bits(b) as u64) * 0x0001_0001_0001_0001 + quad_bits_16_to_64(b as u16) * 0x0001_0001_0001_0001 } #[inline(always)] fn pack_rows(r0: u8, r1: u8, r2: u8, r3: u8) -> u64 { - (double_bits(r0) as u64) - | ((double_bits(r1) as u64) << 16) - | ((double_bits(r2) as u64) << 32) - | ((double_bits(r3) as u64) << 48) + quad_bits_16_to_64(r0 as u16) + | (quad_bits_16_to_64(r1 as u16) << 16) + | (quad_bits_16_to_64(r2 as u16) << 32) + | (quad_bits_16_to_64(r3 as u16) << 48) } #[inline(always)] @@ -285,6 +436,10 @@ impl Word for u64 { // b1 b0 c1 c0 r1 r0 p2 p1 p0 output } + + fn broadcast(rkey: MinWord) -> Self { + quad_bits_16_to_64(rkey) + } } /// Width-generic delta-swap pipeline shared by `bitslice` and `inv_bitslice` diff --git a/aes/src/backends/soft.rs b/aes/src/backends/soft.rs index 07c35a65..7487ad45 100644 --- a/aes/src/backends/soft.rs +++ b/aes/src/backends/soft.rs @@ -1,8 +1,8 @@ #![deny(unsafe_code)] -use crate::Block; +use crate::{Block, backends::soft::fixslice::BatchBlocks}; use cipher::{ - BlockCipherDecBackend, BlockCipherEncBackend, BlockSizeUser, ParBlocks, ParBlocksSizeUser, - consts::U16, inout::InOut, + BlockCipherDecBackend, BlockCipherDecClosure, BlockCipherEncBackend, BlockCipherEncClosure, + BlockSizeUser, ParBlocks, ParBlocksSizeUser, consts::U16, inout::InOut, }; #[path = "fixslice/mod.rs"] @@ -11,11 +11,12 @@ pub(crate) mod fixslice; #[cfg(feature = "hazmat")] pub(crate) use fixslice::hazmat; -use fixslice::{BatchBlocks, NativeBatchSize, NativeWord}; +use fixslice::{MinWord, NativeBatchSize, NativeWord, Word}; macro_rules! impl_backend { ( name = $name:tt, + backend = $backend:tt, key_size = $key_size:literal, module = $module:ident, doc = $doc:expr, @@ -24,53 +25,77 @@ macro_rules! impl_backend { #[doc = "block cipher"] #[derive(Clone, Copy)] pub(crate) struct $name { - keys: fixslice::$module::RoundKeys, + rk: fixslice::$module::RoundKeys, } impl $name { #[inline] pub(crate) fn new(key: &[u8; $key_size]) -> Self { - let keys = fixslice::$module::key_schedule(key); - Self { keys } + let rk = fixslice::$module::key_schedule(key); + Self { rk } } + + #[inline] + pub(crate) fn encrypt(&self, f: impl BlockCipherEncClosure) { + let rk = &self.rk; + let rk_native = self.rk.map(Word::broadcast); + let backend = $backend { rk, rk_native }; + f.call(&backend) + } + + #[inline] + pub(crate) fn decrypt(&self, f: impl BlockCipherDecClosure) { + let rk = &self.rk; + let rk_native = self.rk.map(Word::broadcast); + let backend = $backend { rk, rk_native }; + f.call(&backend) + } + } + + #[doc=$doc] + #[doc = "block cipher"] + #[derive(Clone, Copy)] + pub(crate) struct $backend<'a> { + rk: &'a fixslice::$module::RoundKeys, + rk_native: fixslice::$module::RoundKeys, } - impl BlockSizeUser for $name { + impl BlockSizeUser for $backend<'_> { type BlockSize = U16; } - impl ParBlocksSizeUser for $name { + impl ParBlocksSizeUser for $backend<'_> { type ParBlocksSize = NativeBatchSize; } - impl BlockCipherEncBackend for $name { + impl BlockCipherEncBackend for $backend<'_> { #[inline(always)] fn encrypt_block(&self, mut block: InOut<'_, '_, Block>) { - let mut blocks = BatchBlocks::::default(); + let mut blocks = BatchBlocks::::default(); blocks[0] = block.clone_in().into(); - let res = fixslice::$module::encrypt(&self.keys, &blocks); + let res = fixslice::$module::encrypt(&self.rk, &blocks); *block.get_out() = res[0].into(); } #[inline(always)] fn encrypt_par_blocks(&self, mut blocks: InOut<'_, '_, ParBlocks>) { - let res = fixslice::$module::encrypt(&self.keys, blocks.get_in()); + let res = fixslice::$module::encrypt(&self.rk_native, blocks.get_in()); *blocks.get_out() = res; } } - impl BlockCipherDecBackend for $name { + impl BlockCipherDecBackend for $backend<'_> { #[inline(always)] fn decrypt_block(&self, mut block: InOut<'_, '_, Block>) { - let mut blocks = BatchBlocks::::default(); + let mut blocks = BatchBlocks::::default(); blocks[0] = block.clone_in(); - let res = fixslice::$module::decrypt(&self.keys, &blocks); + let res = fixslice::$module::decrypt(&self.rk, &blocks); *block.get_out() = res[0]; } #[inline(always)] fn decrypt_par_blocks(&self, mut blocks: InOut<'_, '_, ParBlocks>) { - let res = fixslice::$module::decrypt(&self.keys, blocks.get_in()); + let res = fixslice::$module::decrypt(&self.rk_native, blocks.get_in()); *blocks.get_out() = res; } } @@ -79,18 +104,21 @@ macro_rules! impl_backend { impl_backend!( name = Aes128, + backend = Aes128Backend, key_size = 16, module = aes128, doc = "AES-128", ); impl_backend!( name = Aes192, + backend = Aes192Backend, key_size = 24, module = aes192, doc = "AES-192", ); impl_backend!( name = Aes256, + backend = Aes256Backend, key_size = 32, module = aes256, doc = "AES-256", diff --git a/aes/src/lib.rs b/aes/src/lib.rs index 2ee6820a..fc995922 100644 --- a/aes/src/lib.rs +++ b/aes/src/lib.rs @@ -298,8 +298,8 @@ macro_rules! impl_encrypt { } // SAFETY: we access correct union variant - let backend = unsafe { &self.inner.soft }; - f.call(backend); + let aes = unsafe { &self.inner.soft }; + aes.encrypt(f); } } }; @@ -348,8 +348,8 @@ macro_rules! impl_decrypt { } // SAFETY: we access correct union variant - let backend = unsafe { &self.inner.soft }; - f.call(backend); + let aes = unsafe { &self.inner.soft }; + aes.decrypt(f); } } };