Skip to main content

vitaminc_permutation/
key.rs

1use serde::{Deserialize, Serialize};
2use vitaminc_protected::{Controlled, Exportable, Protected, Zeroed};
3use vitaminc_random::{Generatable, RandomError, SafeRand, SeedableRng};
4use zeroize::Zeroize;
5
6use super::private::IsPermutable;
7use crate::{
8    elementwise::{depermute_array, permute_array, Permute},
9    private::identity,
10};
11
12pub(crate) type KeyInner<const N: usize> = Exportable<Protected<[u8; N]>>;
13
14#[derive(Copy, Clone, Debug, Serialize, Deserialize, Zeroize)]
15pub struct PermutationKey<const N: usize>(KeyInner<N>);
16
17impl<const N: usize> PermutationKey<N> {
18    /// # Safety
19    ///
20    /// This function is unsafe because it does not check that the key is a valid permutation.
21    ///
22    pub unsafe fn new_unchecked(key: [u8; N]) -> Self {
23        Self(KeyInner::<N>::new(key))
24    }
25
26    /// Creates a new permutation key from a seed.
27    /// TODO: Perhaps seed should be protected?
28    pub fn from_seed(seed: [u8; 32]) -> Result<Self, RandomError>
29    where
30        [u8; N]: IsPermutable,
31    {
32        let mut rng = SafeRand::from_seed(seed);
33        Generatable::random(&mut rng)
34    }
35
36    /// Consumes the key and returns its inverse.
37    pub fn invert(self) -> Self
38    where
39        [u8; N]: IsPermutable,
40    {
41        Self(KeyInner::new(depermute_array(&self, identity())))
42    }
43
44    /// Returns the complement of the key with respect to the target key.
45    /// That is: `C(T) = Self`
46    ///
47    /// # Example
48    ///
49    /// ```
50    /// # mod vitaminc { pub mod permutation { pub use vitaminc_permutation::*; } pub mod random { pub use vitaminc_random::*; } }
51    /// use vitaminc::permutation::{Permute, PermutationKey};
52    /// use vitaminc::random::{Generatable, SafeRand, SeedableRng};
53    /// let mut rng = SafeRand::from_entropy().expect("Failed to seed RNG");
54    /// let key = PermutationKey::random(&mut rng).expect("Random error");
55    /// let target = PermutationKey::random(&mut rng).expect("Random error");
56    /// let complement = key.complement(&target);
57    /// let input: [u8; 16] = Generatable::random(&mut rng).expect("Random error");
58    /// assert_eq!(
59    ///     complement.permute(target).permute(input),
60    ///     key.permute(input)
61    /// );
62    /// ```
63    pub fn complement(&self, target: &Self) -> Self
64    where
65        [u8; N]: IsPermutable + Zeroed,
66    {
67        Self(target.invert().0.map(|arr| permute_array(self, arr)))
68    }
69
70    pub(crate) fn iter(&self) -> impl Iterator<Item = Protected<u8>> + '_ {
71        self.0.iter()
72    }
73}
74
75impl<const N: usize> Generatable for PermutationKey<N>
76where
77    [u8; N]: IsPermutable,
78{
79    fn random(rng: &mut SafeRand) -> Result<Self, RandomError> {
80        let key = KeyInner::<N>::generate(identity).map(|key| {
81            (0..N).rev().fold(key, |mut key, i| {
82                let mut j = rng.next_bounded_u32(i as u32) as usize;
83                key.swap(i, j);
84                j.zeroize();
85                key
86            })
87        });
88
89        Ok(Self(key))
90    }
91}
92
93impl<const N: usize> Permute<PermutationKey<N>> for PermutationKey<N>
94where
95    [u8; N]: IsPermutable + Zeroed,
96{
97    fn permute(&self, Self(inner): Self) -> Self {
98        Self(inner.map(|arr| permute_array(self, arr)))
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use crate::{
105        elementwise::Permute,
106        key::KeyInner,
107        private::{identity, IsPermutable},
108        PermutationKey,
109    };
110    use vitaminc_protected::{Controlled, Zeroed};
111    use vitaminc_random::{Generatable, SafeRand};
112
113    use crate::tests;
114
115    fn test_key_invert<const N: usize>() -> Result<(), Box<dyn std::error::Error>>
116    where
117        [u8; N]: IsPermutable + Zeroed,
118    {
119        let key: PermutationKey<N> = tests::gen_rand_key()?;
120        let inverted = key.invert();
121
122        // p(p^-1(x)) = x
123        assert_eq!(
124            key.permute(inverted).0.risky_unwrap(),
125            KeyInner::<N>::generate(identity).risky_unwrap(),
126            "Failed to invert key of size {N}"
127        );
128        Ok(())
129    }
130
131    fn test_key_complement<const N: usize>() -> Result<(), Box<dyn std::error::Error>>
132    where
133        [u8; N]: IsPermutable + Zeroed,
134    {
135        let key: PermutationKey<N> = tests::gen_rand_key()?;
136        let target: PermutationKey<N> = tests::gen_rand_key()?;
137        let complement = key.complement(&target);
138
139        let mut rng = SafeRand::from_entropy()?;
140        let input: [u8; N] = Generatable::random(&mut rng)?;
141
142        // c(t)(x) = p(x)
143        assert_eq!(
144            complement.permute(target).permute(input),
145            key.permute(input),
146            "Failed to complement key of size {N}"
147        );
148        Ok(())
149    }
150
151    #[test]
152    fn key_inversion_case() -> Result<(), Box<dyn std::error::Error>> {
153        test_key_invert::<8>()?;
154        test_key_invert::<16>()?;
155        test_key_invert::<32>()?;
156        test_key_invert::<64>()?;
157        Ok(())
158    }
159
160    #[test]
161    fn key_complement_case() -> Result<(), Box<dyn std::error::Error>> {
162        test_key_complement::<8>()?;
163        test_key_complement::<16>()?;
164        test_key_complement::<32>()?;
165        test_key_complement::<64>()?;
166        Ok(())
167    }
168}