spongefish/instantiations/
hash.rs1use alloc::vec::Vec;
13
14use digest::{
15 block_api::{Block, BlockSizeUser},
16 typenum::Unsigned,
17 Digest, FixedOutputReset, Output, Reset,
18};
19#[cfg(feature = "zeroize")]
20use zeroize::Zeroize;
21
22use crate::DuplexSpongeInterface;
23
24#[derive(Clone)]
26pub struct Hash<D: Digest + Clone + Reset + BlockSizeUser> {
27 hasher: D,
29 cv: Output<D>,
31 mode: Mode,
34 leftovers: Vec<u8>,
36}
37
38impl<D: BlockSizeUser + Digest + Clone + FixedOutputReset> DuplexSpongeInterface for Hash<D> {
39 type U = u8;
40
41 fn absorb(&mut self, input: &[u8]) -> &mut Self {
42 self.squeeze_end();
43
44 if self.mode == Mode::Start {
45 self.mode = Mode::Absorb;
46 Digest::update(&mut self.hasher, Self::mask_absorb());
47 Digest::update(&mut self.hasher, &self.cv);
48 }
49
50 Digest::update(&mut self.hasher, input);
51 self
52 }
53
54 fn ratchet(&mut self) -> &mut Self {
55 self.squeeze_end();
56 self.cv = <D as Digest>::digest(self.hasher.finalize_reset());
58 #[cfg(feature = "zeroize")]
60 self.leftovers.zeroize();
61 self.leftovers.clear();
62 self.mode = Mode::Start;
63 self
64 }
65
66 fn squeeze(&mut self, output: &mut [u8]) -> &mut Self {
67 if self.mode == Mode::Start {
68 self.mode = Mode::Squeeze(0);
69 Digest::update(&mut self.hasher, Self::mask_squeeze());
71 Digest::update(&mut self.hasher, &self.cv);
72 self.squeeze(output)
73 } else if self.mode == Mode::Absorb {
75 self.ratchet();
76 self.squeeze(output)
77 } else if output.is_empty() {
79 self
80 } else if !self.leftovers.is_empty() {
83 let len = usize::min(output.len(), self.leftovers.len());
84 output[..len].copy_from_slice(&self.leftovers[..len]);
85 self.leftovers.drain(..len);
86 self.squeeze(&mut output[len..])
87 } else if let Mode::Squeeze(i) = self.mode {
89 let mut output_hasher_prefix = self.hasher.clone();
94 Digest::update(&mut output_hasher_prefix, (i as u64).to_be_bytes());
95 let digest = output_hasher_prefix.finalize();
96 let chunk_len = usize::min(output.len(), Self::DIGEST_SIZE);
98 output[..chunk_len].copy_from_slice(&digest[..chunk_len]);
99 self.leftovers.extend_from_slice(&digest[chunk_len..]);
100 self.mode = Mode::Squeeze(i + 1);
102 self.squeeze(&mut output[chunk_len..])
103 } else {
104 unreachable!()
105 }
106 }
107}
108
109#[derive(Clone, PartialEq, Eq)]
110enum Mode {
111 Start,
112 Absorb,
113 Squeeze(usize),
114}
115
116impl<D: BlockSizeUser + Digest + Clone + Reset> Hash<D> {
117 const BLOCK_SIZE: usize = D::BlockSize::USIZE;
118 const DIGEST_SIZE: usize = D::OutputSize::USIZE;
119
120 fn pad_block(start: &[u8], end: &[u8]) -> Block<D> {
123 debug_assert!(start.len() + end.len() < Self::BLOCK_SIZE);
124 let mut mask = Block::<D>::default();
125 mask[..start.len()].copy_from_slice(start);
126 mask[Self::BLOCK_SIZE - end.len()..].copy_from_slice(end);
127 mask
128 }
129
130 fn mask_absorb() -> Block<D> {
131 Self::pad_block(&[], &[0x00])
132 }
133
134 fn mask_squeeze() -> Block<D> {
135 Self::pad_block(&[], &[0x01])
136 }
137
138 fn mask_squeeze_end() -> Block<D> {
139 Self::pad_block(&[], &[0x02])
140 }
141
142 fn squeeze_end(&mut self) {
143 if let Mode::Squeeze(count) = self.mode {
144 Digest::reset(&mut self.hasher);
145
146 let byte_count = count * Self::DIGEST_SIZE - self.leftovers.len();
150 let mut squeeze_hasher = D::new();
151 Digest::update(&mut squeeze_hasher, Self::mask_squeeze_end());
152 Digest::update(&mut squeeze_hasher, &self.cv);
153 Digest::update(&mut squeeze_hasher, (byte_count as u64).to_be_bytes());
156 self.cv = Digest::finalize(squeeze_hasher);
157
158 self.mode = Mode::Start;
160 self.leftovers.clear();
161 }
162 }
163}
164
165#[cfg(feature = "zeroize")]
166impl<D: Clone + Digest + Reset + BlockSizeUser> Zeroize for Hash<D> {
167 fn zeroize(&mut self) {
168 self.cv.zeroize();
169 Digest::reset(&mut self.hasher);
170 }
171}
172
173#[cfg(feature = "zeroize")]
174impl<D: Clone + Digest + Reset + BlockSizeUser> Drop for Hash<D> {
175 fn drop(&mut self) {
176 self.zeroize();
177 }
178}
179
180impl<D: BlockSizeUser + Digest + Clone + FixedOutputReset> Default for Hash<D> {
181 fn default() -> Self {
182 Self {
183 hasher: D::new(),
184 cv: Output::<D>::default(),
185 mode: Mode::Start,
186 leftovers: Vec::new(),
187 }
188 }
189}
190
191#[cfg(all(test, feature = "sha2"))]
192#[test]
193fn test_shosha() {
194 let expected = b"\xEB\xE4\xEF\x29\xE1\x8A\xA5\x41\x37\xED\xD8\x9C\x23\xF8\
195 \xBF\xEA\xC2\x73\x1C\x9F\x67\x5D\xA2\x0E\x7C\x67\xD5\xAD\
196 \x68\xD7\xEE\x2D\x40\xA4\x52\x32\xB5\x99\x55\x2D\x46\xB5\
197 \x20\x08\x2F\xB2\x70\x59\x71\xF0\x7B\x31\x58\xB0\x72\xB6\
198 \x3A\xB0\x93\x4A\x05\xE6\xAF\x64";
199 let mut sho = Hash::<sha2::Sha256>::default();
200 let mut got = [0u8; 64];
201 sho.absorb(b"asd");
202 sho.ratchet();
203 sho.absorb(b"asd");
205 sho.absorb(b"asd");
206 sho.squeeze(&mut got[..32]);
208 sho.squeeze(&mut got[32..]);
209 assert_eq!(&got, expected);
210
211 let expected = b"\xEB\xE4\xEF\x29\xE1\x8A\xA5\x41\x37\xED\xD8\x9C\x23\xF8\
212 \xBF\xEA\xC2\x73\x1C\x9F\x67\x5D\xA2\x0E\x7C\x67\xD5\xAD\
213 \x68\xD7\xEE\x2D\x40\xA4\x52\x32\xB5\x99\x55\x2D\x46\xB5\
214 \x20\x08\x2F\xB2\x70\x59\x71\xF0\x7B\x31\x58\xB0\x72\xB6\
215 \x3A\xB0\x93\x4A\x05\xE6\xAF\x64\x48";
216 let mut sho = Hash::<sha2::Sha256>::default();
217 let mut got = [0u8; 65];
218 sho.absorb(b"asd");
219 sho.ratchet();
220 sho.absorb(b"asdasd");
221 sho.squeeze(&mut got);
222 assert_eq!(&got, expected);
223
224 let expected = b"\x0D\xDE\xEA\x97\x3F\x32\x10\xF7\x72\x5A\x3C\xDB\x24\x73\
225 \xF8\x73\xAE\xAB\x8F\xEB\x32\xB8\x0D\xEE\x67\xF0\xCD\xE7\
226 \x95\x4E\x92\x9A\x4E\x78\x7A\xEF\xEE\x6D\xBE\x91\xD3\xFF\
227 \xF1\x62\x1A\xAB\x8D\x0D\x29\x19\x4F\x8A\xF9\x86\xD6\xF3\
228 \x57\xAD\xD0\x15\x0D\xF7\xD9";
229
230 let mut sho = Hash::<sha2::Sha256>::default();
231 let mut got = [0u8; 150];
232 sho.absorb(b"");
233 sho.ratchet();
234 sho.absorb(b"abc");
235 sho.ratchet();
236 sho.absorb(&[0u8; 63]);
237 sho.ratchet();
238 sho.absorb(&[0u8; 64]);
239 sho.ratchet();
240 sho.absorb(&[0u8; 65]);
241 sho.ratchet();
242 sho.absorb(&[0u8; 127]);
243 sho.ratchet();
244 sho.absorb(&[0u8; 128]);
245 sho.ratchet();
246 sho.absorb(&[0u8; 129]);
247 sho.ratchet();
248 sho.squeeze(&mut got[..63]);
249 sho.squeeze_end();
251 sho.squeeze(&mut got[..64]);
252 sho.squeeze_end();
254 sho.squeeze(&mut got[..65]);
255 sho.squeeze_end();
256 sho.squeeze(&mut got[..127]);
257 sho.squeeze_end();
258 sho.squeeze(&mut got[..128]);
259 sho.squeeze_end();
260 sho.squeeze(&mut got[..129]);
261 assert_eq!(got[0], 0xd0);
262 sho.absorb(b"def");
263 sho.ratchet();
264 sho.squeeze(&mut got[..63]);
265 assert_eq!(&got[..63], expected);
266}