use super::block::Block; #[cfg(target_arch = "x86_64")] pub type AesImpl = x86_64::AesNi; #[cfg(not(target_arch = "x86_64"))] pub type AesImpl = AesSoft; pub trait AesRound { fn new(key_i: Block, key_j: Block, key_l: Block) -> Self; fn aes4(&self, value: Block) -> Block; fn aes10(&self, value: Block) -> Block; } /// Implementation of aes4 and aes10 in software. /// /// Always available. /// /// Uses the `aes` crate under the hood. pub struct AesSoft { key_i: aes::Block, key_j: aes::Block, key_l: aes::Block, } impl AesRound for AesSoft { fn new(key_i: Block, key_j: Block, key_l: Block) -> Self { Self { key_i: key_i.bytes().into(), key_j: key_j.bytes().into(), key_l: key_l.bytes().into(), } } fn aes4(&self, value: Block) -> Block { let mut block: aes::Block = value.bytes().into(); ::aes::hazmat::cipher_round(&mut block, &self.key_j); ::aes::hazmat::cipher_round(&mut block, &self.key_i); ::aes::hazmat::cipher_round(&mut block, &self.key_l); ::aes::hazmat::cipher_round(&mut block, &Block::null().bytes().into()); >::from(block.into()) } fn aes10(&self, value: Block) -> Block { let mut block: aes::Block = value.bytes().into(); ::aes::hazmat::cipher_round(&mut block, &self.key_i); ::aes::hazmat::cipher_round(&mut block, &self.key_j); ::aes::hazmat::cipher_round(&mut block, &self.key_l); ::aes::hazmat::cipher_round(&mut block, &self.key_i); ::aes::hazmat::cipher_round(&mut block, &self.key_j); ::aes::hazmat::cipher_round(&mut block, &self.key_l); ::aes::hazmat::cipher_round(&mut block, &self.key_i); ::aes::hazmat::cipher_round(&mut block, &self.key_j); ::aes::hazmat::cipher_round(&mut block, &self.key_l); ::aes::hazmat::cipher_round(&mut block, &self.key_i); >::from(block.into()) } } #[cfg(target_arch = "x86_64")] pub mod x86_64 { use super::*; use core::arch::x86_64::*; cpufeatures::new!(cpuid_aes, "aes"); pub struct AesNi { support: cpuid_aes::InitToken, fallback: AesSoft, key_i: __m128i, key_j: __m128i, key_l: __m128i, null: __m128i, } impl AesRound for AesNi { fn new(key_i: Block, key_j: Block, key_l: Block) -> Self { Self { support: cpuid_aes::init(), fallback: AesSoft::new(key_i, key_j, key_l), key_i: key_i.simd().into(), key_j: key_j.simd().into(), key_l: key_l.simd().into(), null: Block::null().simd().into(), } } fn aes4(&self, value: Block) -> Block { if !self.support.get() { return self.fallback.aes4(value); } // SAFETY: Nothing should go wrong when calling AESENC unsafe { let mut block = value.simd().into(); block = _mm_aesenc_si128(block, self.key_j); block = _mm_aesenc_si128(block, self.key_i); block = _mm_aesenc_si128(block, self.key_l); block = _mm_aesenc_si128(block, self.null); Block::from_simd(block.into()) } } fn aes10(&self, value: Block) -> Block { if !self.support.get() { return self.fallback.aes10(value); } // SAFETY: Nothing should go wrong when calling AESENC unsafe { let mut block = value.simd().into(); block = _mm_aesenc_si128(block, self.key_i); block = _mm_aesenc_si128(block, self.key_j); block = _mm_aesenc_si128(block, self.key_l); block = _mm_aesenc_si128(block, self.key_i); block = _mm_aesenc_si128(block, self.key_j); block = _mm_aesenc_si128(block, self.key_l); block = _mm_aesenc_si128(block, self.key_i); block = _mm_aesenc_si128(block, self.key_j); block = _mm_aesenc_si128(block, self.key_l); block = _mm_aesenc_si128(block, self.key_i); Block::from_simd(block.into()) } } } }