1use 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};
35use crate::{
36 DEFAULT_ROUND_COUNT,
37 SHAKE_PAD,
38};
39
40macro_rules! impl_shake {
41 (
42 $name:ident, $reader_name:ident, $rate:ty, $alg_name:expr
43 ) => {
44 #[doc = $alg_name]
45 #[doc = " hasher."]
46 #[derive(Clone)]
47 pub struct $name {
48 core: Sha3HasherCore<$rate, U0, SHAKE_PAD, DEFAULT_ROUND_COUNT>,
49 buffer: EagerBuffer<$rate>,
50 }
51
52 impl Default for $name {
53 #[inline]
54 fn default() -> Self {
55 Self {
56 core: Default::default(),
57 buffer: Default::default(),
58 }
59 }
60 }
61
62 impl HashMarker for $name {}
63
64 impl BlockSizeUser for $name {
65 type BlockSize = $rate;
66 }
67
68 impl Update for $name {
69 #[inline]
70 fn update(&mut self, data: &[u8]) {
71 let Self { core, buffer } = self;
72 buffer.digest_blocks(data, |blocks| core.update_blocks(blocks));
73 }
74 }
75
76 impl ExtendableOutput for $name {
77 type Reader = $reader_name;
78
79 #[inline]
80 fn finalize_xof(mut self) -> Self::Reader {
81 let Self { core, buffer } = &mut self;
82 let core = core.finalize_xof_core(buffer);
83 let buffer = Default::default();
84 Self::Reader { core, buffer }
85 }
86 }
87
88 impl ExtendableOutputReset for $name {
89 #[inline]
90 fn finalize_xof_reset(&mut self) -> Self::Reader {
91 let Self { core, buffer } = self;
92 let core = core.finalize_xof_core(buffer);
93 self.reset();
94 let buffer = Default::default();
95 Self::Reader { core, buffer }
96 }
97 }
98
99 impl Reset for $name {
100 #[inline]
101 fn reset(&mut self) {
102 *self = Default::default();
103 }
104 }
105
106 impl AlgorithmName for $name {
107 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 f.write_str($alg_name)
109 }
110 }
111
112 impl fmt::Debug for $name {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 f.write_str(concat!(stringify!($name), " { ... }"))
115 }
116 }
117
118 #[cfg(feature = "zeroize")]
119 impl digest::zeroize::ZeroizeOnDrop for $name {}
120
121 #[doc = $alg_name]
122 #[doc = " XOF reader."]
123 #[derive(Clone)]
124 pub struct $reader_name {
125 core: Sha3ReaderCore<$rate, DEFAULT_ROUND_COUNT>,
126 buffer: ReadBuffer<$rate>,
127 }
128
129 impl XofReader for $reader_name {
130 #[inline]
131 fn read(&mut self, buf: &mut [u8]) {
132 let Self { core, buffer } = self;
133 buffer.read(buf, |block| {
134 *block = core.read_block();
135 });
136 }
137 }
138
139 impl fmt::Debug for $reader_name {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 f.write_str(concat!(stringify!($reader_name), " { ... }"))
142 }
143 }
144 };
145}
146
147impl_shake!(Shake128, Shake128Reader, U168, "SHAKE128");
148impl_shake!(Shake256, Shake256Reader, U136, "SHAKE256");
149
150impl CollisionResistance for Shake128 {
159 type CollisionResistance = U16;
161}
162
163impl CollisionResistance for Shake256 {
164 type CollisionResistance = U32;
166}
167
168#[cfg(test)]
169mod tests {
170 use digest::CollisionResistance;
171 use digest::consts::{
172 U16,
173 U32,
174 };
175 use digest::typenum::Unsigned;
176
177 use super::{
178 Shake128,
179 Shake256,
180 };
181
182 #[test]
190 fn collision_resistance_is_in_bytes_not_the_sponge_rate() {
191 assert_eq!(
192 <Shake128 as CollisionResistance>::CollisionResistance::USIZE,
193 U16::USIZE,
194 "SHAKE128 collision resistance must be 16 bytes (128 bits), not the 168-byte rate"
195 );
196 assert_eq!(
197 <Shake256 as CollisionResistance>::CollisionResistance::USIZE,
198 U32::USIZE,
199 "SHAKE256 collision resistance must be 32 bytes (256 bits), not the 136-byte rate"
200 );
201
202 assert_ne!(U16::USIZE, U32::USIZE);
205 }
206}