Skip to main content

aes/backends/fixslice/
utils.rs

1use super::{BatchBlocks, State, Word};
2
3/// Replicate a single 16-byte input block across all slots of a `Batch<W>`.
4///
5/// Used by the key schedules, which conceptually call `bitslice(...)` on the
6/// same input block several times to fill the bitsliced state.
7pub(super) fn broadcast<W: Word>(block: &[u8]) -> BatchBlocks<W> {
8    debug_assert_eq!(block.len(), 16);
9    let mut out = BatchBlocks::<W>::default();
10    for slot in out.iter_mut() {
11        slot.copy_from_slice(block);
12    }
13    out
14}
15
16#[inline]
17pub(super) fn delta_swap_1<W: Word>(a: &mut W, shift: u32, mask: W) {
18    let t = (*a ^ ((*a) >> shift)) & mask;
19    *a ^= t ^ (t << shift);
20}
21
22#[inline]
23pub(super) fn delta_swap_2<W: Word>(a: &mut W, b: &mut W, shift: u32, mask: W) {
24    let t = (*a ^ ((*b) >> shift)) & mask;
25    *a ^= t;
26    *b ^= t << shift;
27}
28
29/// Applies ShiftRows once on an AES state (or key).
30#[cfg(any(not(aes_backend_soft = "compact"), feature = "hazmat"))]
31#[inline]
32pub(super) fn shift_rows_1<W: Word>(state: &mut [W]) {
33    debug_assert_eq!(state.len(), 8);
34    for x in state.iter_mut() {
35        delta_swap_1(x, W::HALF_ROW, W::pack_rows(0x00, 0x03, 0x0f, 0x0c));
36        delta_swap_1(x, W::QUARTER_ROW, W::pack_rows(0x00, 0x33, 0x00, 0x33));
37    }
38}
39
40/// Applies ShiftRows twice on an AES state (or key).
41#[inline]
42pub(super) fn shift_rows_2<W: Word>(state: &mut [W]) {
43    debug_assert_eq!(state.len(), 8);
44    for x in state.iter_mut() {
45        delta_swap_1(x, W::HALF_ROW, W::pack_rows(0x00, 0x0f, 0x00, 0x0f));
46    }
47}
48
49/// Applies ShiftRows three times on an AES state (or key).
50#[inline]
51pub(super) fn shift_rows_3<W: Word>(state: &mut [W]) {
52    debug_assert_eq!(state.len(), 8);
53    for x in state.iter_mut() {
54        delta_swap_1(x, W::HALF_ROW, W::pack_rows(0x00, 0x0c, 0x0f, 0x03));
55        delta_swap_1(x, W::QUARTER_ROW, W::pack_rows(0x00, 0x33, 0x00, 0x33));
56    }
57}
58
59#[inline(always)]
60pub(super) fn inv_shift_rows_1<W: Word>(state: &mut [W]) {
61    shift_rows_3(state);
62}
63
64#[inline(always)]
65pub(super) fn inv_shift_rows_2<W: Word>(state: &mut [W]) {
66    shift_rows_2(state);
67}
68
69#[cfg(not(aes_backend_soft = "compact"))]
70#[inline(always)]
71pub(super) fn inv_shift_rows_3<W: Word>(state: &mut [W]) {
72    shift_rows_1(state);
73}
74
75/// XOR the columns after the S-box during the key schedule round function.
76///
77/// The `idx_xor` parameter refers to the index of the previous round key
78/// involved in the XOR computation (should be 8 and 16 for AES-128 and AES-256,
79/// respectively).
80///
81/// The `idx_ror` parameter refers to the rotation value, which varies between the
82/// different key schedules.
83pub(super) fn xor_columns<W: Word>(rkeys: &mut [W], offset: usize, idx_xor: usize, idx_ror: u32) {
84    for i in 0..8 {
85        let off_i = offset + i;
86        let rk = rkeys[off_i - idx_xor] ^ (W::uniform_row(0x03) & rkeys[off_i].ror(idx_ror));
87        rkeys[off_i] = rk
88            ^ (W::uniform_row(0xfc) & (rk << W::QUARTER_ROW))
89            ^ (W::uniform_row(0xf0) & (rk << W::HALF_ROW))
90            ^ (W::uniform_row(0xc0) & (rk << (3 * W::QUARTER_ROW)));
91    }
92}
93
94/// Copy 32-bytes within the provided slice to an 8-byte offset.
95pub(super) fn memshift32<W: Word>(buffer: &mut [W], src_offset: usize) {
96    debug_assert_eq!(src_offset % 8, 0);
97
98    let dst_offset = src_offset + 8;
99    debug_assert!(dst_offset + 8 <= buffer.len());
100
101    for i in (0..8).rev() {
102        buffer[dst_offset + i] = buffer[src_offset + i];
103    }
104}
105
106/// XOR the round key into the internal state. The round keys are expected
107/// to be pre-computed and packed in the fixsliced representation.
108#[inline]
109pub(super) fn add_round_key<W: Word>(state: &mut State<W>, rkey: &[W]) {
110    debug_assert_eq!(rkey.len(), 8);
111    for (a, b) in state.iter_mut().zip(rkey) {
112        *a ^= *b;
113    }
114}
115
116#[inline(always)]
117pub(super) fn add_round_constant_bit<W: Word>(state: &mut [W], bit: usize) {
118    state[bit] ^= W::pack_rows(0x00, 0xc0, 0x00, 0x00);
119}