1#![no_std]
2#![doc = include_str!("../README.md")]
3#![warn(missing_docs, rust_2018_idioms)]
4
5mod hash;
6
7pub use aead;
8
9use aead::{
10 array::{
11 typenum::{Gr, IsGreater, Prod, Quot, Sub1, Sum, Unsigned},
12 Array, ArraySize,
13 },
14 consts::{False, True, B1, U0, U12, U16, U2, U32, U4, U6, U8},
15 AeadCore, AeadInPlace, KeyInit, KeySizeUser,
16};
17use chacha20::{
18 cipher::{StreamCipher, StreamCipherSeek},
19 ChaCha12, ChaCha20, ChaCha8, KeyIvInit,
20};
21use core::{
22 marker::PhantomData,
23 mem,
24 ops::{Add, Div, Mul, Sub},
25};
26use hash::Hasher;
27
28#[derive(Clone)]
38pub struct Hs1Siv<P>
39where
40 P: Hs1Params,
41{
42 key: Hs1Key<P>,
43 _marker: PhantomData<P>,
44}
45
46pub type Hs1SivLo = Hs1Siv<params::Hs1SivLo>;
54
55pub type Hs1SivMe = Hs1Siv<params::Hs1SivMe>;
63
64pub type Hs1SivHi = Hs1Siv<params::Hs1SivHi>;
72
73impl<P> AeadCore for Hs1Siv<P>
74where
75 P: Hs1Params,
76{
77 type TagSize = P::L;
78 type NonceSize = U12;
79 type CiphertextOverhead = U0;
80}
81
82impl<P> AeadInPlace for Hs1Siv<P>
83where
84 P: Hs1Params,
85{
86 fn encrypt_in_place_detached(
87 &self,
88 nonce: &aead::Nonce<Self>,
89 associated_data: &[u8],
90 buffer: &mut [u8],
91 ) -> aead::Result<aead::Tag<Self>> {
92 hs1_siv_encrypt::<P>(&self.key, nonce, associated_data, buffer)
93 }
94
95 fn decrypt_in_place_detached(
96 &self,
97 nonce: &aead::Nonce<Self>,
98 associated_data: &[u8],
99 buffer: &mut [u8],
100 tag: &aead::Tag<Self>,
101 ) -> aead::Result<()> {
102 hs1_siv_decrypt::<P>(&self.key, nonce, associated_data, buffer, tag)
103 }
104}
105
106impl<P> KeySizeUser for Hs1Siv<P>
107where
108 P: Hs1Params,
109{
110 type KeySize = U32;
111}
112
113impl<P> KeyInit for Hs1Siv<P>
114where
115 P: Hs1Params,
116{
117 fn new(key: &aead::Key<Self>) -> Self {
118 assert!((1..=32).contains(&key.len()));
119 let key = hs1_subkeygen::<P>(key);
120 Self {
121 key,
122 _marker: PhantomData,
123 }
124 }
125}
126
127pub mod params {
131 use super::*;
132
133 #[derive(Clone, Copy)]
141 pub struct Hs1SivLo;
142
143 #[derive(Clone, Copy)]
151 pub struct Hs1SivMe;
152
153 #[derive(Clone, Copy)]
161 pub struct Hs1SivHi;
162
163 impl Hs1Params for Hs1SivLo {
164 type B = U4;
165 type T = U2;
166 type C = ChaCha8;
167 type L = U8;
168 }
169
170 impl Hs1Params for Hs1SivMe {
171 type B = U4;
172 type T = U4;
173 type C = ChaCha12;
174 type L = U16;
175 }
176
177 impl Hs1Params for Hs1SivHi {
178 type B = U4;
179 type T = U6;
180 type C = ChaCha20;
181 type L = U32;
182 }
183}
184
185#[derive(Clone)]
186#[repr(C, align(16))]
187struct Hs1Key<P: Hs1Params> {
188 chacha: Array<u8, U32>,
189 hash: Hs1HashKey<P>,
190}
191
192#[derive(Clone)]
193#[repr(C, align(16))]
194struct Hs1HashKey<P: Hs1Params> {
195 nh: Array<u32, NhLen<P>>,
196 poly: Array<u64, P::T>,
197 asu: Array<hash::Asu<P>, P::T>,
198}
199
200impl<P: Hs1Params> Hs1Key<P> {
201 fn as_bytes_mut(&mut self) -> &mut [u8] {
202 const {
205 const fn chk<T, L: ArraySize>() {
206 assert!(mem::size_of::<Array<T, L>>() % 16 == 0);
207 }
208 chk::<u8, U32>();
209 chk::<u32, NhLen<P>>();
210 chk::<u64, P::T>();
211 chk::<hash::Asu<P>, P::T>();
212 }
213 unsafe {
217 let len = mem::size_of_val(self);
218 let ptr = self as *mut Self as *mut u8;
219 core::slice::from_raw_parts_mut(ptr, len)
220 }
221 }
222}
223
224type B16<P> = Prod<<P as Hs1Params>::B, U16>;
225type NhLen<P> = Sum<Quot<B16<P>, U4>, Prod<Sub1<<P as Hs1Params>::T>, U4>>;
226
227pub trait Hs1Params: Copy + Sync + Send
230where
231 Self::B: Mul<U16> + 'static,
232 B16<Self>: ArraySize,
233 Self::T: ArraySize,
234 Self::L: ArraySize,
235 Quot<B16<Self>, U4>: ArraySize,
236 Self::T: Sub<B1>,
238 Sub1<Self::T>: Mul<U4>,
239 B16<Self>: Div<U4>,
240 Quot<B16<Self>, U4>: Add<Prod<Sub1<Self::T>, U4>>,
241 NhLen<Self>: ArraySize,
242 Self::T: IsGreater<U4>,
244 Gr<Self::T, U4>: hash::sealed::Hs1HashFinal,
245 hash::Output<Self>: Default + AsRef<[u8]>,
246{
247 type B;
249 type T;
251 type C: KeyIvInit<KeySize = U32, IvSize = U12>
253 + StreamCipher
254 + StreamCipherSeek
255 + sealed::ChaChaImpl;
256 type L;
258}
259
260mod sealed {
261 pub trait ChaChaImpl {
263 const ROUNDS: u8;
264 }
265}
266
267impl sealed::ChaChaImpl for ChaCha8 {
268 const ROUNDS: u8 = 8;
269}
270impl sealed::ChaChaImpl for ChaCha12 {
271 const ROUNDS: u8 = 12;
272}
273impl sealed::ChaChaImpl for ChaCha20 {
274 const ROUNDS: u8 = 20;
275}
276
277fn hs1_siv_encrypt<P: Hs1Params>(
281 k: &Hs1Key<P>,
282 n: &Array<u8, U12>,
283 a: &[u8],
284 m: &mut [u8],
285) -> Result<Array<u8, P::L>, aead::Error> {
286 if m.len() as u128 > 1 << 38 {
287 return Err(aead::Error);
288 }
289 let t = hs1_tag::<P>(k, a, n, &*m);
290 hs1::<P>(k, &[&*t], n, 64, m);
291 Ok(t)
292}
293
294fn hs1_siv_decrypt<P: Hs1Params>(
295 k: &Hs1Key<P>,
296 n: &Array<u8, U12>,
297 a: &[u8],
298 m: &mut [u8],
299 t: &Array<u8, P::L>,
300) -> Result<(), aead::Error> {
301 if m.len() as u128 > 1 << 38 {
302 return Err(aead::Error);
303 }
304 hs1::<P>(k, &[t], n, 64, m);
305 let t2 = hs1_tag::<P>(k, a, n, m);
306 let diff = t.iter().zip(t2.iter()).fold(0, |s, (x, y)| s | (x ^ y));
307 (diff == 0).then_some(()).ok_or_else(|| {
308 m.fill(0);
311 aead::Error
312 })
313}
314
315fn hs1_tag<P: Hs1Params>(k: &Hs1Key<P>, a: &[u8], n: &Array<u8, U12>, m: &[u8]) -> Array<u8, P::L> {
316 let a_m_len = &mut [0; 16];
317 a_m_len[..8].copy_from_slice(&(a.len() as u64).to_le_bytes());
318 a_m_len[8..].copy_from_slice(&(m.len() as u64).to_le_bytes());
319 let m2 = &[a, m, a_m_len];
320 let mut t = Array::<u8, P::L>::default();
321 hs1::<P>(k, m2, n, 0, &mut t);
322 t
323}
324
325#[inline(always)]
326fn hs1<P: Hs1Params>(k: &Hs1Key<P>, m: &[&[u8]], n: &Array<u8, U12>, y_offset: u32, y: &mut [u8]) {
327 let mut key = k.chacha;
328
329 let mut hasher = Hasher::<P>::new(&k.hash);
330 for (i, b) in m.iter().enumerate() {
331 if i > 0 {
332 hasher.pad_to(4);
333 }
334 hasher.update(b);
335 }
336 let input = hasher.finalize();
337
338 key.iter_mut()
339 .zip(input.iter().flat_map(|x| x.as_ref()))
340 .for_each(|(w, r)| *w ^= *r);
341 let mut cipher = P::C::new(&key, n);
342 cipher.seek(y_offset);
343 cipher.apply_keystream(y)
344}
345
346fn hs1_subkeygen<P: Hs1Params>(k: &[u8]) -> Hs1Key<P> {
347 assert!((1..=32).contains(&k.len()));
348
349 let k2 = &mut Array::<u8, U32>::default();
350 k2.iter_mut()
351 .zip(k.iter().cycle())
352 .for_each(|(w, r)| *w = *r);
353
354 let n = &mut Array::<u8, U12>::default();
355 debug_assert!(k.len() < 256);
356 debug_assert!(P::L::U64 < 256);
357 debug_assert!(P::T::U64 < 256);
358 debug_assert!(B16::<P>::U64 < 256);
359 n[0] = k.len() as u8;
360 n[2] = P::L::to_u8();
361 n[4] = <P::C as sealed::ChaChaImpl>::ROUNDS;
362 n[5] = P::T::to_u8();
363 n[6] = B16::<P>::to_u8();
364
365 let mut k = Hs1Key {
366 chacha: Array::default(),
367 hash: Hs1HashKey {
368 nh: Array::default(),
369 poly: Array::default(),
370 asu: Array::default(),
371 },
372 };
373
374 <P::C as KeyIvInit>::new(k2, n).apply_keystream(k.as_bytes_mut());
375 k.hash.poly.iter_mut().for_each(|p| *p &= mask(60));
376
377 k
378}
379
380#[inline(always)]
381const fn mask(bits: u8) -> u64 {
382 (1u64 << bits).wrapping_sub(1)
383}
384
385#[cfg(test)]
386mod test {
387 use super::*;
388 use aead::{Aead, KeyInit};
389
390 const MSG: &[u8] = b"Hello to the entire wide, round, global globe!";
391 const MSG_LONG: &[u8] = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
392 const KEY: &[u8; 32] = b"Short keys? Use long for testing";
393 const NONCE: &[u8; 12] = b"Quack quack!";
394
395 fn hs1siv<P: Hs1Params>() {
396 let hs1 = Hs1Siv::<P>::new(KEY.into());
397 let cph = hs1.encrypt(NONCE.into(), MSG).unwrap();
398 let msg = hs1.decrypt(NONCE.into(), &*cph).unwrap();
399 assert_eq!(&msg, MSG);
400 }
401
402 #[test]
403 fn hs1siv_me() {
404 hs1siv::<params::Hs1SivMe>();
405 }
406
407 #[test]
408 fn hs1siv_lo() {
409 hs1siv::<params::Hs1SivLo>();
410 }
411
412 #[test]
413 fn hs1siv_hi() {
414 hs1siv::<params::Hs1SivHi>();
415 }
416
417 mod test_vectors {
421 use super::*;
422
423 #[test]
424 fn subkeygen_me() {
425 let k = hs1_subkeygen::<params::Hs1SivMe>(KEY);
426 assert_eq!(
427 k.chacha,
428 [
429 0x02, 0xea, 0xb5, 0x34, 0x85, 0x3e, 0xf7, 0xf4, 0x81, 0x3f, 0x87, 0xd8, 0xd2,
430 0x63, 0x1e, 0x05, 0xf9, 0x68, 0x91, 0xd0, 0x8a, 0x03, 0x34, 0xfc, 0x64, 0xbe,
431 0x6b, 0x3a, 0x89, 0xfe, 0x20, 0x8d,
432 ]
433 );
434 assert_eq!(
435 k.hash.nh,
436 [
437 0x74e7102f, 0x374603b7, 0xf470c90c, 0x8c829c82, 0x07d6f293, 0xf9e7e569,
438 0xcd590406, 0xe6bdc9ad, 0xa2687cda, 0xfc1a8b80, 0x501efbee, 0x0df51d32,
439 0x7fd3f594, 0xc3d1520b, 0x1b83db2f, 0x0791c054, 0x66583c46, 0xcb096241,
440 0x7afc8085, 0x4b37d47a, 0x540287e0, 0xe1ace58b, 0x4f125f3b, 0xb69b5935,
441 0x6cb2cf06, 0xbf86407b, 0x18a6a2e5, 0xe1eaa248,
442 ]
443 );
444 assert_eq!(
445 k.hash.poly,
446 [
447 0x09aad6627602f656,
448 0x07f2089068131f87,
449 0x0a982e724caf2722,
450 0x004f2d42b1092d0a,
451 ]
452 );
453 assert_eq!(k.hash.asu, [[]; 4]);
454 }
455
456 #[test]
457 fn subkeygen_lo() {
458 let k = hs1_subkeygen::<params::Hs1SivLo>(KEY);
459 assert_eq!(
460 k.chacha,
461 [
462 0xab, 0x1b, 0x65, 0x62, 0xe5, 0x4c, 0x79, 0x27, 0x30, 0xa3, 0x4c, 0xa6, 0x7e,
463 0x79, 0x0f, 0xb9, 0xa9, 0x85, 0x62, 0xb2, 0x17, 0x2e, 0x47, 0x99, 0xe3, 0x7a,
464 0x0c, 0x63, 0x77, 0xc4, 0x85, 0xca,
465 ]
466 );
467 assert_eq!(
468 k.hash.nh,
469 [
470 0xd743ff76, 0x64b9e928, 0x0effa5ae, 0xf850ec1d, 0xda1249a9, 0x29afefcf,
471 0x18bb4916, 0x35d0b524, 0x2036f9c4, 0x0ae224a6, 0x98f18f97, 0x3aad32e2,
472 0x85256859, 0x30e4ad2e, 0x63b08461, 0x13c97c7d, 0xe4d45609, 0x0ca44ba2,
473 0x6c4b356e, 0x9b960e6b,
474 ]
475 );
476 assert_eq!(k.hash.poly, [0x0ef85bac983cb194, 0x0a584b5179c75231]);
477 assert_eq!(k.hash.asu, [[]; 2]);
478 }
479
480 #[test]
481 fn hash_me() {
482 let k = hs1_subkeygen::<params::Hs1SivMe>(KEY);
483 let h = Hasher::new(&k.hash).update(MSG).finalize();
484 assert_eq!(
485 h,
486 [
487 0x1808a23d991ae22c,
488 0x08f96bf01b438f3b,
489 0x194ee1ffd24b84a0,
490 0x0b25578352a73e9d,
491 ]
492 .map(u64::to_le_bytes)
493 );
494 }
495
496 #[test]
497 fn hash_me_64() {
498 const MSG_64: &[u8; 64] =
499 b"Hello to the entire wide, round, global globe!!! okookokokokokok";
500 let k = hs1_subkeygen::<params::Hs1SivMe>(KEY);
501 let h = Hasher::new(&k.hash).update(MSG_64).finalize();
502 assert_eq!(
503 h,
504 [
505 0x0f128a7f7b601324,
506 0x0dc82e748a2a1395,
507 0x106966138221d2ba,
508 0x09f86f41d6677d4d,
509 ]
510 .map(u64::to_le_bytes)
511 );
512 }
513
514 #[test]
515 fn hash_me_65() {
516 const MSG_65: &[u8; 65] =
517 b"Hello to the entire wide, round, global globe!!! okookokokokokok?";
518 let k = hs1_subkeygen::<params::Hs1SivMe>(KEY);
519 let h = Hasher::new(&k.hash).update(MSG_65).finalize();
520 assert_eq!(
521 h,
522 [
523 0x10619b1a23127759,
524 0x160f2049c69ee554,
525 0x1de3d0b0f4d56bec,
526 0x03e8ec8fdef39c71,
527 ]
528 .map(u64::to_le_bytes)
529 );
530 }
531
532 #[test]
533 fn hash_me_128() {
534 const MSG_128: &[u8; 128] =
535 b"Hello to the entire wide, round, global globe!!! okookokokokokokHello to the entire wide, round, global globe!!! okookokokokokok";
536 let k = hs1_subkeygen::<params::Hs1SivMe>(KEY);
537 let h = Hasher::new(&k.hash).update(MSG_128).finalize();
538 assert_eq!(
539 h,
540 [
541 0x07d3154786d50a10,
542 0x145bceb11f846780,
543 0x0321fdeb01118846,
544 0x0a0ac6ce29b11e5a,
545 ]
546 .map(u64::to_le_bytes)
547 );
548 }
549
550 #[test]
551 fn hash_lo() {
552 let k = hs1_subkeygen::<params::Hs1SivLo>(KEY);
553 let h = Hasher::new(&k.hash).update(MSG).finalize();
554 assert_eq!(
555 h,
556 [0x1afa0c19eba9a66b, 0x15ceb31a087f2657,].map(u64::to_le_bytes)
557 );
558 }
559
560 #[test]
561 fn hash_hi() {
562 let k = hs1_subkeygen::<params::Hs1SivHi>(KEY);
563 let h = Hasher::new(&k.hash).update(MSG).finalize();
564 assert_eq!(
565 h,
566 [0xcf452c22, 0x452317a2, 0x7fa1f1d6, 0x100d9702, 0xcf1defb0, 0x4c73da69,]
567 .map(u32::to_le_bytes)
568 );
569 }
570
571 #[test]
572 fn hash_lo_long() {
573 let k = hs1_subkeygen::<params::Hs1SivLo>(KEY);
574 let h = Hasher::new(&k.hash).update(MSG_LONG).finalize();
575 assert_eq!(
576 h,
577 [0x0b65743a2f4c73aa, 0x1863d3ec1873cd72,].map(u64::to_le_bytes)
578 );
579 }
580
581 #[test]
582 fn hash_me_long() {
583 let k = hs1_subkeygen::<params::Hs1SivMe>(KEY);
584 let h = Hasher::new(&k.hash).update(MSG_LONG).finalize();
585 assert_eq!(
586 h,
587 [
588 0x1f8e6282cbc4455f,
589 0x0e6ade357355de7b,
590 0x1a5834576032c7b0,
591 0x1bd063cb8b70044a,
592 ]
593 .map(u64::to_le_bytes)
594 );
595 }
596
597 #[test]
598 fn hash_hi_long() {
599 let k = hs1_subkeygen::<params::Hs1SivHi>(KEY);
600 let h = Hasher::new(&k.hash).update(MSG_LONG).finalize();
601 assert_eq!(
602 h,
603 [0x52645829, 0x8f0c0687, 0x01f33121, 0xc94264e3, 0x85dc8143, 0xc8fd435e,]
604 .map(u32::to_le_bytes)
605 );
606 }
607
608 #[test]
612 fn hash_me_empty() {
613 let k = hs1_subkeygen::<params::Hs1SivMe>(KEY);
614 let h = Hasher::new(&k.hash).finalize();
615 assert_eq!(
616 h,
617 [
618 0x0000000000000001,
619 0x0000000000000001,
620 0x0000000000000001,
621 0x0000000000000001,
622 ]
623 .map(u64::to_le_bytes)
624 );
625 }
626
627 #[test]
628 fn hs1siv_me() {
629 let hs1 = Hs1SivMe::new(KEY.into());
630 let cph = hs1.encrypt(NONCE.into(), MSG).unwrap();
631 assert_eq!(
632 &cph,
633 &[
634 0x1b, 0x26, 0x40, 0x4d, 0xe3, 0x46, 0xb3, 0x65, 0x07, 0xa7, 0x93, 0xf3, 0x6e,
635 0xab, 0xb5, 0xcb, 0x1a, 0x99, 0x7c, 0xbf, 0xdf, 0x6c, 0xed, 0x15, 0xd9, 0xd0,
636 0x26, 0x37, 0xf7, 0xcc, 0xd4, 0xb1, 0x20, 0xee, 0x02, 0x52, 0x3c, 0xee, 0xcc,
637 0x41, 0x04, 0xbf, 0x42, 0xa9, 0xfc, 0x2e, 0x45, 0x06, 0x67, 0xa6, 0xfe, 0x07,
638 0x2f, 0x00, 0x81, 0x72, 0x52, 0xa8, 0xb0, 0xb1, 0x2e, 0xd6,
639 ]
640 );
641 }
642
643 #[test]
644 fn hs1siv_lo() {
645 let hs1 = Hs1SivLo::new(KEY.into());
646 let cph = hs1.encrypt(NONCE.into(), MSG).unwrap();
647 assert_eq!(
648 &cph,
649 &[
650 0xa8, 0xac, 0xcd, 0x91, 0x09, 0x39, 0xac, 0x6a, 0x13, 0x81, 0xa3, 0xa4, 0xbe,
651 0xa1, 0xc9, 0x97, 0xa7, 0xda, 0xe6, 0x5e, 0x73, 0xd6, 0x0f, 0x2e, 0x87, 0xcf,
652 0xe7, 0x20, 0xaf, 0x0d, 0x94, 0x45, 0xaa, 0x9b, 0x91, 0xf2, 0x11, 0x33, 0x48,
653 0xc5, 0x7d, 0x0f, 0xd8, 0xda, 0xd7, 0x9a, 0x3d, 0xcf, 0x63, 0xea, 0xda, 0x32,
654 0x7c, 0xa6,
655 ]
656 );
657 }
658
659 #[test]
660 fn hs1siv_hi() {
661 let hs1 = Hs1SivHi::new(KEY.into());
662 let cph = hs1.encrypt(NONCE.into(), MSG).unwrap();
663 assert_eq!(
664 &cph,
665 &[
666 0xbc, 0x5d, 0xbb, 0x49, 0x52, 0x97, 0xb8, 0xb0, 0xab, 0x3a, 0x0b, 0x69, 0xb0,
667 0x60, 0xd2, 0x75, 0xd1, 0x4e, 0x14, 0x73, 0x8f, 0xe3, 0xb6, 0x14, 0xb0, 0x06,
668 0x01, 0x96, 0x4f, 0x90, 0x6e, 0x6a, 0x67, 0x71, 0xd0, 0x71, 0xf0, 0x4b, 0xc9,
669 0xf8, 0x14, 0x54, 0x30, 0xe3, 0x33, 0xb0, 0x09, 0x97, 0x47, 0xf4, 0x8c, 0xd0,
670 0x60, 0xae, 0x68, 0x40, 0xcb, 0x58, 0x64, 0x6b, 0xf9, 0x66, 0x5f, 0x58, 0xfa,
671 0xdf, 0xd0, 0x50, 0xa7, 0x00, 0x43, 0x55, 0x5e, 0x63, 0xe9, 0x89, 0x31, 0x29,
672 ]
673 );
674 }
675 }
676}