Skip to main content

lib_q_hash/
shake.rs

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    U136,
18    U168,
19};
20use digest::{
21    CollisionResistance,
22    ExtendableOutput,
23    ExtendableOutputReset,
24    HashMarker,
25    Update,
26    XofReader,
27};
28
29use crate::internal_block_api::{
30    Sha3HasherCore,
31    Sha3ReaderCore,
32};
33use crate::{
34    DEFAULT_ROUND_COUNT,
35    SHAKE_PAD,
36};
37
38macro_rules! impl_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 {
46            core: Sha3HasherCore<$rate, U0, SHAKE_PAD, DEFAULT_ROUND_COUNT>,
47            buffer: EagerBuffer<$rate>,
48        }
49
50        impl Default for $name {
51            #[inline]
52            fn default() -> Self {
53                Self {
54                    core: Default::default(),
55                    buffer: Default::default(),
56                }
57            }
58        }
59
60        impl HashMarker for $name {}
61
62        impl BlockSizeUser for $name {
63            type BlockSize = $rate;
64        }
65
66        impl Update for $name {
67            #[inline]
68            fn update(&mut self, data: &[u8]) {
69                let Self { core, buffer } = self;
70                buffer.digest_blocks(data, |blocks| core.update_blocks(blocks));
71            }
72        }
73
74        impl ExtendableOutput for $name {
75            type Reader = $reader_name;
76
77            #[inline]
78            fn finalize_xof(mut self) -> Self::Reader {
79                let Self { core, buffer } = &mut self;
80                let core = core.finalize_xof_core(buffer);
81                let buffer = Default::default();
82                Self::Reader { core, buffer }
83            }
84        }
85
86        impl ExtendableOutputReset for $name {
87            #[inline]
88            fn finalize_xof_reset(&mut self) -> Self::Reader {
89                let Self { core, buffer } = self;
90                let core = core.finalize_xof_core(buffer);
91                self.reset();
92                let buffer = Default::default();
93                Self::Reader { core, buffer }
94            }
95        }
96
97        impl Reset for $name {
98            #[inline]
99            fn reset(&mut self) {
100                *self = Default::default();
101            }
102        }
103
104        impl AlgorithmName for $name {
105            fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
106                f.write_str($alg_name)
107            }
108        }
109
110        impl fmt::Debug for $name {
111            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112                f.write_str(concat!(stringify!($name), " { ... }"))
113            }
114        }
115
116        #[cfg(feature = "zeroize")]
117        impl digest::zeroize::ZeroizeOnDrop for $name {}
118
119        #[doc = $alg_name]
120        #[doc = " XOF reader."]
121        #[derive(Clone)]
122        pub struct $reader_name {
123            core: Sha3ReaderCore<$rate, DEFAULT_ROUND_COUNT>,
124            buffer: ReadBuffer<$rate>,
125        }
126
127        impl XofReader for $reader_name {
128            #[inline]
129            fn read(&mut self, buf: &mut [u8]) {
130                let Self { core, buffer } = self;
131                buffer.read(buf, |block| {
132                    *block = core.read_block();
133                });
134            }
135        }
136
137        impl fmt::Debug for $reader_name {
138            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139                f.write_str(concat!(stringify!($reader_name), " { ... }"))
140            }
141        }
142    };
143}
144
145impl_shake!(Shake128, Shake128Reader, U168, "SHAKE128");
146impl_shake!(Shake256, Shake256Reader, U136, "SHAKE256");
147
148impl CollisionResistance for Shake128 {
149    // SHAKE128 provides 128-bit collision resistance
150    type CollisionResistance = U168;
151}
152
153impl CollisionResistance for Shake256 {
154    // SHAKE256 provides 256-bit collision resistance
155    type CollisionResistance = U136;
156}