literate_crypto/cipher/block/
aes.rs

1//! AES is a commonly used block cipher.
2//!
3//! AES works on 128-bit blocks, and supports key sizes of 128, 192, and 256
4//! bits. It works by applying a series of rounds of substitutions and
5//! permutations to the plaintext, using a substitution box (S-box) and XORing
6//! the output with a different key every round. The round keys are derived from
7//! the decryption key.
8//!
9//! The S-box is a fixed, non-linear mapping from original to substituted bytes.
10//! It's implemented as a lookup table. This achieves
11//! [confusion](crate::doc::encryption#confusion). In particular, for
12//! AES, the S-box is a matrix with some desirable properties.
13//!
14//! The permutations are achieved by first treating the plaintext block as a 4x4
15//! matrix, and then shifting rows and mixing columns together. This ensures
16//! [diffusion](crate::doc::encryption#diffusion).
17//!
18//! The specification for this cipher is available as [FIPS 197](https://doi.org/10.6028/NIST.FIPS.197).
19//!
20//! You can read about AES's implementation details in the [`encrypt`] and
21//! [`decrypt`] methods.
22
23use {
24    crate::{BlockCipher, BlockDecrypt, BlockEncrypt},
25    docext::docext,
26};
27
28/// AES word size in bytes.
29const WORD_SIZE: usize = 4;
30
31/// AES block size in words.
32const NB: usize = 4;
33
34/// The substitution table, defined in Figure 7 of the AES specification.
35pub const S_BOX: [u8; 256] = [
36    0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
37    0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
38    0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
39    0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
40    0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
41    0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
42    0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
43    0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
44    0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
45    0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
46    0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
47    0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
48    0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
49    0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
50    0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
51    0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
52];
53
54/// Inverse [substitution table](S_BOX), defined in Figure 14 of the AES
55/// specification.
56pub const INV_S_BOX: [u8; 256] = [
57    0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
58    0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
59    0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
60    0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
61    0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
62    0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
63    0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
64    0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
65    0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
66    0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
67    0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
68    0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
69    0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
70    0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
71    0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
72    0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
73];
74
75/// The round constant word array, defined in Section 5.2 of the AES
76/// specification.
77pub const RCON: [u8; 15] = [
78    0x0, 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d,
79];
80
81const AES128_NK: usize = 4;
82const AES128_NR: usize = 10;
83const AES128_BLOCK_BYTES: usize = NB * WORD_SIZE;
84const AES128_KEY_BYTES: usize = AES128_NK * WORD_SIZE;
85const AES128_EXPANSION_BYTES: usize = NB * (AES128_NR + 1) * WORD_SIZE;
86
87const AES192_NK: usize = 6;
88const AES192_NR: usize = 12;
89const AES192_BLOCK_BYTES: usize = NB * WORD_SIZE;
90const AES192_KEY_BYTES: usize = AES192_NK * WORD_SIZE;
91const AES192_EXPANSION_BYTES: usize = NB * (AES192_NR + 1) * WORD_SIZE;
92
93const AES256_NK: usize = 8;
94const AES256_NR: usize = 14;
95const AES256_BLOCK_BYTES: usize = NB * WORD_SIZE;
96const AES256_KEY_BYTES: usize = AES256_NK * WORD_SIZE;
97const AES256_EXPANSION_BYTES: usize = NB * (AES256_NR + 1) * WORD_SIZE;
98
99/// [AES block cipher](self) with 128-bit keys.
100#[derive(Debug, Default)]
101pub struct Aes128(());
102
103impl BlockEncrypt for Aes128 {
104    type EncryptionBlock = [u8; NB * WORD_SIZE];
105    type EncryptionKey = [u8; AES128_NK * WORD_SIZE];
106
107    fn encrypt(
108        &self,
109        data: Self::EncryptionBlock,
110        key: Self::EncryptionKey,
111    ) -> Self::EncryptionBlock {
112        encrypt::<AES128_NK, AES128_NR, AES128_BLOCK_BYTES, AES128_KEY_BYTES, AES128_EXPANSION_BYTES>(
113            data, key,
114        )
115    }
116}
117
118impl BlockDecrypt for Aes128 {
119    type DecryptionBlock = [u8; NB * WORD_SIZE];
120    type DecryptionKey = [u8; AES128_NK * WORD_SIZE];
121
122    fn decrypt(
123        &self,
124        data: Self::DecryptionBlock,
125        key: Self::DecryptionKey,
126    ) -> Self::DecryptionBlock {
127        decrypt::<AES128_NK, AES128_NR, AES128_BLOCK_BYTES, AES128_KEY_BYTES, AES128_EXPANSION_BYTES>(
128            data, key,
129        )
130    }
131}
132
133impl BlockCipher for Aes128 {
134    type Block = [u8; NB * WORD_SIZE];
135    type Key = [u8; AES128_NK * WORD_SIZE];
136}
137
138/// [AES block cipher](self) with 192-bit keys.
139#[derive(Debug, Default)]
140pub struct Aes192(());
141
142impl BlockEncrypt for Aes192 {
143    type EncryptionBlock = [u8; NB * WORD_SIZE];
144    type EncryptionKey = [u8; AES192_NK * WORD_SIZE];
145
146    fn encrypt(
147        &self,
148        data: Self::EncryptionBlock,
149        key: Self::EncryptionKey,
150    ) -> Self::EncryptionBlock {
151        encrypt::<AES192_NK, AES192_NR, AES192_BLOCK_BYTES, AES192_KEY_BYTES, AES192_EXPANSION_BYTES>(
152            data, key,
153        )
154    }
155}
156
157impl BlockDecrypt for Aes192 {
158    type DecryptionBlock = [u8; NB * WORD_SIZE];
159    type DecryptionKey = [u8; AES192_NK * WORD_SIZE];
160
161    fn decrypt(
162        &self,
163        data: Self::DecryptionBlock,
164        key: Self::DecryptionKey,
165    ) -> Self::DecryptionBlock {
166        decrypt::<AES192_NK, AES192_NR, AES192_BLOCK_BYTES, AES192_KEY_BYTES, AES192_EXPANSION_BYTES>(
167            data, key,
168        )
169    }
170}
171
172impl BlockCipher for Aes192 {
173    type Block = [u8; NB * WORD_SIZE];
174    type Key = [u8; AES192_NK * WORD_SIZE];
175}
176
177/// [AES block cipher](self) with 256-bit keys.
178#[derive(Debug, Default)]
179pub struct Aes256(());
180
181impl BlockEncrypt for Aes256 {
182    type EncryptionBlock = [u8; NB * WORD_SIZE];
183    type EncryptionKey = [u8; AES256_NK * WORD_SIZE];
184
185    fn encrypt(
186        &self,
187        data: Self::EncryptionBlock,
188        key: Self::EncryptionKey,
189    ) -> Self::EncryptionBlock {
190        encrypt::<AES256_NK, AES256_NR, AES256_BLOCK_BYTES, AES256_KEY_BYTES, AES256_EXPANSION_BYTES>(
191            data, key,
192        )
193    }
194}
195
196impl BlockDecrypt for Aes256 {
197    type DecryptionBlock = [u8; NB * WORD_SIZE];
198    type DecryptionKey = [u8; AES256_NK * WORD_SIZE];
199
200    fn decrypt(
201        &self,
202        data: Self::DecryptionBlock,
203        key: Self::DecryptionKey,
204    ) -> Self::DecryptionBlock {
205        decrypt::<AES256_NK, AES256_NR, AES256_BLOCK_BYTES, AES256_KEY_BYTES, AES256_EXPANSION_BYTES>(
206            data, key,
207        )
208    }
209}
210
211impl BlockCipher for Aes256 {
212    type Block = [u8; NB * WORD_SIZE];
213    type Key = [u8; AES256_NK * WORD_SIZE];
214}
215
216/// AES encryption routine defined in Section 5.1 of the AES specification.
217///
218/// Applies the [SubBytes](sub_bytes), [ShiftRows](shift_rows),
219/// [MixColumns](mix_columns), and [AddRoundKey](add_round_key)
220/// transformations to the internal state in each round, and returns the
221/// resulting state as the ciphertext. The initial state is simply the plaintext
222/// block.
223///
224/// The encryption key is expanded into round keys using the
225/// [KeyExpansion](key_expansion) routine.
226#[docext]
227pub fn encrypt<
228    const NK: usize,              // Key size in words.
229    const NR: usize,              // Number of rounds.
230    const BLOCK_BYTES: usize,     // NB * WORD_SIZE.
231    const KEY_BYTES: usize,       // NK * WORD_SIZE.
232    const EXPANSION_BYTES: usize, // NB * (NR + 1) * WORD_SIZE.
233>(
234    data: [u8; BLOCK_BYTES],
235    key: [u8; KEY_BYTES],
236) -> [u8; BLOCK_BYTES] {
237    let mut state = data;
238    let w = key_expansion::<NK, NR, KEY_BYTES, EXPANSION_BYTES>(key);
239    add_round_key(&mut state, &w, 0);
240
241    for round in 1..NR {
242        sub_bytes(&mut state);
243        shift_rows(&mut state);
244        mix_columns(&mut state);
245        add_round_key(&mut state, &w, round);
246    }
247
248    sub_bytes(&mut state);
249    shift_rows(&mut state);
250    add_round_key(&mut state, &w, NR);
251
252    state
253}
254
255/// AES decryption routine defined in Section 5.3 of the AES specification.
256///
257/// Applies the [InvSubBytes](inv_sub_bytes),
258/// [InvShiftRows](inv_shift_rows), [InvMixColumns](inv_mix_columns), and
259/// [AddRoundKey](add_round_key) transformations to the internal state in each
260/// round, and returns the resulting state as the ciphertext. The initial state
261/// is simply the ciphertext block. The operations are applied in the opposite
262/// order from [encryption](encrypt).
263///
264/// Just like encryption, the decryption key is expanded into round keys using
265/// the [KeyExpansion](key_expansion) routine.
266#[docext]
267pub fn decrypt<
268    const NK: usize,              // Key size in words.
269    const NR: usize,              // Number of rounds.
270    const BLOCK_BYTES: usize,     // NB * WORD_SIZE.
271    const KEY_BYTES: usize,       // NK * WORD_SIZE.
272    const EXPANSION_BYTES: usize, // NB * (NR + 1) * WORD_SIZE.
273>(
274    data: [u8; BLOCK_BYTES],
275    key: [u8; KEY_BYTES],
276) -> [u8; BLOCK_BYTES] {
277    let mut state = data;
278    let w = key_expansion::<NK, NR, KEY_BYTES, EXPANSION_BYTES>(key);
279    add_round_key(&mut state, &w, NR);
280
281    for round in (1..NR).rev() {
282        inv_shift_rows(&mut state);
283        inv_sub_bytes(&mut state);
284        add_round_key(&mut state, &w, round);
285        inv_mix_columns(&mut state);
286    }
287
288    inv_shift_rows(&mut state);
289    inv_sub_bytes(&mut state);
290    add_round_key(&mut state, &w, 0);
291
292    state
293}
294
295/// The AddRoundKey transformation defined in Section 5.1.4 of the AES
296/// specification.
297///
298/// XORs bytes in the state with the corresponding bytes in the round key.
299#[docext]
300pub fn add_round_key(state: &mut [u8], w: &[u8], round: usize) {
301    state
302        .iter_mut()
303        .zip(&w[round * NB * WORD_SIZE..(round + 1) * NB * WORD_SIZE])
304        .for_each(|(s, k)| {
305            *s ^= k;
306        })
307}
308
309/// The SubBytes transformation defined in Section 5.1.1 of the AES
310/// specification.
311///
312/// Replaces each byte in the input with the corresponding byte from the
313/// [S-box](S_BOX).
314#[docext]
315pub fn sub_bytes(bytes: &mut [u8]) {
316    for b in bytes.iter_mut() {
317        *b = S_BOX[usize::try_from(*b).unwrap()];
318    }
319}
320
321/// The InvSubBytes transformation defined in Section 5.3.2 of the AES
322/// specification.
323///
324/// Replaces each byte in the input with the corresponding byte from the inverse
325/// S-box.
326///
327/// Inverse of [SubBytes](sub_bytes).
328#[docext]
329pub fn inv_sub_bytes(bytes: &mut [u8]) {
330    for b in bytes.iter_mut() {
331        *b = INV_S_BOX[usize::try_from(*b).unwrap()];
332    }
333}
334
335/// The ShiftRows transformation defined in Section 5.1.2 of the AES
336/// specification.
337///
338/// Rotates all rows by a certain offset, except the first one.
339#[docext]
340pub fn shift_rows(state: &mut [u8]) {
341    // Shift second row.
342    state.swap(1, 13);
343    state.swap(5, 9);
344    state.swap(1, 9);
345
346    // Shift third row.
347    state.swap(2, 10);
348    state.swap(6, 14);
349
350    // Shift fourth row.
351    state.swap(3, 7);
352    state.swap(11, 15);
353    state.swap(3, 11);
354}
355
356/// The InvShiftRows transformation defined in Section 5.3.1 of the AES
357/// specification.
358///
359/// Rotates all rows by a certain offset, except the first one, in the opposite
360/// direction of [ShiftRows](shift_rows).
361#[docext]
362pub fn inv_shift_rows(state: &mut [u8]) {
363    // Shift second row.
364    state.swap(1, 13);
365    state.swap(5, 9);
366    state.swap(5, 13);
367
368    // Shift third row.
369    state.swap(2, 10);
370    state.swap(6, 14);
371
372    // Shift fourth row.
373    state.swap(3, 15);
374    state.swap(7, 11);
375    state.swap(3, 11);
376}
377
378/// The MixColumns transformation defined in Section 5.1.3 of the AES
379/// specification.
380///
381/// Multiplies each column of the state array (represented as a column vector of
382/// $GF(2^8)$ polynomials) by a fixed matrix. The matrix is designed to cause a
383/// nonlinear correlation between the elements of the column, mixing them
384/// together.
385///
386/// The multiplications are carried out via [`times_02`] and related functions.
387#[docext]
388pub fn mix_columns<const BLOCK_BYTES: usize>(state: &mut [u8; BLOCK_BYTES]) {
389    let copy = *state;
390    state.chunks_mut(4).zip(copy.chunks(4)).for_each(|(s, c)| {
391        s[0] = times_02(c[0]) ^ times_03(c[1]) ^ c[2] ^ c[3];
392        s[1] = c[0] ^ times_02(c[1]) ^ times_03(c[2]) ^ c[3];
393        s[2] = c[0] ^ c[1] ^ times_02(c[2]) ^ times_03(c[3]);
394        s[3] = times_03(c[0]) ^ c[1] ^ c[2] ^ times_02(c[3]);
395    });
396}
397
398/// The InvMixColumns transformation defined in Section 5.3.1 of the AES
399/// specification.
400///
401/// Multiplies the state array by the inverse matrix of that used in
402/// [MixColumns](mix_columns).
403#[docext]
404pub fn inv_mix_columns<const BLOCK_BYTES: usize>(state: &mut [u8; BLOCK_BYTES]) {
405    let copy = *state;
406    state.chunks_mut(4).zip(copy.chunks(4)).for_each(|(s, c)| {
407        s[0] = times_0e(c[0]) ^ times_0b(c[1]) ^ times_0d(c[2]) ^ times_09(c[3]);
408        s[1] = times_09(c[0]) ^ times_0e(c[1]) ^ times_0b(c[2]) ^ times_0d(c[3]);
409        s[2] = times_0d(c[0]) ^ times_09(c[1]) ^ times_0e(c[2]) ^ times_0b(c[3]);
410        s[3] = times_0b(c[0]) ^ times_0d(c[1]) ^ times_09(c[2]) ^ times_0e(c[3]);
411    });
412}
413
414/// Multiply `b` by 0x02 in the Galois field $GF(2^8)$.
415///
416/// This operations is required by the
417/// [MixColumns](mix_columns) transformation and described in Section 4.2.1 of
418/// the AES specification.
419///
420/// In $GF(2^8)$:
421///
422/// $$
423/// abcdefgh_2 \equiv a x^7 + b x^6 + c x^5 + d x^4 + e x^3 + f x^2 + g x + h
424/// $$
425///
426/// The primary reason why this polynomial notation is useful is because
427/// addition and multiplication can be defined using polynomials in a meaningful
428/// way. Addition of polynomial _terms_ is defined as addition modulo two, which
429/// is equivalent to an XOR operation. Therefore,
430///
431/// $$
432/// abcdefgh_2 + ijklmnop_2 \equiv \\
433/// (a x^7 + b x^6 + c x^5 + d x^4 + e x^3 + f x^2 + g x + h) + (i x^7 + j x^6 +
434/// k x^5 + l x^4 + m x^3 + n x^2 + o x + p) \equiv \\
435/// (a \oplus i) x^7 + (b \oplus j) x^6 + (c \oplus k) x^5 + (d \oplus l) x^4 +
436/// (e \oplus m) x^3 + (f \oplus n) x^2 + (g \oplus o) x + h \oplus p \equiv
437/// \\ abcdefgh_2 \oplus ijklmnop_2
438/// $$
439///
440/// This shows that addition in $GF(2^8)$ is equivalent to the XOR of two
441/// binary numbers, which is very efficient to implement.
442///
443/// Multiplication of polynomials in $GF(2^8)$ is defined modulo $m(x) = x^8 +
444/// x^4 + x^3 + x + 1 \equiv \mathrm{1b_{16}}$. Multiplication of _terms_ is
445/// defined as a binary AND operation. However, multiplication by the trivial
446/// polynomial $x$ can be implemented more efficiently:
447///
448/// $$
449/// 02_{16} \cdot abcdefgh_2 \equiv \\
450/// x \cdot (a x^7 + b x^6 + c x^5 + d x^4 +
451/// e x^3 + f x^2 + g x + h) \mod m(x) =\\
452/// a x^8 + b x^7 + c x^6 + d x^5 + e x^4 + f x^3 + g x^2 + h x \mod m(x)
453/// $$
454///
455/// In the case that $a = 0$, the resulting polynomial $b x^7 + c
456/// x^6 + d x^5 + e x^4 + f x^3 + g x^2 + h x$ is already reduced modulo $m(x)$
457/// and can be represented as a binary number. If $a$ is $1$, then the resulting
458/// polynomial is not reduced. Since addition of terms in $GF(2^8)$ is defined
459/// modulo 2, addition and subtraction are equivalent. Polynomial
460/// reduction can be achieved by subtracting $m(x)$, which is equivalent to
461/// adding $m(x)$, which is equivalent to an XOR operation.
462///
463/// Therefore, multiplication by $x$ can be implemented as a left shift of the
464/// binary number (_notice that in the equation above, if the $ax^8$ term is
465/// dropped, the remaining terms are equivalent to a left shift of the original
466/// binary number_) followed by an XOR with $m(x) \equiv \mathrm{1b_{16}}$ if
467/// the high bit was set before the shift.
468///
469/// This is useful because multiplication by any polynomial can be represented
470/// as a series of multiplications by $x$ and additions of the resulting terms.
471/// This is how multiplications in related functions ([`times_03`],
472/// [`times_0e`], etc.) are defined: as a series of [`times_02`] and XOR
473/// operations.
474#[docext]
475pub fn times_02(b: u8) -> u8 {
476    // As the FIP explains, this is implemented via a bit shift and conditional XOR
477    // with 0x1b if the high bit is set.
478    let mut r = b << 1;
479    // The high bit will be set in the shifted bitset if the high bit was set
480    // in the original bitset before the shift.
481    if b & 0x80 != 0 {
482        r ^= 0x1b;
483    }
484    r
485}
486
487/// Multiply `b` by `0x03` in the Galois field $GF(2^8)$.
488///
489/// $$
490/// 03_{16} = 02_{16} \oplus 01_{16},\\
491/// b \cdot 03_{16} =
492/// b \cdot (02_{16} \oplus 01_{16}) =
493/// b \cdot 02_{16} \oplus b \cdot 01_{16} =
494/// b \cdot 02_{16} \oplus b
495/// $$
496///
497/// Which is equivalent to `times_02(b) ^ b`.
498#[docext]
499pub fn times_03(b: u8) -> u8 {
500    times_02(b) ^ b
501}
502
503/// Multiplication by `0x04` in the Galois field $GF(2^8)$.
504///
505/// $$
506/// 04_{16} \equiv 100_2 \equiv x^2 =
507/// x \cdot x \equiv 02_{16} \cdot 02_{16},\\ b \cdot 04_{16} =
508/// b \cdot (02_{16} \cdot 02_{16}) = (b \cdot 02_{16}) \cdot 02_{16}
509/// $$
510///
511/// Which is equivalent to `times_02(times_02(b))`.
512#[docext]
513pub fn times_04(b: u8) -> u8 {
514    times_02(times_02(b))
515}
516
517/// Multiplication by `0x08` in the Galois field $GF(2^8)$.
518///
519/// $$
520/// 08_{16} \equiv 1000_2 \equiv x^3 =
521/// x^2 \cdot x \equiv 04_{16} \cdot 02_{16},\\
522/// b \cdot 08_{16} =
523/// b \cdot (04_{16} \cdot 02_{16}) = (b \cdot 04_{16}) \cdot 02_{16}
524/// $$
525///
526/// Which is equivalent to `times_02(times_04(b))`.
527#[docext]
528pub fn times_08(b: u8) -> u8 {
529    times_02(times_04(b))
530}
531
532/// Multiplication by `0x09` in the Galois field $GF(2^8)$.
533///
534/// $$
535/// 09_{16} = 08_{16} \oplus 01_{16},\\
536/// b \cdot 09_{16} =
537/// b \cdot (08_{16} \oplus 01_{16}) =
538/// b \cdot 08_{16} \oplus b \cdot 01_{16} =
539/// b \cdot 08_{16} \oplus b
540/// $$
541///
542/// Which is equivalent to `times_08(b) ^ b`.
543#[docext]
544pub fn times_09(b: u8) -> u8 {
545    times_08(b) ^ b
546}
547
548/// Multiplication by `0x0b` in the Galois field $GF(2^8)$.
549///
550/// $$
551/// \mathrm{0b_{16}} = 08_{16} \oplus 03_{16},\\
552/// b \cdot \mathrm{0b_{16}} =
553/// b \cdot (08_{16} \oplus 03_{16}) =
554/// b \cdot 08_{16} \oplus b \cdot 03_{16}
555/// $$
556///
557/// Which is equivalent to `times_08(b) ^ times_03(b)`.
558#[docext]
559pub fn times_0b(b: u8) -> u8 {
560    times_08(b) ^ times_03(b)
561}
562
563/// Multiplication by `0x0d` in the Galois field $GF(2^8)$.
564///
565/// $$
566/// \mathrm{0d_{16}} = 08_{16} \oplus 04_{16} \oplus 01_{16},\\
567/// b \cdot \mathrm{0d_{16}} =
568/// b \cdot (08_{16} \oplus 04_{16} \oplus 01_{16}) =\\
569/// b \cdot 08_{16} \oplus b \cdot 04_{16} \oplus b \cdot 01_{16} =\\
570/// b \cdot 08_{16} \oplus b \cdot 04_{16} \oplus b
571/// $$
572///
573/// Which is equivalent to `times_08(b) ^ times_04(b) ^ b`.
574#[docext]
575pub fn times_0d(b: u8) -> u8 {
576    times_08(b) ^ times_04(b) ^ b
577}
578
579/// Multiplication by `0x0e` in the Galois field $GF(2^8)$.
580///
581/// $$
582/// \mathrm{0e_{16}} = 08_{16} \oplus 04_{16} \oplus 02_{16},\\
583/// b \cdot \mathrm{0e_{16}} =
584/// b \cdot (08_{16} \oplus 04_{16} \oplus 02_{16}) =\\
585/// b \cdot 08_{16} \oplus b \cdot 04_{16} \oplus b \cdot 02_{16} =\\
586/// b \cdot 08_{16} \oplus b \cdot 04_{16} \oplus b
587/// $$
588///
589/// Which is equivalent to `times_08(b) ^ times_04(b) ^ times_02(b)`.
590#[docext]
591pub fn times_0e(b: u8) -> u8 {
592    times_08(b) ^ times_04(b) ^ times_02(b)
593}
594
595/// The KeyExpansion routine defined in Section 5.2 of the AES specification.
596///
597/// Expands they key into a longer key schedule. A different part of the key
598/// schedule is used each round for the [AddRoundKey](add_round_key)
599/// transformation.
600pub fn key_expansion<
601    const NK: usize,
602    const NR: usize,
603    const KEY_BYTES: usize,       // NK * WORD_SIZE
604    const EXPANSION_BYTES: usize, // NB * (NR + 1) * WORD_SIZE
605>(
606    key: [u8; KEY_BYTES],
607) -> [u8; EXPANSION_BYTES] {
608    let mut w = [0; EXPANSION_BYTES];
609    w[0..NK * WORD_SIZE].copy_from_slice(&key);
610    for i in NK..NB * (NR + 1) {
611        let mut temp = [0; WORD_SIZE];
612        temp.copy_from_slice(&w[(i - 1) * WORD_SIZE..i * WORD_SIZE]);
613        if i % NK == 0 {
614            rot_word(&mut temp);
615            sub_bytes(&mut temp);
616            temp[0] ^= RCON[i / NK];
617        } else if NK > 6 && i % NK == 4 {
618            sub_bytes(&mut temp);
619        }
620        for j in 0..WORD_SIZE {
621            w[i * WORD_SIZE + j] = w[(i - NK) * WORD_SIZE + j];
622        }
623        w[i * WORD_SIZE..(i + 1) * WORD_SIZE]
624            .iter_mut()
625            .zip(temp)
626            .for_each(|(w, t)| *w ^= t)
627    }
628    w
629}
630
631/// The RotWord function defined in Section 5.2 of the AES specification.
632///
633/// Rotates the byte array left by one index.
634pub fn rot_word(word: &mut [u8; WORD_SIZE]) {
635    word.rotate_left(1);
636}