Skip to main content

lib_q_hash/
cshake.rs

1use core::fmt;
2
3use digest::block_api::{
4    AlgorithmName,
5    Block,
6    BlockSizeUser,
7    Buffer,
8    BufferKindUser,
9    Eager,
10    ExtendableOutputCore,
11    UpdateCore,
12};
13use digest::common::hazmat::{
14    DeserializeStateError,
15    SerializableState,
16    SerializedState,
17};
18use digest::consts::{
19    U16,
20    U32,
21    U136,
22    U168,
23    U400,
24};
25use digest::typenum::Unsigned;
26use digest::{
27    CollisionResistance,
28    CustomizedInit,
29    HashMarker,
30    Reset,
31};
32
33#[cfg(not(feature = "simd"))]
34use crate::DEFAULT_ROUND_COUNT as ROUNDS;
35use crate::internal_block_api::{
36    Sha3ReaderCore,
37    xor_block,
38};
39use crate::{
40    CSHAKE_PAD,
41    PLEN,
42    SHAKE_PAD,
43};
44
45macro_rules! impl_cshake {
46    (
47        $name:ident, $full_name:ident, $reader_name:ident, $rate:ident, $alg_name:expr
48    ) => {
49        #[doc = $alg_name]
50        #[doc = " core hasher."]
51        #[derive(Clone, Default)]
52        pub struct $name {
53            state: [u64; PLEN],
54            initial_state: [u64; PLEN],
55        }
56
57        impl $name {
58            /// Creates a new CSHAKE instance with the given function name and customization.
59            ///
60            /// Note that the function name is intended for use by NIST and should only be set to
61            /// values defined by NIST. You probably don't need to use this function.
62            pub fn new_with_function_name(function_name: &[u8], customization: &[u8]) -> Self {
63                let mut state = Self::default();
64
65                if function_name.is_empty() && customization.is_empty() {
66                    return state;
67                }
68
69                #[inline(always)]
70                pub(crate) fn left_encode(val: u64, b: &mut [u8; 9]) -> &[u8] {
71                    b[1..].copy_from_slice(&val.to_be_bytes());
72                    let i = b[1..8].iter().take_while(|&&a| a == 0).count();
73                    b[i] = (8 - i) as u8;
74                    &b[i..]
75                }
76
77                let mut buffer = Buffer::<Self>::default();
78                let mut b = [0u8; 9];
79                buffer.digest_blocks(left_encode($rate::to_u64(), &mut b), |blocks| {
80                    state.update_blocks(blocks)
81                });
82                buffer.digest_blocks(
83                    left_encode(8 * (function_name.len() as u64), &mut b),
84                    |blocks| state.update_blocks(blocks),
85                );
86                buffer.digest_blocks(function_name, |blocks| state.update_blocks(blocks));
87                buffer.digest_blocks(
88                    left_encode(8 * (customization.len() as u64), &mut b),
89                    |blocks| state.update_blocks(blocks),
90                );
91                buffer.digest_blocks(customization, |blocks| state.update_blocks(blocks));
92                state.update_blocks(&[buffer.pad_with_zeros()]);
93                state.initial_state = state.state;
94                state
95            }
96        }
97
98        impl CustomizedInit for $name {
99            #[inline]
100            fn new_customized(customization: &[u8]) -> Self {
101                Self::new_with_function_name(&[], customization)
102            }
103        }
104
105        impl BlockSizeUser for $name {
106            type BlockSize = $rate;
107        }
108
109        impl BufferKindUser for $name {
110            type BufferKind = Eager;
111        }
112
113        impl HashMarker for $name {}
114
115        impl UpdateCore for $name {
116            #[inline]
117            fn update_blocks(&mut self, blocks: &[Block<Self>]) {
118                for block in blocks {
119                    xor_block(&mut self.state, block);
120                    #[cfg(feature = "simd")]
121                    {
122                        lib_q_keccak::p1600_optimized(&mut self.state, lib_q_keccak::OptimizationLevel::best_available());
123                    }
124                    #[cfg(not(feature = "simd"))]
125                    {
126                        lib_q_keccak::p1600(&mut self.state, ROUNDS);
127                    }
128                }
129            }
130        }
131
132        impl ExtendableOutputCore for $name {
133            type ReaderCore = Sha3ReaderCore<$rate>;
134
135            #[inline]
136            fn finalize_xof_core(&mut self, buffer: &mut Buffer<Self>) -> Self::ReaderCore {
137                let pos = buffer.get_pos();
138                let mut block = buffer.pad_with_zeros();
139                let pad = if self.initial_state == [0; PLEN] {
140                    SHAKE_PAD
141                } else {
142                    CSHAKE_PAD
143                };
144                block[pos] = pad;
145                let n = block.len();
146                block[n - 1] |= 0x80;
147
148                xor_block(&mut self.state, &block);
149                #[cfg(feature = "simd")]
150                {
151                    lib_q_keccak::p1600_optimized(&mut self.state, lib_q_keccak::OptimizationLevel::best_available());
152                }
153                #[cfg(not(feature = "simd"))]
154                {
155                    lib_q_keccak::p1600(&mut self.state, ROUNDS);
156                }
157
158                Sha3ReaderCore::new(&self.state)
159            }
160        }
161
162        impl Reset for $name {
163            #[inline]
164            fn reset(&mut self) {
165                self.state = self.initial_state;
166            }
167        }
168
169        impl AlgorithmName for $name {
170            fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
171                f.write_str($alg_name)
172            }
173        }
174
175        impl fmt::Debug for $name {
176            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177                f.write_str(concat!(stringify!($name), " { ... }"))
178            }
179        }
180
181        impl Drop for $name {
182            fn drop(&mut self) {
183                #[cfg(feature = "zeroize")]
184                {
185                    use digest::zeroize::Zeroize;
186                    self.state.zeroize();
187                    self.initial_state.zeroize();
188                }
189            }
190        }
191
192        #[cfg(feature = "zeroize")]
193        impl digest::zeroize::ZeroizeOnDrop for $name {}
194
195        impl SerializableState for $name {
196            type SerializedStateSize = U400;
197
198            fn serialize(&self) -> SerializedState<Self> {
199                let mut serialized_state = SerializedState::<Self>::default();
200                let mut chunks = serialized_state.chunks_exact_mut(8);
201
202                for (val, chunk) in self.state.iter().zip(&mut chunks) {
203                    chunk.copy_from_slice(&val.to_le_bytes());
204                }
205                for (val, chunk) in self.initial_state.iter().zip(&mut chunks) {
206                    chunk.copy_from_slice(&val.to_le_bytes());
207                }
208
209                serialized_state
210            }
211
212            fn deserialize(
213                serialized_state: &SerializedState<Self>,
214            ) -> Result<Self, DeserializeStateError> {
215                let (state_src, initial_state_src) = serialized_state.split_at(200);
216                let state = core::array::from_fn(|i| {
217                    let chunk = state_src[8 * i..][..8].try_into().unwrap();
218                    u64::from_le_bytes(chunk)
219                });
220                let initial_state = core::array::from_fn(|i| {
221                    let chunk = initial_state_src[8 * i..][..8].try_into().unwrap();
222                    u64::from_le_bytes(chunk)
223                });
224                Ok(Self{ state, initial_state })
225            }
226        }
227
228        digest::buffer_xof!(
229            #[doc = $alg_name]
230            #[doc = " hasher."]
231            pub struct $full_name($name);
232            // Keep `CoreProxy` (not `XofHasherTraits` alone): serialized state for this façade must
233            // stay compatible with manual `SerializableState` below and with KMAC/ParallelHash/TupleHash.
234            impl: Debug AlgorithmName Clone Default BlockSizeUser CoreProxy HashMarker Update Reset ExtendableOutputReset CustomizedInit;
235            #[doc = $alg_name]
236            #[doc = " XOF reader."]
237            pub struct $reader_name(Sha3ReaderCore<$rate>);
238            impl: XofReaderTraits;
239        );
240
241        impl $full_name {
242            /// Creates a new cSHAKE instance with the given function name and customization.
243            ///
244            /// Note that the function name is intended for use by NIST and should only be set to
245            /// values defined by NIST. You probably don't need to use this function.
246            pub fn new_with_function_name(function_name: &[u8], customization: &[u8]) -> Self {
247                Self {
248                    core: $name::new_with_function_name(function_name, customization),
249                    buffer: Default::default(),
250                }
251            }
252        }
253    };
254}
255
256impl_cshake!(CShake128Core, CShake128, CShake128Reader, U168, "cSHAKE128");
257impl_cshake!(CShake256Core, CShake256, CShake256Reader, U136, "cSHAKE256");
258
259impl CollisionResistance for CShake128 {
260    // https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf#[{"num":68,"gen":0},{"name":"XYZ"},108,440,null]
261    type CollisionResistance = U16;
262}
263
264impl CollisionResistance for CShake256 {
265    // https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-185.pdf#[{"num":68,"gen":0},{"name":"XYZ"},108,440,null]
266    type CollisionResistance = U32;
267}
268
269/// `SerializedState` for the public `CShake*` types is **core-only** (plus empty buffer) so
270/// [SP-800-185] helpers in this crate (KMAC, etc.) can delegate safely.
271impl SerializableState for CShake128 {
272    type SerializedStateSize = U400;
273
274    fn serialize(&self) -> SerializedState<Self> {
275        self.core.serialize()
276    }
277
278    fn deserialize(
279        serialized_state: &SerializedState<Self>,
280    ) -> Result<Self, DeserializeStateError> {
281        let core = CShake128Core::deserialize(serialized_state)?;
282        Ok(Self {
283            core,
284            buffer: Default::default(),
285        })
286    }
287}
288
289impl SerializableState for CShake256 {
290    type SerializedStateSize = U400;
291
292    fn serialize(&self) -> SerializedState<Self> {
293        self.core.serialize()
294    }
295
296    fn deserialize(
297        serialized_state: &SerializedState<Self>,
298    ) -> Result<Self, DeserializeStateError> {
299        let core = CShake256Core::deserialize(serialized_state)?;
300        Ok(Self {
301            core,
302            buffer: Default::default(),
303        })
304    }
305}