1use std::{fmt::Formatter, marker::PhantomData, ops::Sub};
7
8#[allow(deprecated)] use cipher::{
10 AlgorithmName, ArrayLength, Block, BlockSizeUser, Iv, IvSizeUser, Key, KeyInit, KeyIvInit, KeySizeUser,
11 StreamCipher, generic_array::GenericArray, inout::InOut,
12};
13use digest::{Digest, OutputSizeUser};
14use typenum::{B1, Diff, IsEqual, IsGreater, Unsigned};
15
16use crate::crypto_traits::PRP;
17
18#[derive(Clone, zeroize::ZeroizeOnDrop)]
32pub struct Lioness<H: KeySizeUser + OutputSizeUser, S: KeySizeUser + IvSizeUser, B: ArrayLength<u8>>
33where
34 H::OutputSize: IsEqual<S::KeySize, Output = B1>,
38 H::KeySize: IsEqual<S::KeySize, Output = B1>,
40 B: IsGreater<<S as KeySizeUser>::KeySize, Output = B1>,
42{
43 k1: GenericArray<u8, S::KeySize>,
44 k2: GenericArray<u8, H::KeySize>,
45 k3: GenericArray<u8, S::KeySize>,
46 k4: GenericArray<u8, H::KeySize>,
47 iv1: GenericArray<u8, S::IvSize>,
48 iv2: GenericArray<u8, S::IvSize>,
49 _phantom: PhantomData<(H, S, B)>,
50}
51
52impl<H: KeySizeUser + OutputSizeUser, S: KeySizeUser + IvSizeUser, B: ArrayLength<u8>> KeySizeUser for Lioness<H, S, B>
53where
54 H::OutputSize: IsEqual<S::KeySize, Output = B1>,
55 H::KeySize: IsEqual<S::KeySize, Output = B1>,
56 B: IsGreater<<S as KeySizeUser>::KeySize, Output = B1>,
57 H::OutputSize: std::ops::Mul<cipher::consts::U4>,
59 <H::OutputSize as std::ops::Mul<cipher::consts::U4>>::Output: ArrayLength<u8>,
61{
62 type KeySize = typenum::Prod<H::OutputSize, cipher::consts::U4>;
63}
64
65impl<H: KeySizeUser + OutputSizeUser, S: KeySizeUser + IvSizeUser, B: ArrayLength<u8>> IvSizeUser for Lioness<H, S, B>
66where
67 H::OutputSize: IsEqual<S::KeySize, Output = B1>,
68 H::KeySize: IsEqual<S::KeySize, Output = B1>,
69 B: IsGreater<<S as KeySizeUser>::KeySize, Output = B1>,
70 S::IvSize: std::ops::Mul<cipher::consts::U2>,
72 <S::IvSize as std::ops::Mul<cipher::consts::U2>>::Output: ArrayLength<u8>,
74{
75 type IvSize = typenum::Prod<S::IvSize, cipher::consts::U2>;
76}
77
78impl<H: KeySizeUser + OutputSizeUser, S: KeySizeUser + IvSizeUser, B: ArrayLength<u8>> BlockSizeUser
79 for Lioness<H, S, B>
80where
81 H::OutputSize: IsEqual<S::KeySize, Output = B1>,
82 H::KeySize: IsEqual<S::KeySize, Output = B1>,
83 B: IsGreater<<S as KeySizeUser>::KeySize, Output = B1>,
84 H::OutputSize: std::ops::Mul<cipher::consts::U4>,
85 S::IvSize: std::ops::Mul<cipher::consts::U2>,
86 <H::OutputSize as std::ops::Mul<cipher::consts::U4>>::Output: ArrayLength<u8>,
87 <S::IvSize as std::ops::Mul<cipher::consts::U2>>::Output: ArrayLength<u8>,
88{
89 type BlockSize = B;
90}
91
92impl<H: KeySizeUser + OutputSizeUser, S: KeySizeUser + IvSizeUser, B: ArrayLength<u8>> KeyIvInit for Lioness<H, S, B>
93where
94 H::OutputSize: IsEqual<S::KeySize, Output = B1>,
95 H::KeySize: IsEqual<S::KeySize, Output = B1>,
96 B: IsGreater<<S as KeySizeUser>::KeySize, Output = B1>,
97 H::OutputSize: std::ops::Mul<cipher::consts::U4>,
98 S::IvSize: std::ops::Mul<cipher::consts::U2>,
99 <H::OutputSize as std::ops::Mul<cipher::consts::U4>>::Output: ArrayLength<u8>,
100 <S::IvSize as std::ops::Mul<cipher::consts::U2>>::Output: ArrayLength<u8>,
101{
102 fn new(key: &Key<Self>, iv: &Iv<Self>) -> Self {
103 let k = H::OutputSize::to_usize();
104 let i = S::IvSize::to_usize();
105 Self {
106 k1: GenericArray::clone_from_slice(&key[0..k]),
107 k2: GenericArray::clone_from_slice(&key[k..2 * k]),
108 k3: GenericArray::clone_from_slice(&key[2 * k..3 * k]),
109 k4: GenericArray::clone_from_slice(&key[3 * k..4 * k]),
110 iv1: GenericArray::clone_from_slice(&iv[0..i]),
111 iv2: GenericArray::clone_from_slice(&iv[i..2 * i]),
112 _phantom: Default::default(),
113 }
114 }
115}
116
117impl<H: KeySizeUser + OutputSizeUser + AlgorithmName, S: AlgorithmName + KeySizeUser + IvSizeUser, B: ArrayLength<u8>>
118 AlgorithmName for Lioness<H, S, B>
119where
120 H::OutputSize: IsEqual<<S as KeySizeUser>::KeySize, Output = B1>,
121 H::KeySize: IsEqual<S::KeySize, Output = B1>,
122 B: IsGreater<<S as KeySizeUser>::KeySize, Output = B1>,
123{
124 fn write_alg_name(f: &mut Formatter<'_>) -> std::fmt::Result {
125 f.write_str("Lioness<")?;
126 H::write_alg_name(f)?;
127 f.write_str(", ")?;
128 S::write_alg_name(f)?;
129 f.write_str(">")
130 }
131}
132
133impl<H: Digest + KeyInit, S: StreamCipher + KeyIvInit, B: ArrayLength<u8>> Lioness<H, S, B>
134where
135 H::OutputSize: IsEqual<<S as KeySizeUser>::KeySize, Output = B1>,
136 H::KeySize: IsEqual<S::KeySize, Output = B1>,
137 B: IsGreater<<S as KeySizeUser>::KeySize, Output = B1> + Sub<<S as KeySizeUser>::KeySize>,
139 <B as Sub<<S as KeySizeUser>::KeySize>>::Output: ArrayLength<u8>,
141 H::OutputSize: std::ops::Mul<cipher::consts::U4>,
142 <S as IvSizeUser>::IvSize: std::ops::Mul<cipher::consts::U2>,
143 <H::OutputSize as std::ops::Mul<cipher::consts::U4>>::Output: ArrayLength<u8>,
144 <<S as IvSizeUser>::IvSize as std::ops::Mul<cipher::consts::U2>>::Output: ArrayLength<u8>,
145{
146 const K: usize = <S as KeySizeUser>::KeySize::USIZE;
147
148 pub fn encrypt_block(&self, mut block: InOut<'_, '_, Block<Self>>) {
150 let mut left_prime =
152 GenericArray::<u8, <S as KeySizeUser>::KeySize>::clone_from_slice(&block.get_in()[0..Self::K]);
153 for i in 0..Self::K {
154 left_prime[i] ^= self.k1[i];
155 }
156
157 let r_cpy = GenericArray::<u8, Diff<B, <S as KeySizeUser>::KeySize>>::clone_from_slice(
159 &block.get_in()[Self::K..B::USIZE],
160 );
161 S::new(&left_prime, &self.iv1)
162 .apply_keystream_b2b(&r_cpy, &mut block.get_out()[Self::K..B::USIZE])
163 .expect("slices have always equal sizes");
164
165 let r_prime = <H as KeyInit>::new(&self.k2)
167 .chain_update(&block.get_out()[Self::K..B::USIZE])
168 .finalize();
169
170 for i in 0..Self::K {
172 block.get_out()[i] = block.get_in()[i] ^ r_prime[i];
173 }
174
175 let mut left_prime =
177 GenericArray::<u8, <S as KeySizeUser>::KeySize>::clone_from_slice(&block.get_out()[0..Self::K]);
178 for i in 0..Self::K {
179 left_prime[i] ^= self.k3[i];
180 }
181 S::new(&left_prime, &self.iv2).apply_keystream(&mut block.get_out()[Self::K..B::USIZE]);
183
184 let r_prime = <H as KeyInit>::new(&self.k4)
186 .chain_update(&block.get_out()[Self::K..B::USIZE])
187 .finalize();
188
189 for i in 0..Self::K {
191 block.get_out()[i] ^= r_prime[i];
192 }
193 }
194
195 pub fn decrypt_block(&self, mut block: InOut<'_, '_, Block<Self>>) {
197 let r_prime = <H as KeyInit>::new(&self.k4)
199 .chain_update(&block.get_in()[Self::K..B::USIZE])
200 .finalize();
201
202 for i in 0..Self::K {
204 block.get_out()[i] = block.get_in()[i] ^ r_prime[i];
205 }
206
207 let mut left_prime =
209 GenericArray::<u8, <S as KeySizeUser>::KeySize>::clone_from_slice(&block.get_out()[0..Self::K]);
210 for i in 0..Self::K {
211 left_prime[i] ^= self.k3[i];
212 }
213
214 let r_cpy = GenericArray::<u8, Diff<B, <S as KeySizeUser>::KeySize>>::clone_from_slice(
216 &block.get_in()[Self::K..B::USIZE],
217 );
218 S::new(&left_prime, &self.iv2)
219 .apply_keystream_b2b(&r_cpy, &mut block.get_out()[Self::K..B::USIZE])
220 .expect("slices have always equal sizes");
221
222 let r_prime = <H as KeyInit>::new(&self.k2)
224 .chain_update(&block.get_out()[Self::K..B::USIZE])
225 .finalize();
226
227 for i in 0..Self::K {
229 block.get_out()[i] ^= r_prime[i];
230 }
231
232 let mut left_prime =
234 GenericArray::<u8, <S as KeySizeUser>::KeySize>::clone_from_slice(&block.get_out()[0..Self::K]);
235 for i in 0..Self::K {
236 left_prime[i] ^= self.k1[i];
237 }
238
239 S::new(&left_prime, &self.iv1).apply_keystream(&mut block.get_out()[Self::K..B::USIZE]);
241 }
242}
243
244impl<H: Digest + KeyInit, S: StreamCipher + KeyIvInit, B: ArrayLength<u8>> PRP for Lioness<H, S, B>
245where
246 H::OutputSize: IsEqual<<S as KeySizeUser>::KeySize, Output = B1>,
247 H::KeySize: IsEqual<S::KeySize, Output = B1>,
248 B: IsGreater<<S as KeySizeUser>::KeySize, Output = B1> + Sub<<S as KeySizeUser>::KeySize>,
249 <B as Sub<<S as KeySizeUser>::KeySize>>::Output: ArrayLength<u8>,
250 H::OutputSize: std::ops::Mul<cipher::consts::U4>,
251 <S as IvSizeUser>::IvSize: std::ops::Mul<cipher::consts::U2>,
252 <H::OutputSize as std::ops::Mul<cipher::consts::U4>>::Output: ArrayLength<u8>,
253 <<S as IvSizeUser>::IvSize as std::ops::Mul<cipher::consts::U2>>::Output: ArrayLength<u8>,
254{
255 fn forward(&self, data: &mut Block<Self>) {
256 self.encrypt_block(data.into());
257 }
258
259 fn inverse(&self, data: &mut Block<Self>) {
260 self.decrypt_block(data.into());
261 }
262}
263
264pub type LionessBlake3ChaCha20<B> = Lioness<blake3::Hasher, chacha20::ChaCha20, B>;
267
268#[cfg(test)]
269mod tests {
270 use hex_literal::hex;
271 use typenum::{U33, U1024};
272
273 use super::*;
274
275 #[test]
276 fn lioness_sizes() {
277 assert_eq!(
278 <blake3::Hasher as OutputSizeUser>::output_size(),
279 chacha20::ChaCha20::key_size()
280 );
281
282 let key_sz = LionessBlake3ChaCha20::<U33>::key_size();
283 let iv_sz = LionessBlake3ChaCha20::<U33>::iv_size();
284 let block_sz = LionessBlake3ChaCha20::<U33>::block_size();
285
286 assert_eq!(key_sz, <blake3::Hasher as OutputSizeUser>::output_size() * 4);
287 assert_eq!(iv_sz, chacha20::ChaCha20::iv_size() * 2);
288 assert_eq!(block_sz, U33::USIZE);
289 }
290
291 #[test]
292 fn lioness_forward_inverse() {
293 let lioness = LionessBlake3ChaCha20::<U1024>::new(&Default::default(), &Default::default());
294
295 let mut data = GenericArray::<u8, U1024>::default();
296 let data_clone = data.clone();
297 assert_eq!(data, data_clone);
298
299 lioness.encrypt_block((&mut data).into());
300 assert_ne!(data, data_clone);
301
302 lioness.decrypt_block((&mut data).into());
303 assert_eq!(data, data_clone);
304 }
305
306 #[test]
307 fn lioness_forward_kat() {
308 let lioness = LionessBlake3ChaCha20::<U33>::new(&Default::default(), &Default::default());
309
310 let mut data = GenericArray::<u8, U33>::default();
311
312 lioness.encrypt_block((&mut data).into());
313 let ka = hex!("36690b60686f3c997a7bfb3808aa18a1b5808b750587ed04a01ebd836dd3ea97b4");
314 assert_eq!(data.as_slice(), &ka);
315 }
316
317 #[test]
318 fn lioness_inverse_kat() {
319 let lioness = LionessBlake3ChaCha20::<U33>::new(&Default::default(), &Default::default());
320
321 let mut data = GenericArray::<u8, U33>::default();
322
323 lioness.decrypt_block((&mut data).into());
324 let ka = hex!("7857b5bb58995ac8c59eff412dad35af72a7d1e1ff1caba132aef382b15789a6cb");
325 assert_eq!(data.as_slice(), &ka);
326 }
327
328 #[test]
329 fn lioness_forward_inverse_random() {
330 let (k, iv) = LionessBlake3ChaCha20::<U1024>::generate_key_iv(hopr_crypto_random::rng());
331 let lioness = LionessBlake3ChaCha20::<U1024>::new(&k, &iv);
332
333 let mut data = GenericArray::<u8, U1024>::default();
334 hopr_crypto_random::random_fill(&mut data);
335 let data_clone = data.clone();
336 assert_eq!(data, data_clone);
337
338 lioness.encrypt_block((&mut data).into());
339 assert_ne!(data, data_clone);
340
341 lioness.decrypt_block((&mut data).into());
342 assert_eq!(data, data_clone);
343 }
344
345 #[test]
346 fn lioness_forward_inverse_random_separate_buffers() {
347 let (k, iv) = LionessBlake3ChaCha20::<U1024>::generate_key_iv(hopr_crypto_random::rng());
348 let lioness = LionessBlake3ChaCha20::<U1024>::new(&k, &iv);
349
350 let mut data_in = GenericArray::<u8, U1024>::default();
351 let mut data_out = GenericArray::<u8, U1024>::default();
352 hopr_crypto_random::random_fill(&mut data_in);
353 let data_orig = data_in.clone();
354 assert_eq!(data_in, data_orig);
355
356 lioness.encrypt_block((&data_in, &mut data_out).into());
357 assert_ne!(data_out, data_orig);
358
359 let data_in = data_out;
360 let mut data_out = GenericArray::<u8, U1024>::default();
361 lioness.decrypt_block((&data_in, &mut data_out).into());
362 assert_eq!(data_out, data_orig);
363 }
364}