1use crate::{Sha3HasherCore, Sha3ReaderCore};
2use core::fmt;
3use digest::{
4 CollisionResistance, ExtendableOutput, ExtendableOutputReset, HashMarker, Update, XofReader,
5 block_api::{
6 AlgorithmName, BlockSizeUser, ExtendableOutputCore, Reset, UpdateCore, XofReaderCore,
7 },
8 block_buffer::{EagerBuffer, ReadBuffer},
9 consts::{U0, U16, U32, U136, U168},
10};
11
12const TURBO_SHAKE_ROUND_COUNT: usize = 12;
13
14macro_rules! impl_turbo_shake {
15 (
16 $name:ident, $reader_name:ident, $rate:ty, $alg_name:expr
17 ) => {
18 #[doc = $alg_name]
19 #[doc = "hasher with domain separator."]
20 #[doc = ""]
21 #[doc = "Domain separator `DS` MUST be in the range `0x01..=0x7f`, the default value is `0x1F`."]
22 #[doc = "Using `DS` outside of the range will result in a panic during initialization."]
23 #[derive(Clone)]
24 pub struct $name<const DS: u8 = 0x1F> {
25 core: Sha3HasherCore<$rate, U0, DS, TURBO_SHAKE_ROUND_COUNT>,
26 buffer: EagerBuffer<$rate>,
27 }
28
29 impl<const DS: u8> Default for $name<DS> {
30 #[inline]
31 fn default() -> Self {
32 assert!((0x01..=0x7F).contains(&DS), "invalid domain separator");
33 Self {
34 core: Default::default(),
35 buffer: Default::default(),
36 }
37 }
38 }
39
40 impl<const DS: u8> HashMarker for $name<DS> {}
41
42 impl<const DS: u8> BlockSizeUser for $name<DS> {
43 type BlockSize = $rate;
44 }
45
46 impl<const DS: u8> Update for $name<DS> {
47 #[inline]
48 fn update(&mut self, data: &[u8]) {
49 let Self { core, buffer } = self;
50 buffer.digest_blocks(data, |blocks| core.update_blocks(blocks));
51 }
52 }
53
54 impl<const DS: u8> ExtendableOutput for $name<DS> {
55 type Reader = $reader_name;
56
57 #[inline]
58 fn finalize_xof(mut self) -> Self::Reader {
59 let Self { core, buffer } = &mut self;
60 let core = core.finalize_xof_core(buffer);
61 let buffer = Default::default();
62 Self::Reader { core, buffer }
63 }
64 }
65
66 impl<const DS: u8> ExtendableOutputReset for $name<DS> {
67 #[inline]
68 fn finalize_xof_reset(&mut self) -> Self::Reader {
69 let Self { core, buffer } = self;
70 let core = core.finalize_xof_core(buffer);
71 self.reset();
72 let buffer = Default::default();
73 Self::Reader { core, buffer }
74 }
75 }
76
77 impl<const DS: u8> Reset for $name<DS> {
78 #[inline]
79 fn reset(&mut self) {
80 *self = Default::default();
81 }
82 }
83
84 impl<const DS: u8> AlgorithmName for $name<DS> {
85 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 f.write_str(stringify!($alg_name))
87 }
88 }
89
90 impl<const DS: u8> fmt::Debug for $name<DS> {
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 f.write_str(concat!(stringify!($name), " { ... }"))
93 }
94 }
95
96 #[cfg(feature = "zeroize")]
97 impl<const DS: u8> digest::zeroize::ZeroizeOnDrop for $name<DS> {}
98
99 #[doc = $alg_name]
100 #[doc = " XOF reader."]
101 #[derive(Clone)]
102 pub struct $reader_name {
103 core: Sha3ReaderCore<$rate, TURBO_SHAKE_ROUND_COUNT>,
104 buffer: ReadBuffer<$rate>,
105 }
106
107 impl XofReader for $reader_name {
108 #[inline]
109 fn read(&mut self, buf: &mut [u8]) {
110 let Self { core, buffer } = self;
111 buffer.read(buf, |block| {
112 *block = core.read_block();
113 });
114 }
115 }
116
117 impl fmt::Debug for $reader_name {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 f.write_str(concat!(stringify!($reader_name), " { ... }"))
120 }
121 }
122 };
123}
124
125impl_turbo_shake!(TurboShake128, TurboShake128Reader, U168, "TurboSHAKE128");
126impl_turbo_shake!(TurboShake256, TurboShake256Reader, U136, "TurboSHAKE256");
127
128impl<const DS: u8> CollisionResistance for TurboShake128<DS> {
129 type CollisionResistance = U16;
131}
132
133impl<const DS: u8> CollisionResistance for TurboShake256<DS> {
134 type CollisionResistance = U32;
136}