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();
91 Digest::update(&mut output_hasher_prefix, i.to_be_bytes());
92 let digest = output_hasher_prefix.finalize();
93 let chunk_len = usize::min(output.len(), Self::DIGEST_SIZE);
95 output[..chunk_len].copy_from_slice(&digest[..chunk_len]);
96 self.leftovers.extend_from_slice(&digest[chunk_len..]);
97 self.mode = Mode::Squeeze(i + 1);
99 self.squeeze(&mut output[chunk_len..])
100 } else {
101 unreachable!()
102 }
103 }
104}
105
106#[derive(Clone, PartialEq, Eq)]
107enum Mode {
108 Start,
109 Absorb,
110 Squeeze(usize),
111}
112
113impl<D: BlockSizeUser + Digest + Clone + Reset> Hash<D> {
114 const BLOCK_SIZE: usize = D::BlockSize::USIZE;
115 const DIGEST_SIZE: usize = D::OutputSize::USIZE;
116
117 fn pad_block(start: &[u8], end: &[u8]) -> Block<D> {
120 debug_assert!(start.len() + end.len() < Self::BLOCK_SIZE);
121 let mut mask = Block::<D>::default();
122 mask[..start.len()].copy_from_slice(start);
123 mask[Self::BLOCK_SIZE - end.len()..].copy_from_slice(end);
124 mask
125 }
126
127 fn mask_absorb() -> Block<D> {
128 Self::pad_block(&[], &[0x00])
129 }
130
131 fn mask_squeeze() -> Block<D> {
132 Self::pad_block(&[], &[0x01])
133 }
134
135 fn mask_squeeze_end() -> Block<D> {
136 Self::pad_block(&[], &[0x02])
137 }
138
139 fn squeeze_end(&mut self) {
140 if let Mode::Squeeze(count) = self.mode {
141 Digest::reset(&mut self.hasher);
142
143 let byte_count = count * Self::DIGEST_SIZE - self.leftovers.len();
147 let mut squeeze_hasher = D::new();
148 Digest::update(&mut squeeze_hasher, Self::mask_squeeze_end());
149 Digest::update(&mut squeeze_hasher, &self.cv);
150 Digest::update(&mut squeeze_hasher, byte_count.to_be_bytes());
151 self.cv = Digest::finalize(squeeze_hasher);
152
153 self.mode = Mode::Start;
155 self.leftovers.clear();
156 }
157 }
158}
159
160#[cfg(feature = "zeroize")]
161impl<D: Clone + Digest + Reset + BlockSizeUser> Zeroize for Hash<D> {
162 fn zeroize(&mut self) {
163 self.cv.zeroize();
164 Digest::reset(&mut self.hasher);
165 }
166}
167
168#[cfg(feature = "zeroize")]
169impl<D: Clone + Digest + Reset + BlockSizeUser> Drop for Hash<D> {
170 fn drop(&mut self) {
171 self.zeroize();
172 }
173}
174
175impl<D: BlockSizeUser + Digest + Clone + FixedOutputReset> Default for Hash<D> {
176 fn default() -> Self {
177 Self {
178 hasher: D::new(),
179 cv: Output::<D>::default(),
180 mode: Mode::Start,
181 leftovers: Vec::new(),
182 }
183 }
184}
185
186#[cfg(all(test, feature = "sha2"))]
187#[test]
188fn test_shosha() {
189 let expected = b"\xEB\xE4\xEF\x29\xE1\x8A\xA5\x41\x37\xED\xD8\x9C\x23\xF8\
190 \xBF\xEA\xC2\x73\x1C\x9F\x67\x5D\xA2\x0E\x7C\x67\xD5\xAD\
191 \x68\xD7\xEE\x2D\x40\xA4\x52\x32\xB5\x99\x55\x2D\x46\xB5\
192 \x20\x08\x2F\xB2\x70\x59\x71\xF0\x7B\x31\x58\xB0\x72\xB6\
193 \x3A\xB0\x93\x4A\x05\xE6\xAF\x64";
194 let mut sho = Hash::<sha2::Sha256>::default();
195 let mut got = [0u8; 64];
196 sho.absorb(b"asd");
197 sho.ratchet();
198 sho.absorb(b"asd");
200 sho.absorb(b"asd");
201 sho.squeeze(&mut got[..32]);
203 sho.squeeze(&mut got[32..]);
204 assert_eq!(&got, expected);
205
206 let expected = b"\xEB\xE4\xEF\x29\xE1\x8A\xA5\x41\x37\xED\xD8\x9C\x23\xF8\
207 \xBF\xEA\xC2\x73\x1C\x9F\x67\x5D\xA2\x0E\x7C\x67\xD5\xAD\
208 \x68\xD7\xEE\x2D\x40\xA4\x52\x32\xB5\x99\x55\x2D\x46\xB5\
209 \x20\x08\x2F\xB2\x70\x59\x71\xF0\x7B\x31\x58\xB0\x72\xB6\
210 \x3A\xB0\x93\x4A\x05\xE6\xAF\x64\x48";
211 let mut sho = Hash::<sha2::Sha256>::default();
212 let mut got = [0u8; 65];
213 sho.absorb(b"asd");
214 sho.ratchet();
215 sho.absorb(b"asdasd");
216 sho.squeeze(&mut got);
217 assert_eq!(&got, expected);
218
219 let expected = b"\x0D\xDE\xEA\x97\x3F\x32\x10\xF7\x72\x5A\x3C\xDB\x24\x73\
220 \xF8\x73\xAE\xAB\x8F\xEB\x32\xB8\x0D\xEE\x67\xF0\xCD\xE7\
221 \x95\x4E\x92\x9A\x4E\x78\x7A\xEF\xEE\x6D\xBE\x91\xD3\xFF\
222 \xF1\x62\x1A\xAB\x8D\x0D\x29\x19\x4F\x8A\xF9\x86\xD6\xF3\
223 \x57\xAD\xD0\x15\x0D\xF7\xD9";
224
225 let mut sho = Hash::<sha2::Sha256>::default();
226 let mut got = [0u8; 150];
227 sho.absorb(b"");
228 sho.ratchet();
229 sho.absorb(b"abc");
230 sho.ratchet();
231 sho.absorb(&[0u8; 63]);
232 sho.ratchet();
233 sho.absorb(&[0u8; 64]);
234 sho.ratchet();
235 sho.absorb(&[0u8; 65]);
236 sho.ratchet();
237 sho.absorb(&[0u8; 127]);
238 sho.ratchet();
239 sho.absorb(&[0u8; 128]);
240 sho.ratchet();
241 sho.absorb(&[0u8; 129]);
242 sho.ratchet();
243 sho.squeeze(&mut got[..63]);
244 sho.squeeze_end();
246 sho.squeeze(&mut got[..64]);
247 sho.squeeze_end();
249 sho.squeeze(&mut got[..65]);
250 sho.squeeze_end();
251 sho.squeeze(&mut got[..127]);
252 sho.squeeze_end();
253 sho.squeeze(&mut got[..128]);
254 sho.squeeze_end();
255 sho.squeeze(&mut got[..129]);
256 assert_eq!(got[0], 0xd0);
257 sho.absorb(b"def");
258 sho.ratchet();
259 sho.squeeze(&mut got[..63]);
260 assert_eq!(&got[..63], expected);
261}