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