From 59097cca9873628cb71a62da5563264545220a5c Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 1 Nov 2020 08:13:23 -0800 Subject: [PATCH 1/2] cipher: add encrypt/decrypt-only block cipher traits Closes #349 Adds `Encrypt` and `Decrypt` traits which can be used in cases where e.g. only the encryption portion of a block cipher is used, as in CTR mode. This PR does not otherwise attempt to add things like a blanket impl. --- cipher/src/block.rs | 94 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/cipher/src/block.rs b/cipher/src/block.rs index 551e9d14a..a03bb6147 100644 --- a/cipher/src/block.rs +++ b/cipher/src/block.rs @@ -185,3 +185,97 @@ impl BlockCipher for &Alg { Alg::decrypt_blocks(self, blocks); } } + +/// Encrypt-only functionality for block ciphers +pub trait Encrypt { + /// Size of the block in bytes + type BlockSize: ArrayLength; + + /// Number of blocks which can be processed in parallel by + /// cipher implementation + type ParBlocks: ArrayLength>; + + /// Encrypt block in-place + fn encrypt_block(&self, block: &mut GenericArray); + + /// Encrypt several blocks in parallel using instruction level parallelism + /// if possible. + /// + /// If `ParBlocks` equals to 1 it's equivalent to `encrypt_block`. + #[inline] + fn encrypt_par_blocks( + &self, + blocks: &mut GenericArray, Self::ParBlocks>, + ) { + for block in blocks.iter_mut() { + self.encrypt_block(block); + } + } + + /// Encrypt a slice of blocks, leveraging parallelism when available. + #[inline] + fn encrypt_blocks(&self, mut blocks: &mut [GenericArray]) { + let pb = Self::ParBlocks::to_usize(); + + if pb > 1 { + let mut iter = blocks.chunks_exact_mut(pb); + + for chunk in &mut iter { + self.encrypt_par_blocks(chunk.try_into().unwrap()) + } + + blocks = iter.into_remainder(); + } + + for block in blocks { + self.encrypt_block(block); + } + } +} + +/// Decrypt-only functionality for block ciphers +pub trait Decrypt { + /// Size of the block in bytes + type BlockSize: ArrayLength; + + /// Number of blocks which can be processed in parallel by + /// cipher implementation + type ParBlocks: ArrayLength>; + + /// Decrypt block in-place + fn decrypt_block(&self, block: &mut GenericArray); + + /// Decrypt several blocks in parallel using instruction level parallelism + /// if possible. + /// + /// If `ParBlocks` equals to 1 it's equivalent to `decrypt_block`. + #[inline] + fn decrypt_par_blocks( + &self, + blocks: &mut GenericArray, Self::ParBlocks>, + ) { + for block in blocks.iter_mut() { + self.decrypt_block(block); + } + } + + /// Decrypt a slice of blocks, leveraging parallelism when available. + #[inline] + fn decrypt_blocks(&self, mut blocks: &mut [GenericArray]) { + let pb = Self::ParBlocks::to_usize(); + + if pb > 1 { + let mut iter = blocks.chunks_exact_mut(pb); + + for chunk in &mut iter { + self.decrypt_par_blocks(chunk.try_into().unwrap()) + } + + blocks = iter.into_remainder(); + } + + for block in blocks { + self.decrypt_block(block); + } + } +} From ebfffdc40bb2923b0ef1936f63eb67deccb87576 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 1 Nov 2020 09:08:29 -0800 Subject: [PATCH 2/2] [WIP] cipher: split Encrypt/EncryptPar and Decrypt/DecryptPar Adds traits explicitly for parallel encryption/decryption, and blanket impls of the `Encrypt`/`Decrypt` traits for `EncryptPar`/`DecryptPar`. This makes the slice-based methods the primary user-facing API, and with it eliminating the need to worry about the `ParBlocks` associated type where it doesn't matter. --- cipher/src/block.rs | 68 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/cipher/src/block.rs b/cipher/src/block.rs index a03bb6147..06f9f58fc 100644 --- a/cipher/src/block.rs +++ b/cipher/src/block.rs @@ -191,6 +191,23 @@ pub trait Encrypt { /// Size of the block in bytes type BlockSize: ArrayLength; + /// Encrypt block in-place + fn encrypt_block(&self, block: &mut GenericArray); + + /// Encrypt a slice of blocks, leveraging parallelism when available. + #[inline] + fn encrypt_blocks(&self, blocks: &mut [GenericArray]) { + for block in blocks { + self.encrypt_block(block); + } + } +} + +/// Block cipher which can encrypt several blocks in parallel +pub trait EncryptPar { + /// Size of the block in bytes + type BlockSize: ArrayLength; + /// Number of blocks which can be processed in parallel by /// cipher implementation type ParBlocks: ArrayLength>; @@ -202,20 +219,23 @@ pub trait Encrypt { /// if possible. /// /// If `ParBlocks` equals to 1 it's equivalent to `encrypt_block`. - #[inline] fn encrypt_par_blocks( &self, blocks: &mut GenericArray, Self::ParBlocks>, - ) { - for block in blocks.iter_mut() { - self.encrypt_block(block); - } + ); +} + +impl Encrypt for Alg { + type BlockSize = Alg::BlockSize; + + #[inline] + fn encrypt_block(&self, block: &mut GenericArray) { + ::encrypt_block(self, block); } - /// Encrypt a slice of blocks, leveraging parallelism when available. #[inline] fn encrypt_blocks(&self, mut blocks: &mut [GenericArray]) { - let pb = Self::ParBlocks::to_usize(); + let pb = ::ParBlocks::to_usize(); if pb > 1 { let mut iter = blocks.chunks_exact_mut(pb); @@ -238,6 +258,23 @@ pub trait Decrypt { /// Size of the block in bytes type BlockSize: ArrayLength; + /// Decrypt block in-place + fn decrypt_block(&self, block: &mut GenericArray); + + /// Decrypt a slice of blocks, leveraging parallelism when available. + #[inline] + fn decrypt_blocks(&self, blocks: &mut [GenericArray]) { + for block in blocks.iter_mut() { + self.decrypt_block(block); + } + } +} + +/// Block cipher which can decrypt several blocks in parallel +pub trait DecryptPar { + /// Size of the block in bytes + type BlockSize: ArrayLength; + /// Number of blocks which can be processed in parallel by /// cipher implementation type ParBlocks: ArrayLength>; @@ -249,20 +286,23 @@ pub trait Decrypt { /// if possible. /// /// If `ParBlocks` equals to 1 it's equivalent to `decrypt_block`. - #[inline] fn decrypt_par_blocks( &self, blocks: &mut GenericArray, Self::ParBlocks>, - ) { - for block in blocks.iter_mut() { - self.decrypt_block(block); - } + ); +} + +impl Decrypt for Alg { + type BlockSize = Alg::BlockSize; + + #[inline] + fn decrypt_block(&self, block: &mut GenericArray) { + ::decrypt_block(self, block); } - /// Decrypt a slice of blocks, leveraging parallelism when available. #[inline] fn decrypt_blocks(&self, mut blocks: &mut [GenericArray]) { - let pb = Self::ParBlocks::to_usize(); + let pb = ::ParBlocks::to_usize(); if pb > 1 { let mut iter = blocks.chunks_exact_mut(pb);