feistel/
symmetric.rs

1use core::{marker::PhantomData, ops::BitXor};
2
3use crate::{Network, Round};
4
5/// [`Network`] with [`Network::L`] equal to [`Network::R`] and [`Network::forward`] equivalent to
6/// [`Network::backward`].
7pub trait SymmetricNetwork:
8    Sized + IntoIterator<Item: Round<Self::T, L = Self::T>, IntoIter: DoubleEndedIterator>
9{
10    /// Half of a block.
11    type T: BitXor<Output = Self::T>;
12    /// `swap(swap(block)) == block`
13    fn swap(block: (Self::T, Self::T)) -> (Self::T, Self::T) {
14        let (left, right) = block;
15        (right, left)
16    }
17}
18
19impl<I: SymmetricNetwork> Network for I {
20    type L = I::T;
21    type R = I::T;
22    fn forward(block: (Self::R, Self::L)) -> (Self::L, Self::R) {
23        I::swap(block)
24    }
25    fn backward(block: (Self::L, Self::R)) -> (Self::L, Self::R) {
26        I::swap(block)
27    }
28}
29
30/// [`SymmetricNetwork`] wrapper around an [`IntoIterator`].
31pub struct Symmetric<I, T>(I, PhantomData<T>);
32
33impl<I: Clone, T> Clone for Symmetric<I, T> {
34    fn clone(&self) -> Self {
35        Self(self.0.clone(), PhantomData)
36    }
37}
38
39impl<I: Copy, T> Copy for Symmetric<I, T> {}
40
41impl<I, T: BitXor<Output = T>> Symmetric<I, T> {
42    /// Make a [`SymmetricNetwork`] out of an [`IntoIterator`].
43    pub fn new(rounds: I) -> Self {
44        Self(rounds, PhantomData)
45    }
46}
47
48impl<I: IntoIterator, T> IntoIterator for Symmetric<I, T> {
49    type Item = I::Item;
50    type IntoIter = I::IntoIter;
51    fn into_iter(self) -> Self::IntoIter {
52        self.0.into_iter()
53    }
54}
55
56impl<
57        T: BitXor<Output = T>,
58        I: IntoIterator<Item: Round<T, L = T>, IntoIter: DoubleEndedIterator>,
59    > SymmetricNetwork for Symmetric<I, T>
60{
61    type T = T;
62}
63
64mod private {
65    pub trait Sealed<T> {}
66}
67
68/// Extension trait for creating [`SymmetricNetwork`]s.
69pub trait SymmetricExt<T: BitXor<Output = T>>:
70    Sized + IntoIterator<Item: Round<T, L = T>, IntoIter: DoubleEndedIterator> + private::Sealed<T>
71{
72    /// Make a [`SymmetricNetwork`] from an [`IntoIterator`].
73    fn feistel_symmetric(self) -> Symmetric<Self, T> {
74        Symmetric::new(self)
75    }
76}
77
78impl<
79        T: BitXor<Output = T>,
80        I: IntoIterator<Item: Round<T, L = T>, IntoIter: DoubleEndedIterator>,
81    > private::Sealed<T> for I
82{
83}
84
85impl<
86        T: BitXor<Output = T>,
87        I: IntoIterator<Item: Round<T, L = T>, IntoIter: DoubleEndedIterator> + private::Sealed<T>,
88    > SymmetricExt<T> for I
89{
90}