Skip to content

Commit

Permalink
cipher: add traits for tweakable block ciphers (#1721)
Browse files Browse the repository at this point in the history
The trait design generally follows the `BlockCipherEnc/Dec` traits. We
currently do not have tweakable block cipher implementations which use
the backend capability, but I think it's still worth to include it for
API consistency and to future-proof the traits. Some of the helper
methods (e.g. `encrypt_blocks`) are not translated since it's unclear
how to organize passing of tweaks. Arguably, such methods should not be
used with tweakable block ciphers either way.

As a bridge between tweakable and non-tweakable traits the `ZeroTweak`
wrapper is introduced. It allows users to use tweakable block cipher
implementations with the parts of the ecosystem which expects
non-tweakble block ciphers while still being explicit in the code (e.g.
`ZeroTweak<Threefish256>`).
  • Loading branch information
newpavlov authored Jan 30, 2025
1 parent fb85f46 commit 1a770af
Show file tree
Hide file tree
Showing 4 changed files with 313 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
152 changes: 152 additions & 0 deletions cipher/src/tweak.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
//! 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},
Block, BlockSizeUser,
};
use inout::InOut;

mod ctx;
mod zero;

pub use zero::ZeroTweak;

/// 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: BlockSizeUser + TweakSizeUser {
/// Encrypt single inout block.
fn encrypt_block_inout(&self, tweak: &Tweak<Self>, block: InOut<'_, '_, Block<Self>>);

/// 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());
}
}

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

/// 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());
}
}
41 changes: 41 additions & 0 deletions cipher/src/tweak/ctx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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]
fn call<B>(self, backend: &B)
where
B: TweakBlockCipherEncBackend<BlockSize = BS, TweakSize = TS>,
{
backend.encrypt_block_inout(self.tweak, self.block);
}
}

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

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

use super::{
TweakBlockCipherDecBackend, TweakBlockCipherDecClosure, TweakBlockCipherDecrypt,
TweakBlockCipherEncBackend, TweakBlockCipherEncrypt, TweakSizeUser,
};
use crate::{
consts::U1, 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> {
#[inline]
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> {
#[inline]
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>,
{
#[inline]
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>,
{
#[inline]
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 for BackendWrapper<'_, BS, B> {
type ParBlocksSize = U1;
}

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

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

0 comments on commit 1a770af

Please sign in to comment.