1use crate::{CSHAKE_PAD, SHAKE_PAD, Sha3ReaderCore, block_api::xor_block};
2use core::fmt;
3use digest::{
4 CollisionResistance, CustomizedInit, HashMarker, Reset,
5 block_api::{
6 AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, Eager, ExtendableOutputCore,
7 UpdateCore,
8 },
9 common::hazmat::{DeserializeStateError, SerializableState, SerializedState},
10 consts::{U16, U32, U136, U168, U400},
11 typenum::Unsigned,
12};
13use keccak::{F1600_ROUNDS as ROUNDS, Keccak, State1600};
14
15macro_rules! impl_cshake {
16 (
17 $name:ident, $full_name:ident, $reader_name:ident, $rate:ident, $alg_name:expr
18 ) => {
19 #[doc = $alg_name]
20 #[doc = " core hasher."]
21 #[derive(Clone, Default)]
22 pub struct $name {
23 state: State1600,
24 initial_state: State1600,
25 keccak: Keccak,
26 }
27
28 impl $name {
29 pub fn new_with_function_name(function_name: &[u8], customization: &[u8]) -> Self {
34 let mut state = Self::default();
35
36 if function_name.is_empty() && customization.is_empty() {
37 return state;
38 }
39
40 #[inline(always)]
41 pub(crate) fn left_encode(val: u64, b: &mut [u8; 9]) -> &[u8] {
42 b[1..].copy_from_slice(&val.to_be_bytes());
43 let i = b[1..8].iter().take_while(|&&a| a == 0).count();
44 b[i] = (8 - i) as u8;
45 &b[i..]
46 }
47
48 let mut buffer = Buffer::<Self>::default();
49 let mut b = [0u8; 9];
50 buffer.digest_blocks(left_encode($rate::to_u64(), &mut b), |blocks| {
51 state.update_blocks(blocks)
52 });
53 buffer.digest_blocks(
54 left_encode(8 * (function_name.len() as u64), &mut b),
55 |blocks| state.update_blocks(blocks),
56 );
57 buffer.digest_blocks(function_name, |blocks| state.update_blocks(blocks));
58 buffer.digest_blocks(
59 left_encode(8 * (customization.len() as u64), &mut b),
60 |blocks| state.update_blocks(blocks),
61 );
62 buffer.digest_blocks(customization, |blocks| state.update_blocks(blocks));
63 state.update_blocks(&[buffer.pad_with_zeros()]);
64 state.initial_state = state.state;
65 state
66 }
67 }
68
69 impl CustomizedInit for $name {
70 #[inline]
71 fn new_customized(customization: &[u8]) -> Self {
72 Self::new_with_function_name(&[], customization)
73 }
74 }
75
76 impl BufferKindUser for $name {
77 type BufferKind = Eager;
78 }
79
80 impl HashMarker for $name {}
81
82 impl BlockSizeUser for $name {
83 type BlockSize = $rate;
84 }
85
86 impl UpdateCore for $name {
87 #[inline]
88 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
89 self.keccak.with_p1600::<ROUNDS>(|p1600| {
90 for block in blocks {
91 xor_block(&mut self.state, block);
92 p1600(&mut self.state);
93 }
94 })
95 }
96 }
97
98 impl ExtendableOutputCore for $name {
99 type ReaderCore = Sha3ReaderCore<$rate>;
100
101 #[inline]
102 fn finalize_xof_core(&mut self, buffer: &mut Buffer<Self>) -> Self::ReaderCore {
103 let pos = buffer.get_pos();
104 let mut block = buffer.pad_with_zeros();
105 let pad = if self.initial_state == State1600::default() {
106 SHAKE_PAD
107 } else {
108 CSHAKE_PAD
109 };
110 block[pos] = pad;
111 let n = block.len();
112 block[n - 1] |= 0x80;
113
114 self.keccak.with_p1600::<ROUNDS>(|p1600| {
115 xor_block(&mut self.state, &block);
116 p1600(&mut self.state);
117 });
118
119 Sha3ReaderCore::new(&self.state, self.keccak)
120 }
121 }
122
123 impl Reset for $name {
124 #[inline]
125 fn reset(&mut self) {
126 self.state = self.initial_state;
127 }
128 }
129
130 impl AlgorithmName for $name {
131 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
132 f.write_str($alg_name)
133 }
134 }
135
136 impl fmt::Debug for $name {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 f.write_str(concat!(stringify!($name), " { ... }"))
139 }
140 }
141
142 impl Drop for $name {
143 fn drop(&mut self) {
144 #[cfg(feature = "zeroize")]
145 {
146 use digest::zeroize::Zeroize;
147 self.state.zeroize();
148 self.initial_state.zeroize();
149 }
150 }
151 }
152
153 #[cfg(feature = "zeroize")]
154 impl digest::zeroize::ZeroizeOnDrop for $name {}
155
156 impl SerializableState for $name {
157 type SerializedStateSize = U400;
158
159 fn serialize(&self) -> SerializedState<Self> {
160 let mut serialized_state = SerializedState::<Self>::default();
161 let mut chunks = serialized_state.chunks_exact_mut(8);
162
163 for (val, chunk) in self.state.iter().zip(&mut chunks) {
164 chunk.copy_from_slice(&val.to_le_bytes());
165 }
166 for (val, chunk) in self.initial_state.iter().zip(&mut chunks) {
167 chunk.copy_from_slice(&val.to_le_bytes());
168 }
169
170 serialized_state
171 }
172
173 fn deserialize(
174 serialized_state: &SerializedState<Self>,
175 ) -> Result<Self, DeserializeStateError> {
176 let (state_src, initial_state_src) = serialized_state.split_at(200);
177 let state = core::array::from_fn(|i| {
178 let chunk = state_src[8 * i..][..8].try_into().unwrap();
179 u64::from_le_bytes(chunk)
180 });
181 let initial_state = core::array::from_fn(|i| {
182 let chunk = initial_state_src[8 * i..][..8].try_into().unwrap();
183 u64::from_le_bytes(chunk)
184 });
185 Ok(Self{ state, initial_state, keccak: Keccak::new() })
186 }
187 }
188
189 digest::buffer_xof!(
190 #[doc = $alg_name]
191 #[doc = " hasher."]
192 pub struct $full_name($name);
193 impl: Debug AlgorithmName Clone Default BlockSizeUser CoreProxy HashMarker Update Reset ExtendableOutputReset CustomizedInit;
195 #[doc = $alg_name]
196 #[doc = " XOF reader."]
197 pub struct $reader_name(Sha3ReaderCore<$rate>);
198 impl: XofReaderTraits;
199 );
200
201 impl $full_name {
202 pub fn new_with_function_name(function_name: &[u8], customization: &[u8]) -> Self {
207 Self {
208 core: $name::new_with_function_name(function_name, customization),
209 buffer: Default::default(),
210 }
211 }
212 }
213 };
214}
215
216impl_cshake!(CShake128Core, CShake128, CShake128Reader, U168, "cSHAKE128");
217impl_cshake!(CShake256Core, CShake256, CShake256Reader, U136, "cSHAKE256");
218
219impl CollisionResistance for CShake128 {
220 type CollisionResistance = U16;
222}
223
224impl CollisionResistance for CShake256 {
225 type CollisionResistance = U32;
227}