| 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 | |