feistel/
array.rs

1use core::{
2    marker::PhantomData,
3    ops::{Add, BitXor, BitXorAssign, Sub},
4};
5
6use generic_array::{
7    sequence::{Concat, Split},
8    typenum::Sum,
9    ArrayLength, GenericArray,
10};
11
12use crate::{Network, Reverse, Round, XorArray};
13
14/// [`Network`] dealing with [`GenericArray`]s.
15pub trait ArrayNetwork:
16    Network<L = XorArray<Self::T, Self::LN>, R = XorArray<Self::T, Self::RN>>
17{
18    /// Length of the left half of a block.
19    type LN: ArrayLength
20        + Add<
21            Self::RN,
22            Output: ArrayLength
23                        + Sub<Self::LN, Output = Self::RN>
24                        + Sub<Self::RN, Output = Self::LN>,
25        >;
26    /// Length of the right half of a block.
27    type RN: ArrayLength + Add<Self::LN, Output = <Self::LN as Add<Self::RN>>::Output>;
28    /// Element of an array.
29    type T: BitXor;
30    /// Encrypt an array.
31    fn array_encrypt(self, block: Block<Self>) -> Block<Self> {
32        let (left, right) = Split::split(block);
33        let (left, right) = (XorArray(left), XorArray(right));
34        let (left, right) = self.encrypt((left, right));
35        Concat::concat(left.0, right.0)
36    }
37    /// Decrypt an array.
38    fn array_decrypt(self, block: Block<Self>) -> Block<Self> {
39        Reverse(self).array_encrypt(block)
40    }
41}
42
43type Block<I> =
44    GenericArray<<I as ArrayNetwork>::T, Sum<<I as ArrayNetwork>::LN, <I as ArrayNetwork>::RN>>;
45
46impl<
47        T: BitXor,
48        L: ArrayLength + Add<R, Output: ArrayLength + Sub<L, Output = R> + Sub<R, Output = L>>,
49        R: ArrayLength + Add<L, Output = <L as Add<R>>::Output>,
50        I: Network<L = XorArray<T, L>, R = XorArray<T, R>>,
51    > ArrayNetwork for I
52{
53    type LN = L;
54    type RN = R;
55    type T = T;
56}
57
58/// [`ArrayNetwork`] wrapper around an [`IntoIterator`].
59pub struct Array<I, T, R>(I, PhantomData<(T, R)>);
60
61impl<I: Clone, T, R> Clone for Array<I, T, R> {
62    fn clone(&self) -> Self {
63        Self(self.0.clone(), PhantomData)
64    }
65}
66
67impl<I: Copy, T, R> Copy for Array<I, T, R> {}
68
69impl<
70        T: BitXorAssign,
71        L: ArrayLength + Add<R, Output: ArrayLength + Sub<L, Output = R> + Sub<R, Output = L>>,
72        R: ArrayLength + Add<L, Output = <L as Add<R>>::Output>,
73        I: IntoIterator<
74            Item: Round<XorArray<T, R>, L = XorArray<T, L>>,
75            IntoIter: DoubleEndedIterator,
76        >,
77    > Array<I, T, R>
78{
79    /// Make an [`ArrayNetwork`] out of an [`IntoIterator`].
80    pub fn new(rounds: I) -> Self {
81        Self(rounds, PhantomData)
82    }
83}
84
85impl<I: IntoIterator, T, R> IntoIterator for Array<I, T, R> {
86    type Item = I::Item;
87    type IntoIter = I::IntoIter;
88    fn into_iter(self) -> Self::IntoIter {
89        self.0.into_iter()
90    }
91}
92
93impl<
94        T: BitXorAssign,
95        L: ArrayLength + Add<R, Output: ArrayLength + Sub<L, Output = R> + Sub<R, Output = L>>,
96        R: ArrayLength + Add<L, Output = <L as Add<R>>::Output>,
97        I: IntoIterator<
98            Item: Round<XorArray<T, R>, L = XorArray<T, L>>,
99            IntoIter: DoubleEndedIterator,
100        >,
101    > Network for Array<I, T, R>
102{
103    type L = XorArray<T, L>;
104    type R = XorArray<T, R>;
105    fn forward(block: (Self::L, Self::R)) -> (Self::L, Self::R) {
106        let (left, right) = block;
107        let (left, right) = Split::split(Concat::concat(right.0, left.0));
108        let (left, right) = (XorArray(left), XorArray(right));
109        (left, right)
110    }
111    fn backward(block: (Self::L, Self::R)) -> (Self::L, Self::R) {
112        let (left, right) = block;
113        let (right, left) = Split::split(Concat::concat(left.0, right.0));
114        let (right, left) = (XorArray(right), XorArray(left));
115        (left, right)
116    }
117}
118
119mod private {
120    pub trait Sealed<T, R> {}
121}
122
123/// Extension trait for creating [`ArrayNetwork`]s.
124pub trait ArrayExt<
125    T: BitXorAssign,
126    R: ArrayLength
127        + Add<Self::L, Output: ArrayLength + Sub<R, Output = Self::L> + Sub<Self::L, Output = R>>,
128>:
129    Sized
130    + IntoIterator<
131        Item: Round<XorArray<T, R>, L = XorArray<T, Self::L>>,
132        IntoIter: DoubleEndedIterator,
133    > + private::Sealed<T, R>
134{
135    /// Length of the left half of a block.
136    type L: ArrayLength + Add<R, Output = <R as Add<Self::L>>::Output>;
137
138    /// Make an [`ArrayNetwork`] from an [`IntoIterator`].
139    fn feistel_array(self) -> Array<Self, T, R> {
140        Array::new(self)
141    }
142}
143
144impl<
145        T: BitXorAssign,
146        L: ArrayLength + Add<R, Output = <R as Add<L>>::Output>,
147        R: ArrayLength + Add<L, Output: ArrayLength + Sub<R, Output = L> + Sub<L, Output = R>>,
148        I: IntoIterator<
149            Item: Round<XorArray<T, R>, L = XorArray<T, L>>,
150            IntoIter: DoubleEndedIterator,
151        >,
152    > private::Sealed<T, R> for I
153{
154}
155
156impl<
157        T: BitXorAssign,
158        L: ArrayLength + Add<R, Output = <R as Add<L>>::Output>,
159        R: ArrayLength + Add<L, Output: ArrayLength + Sub<R, Output = L> + Sub<L, Output = R>>,
160        I: IntoIterator<
161            Item: Round<XorArray<T, R>, L = XorArray<T, L>>,
162            IntoIter: DoubleEndedIterator,
163        >,
164    > ArrayExt<T, R> for I
165{
166    type L = L;
167}