1 | //! Low-level "hazmat" AES functions: AES-NI support. |
2 | //! |
3 | //! Note: this isn't actually used in the `Aes128`/`Aes192`/`Aes256` |
4 | //! implementations in this crate, but instead provides raw AES-NI accelerated |
5 | //! access to the AES round function gated under the `hazmat` crate feature. |
6 | |
7 | use super::{ |
8 | arch::*, |
9 | utils::{load8, store8}, |
10 | }; |
11 | use crate::{Block, Block8}; |
12 | |
13 | /// AES cipher (encrypt) round function. |
14 | #[target_feature (enable = "aes" )] |
15 | pub(crate) unsafe fn cipher_round(block: &mut Block, round_key: &Block) { |
16 | // Safety: `loadu` and `storeu` support unaligned access |
17 | let b: __m128i = _mm_loadu_si128(mem_addr:block.as_ptr() as *const __m128i); |
18 | let k: __m128i = _mm_loadu_si128(mem_addr:round_key.as_ptr() as *const __m128i); |
19 | let out: __m128i = _mm_aesenc_si128(a:b, round_key:k); |
20 | _mm_storeu_si128(mem_addr:block.as_mut_ptr() as *mut __m128i, a:out); |
21 | } |
22 | |
23 | /// AES cipher (encrypt) round function: parallel version. |
24 | #[target_feature (enable = "aes" )] |
25 | pub(crate) unsafe fn cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { |
26 | let xmm_keys: [__m128i; 8] = load8(blocks:round_keys); |
27 | let mut xmm_blocks: [__m128i; 8] = load8(blocks); |
28 | |
29 | for i: usize in 0..8 { |
30 | xmm_blocks[i] = _mm_aesenc_si128(a:xmm_blocks[i], round_key:xmm_keys[i]); |
31 | } |
32 | |
33 | store8(blocks, b:xmm_blocks); |
34 | } |
35 | |
36 | /// AES cipher (encrypt) round function. |
37 | #[target_feature (enable = "aes" )] |
38 | pub(crate) unsafe fn equiv_inv_cipher_round(block: &mut Block, round_key: &Block) { |
39 | // Safety: `loadu` and `storeu` support unaligned access |
40 | let b: __m128i = _mm_loadu_si128(mem_addr:block.as_ptr() as *const __m128i); |
41 | let k: __m128i = _mm_loadu_si128(mem_addr:round_key.as_ptr() as *const __m128i); |
42 | let out: __m128i = _mm_aesdec_si128(a:b, round_key:k); |
43 | _mm_storeu_si128(mem_addr:block.as_mut_ptr() as *mut __m128i, a:out); |
44 | } |
45 | |
46 | /// AES cipher (encrypt) round function: parallel version. |
47 | #[target_feature (enable = "aes" )] |
48 | pub(crate) unsafe fn equiv_inv_cipher_round_par(blocks: &mut Block8, round_keys: &Block8) { |
49 | let xmm_keys: [__m128i; 8] = load8(blocks:round_keys); |
50 | let mut xmm_blocks: [__m128i; 8] = load8(blocks); |
51 | |
52 | for i: usize in 0..8 { |
53 | xmm_blocks[i] = _mm_aesdec_si128(a:xmm_blocks[i], round_key:xmm_keys[i]); |
54 | } |
55 | |
56 | store8(blocks, b:xmm_blocks); |
57 | } |
58 | |
59 | /// AES mix columns function. |
60 | #[target_feature (enable = "aes" )] |
61 | pub(crate) unsafe fn mix_columns(block: &mut Block) { |
62 | // Safety: `loadu` and `storeu` support unaligned access |
63 | let mut state: __m128i = _mm_loadu_si128(mem_addr:block.as_ptr() as *const __m128i); |
64 | |
65 | // Emulate mix columns by performing three inverse mix columns operations |
66 | state = _mm_aesimc_si128(state); |
67 | state = _mm_aesimc_si128(state); |
68 | state = _mm_aesimc_si128(state); |
69 | |
70 | _mm_storeu_si128(mem_addr:block.as_mut_ptr() as *mut __m128i, a:state); |
71 | } |
72 | |
73 | /// AES inverse mix columns function. |
74 | #[target_feature (enable = "aes" )] |
75 | pub(crate) unsafe fn inv_mix_columns(block: &mut Block) { |
76 | // Safety: `loadu` and `storeu` support unaligned access |
77 | let b: __m128i = _mm_loadu_si128(mem_addr:block.as_ptr() as *const __m128i); |
78 | let out: __m128i = _mm_aesimc_si128(b); |
79 | _mm_storeu_si128(mem_addr:block.as_mut_ptr() as *mut __m128i, a:out); |
80 | } |
81 | |