vitaminc_permutation/
key.rs1use 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 pub unsafe fn new_unchecked(key: [u8; N]) -> Self {
23 Self(KeyInner::<N>::new(key))
24 }
25
26 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 pub fn invert(self) -> Self
38 where
39 [u8; N]: IsPermutable,
40 {
41 Self(KeyInner::new(depermute_array(&self, identity())))
42 }
43
44 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 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 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}