Skip to content

Commit

Permalink
cipher: add traits for tweakable block ciphers
Browse files Browse the repository at this point in the history
  • Loading branch information
newpavlov committed Dec 4, 2024
1 parent 8bb3381 commit b6f1677
Show file tree
Hide file tree
Showing 4 changed files with 304 additions and 0 deletions.
2 changes: 2 additions & 0 deletions cipher/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ pub mod block;
#[cfg(feature = "dev")]
mod dev;
pub mod stream;
pub mod tweak;

pub use block::*;
pub use stream::*;
pub use tweak::*;

pub use crypto_common::{
array::{self, Array},
Expand Down
145 changes: 145 additions & 0 deletions cipher/src/tweak.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//! Traits used to define functionality of [tweakable block ciphers][1].
//!
//! [1]: https://people.eecs.berkeley.edu/~daw/papers/tweak-crypto02.pdf
use crypto_common::{
array::{Array, ArraySize},
typenum::Unsigned,
Block, BlockSizeUser, ParBlocks, ParBlocksSizeUser,
};
use inout::InOut;

mod ctx;
mod zero;

pub use zero::ZeroTweak;

/// Array of tweaks used by a implementor of [`TweakSizeUser`] and [`ParBlocksSizeUser`].
pub type ParTweaks<C> = Array<Tweak<C>, <C as ParBlocksSizeUser>::ParBlocksSize>;
/// Tweak used by a [`TweakSizeUser`] implementor.
pub type Tweak<C> = Array<u8, <C as TweakSizeUser>::TweakSize>;

/// Trait which contains tweak size used by the tweak cipher traits.
pub trait TweakSizeUser {
/// Size of the tweak in bytes.
type TweakSize: ArraySize;
}

/// Encrypt-only functionality for tweakable block ciphers.
pub trait TweakBlockCipherEncrypt: BlockSizeUser + TweakSizeUser + Sized {
/// Encrypt data using backend provided to the rank-2 closure.
fn encrypt_with_backend(
&self,
f: impl TweakBlockCipherEncClosure<BlockSize = Self::BlockSize, TweakSize = Self::TweakSize>,
);

/// Encrypt single `inout` block.
#[inline]
fn encrypt_block_inout(&self, tweak: &Tweak<Self>, block: InOut<'_, '_, Block<Self>>) {
self.encrypt_with_backend(ctx::BlockCtx { tweak, block });
}

/// Encrypt single block in-place.
#[inline]
fn encrypt_block(&self, tweak: &Tweak<Self>, block: &mut Block<Self>) {
self.encrypt_block_inout(tweak, block.into());
}

/// Encrypt `in_block` and write result to `out_block`.
#[inline]
fn encrypt_block_b2b(
&self,
tweak: &Tweak<Self>,
in_block: &Block<Self>,
out_block: &mut Block<Self>,
) {
self.encrypt_block_inout(tweak, (in_block, out_block).into());
}
}

/// Decrypt-only functionality for tweakable block ciphers.
pub trait TweakBlockCipherDecrypt: BlockSizeUser + TweakSizeUser + Sized {
/// Decrypt data using backend provided to the rank-2 closure.
fn decrypt_with_backend(
&self,
f: impl TweakBlockCipherDecClosure<BlockSize = Self::BlockSize, TweakSize = Self::TweakSize>,
);

/// Decrypt single `inout` block.
#[inline]
fn decrypt_block_inout(&self, tweak: &Tweak<Self>, block: InOut<'_, '_, Block<Self>>) {
self.decrypt_with_backend(ctx::BlockCtx { tweak, block });
}

/// Decrypt single block in-place.
#[inline]
fn decrypt_block(&self, tweak: &Tweak<Self>, block: &mut Block<Self>) {
self.decrypt_block_inout(tweak, block.into());
}

/// Decrypt `in_block` and write result to `out_block`.
#[inline]
fn decrypt_block_b2b(
&self,
tweak: &Tweak<Self>,
in_block: &Block<Self>,
out_block: &mut Block<Self>,
) {
self.decrypt_block_inout(tweak, (in_block, out_block).into());
}
}

/// Trait for [`TweakBlockCipherEncBackend`] users.
///
/// This trait is used to define rank-2 closures.
pub trait TweakBlockCipherEncClosure: BlockSizeUser + TweakSizeUser {
/// Execute closure with the provided block cipher backend.
fn call<B>(self, backend: &B)
where
B: TweakBlockCipherEncBackend<BlockSize = Self::BlockSize, TweakSize = Self::TweakSize>;
}

/// Trait for [`TweakBlockCipherDecBackend`] users.
///
/// This trait is used to define rank-2 closures.
pub trait TweakBlockCipherDecClosure: BlockSizeUser + TweakSizeUser {
/// Execute closure with the provided block cipher backend.
fn call<B>(self, backend: &B)
where
B: TweakBlockCipherDecBackend<BlockSize = Self::BlockSize, TweakSize = Self::TweakSize>;
}

/// Trait implemented by block cipher mode encryption backends.
pub trait TweakBlockCipherEncBackend: ParBlocksSizeUser + TweakSizeUser {
/// Encrypt single inout block.
fn encrypt_block(&self, tweak: &Tweak<Self>, block: InOut<'_, '_, Block<Self>>);

/// Encrypt inout blocks in parallel.
#[inline(always)]
fn encrypt_par_blocks(
&self,
tweak: &ParTweaks<Self>,
mut blocks: InOut<'_, '_, ParBlocks<Self>>,
) {
for i in 0..Self::ParBlocksSize::USIZE {
self.encrypt_block(&tweak[i], blocks.get(i));
}
}
}

/// Trait implemented by block cipher mode decryption backends.
pub trait TweakBlockCipherDecBackend: ParBlocksSizeUser + TweakSizeUser {
/// Decrypt single inout block.
fn decrypt_block(&self, tweak: &Tweak<Self>, block: InOut<'_, '_, Block<Self>>);

/// Decrypt inout blocks in parallel.
#[inline(always)]
fn decrypt_par_blocks(
&self,
tweak: &ParTweaks<Self>,
mut blocks: InOut<'_, '_, ParBlocks<Self>>,
) {
for i in 0..Self::ParBlocksSize::USIZE {
self.decrypt_block(&tweak[i], blocks.get(i));
}
}
}
35 changes: 35 additions & 0 deletions cipher/src/tweak/ctx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use crypto_common::{array::ArraySize, Block, BlockSizeUser, BlockSizes};
use inout::InOut;

use super::{
Tweak, TweakBlockCipherDecBackend, TweakBlockCipherDecClosure, TweakBlockCipherEncBackend,
TweakBlockCipherEncClosure, TweakSizeUser,
};

/// Closure used in methods which operate over separate blocks.
pub(super) struct BlockCtx<'a, TS: ArraySize, BS: BlockSizes> {
pub tweak: &'a Tweak<Self>,
pub block: InOut<'a, 'a, Block<Self>>,
}

impl<TS: ArraySize, BS: BlockSizes> BlockSizeUser for BlockCtx<'_, TS, BS> {
type BlockSize = BS;
}

impl<TS: ArraySize, BS: BlockSizes> TweakSizeUser for BlockCtx<'_, TS, BS> {
type TweakSize = TS;
}

impl<TS: ArraySize, BS: BlockSizes> TweakBlockCipherEncClosure for BlockCtx<'_, TS, BS> {
#[inline(always)]
fn call<B: TweakBlockCipherEncBackend<BlockSize = BS, TweakSize = TS>>(self, backend: &B) {
backend.encrypt_block(self.tweak, self.block);
}
}

impl<TS: ArraySize, BS: BlockSizes> TweakBlockCipherDecClosure for BlockCtx<'_, TS, BS> {
#[inline(always)]
fn call<B: TweakBlockCipherDecBackend<BlockSize = BS, TweakSize = TS>>(self, backend: &B) {
backend.decrypt_block(self.tweak, self.block);
}
}
122 changes: 122 additions & 0 deletions cipher/src/tweak/zero.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use core::marker::PhantomData;

use crypto_common::{array::ArraySize, Block, BlockSizes, ParBlocks, ParBlocksSizeUser};

use super::{
TweakBlockCipherDecBackend, TweakBlockCipherDecClosure, TweakBlockCipherDecrypt,
TweakBlockCipherEncBackend, TweakBlockCipherEncrypt, TweakSizeUser,
};
use crate::{
tweak::TweakBlockCipherEncClosure, BlockCipherDecBackend, BlockCipherDecClosure,
BlockCipherDecrypt, BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt,
BlockSizeUser,
};

/// Wrapper around tweakable block cipher which implements
/// the [common block cipher traits][crate::block] using zero tweak.
#[derive(Debug, Clone)]
pub struct ZeroTweak<C: TweakSizeUser + BlockSizeUser>(pub C);

impl<C: TweakSizeUser + BlockSizeUser> BlockSizeUser for ZeroTweak<C> {
type BlockSize = C::BlockSize;
}

impl<C: TweakBlockCipherEncrypt> BlockCipherEncrypt for ZeroTweak<C> {
fn encrypt_with_backend(&self, f: impl BlockCipherEncClosure<BlockSize = Self::BlockSize>) {
self.0.encrypt_with_backend(ClosureWrapper {
f,
_pd: PhantomData,
});
}
}

impl<C: TweakBlockCipherDecrypt> BlockCipherDecrypt for ZeroTweak<C> {
fn decrypt_with_backend(&self, f: impl BlockCipherDecClosure<BlockSize = Self::BlockSize>) {
self.0.decrypt_with_backend(ClosureWrapper {
f,
_pd: PhantomData,
});
}
}

/// Wrapper around non-tweakble block cipher closures which implements the tweakable
/// block cipher closure traits using zero tweak.
struct ClosureWrapper<TS: ArraySize, BS: BlockSizes, F> {
f: F,
_pd: PhantomData<(TS, BS)>,
}

impl<TS: ArraySize, BS: BlockSizes, F> BlockSizeUser for ClosureWrapper<TS, BS, F> {
type BlockSize = BS;
}

impl<TS: ArraySize, BS: BlockSizes, F> TweakSizeUser for ClosureWrapper<TS, BS, F> {
type TweakSize = TS;
}

impl<TS: ArraySize, BS: BlockSizes, F> TweakBlockCipherEncClosure for ClosureWrapper<TS, BS, F>
where
F: BlockCipherEncClosure<BlockSize = BS>,
{
fn call<B: TweakBlockCipherEncBackend<BlockSize = BS, TweakSize = TS>>(self, backend: &B) {
self.f.call(&BackendWrapper {
backend,
_pd: PhantomData,
})
}
}

impl<TS: ArraySize, BS: BlockSizes, F> TweakBlockCipherDecClosure for ClosureWrapper<TS, BS, F>
where
F: BlockCipherDecClosure<BlockSize = BS>,
{
fn call<B: TweakBlockCipherDecBackend<BlockSize = BS, TweakSize = TS>>(self, backend: &B) {
self.f.call(&BackendWrapper {
backend,
_pd: PhantomData,
})
}
}

/// Wrapper around tweakable block cipher backend which implements non-tweakable
/// block cipher backend traits using zero tweak.
struct BackendWrapper<'a, BS: BlockSizes, B> {
backend: &'a B,
_pd: PhantomData<BS>,
}

impl<BS: BlockSizes, B> BlockSizeUser for BackendWrapper<'_, BS, B> {
type BlockSize = BS;
}

impl<BS: BlockSizes, B: ParBlocksSizeUser> ParBlocksSizeUser for BackendWrapper<'_, BS, B> {
type ParBlocksSize = B::ParBlocksSize;
}

impl<BS: BlockSizes, B: TweakBlockCipherEncBackend<BlockSize = BS>> BlockCipherEncBackend
for BackendWrapper<'_, BS, B>
{
#[inline]
fn encrypt_block(&self, block: inout::InOut<'_, '_, Block<Self>>) {
self.backend.encrypt_block(&Default::default(), block);
}

#[inline]
fn encrypt_par_blocks(&self, blocks: inout::InOut<'_, '_, ParBlocks<Self>>) {
self.backend.encrypt_par_blocks(&Default::default(), blocks);
}
}

impl<BS: BlockSizes, B: TweakBlockCipherDecBackend<BlockSize = BS>> BlockCipherDecBackend
for BackendWrapper<'_, BS, B>
{
#[inline]
fn decrypt_block(&self, block: inout::InOut<'_, '_, Block<Self>>) {
self.backend.decrypt_block(&Default::default(), block);
}

#[inline]
fn decrypt_par_blocks(&self, blocks: inout::InOut<'_, '_, ParBlocks<Self>>) {
self.backend.decrypt_par_blocks(&Default::default(), blocks);
}
}

0 comments on commit b6f1677

Please sign in to comment.