diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/aesround.rs | 43 | ||||
-rw-r--r-- | src/block.rs | 58 | ||||
-rw-r--r-- | src/lib.rs | 2 |
3 files changed, 92 insertions, 11 deletions
diff --git a/src/aesround.rs b/src/aesround.rs index 169c125..6f63243 100644 --- a/src/aesround.rs +++ b/src/aesround.rs @@ -80,15 +80,42 @@ pub mod x86_64 { null: __m128i, } + #[cfg(feature = "simd")] + fn to_simd(block: Block) -> __m128i { + block.simd().into() + } + + #[cfg(not(feature = "simd"))] + fn to_simd(block: Block) -> __m128i { + let bytes = block.bytes(); + // SAFETY: loadu can load from unaligned memory + unsafe { _mm_loadu_si128(bytes.as_ptr() as *const _) } + } + + #[cfg(feature = "simd")] + fn from_simd(simd: __m128i) -> Block { + Block::from_simd(simd.into()) + } + + #[cfg(not(feature = "simd"))] + fn from_simd(simd: __m128i) -> Block { + let mut bytes = [0; 16]; + // SAFETY: storeu can store to unaligned memory + unsafe { + _mm_storeu_si128(bytes.as_mut_ptr() as *mut _, simd); + } + Block::from(bytes) + } + 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(), + key_i: to_simd(key_i), + key_j: to_simd(key_j), + key_l: to_simd(key_l), + null: to_simd(Block::null()), } } @@ -99,12 +126,12 @@ pub mod x86_64 { // SAFETY: Nothing should go wrong when calling AESENC unsafe { - let mut block = value.simd().into(); + let mut block = to_simd(value); 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()) + from_simd(block) } } @@ -115,7 +142,7 @@ pub mod x86_64 { // SAFETY: Nothing should go wrong when calling AESENC unsafe { - let mut block = value.simd().into(); + let mut block = to_simd(value); block = _mm_aesenc_si128(block, self.key_i); block = _mm_aesenc_si128(block, self.key_j); block = _mm_aesenc_si128(block, self.key_l); @@ -126,7 +153,7 @@ pub mod x86_64 { 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()) + from_simd(block) } } } diff --git a/src/block.rs b/src/block.rs index b485b17..bde60fc 100644 --- a/src/block.rs +++ b/src/block.rs @@ -1,10 +1,17 @@ use std::ops::{BitAnd, BitOr, BitXor, Index, IndexMut, Mul, Shl, Shr}; +#[cfg(feature = "simd")] use std::simd::prelude::*; /// A block, the unit of work that AEZ divides the message into. #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg(feature = "simd")] pub struct Block(u8x16); +/// A block, the unit of work that AEZ divides the message into. +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg(not(feature = "simd"))] +pub struct Block([u8; 16]); + impl Block { pub fn null() -> Block { Block([0; 16].into()) @@ -19,13 +26,19 @@ impl Block { } pub fn write_to(&self, output: &mut [u8; 16]) { + #[cfg(feature = "simd")] self.0.copy_to_slice(output); + + #[cfg(not(feature = "simd"))] + output.copy_from_slice(&self.0); } + #[cfg(feature = "simd")] pub(crate) fn simd(&self) -> u8x16 { self.0 } + #[cfg(feature = "simd")] pub(crate) fn from_simd(value: u8x16) -> Self { Block(value) } @@ -102,9 +115,34 @@ impl From<u128> for Block { impl BitXor<Block> for Block { type Output = Block; + #[cfg(feature = "simd")] fn bitxor(self, rhs: Block) -> Block { Block(self.0 ^ rhs.0) } + + #[cfg(not(feature = "simd"))] + fn bitxor(self, rhs: Block) -> Block { + // We unroll here because XOR is by far the operation that is used the most, and the + // int-conversion/bit-operation/int-conversion way is slower (but easier to write) + Block([ + self.0[0] ^ rhs.0[0], + self.0[1] ^ rhs.0[1], + self.0[2] ^ rhs.0[2], + self.0[3] ^ rhs.0[3], + self.0[4] ^ rhs.0[4], + self.0[5] ^ rhs.0[5], + self.0[6] ^ rhs.0[6], + self.0[7] ^ rhs.0[7], + self.0[8] ^ rhs.0[8], + self.0[9] ^ rhs.0[9], + self.0[10] ^ rhs.0[10], + self.0[11] ^ rhs.0[11], + self.0[12] ^ rhs.0[12], + self.0[13] ^ rhs.0[13], + self.0[14] ^ rhs.0[14], + self.0[15] ^ rhs.0[15], + ]) + } } impl Shl<u32> for Block { @@ -124,14 +162,30 @@ impl Shr<u32> for Block { impl BitAnd<Block> for Block { type Output = Block; fn bitand(self, rhs: Block) -> Block { - Block(self.0 & rhs.0) + #[cfg(feature = "simd")] + { + Block(self.0 & rhs.0) + } + + #[cfg(not(feature = "simd"))] + { + Block::from(self.to_int() & rhs.to_int()) + } } } impl BitOr<Block> for Block { type Output = Block; fn bitor(self, rhs: Block) -> Block { - Block(self.0 | rhs.0) + #[cfg(feature = "simd")] + { + Block(self.0 | rhs.0) + } + + #[cfg(not(feature = "simd"))] + { + Block::from(self.to_int() | rhs.to_int()) + } } } @@ -1,4 +1,4 @@ -#![feature(portable_simd)] +#![cfg_attr(feature = "simd", feature(portable_simd))] //! AEZ *\[sic!\]* v5 encryption implemented in Rust. //! //! # ☣️ Cryptographic hazmat ☣️ |