1macro_rules! shake_api {
2 (
3 name: $name:ident,
4 wc: $wc:ty,
5 ds: $ds:literal,
6 init: $init:ident, heap: $heap:expr, devid: $devId:expr,
7 update: $update:ident,
8 finalize: $finalize:ident,
9 free: $free:ident,
10 copy: $copy:ident $(,)?
11 ) => {
12 #[doc = concat!("The `", stringify!($name), "` hasher.")]
13 #[doc = ""]
14 #[doc = "# Example"]
15 #[doc = ""]
16 #[doc = "```"]
17 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
18 #[doc = ""]
19 #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
20 #[doc = ""]
21 #[doc = "let input = b\"hello world\";"]
22 #[doc = "assert!(hasher.try_update(input.as_slice()).is_ok());"]
23 #[doc = ""]
24 #[doc = "let finalized = hasher.try_finalize::<64>().unwrap();"]
25 #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
26 #[doc = "assert_eq!(finalized.len(), 64);"]
27 #[doc = "```"]
28 #[repr(transparent)]
29 pub struct $name {
30 inner: $wc
31 }
32
33 impl $name {
34 #[doc = concat!("Create a new `", stringify!($name), "` instance.")]
35 #[doc = ""]
36 #[doc = "# Errors"]
37 #[doc = ""]
38 #[doc = concat!(
39 "If the underlying initialization function fails (`", stringify!($init), "`)"
40 )]
41 #[doc = ""]
42 #[doc = "# Example"]
43 #[doc = ""]
44 #[doc = "```"]
45 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
46 #[doc = ""]
47 #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
48 #[doc = ""]
49 #[doc = "let input = b\"hello world\";"]
50 #[doc = "assert!(hasher.try_update(input.as_slice()).is_ok());"]
51 #[doc = ""]
52 #[doc = "let finalized = hasher.try_finalize::<32>()"]
53 #[doc = " .unwrap();"]
54 #[doc = "assert_eq!(finalized.len(), 32);"]
55 #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
56 #[doc = "```"]
57 pub fn new() -> Result<Self, $crate::error::Unspecified> {
58 unsafe {
59 let mut res = $crate::opaque_res::Res::new();
60 let mut inner = ::core::mem::MaybeUninit::<$wc>::uninit();
61
62 res.ensure_0($init(inner.as_mut_ptr(), $heap, $devId));
63
64 res.unit_err_with(|| Self { inner: inner.assume_init() })
65 }
66 }
67
68 #[doc = concat!(
69 "Update the underlying `", stringify!($wc), "` instance, without performing any ",
70 "safety checks."
71 )]
72 #[doc = ""]
73 #[doc = "# Safety"]
74 #[doc = ""]
75 #[doc = "The length of data is casted to a 32 bit unsigned integer without checking "]
76 #[doc = "for overflows. While it is incredibly unlikely that this overflow will ever"]
77 #[doc = "take place, it is not impossible. Thus this function is marked unsafe."]
78 #[doc = ""]
79 #[doc = "# Arguments"]
80 #[doc = ""]
81 #[doc = "* `data` - The slice to update the underlying hasher state with."]
82 #[doc = ""]
83 #[doc = "# Returns"]
84 #[doc = ""]
85 #[doc = "This function returns the result of the operation."]
86 #[doc = ""]
87 #[doc = "# Example"]
88 #[doc = ""]
89 #[doc = "```"]
90 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
91 #[doc = ""]
92 #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
93 #[doc = ""]
94 #[doc = "let input = b\"hello world\";"]
95 #[doc = "// SAFETY: The length of `hello world` is 11, which"]
96 #[doc = "// cannot overflow even an 8 bit integer."]
97 #[doc = "let res = unsafe {"]
98 #[doc = " hasher.update_unchecked(input.as_slice())"]
99 #[doc = "};"]
100 #[doc = "assert!(res.is_ok());"]
101 #[doc = ""]
102 #[doc = "let finalized = hasher.finalize_default().unwrap();"]
103 #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
104 #[doc = "```"]
105 #[inline]
106 pub unsafe fn update_unchecked(&mut self, data: &[u8]) -> $crate::opaque_res::Res {
107 let mut res = $crate::opaque_res::Res::new();
108
109 res.ensure_0($update(
110 ::core::ptr::addr_of_mut!(self.inner),
111 data.as_ptr(),
112 data.len() as u32
113 ));
114
115 res
116 }
117
118 #[doc = concat!("Update the underlying `", stringify!($wc), "` instance.")]
119 #[doc = ""]
120 #[doc = "# Arguments"]
121 #[doc = ""]
122 #[doc = "* `data` - The slice to update the underlying hasher state with."]
123 #[doc = ""]
124 #[doc = "# Returns"]
125 #[doc = ""]
126 #[doc = "This function returns the result of the operation."]
127 #[doc = ""]
128 #[doc = "# Errors"]
129 #[doc = ""]
130 #[doc = "- If the length of `data` cannot be safely casted to a `u32`."]
131 #[doc = concat!("- If the underlying `", stringify!($update), "` function fails.")]
132 #[doc = ""]
133 #[doc = "# Example"]
134 #[doc = ""]
135 #[doc = "```"]
136 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
137 #[doc = ""]
138 #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
139 #[doc = ""]
140 #[doc = "let input = b\"hello world\";"]
141 #[doc = "assert!(hasher.try_update(input.as_slice()).is_ok());"]
142 #[doc = ""]
143 #[doc = "let finalized = hasher.finalize_default().unwrap();"]
144 #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
145 #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($ds), ");")]
146 #[doc = "```"]
147 #[doc = ""]
148 #[doc = "**Note**: if the size of the `data` is known at compile time, see "]
149 #[doc = "[`update_sized`] for a slight optimization as the safety checks are done at "]
150 #[doc = "compilation time."]
151 #[doc = ""]
152 #[doc = "[`update_sized`]: Self::update_sized"]
153 #[inline]
154 pub fn try_update(&mut self, data: &[u8]) -> $crate::opaque_res::Res {
155 if !$crate::can_cast_u32(data.len()) {
156 return $crate::opaque_res::Res::ERR;
157 }
158
159 unsafe { self.update_unchecked(data) }
160 }
161
162 #[doc = concat!(
163 "Update the underlying `", stringify!($wc), "` instance, with the safety checks ",
164 "performed at compilation time."
165 )]
166 #[doc = ""]
167 #[doc = "# Arguments"]
168 #[doc = ""]
169 #[doc = "* `data` - The slice to update the underlying hasher state with."]
170 #[doc = ""]
171 #[doc = "# Returns"]
172 #[doc = ""]
173 #[doc = "This function returns the result of the operation."]
174 #[doc = ""]
175 #[doc = "# Errors"]
176 #[doc = ""]
177 #[doc = "- If the length of `data` cannot be safely casted to a `u32`."]
178 #[doc = concat!("- If the underlying `", stringify!($update), "` function fails.")]
179 #[doc = ""]
180 #[doc = "# Example"]
181 #[doc = ""]
182 #[doc = "```"]
183 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
184 #[doc = ""]
185 #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
186 #[doc = ""]
187 #[doc = "let input = b\"hello world\";"]
188 #[doc = "assert!(hasher.update_sized(input).is_ok());"]
189 #[doc = ""]
190 #[doc = "let finalized = hasher.finalize_default().unwrap();"]
191 #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
192 #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($ds), ");")]
193 #[doc = "```"]
194 #[doc = ""]
195 #[doc = "**Note**: if the size of the `data` is not known at compile time, see "]
196 #[doc = "[`try_update`] for more flexibility."]
197 #[doc = ""]
198 #[doc = "[`try_update`]: Self::try_update"]
199 #[inline]
200 pub fn update_sized<const C: usize>(&mut self, data: &[u8; C]) -> $crate::opaque_res::Res {
201 if !$crate::const_can_cast_u32::<{ C }>() {
202 return $crate::opaque_res::Res::ERR;
203 }
204
205 unsafe { self.update_unchecked(data) }
206 }
207
208 panic_api! {
209 #[doc = concat!(
210 "Update the underlying `", stringify!($wc), "`, panicking under any failure."
211 )]
212 #[doc = ""]
213 #[doc = "# Arguments"]
214 #[doc = ""]
215 #[doc = "* `data` - The slice to update the underlying hasher state with."]
216 #[doc = ""]
217 #[doc = "# Panics"]
218 #[doc = ""]
219 #[doc = "- If the length of `data` cannot be safely casted to a `u32`."]
220 #[doc = concat!("- If the underlying `", stringify!($update), "` function fails.")]
221 #[doc = ""]
222 #[doc = "If a `panic` under any failure is not acceptable for your use case, which "]
223 #[doc = "generally is true, please consider using [`try_update`]."]
224 #[doc = ""]
225 #[doc = "# Example"]
226 #[doc = ""]
227 #[doc = "```"]
228 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
229 #[doc = ""]
230 #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
231 #[doc = ""]
232 #[doc = "let input = b\"hello world\";"]
233 #[doc = "hasher.update(input.as_slice());"]
234 #[doc = ""]
235 #[doc = "let finalized = hasher.try_finalize::<64>().unwrap();"]
236 #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
237 #[doc = "assert_eq!(finalized.len(), 64);"]
238 #[doc = "```"]
239 #[doc = ""]
240 #[doc = "[`try_update`]: Self::try_update"]
241 #[track_caller]
242 pub fn update(&mut self, data: &[u8]) {
243 self.try_update(data).unit_err(())
244 .expect(concat!("Failed to update hash in `", stringify!($name), "`"))
245 }
246 }
247
248 #[doc = concat!(
249 "Calls the `", stringify!($finalize), "` function, finalizing the extensible ",
250 "hashing of data and resetting the underlying `", stringify!($wc), "` instance's ",
251 "state without performing any safety checks on the `output` buffer size."
252 )]
253 #[doc = ""]
254 #[doc = "# Safety"]
255 #[doc = ""]
256 #[doc = "The length of `output` is casted to a 32 bit unsigned integer without checking"]
257 #[doc = "for overflows. While it is incredibly unlikely that this overflow will ever"]
258 #[doc = "take place, it is not impossible. Thus this function is marked unsafe."]
259 #[doc = ""]
260 #[doc = "# Arguments"]
261 #[doc = ""]
262 #[doc = "* `output` - The buffer to store the variable-length output digest. Its length must be manually verified."]
263 #[doc = ""]
264 #[doc = "# Errors"]
265 #[doc = ""]
266 #[doc = "If the underlying finalize function fails, the returned result will contain an error."]
267 #[doc = ""]
268 #[doc = "# Example"]
269 #[doc = ""]
270 #[doc = "```"]
271 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
272 #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
273 #[doc = "# let input = b\"hello world\";"]
274 #[doc = "# assert!(hasher.update_sized(input).is_ok());"]
275 #[doc = ""]
276 #[doc = "// Use the hasher ..."]
277 #[doc = ""]
278 #[doc = "let mut output = [0u8; 64];"]
279 #[doc = "unsafe {"]
280 #[doc = " let res = hasher.finalize_unchecked(&mut output);"]
281 #[doc = " assert!(res.is_ok());"]
282 #[doc = "}"]
283 #[doc = "```"]
284 #[doc = ""]
285 #[doc = "**Note**: Prefer using [`finalize_into`] or [`finalize_into_sized`] where possible to "]
286 #[doc = "benefit from safety checks."]
287 #[doc = ""]
288 #[doc = "[`finalize_into`]: Self::finalize_into"]
289 #[doc = "[`finalize_into_sized`]: Self::finalize_into_sized"]
290 pub unsafe fn finalize_unchecked(&mut self, output: &mut [u8]) -> $crate::opaque_res::Res {
291 let mut res = $crate::opaque_res::Res::new();
292 let len = output.len() as u32;
293
294 res.ensure_0($finalize(
295 ::core::ptr::addr_of_mut!(self.inner),
296 output.as_mut_ptr(),
297 len
298 ));
299
300 res
301 }
302
303 #[doc = concat!(
304 "Calls the `", stringify!($finalize), "` function, finalizing the extensible ",
305 "hashing of data and resetting the underlying `", stringify!($wc), "` instance's ",
306 "state."
307 )]
308 #[doc = ""]
309 #[doc = "# Arguments"]
310 #[doc = ""]
311 #[doc = "* `output` - The buffer to store the variable-length output digest."]
312 #[doc = ""]
313 #[doc = "# Errors"]
314 #[doc = ""]
315 #[doc = "- If the size of `output` exceeds what can be represented as a `u32`."]
316 #[doc = "- If the underlying finalize function fails."]
317 #[doc = ""]
318 #[doc = "# Example"]
319 #[doc = ""]
320 #[doc = "```"]
321 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
322 #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
323 #[doc = "# let input = b\"hello world\";"]
324 #[doc = "# assert!(hasher.update_sized(input).is_ok());"]
325 #[doc = ""]
326 #[doc = "// Use the hasher ..."]
327 #[doc = ""]
328 #[doc = "let mut output = [0u8; 64];"]
329 #[doc = "let res = hasher.finalize_into(output.as_mut_slice());"]
330 #[doc = "assert!(res.is_ok());"]
331 #[doc = "```"]
332 #[doc = ""]
333 #[doc = "**Note**: If the size of the `output` slice is known at compile time, see "]
334 #[doc = "[`finalize_into_sized`] for a slight optimization."]
335 #[doc = ""]
336 #[doc = "[`finalize_into_sized`]: Self::finalize_into_sized"]
337 #[inline]
338 pub fn finalize_into(&mut self, output: &mut [u8]) -> $crate::opaque_res::Res {
339 if !$crate::can_cast_u32(output.len()) { return $crate::opaque_res::Res::ERR }
340 unsafe { self.finalize_unchecked(output) }
341 }
342
343 #[doc = concat!(
344 "Calls the `", stringify!($finalize), "` function, finalizing the extensible ",
345 "hashing of data and resetting the underlying `", stringify!($wc), "` instance's ",
346 "state, with the safety checks performed at compilation time."
347 )]
348 #[doc = ""]
349 #[doc = "# Arguments"]
350 #[doc = ""]
351 #[doc = "* `output` - The buffer to store the variable-length output digest."]
352 #[doc = ""]
353 #[doc = "# Errors"]
354 #[doc = ""]
355 #[doc = "- If the size of `output` exceeds what can be represented as a `u32`."]
356 #[doc = "- If the underlying finalize function fails."]
357 #[doc = ""]
358 #[doc = "# Example"]
359 #[doc = ""]
360 #[doc = "```"]
361 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
362 #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
363 #[doc = "# let input = b\"hello world\";"]
364 #[doc = "# assert!(hasher.update_sized(input).is_ok());"]
365 #[doc = ""]
366 #[doc = "// Use the hasher ..."]
367 #[doc = ""]
368 #[doc = "let mut output = [0u8; 64];"]
369 #[doc = "let res = hasher.finalize_into_sized(&mut output);"]
370 #[doc = "assert!(res.is_ok());"]
371 #[doc = "```"]
372 #[doc = ""]
373 #[doc = "**Note**: If the size of the output buffer is not known at compilation time, "]
374 #[doc = "see [`finalize_into`] for greater flexibility."]
375 #[doc = ""]
376 #[doc = "[`finalize_into`]: Self::finalize_into"]
377 #[inline]
378 pub fn finalize_into_sized<const C: usize>(&mut self, output: &mut [u8; C]) -> $crate::opaque_res::Res {
379 if !$crate::const_can_cast_u32::<{ C }>() { return $crate::opaque_res::Res::ERR }
380 unsafe { self.finalize_unchecked(output) }
381 }
382
383 #[doc = concat!(
384 "Calls the `", stringify!($finalize), "` function, finalizing the extensible ",
385 "hashing of data and resetting the underlying `", stringify!($wc), "` instance's ",
386 "state, returning a buffer of the specified output size."
387 )]
388 #[doc = ""]
389 #[doc = "# Returns"]
390 #[doc = ""]
391 #[doc = "On success, this returns the output digest of the given size."]
392 #[doc = ""]
393 #[doc = "# Errors"]
394 #[doc = ""]
395 #[doc = "If the underlying finalize function fails."]
396 #[doc = ""]
397 #[doc = "# Example"]
398 #[doc = ""]
399 #[doc = "```"]
400 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
401 #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
402 #[doc = "# let input = b\"hello world\";"]
403 #[doc = "# assert!(hasher.update_sized(input).is_ok());"]
404 #[doc = ""]
405 #[doc = "// Use the hasher ..."]
406 #[doc = ""]
407 #[doc = "let res = hasher.try_finalize::<64>().unwrap();"]
408 #[doc = "assert_ne!(res.as_slice(), input.as_slice());"]
409 #[doc = "```"]
410 #[inline]
411 pub fn try_finalize<const C: usize>(&mut self) -> Result<[u8; C], $crate::error::Unspecified> {
412 let mut buf = [0u8; C];
413 self.finalize_into_sized(&mut buf).unit_err(buf)
414 }
415
416 #[doc = concat!(
417 "Calls the `", stringify!($finalize), "` function, finalizing the extensible ",
418 "hashing of data and resetting the underlying `", stringify!($wc), "` instance's ",
419 "state with the default digest size of `", stringify!($ds), "` bytes."
420 )]
421 #[doc = ""]
422 #[doc = "# Returns"]
423 #[doc = ""]
424 #[doc = "On success, this returns the default output digest."]
425 #[doc = ""]
426 #[doc = "# Errors"]
427 #[doc = ""]
428 #[doc = "If the underlying finalize function fails."]
429 #[doc = ""]
430 #[doc = "# Example"]
431 #[doc = ""]
432 #[doc = "```"]
433 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
434 #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
435 #[doc = "# let input = b\"hello world\";"]
436 #[doc = "# assert!(hasher.update_sized(input).is_ok());"]
437 #[doc = ""]
438 #[doc = "// Use the hasher ..."]
439 #[doc = ""]
440 #[doc = "let res = hasher.finalize_default().unwrap();"]
441 #[doc = "assert_ne!(res.as_slice(), input.as_slice());"]
442 #[doc = "```"]
443 #[inline]
444 pub fn finalize_default(&mut self) -> Result<[u8; $ds], $crate::error::Unspecified> {
445 self.try_finalize::<{ $ds }>()
446 }
447
448 panic_api! {
449 #[doc = concat!(
450 "Calls the `", stringify!($finalize), "` function, finalizing the extensible ",
451 "hashing of data and resetting the underlying `", stringify!($wc),
452 "` instance's state."
453 )]
454 #[doc = ""]
455 #[doc = "# Panics"]
456 #[doc = ""]
457 #[doc = "If the underlying finalize function fails. If panicking is not acceptable for your "]
458 #[doc = "use case, see [`try_finalize`] or [`finalize_into`] instead."]
459 #[doc = ""]
460 #[doc = "# Example"]
461 #[doc = ""]
462 #[doc = "```"]
463 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
464 #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
465 #[doc = "# let input = b\"hello world\";"]
466 #[doc = "# assert!(hasher.update_sized(input).is_ok());"]
467 #[doc = ""]
468 #[doc = "// Use the hasher ..."]
469 #[doc = ""]
470 #[doc = "let res = hasher.try_finalize::<24>().unwrap();"]
471 #[doc = "assert_ne!(res.as_slice(), input.as_slice());"]
472 #[doc = "```"]
473 #[doc = ""]
474 #[doc = "[`try_finalize`]: Self::try_finalize"]
475 #[doc = "[`finalize_into`]: Self::finalize_into"]
476 #[track_caller]
477 pub fn finalize<const C: usize>(&mut self) -> [u8; C] {
478 self.try_finalize::<{ C }>().expect(concat!(
479 "Failed to finalize in `", stringify!($name), "`"
480 ))
481 }
482 }
483 }
484
485 unsafe impl Send for $name {}
490
491 unsafe impl Sync for $name {}
495
496 impl Drop for $name {
497 #[doc = concat!(
498 "Calls the `", stringify!($free), "` function, cleaning up after itself."
499 )]
500 #[inline]
501 fn drop(&mut self) {
502 unsafe { $free(::core::ptr::addr_of_mut!(self.inner)) }
503 }
504 }
505
506 copy_impl! {
507 name: $name,
508 wc: $wc,
509 copy: $copy,
510 finalize_func: finalize_default
511 }
512
513 #[cfg(test)]
514 mod unit_tests {
515 use super::*;
516
517 #[test]
518 fn test_new() {
519 let hasher = $name::new();
520 assert!(hasher.is_ok());
521 }
522
523 #[test]
524 fn test_update_single_finalize() {
525 let mut hasher = $name::new().unwrap();
526 let input = b"hello world";
527 assert!(hasher.try_update(input).is_ok());
528
529 let mut output = [0u8; 64];
530 assert!(hasher.finalize_into(&mut output).is_ok());
531 assert_eq!(output.len(), 64);
532 }
533
534 #[test]
535 fn test_multiple_updates_before_finalize() {
536 let mut hasher = $name::new().unwrap();
537 let inputs = [b"part1", b"part2", b"part3"];
538 for input in inputs {
539 assert!(hasher.try_update(input).is_ok());
540 }
541
542 let mut output = [0u8; 64];
543 assert!(hasher.finalize_into(&mut output).is_ok());
544 assert_eq!(output.len(), 64);
545 }
546
547 #[test]
548 fn test_empty_input() {
549 let mut hasher = $name::new().unwrap();
550 let input: &[u8] = &[];
551 assert!(hasher.try_update(input).is_ok());
552
553 let mut output = [0u8; 64];
554 assert!(hasher.finalize_into(&mut output).is_ok());
555 assert_eq!(output.len(), 64);
556 }
557
558 #[test]
559 fn test_large_input() {
560 let mut hasher = $name::new().unwrap();
561 let input = vec![0u8; 10 * 1024 * 1024]; assert!(hasher.try_update(&input).is_ok());
563
564 let mut output = [0u8; 64];
565 assert!(hasher.finalize_into(&mut output).is_ok());
566 assert_eq!(output.len(), 64);
567 }
568
569 #[test]
570 fn test_finalize_into_sized_exact() {
571 let mut hasher = $name::new().unwrap();
572 let input = b"exact sized finalize";
573 assert!(hasher.try_update(input).is_ok());
574
575 let mut output = [0u8; $ds];
576 assert!(hasher.finalize_into_sized(&mut output).is_ok());
577 assert_eq!(output.len(), $ds);
578 }
579
580 #[test]
581 fn test_finalize_default() {
582 let mut hasher = $name::new().unwrap();
583 let input = b"default finalize test";
584 assert!(hasher.try_update(input).is_ok());
585
586 let output = hasher.finalize_default();
587 assert!(output.is_ok());
588 assert_eq!(output.unwrap().len(), $ds);
589 }
590
591 #[test]
592 fn test_try_finalize_variable_size() {
593 let mut hasher = $name::new().unwrap();
594 let input = b"variable size finalize test";
595 assert!(hasher.try_update(input).is_ok());
596
597 let res = hasher.try_finalize::<128>();
598 assert!(res.is_ok());
599 assert_eq!(res.unwrap().len(), 128);
600 }
601
602 #[test]
603 fn test_update_sized() {
604 let mut hasher = $name::new().unwrap();
605 let input: &[u8; 5] = b"hello";
606 assert!(hasher.update_sized(input).is_ok());
607
608 let mut output = [0u8; 64];
609 assert!(hasher.finalize_into(&mut output).is_ok());
610 assert_eq!(output.len(), 64);
611 }
612
613 #[test]
614 fn test_finalize_after_reset() {
615 let mut hasher = $name::new().unwrap();
616 let input1 = b"first input";
617 let input2 = b"second input";
618
619 assert!(hasher.try_update(input1).is_ok());
620 let mut output1 = [0u8; 64];
621 assert!(hasher.finalize_into(&mut output1).is_ok());
622
623 assert!(hasher.try_update(input2).is_ok());
624 let mut output2 = [0u8; 64];
625 assert!(hasher.finalize_into(&mut output2).is_ok());
626
627 assert_ne!(output1, output2);
628 }
629
630 #[test]
631 fn test_finalize_default_no_input() {
632 let mut hasher = $name::new().unwrap();
633 let output = hasher.finalize_default();
634 assert!(output.is_ok());
635 assert_eq!(output.unwrap().len(), $ds);
636 }
637
638 #[test]
639 fn test_update_10_mb() {
640 let mut hasher = $name::new().unwrap();
641 let input = vec![0u8; 10_000_000]; assert!(hasher.try_update(&input).is_ok());
643
644 let mut output = [0u8; 64];
645 assert!(hasher.finalize_into_sized(&mut output).is_ok());
646 assert_eq!(output.len(), 64);
647 }
648
649 #[test]
650 fn test_finalize_into_sized_ds_size() {
651 let mut hasher = $name::new().unwrap();
652 let input = b"exact ds size finalize test";
653 assert!(hasher.try_update(input).is_ok());
654
655 let mut output = [0u8; $ds];
656 assert!(hasher.finalize_into_sized(&mut output).is_ok());
657 assert_eq!(output.len(), $ds);
658 }
659
660 #[test]
661 fn test_finalize_into_large_output_buffer() {
662 let mut hasher = $name::new().unwrap();
663 let input = b"large output buffer finalize test";
664 assert!(hasher.try_update(input).is_ok());
665
666 let mut output = vec![0u8; 10_000]; assert!(hasher.finalize_into(&mut output).is_ok());
668 assert_eq!(output.len(), 10_000);
669 }
670
671 #[test]
672 fn test_finalize_after_empty_input() {
673 let mut hasher = $name::new().unwrap();
674 let input: &[u8] = &[];
675 assert!(hasher.try_update(input).is_ok());
676
677 let mut output = [0u8; 64];
678 assert!(hasher.finalize_into(&mut output).is_ok());
679
680 let mut output2 = [0u8; 64];
681 assert!(hasher.finalize_into(&mut output2).is_ok());
682
683 assert_eq!(output, output2);
684 }
685
686 #[test]
687 fn test_finalize_into_exact_zero_length() {
688 let mut hasher = $name::new().unwrap();
689 let input = b"zero length output buffer test";
690 assert!(hasher.try_update(input).is_ok());
691
692 let mut output: [u8; 0] = [];
693 assert!(hasher.finalize_into_sized(&mut output).is_ok());
694 }
695
696 #[test]
697 fn test_finalize_default_multiple_no_updates() {
698 let mut hasher = $name::new().unwrap();
699
700 let output1 = hasher.finalize_default();
701 assert!(output1.is_ok());
702
703 let output2 = hasher.finalize_default();
704 assert!(output2.is_ok());
705
706 assert_eq!(output1.unwrap().as_slice(), output2.unwrap().as_slice());
707 }
708
709 #[test]
710 fn test_update_after_finalize() {
711 let mut hasher = $name::new().unwrap();
712 let input1 = b"input before finalize";
713 let input2 = b"input after finalize";
714
715 assert!(hasher.try_update(input1).is_ok());
716 let mut output1 = [0u8; 64];
717 assert!(hasher.finalize_into(&mut output1).is_ok());
718
719 assert!(hasher.try_update(input2).is_ok());
720 let mut output2 = [0u8; 64];
721 assert!(hasher.finalize_into(&mut output2).is_ok());
722
723 assert_ne!(output1, output2);
724 }
725
726 #[test]
727 fn test_finalize_with_multiple_threads() {
728 use std::sync::{Arc, Mutex};
729 use std::thread;
730
731 let hasher = Arc::new(Mutex::new($name::new().unwrap()));
732 let input = b"multithreaded finalize test";
733
734 let handles: Vec<_> = (0..10).map(|_| {
735 let hasher_clone = Arc::clone(&hasher);
736 let input_clone = input.clone();
737 thread::spawn(move || {
738 let mut hasher = hasher_clone.lock().unwrap();
739 assert!(hasher.try_update(&input_clone).is_ok());
740 let mut output = [0u8; 64];
741 assert!(hasher.finalize_into(&mut output).is_ok());
742 output
743 })
744 }).collect();
745
746 for handle in handles {
747 let output = handle.join().expect("Thread panicked");
748 assert_eq!(output.len(), 64);
749 }
750 }
751
752 #[test]
753 fn test_finalize_with_various_output_sizes() {
754 let mut hasher = $name::new().unwrap();
755 let input = b"various output sizes test";
756 assert!(hasher.try_update(input).is_ok());
757
758 let sizes = [16, 32, 64, 128, 256];
759 for &size in &sizes {
760 let mut output = vec![0u8; size];
761 assert!(hasher.finalize_into(&mut output).is_ok());
762 assert_eq!(output.len(), size);
763 }
764 }
765
766 #[test]
767 fn test_finalize_into_exact_max_size() {
768 let mut hasher = $name::new().unwrap();
769 let input = b"max size finalize test";
770 assert!(hasher.try_update(input).is_ok());
771
772 const MAX_SIZE: usize = 10_000;
773 let mut output = [0u8; MAX_SIZE];
774 assert!(hasher.finalize_into_sized(&mut output).is_ok());
775 assert_eq!(output.len(), MAX_SIZE);
776 }
777
778 #[test]
779 fn test_finalize_into_exact_after_multiple_updates() {
780 let mut hasher = $name::new().unwrap();
781 let inputs = [b"update1", b"update2", b"update3"];
782 for input in inputs {
783 assert!(hasher.try_update(input).is_ok());
784 }
785
786 let mut output = [0u8; $ds];
787 assert!(hasher.finalize_into_sized(&mut output).is_ok());
788 assert_eq!(output.len(), $ds);
789 }
790
791 #[test]
792 fn test_finalize_default_reset_behavior() {
793 let mut hasher = $name::new().unwrap();
794 let input = b"multiple finalize calls test";
795 assert!(hasher.try_update(input).is_ok());
796
797 let output1 = hasher.finalize_default();
798 assert!(output1.is_ok());
799
800 let output2 = hasher.finalize_default();
801 assert!(output2.is_ok());
802
803 assert_ne!(output1.unwrap().as_slice(), output2.unwrap().as_slice());
804 }
805
806 #[test]
807 fn test_finalize_into_overlapping_mut_slices() {
808 let mut hasher = $name::new().unwrap();
809 let input = b"overlapping mutable slices test";
810 assert!(hasher.try_update(input).is_ok());
811
812 let mut buffer = [0u8; 128];
813 let (left, right) = buffer.split_at_mut(64);
814 assert!(hasher.finalize_into(left).is_ok());
815 assert!(hasher.finalize_into(right).is_ok());
816 }
817
818 #[test]
819 fn test_finalize_with_different_output_sizes_sequentially() {
820 let mut hasher = $name::new().unwrap();
821 let input = b"sequential different output sizes test";
822 assert!(hasher.try_update(input).is_ok());
823
824 let mut output1 = [0u8; 32];
825 assert!(hasher.finalize_into(&mut output1).is_ok());
826 assert_eq!(output1.len(), 32);
827
828 let mut output2 = [0u8; 64];
829 assert!(hasher.finalize_into(&mut output2).is_ok());
830 assert_eq!(output2.len(), 64);
831 }
832
833 #[test]
834 fn test_finalize_after_multiple_large_inputs() {
835 let mut hasher = $name::new().unwrap();
836 let inputs = [
837 vec![0u8; 5_000_000],
838 vec![1u8; 10_000_000],
839 vec![2u8; 15_000_000],
840 ];
841
842 for input in &inputs {
843 assert!(hasher.try_update(input).is_ok());
844 let mut output = [0u8; 64];
845 assert!(hasher.finalize_into(&mut output).is_ok());
846 }
847 }
848
849 #[test]
850 fn test_finalize_into_exact_multiple_exact_sizes() {
851 let mut hasher = $name::new().unwrap();
852 let inputs = [b"exact size A", b"exact size B", b"exact size C"];
853 for input in inputs {
854 assert!(hasher.try_update(input).is_ok());
855 let mut output = [0u8; $ds];
856 assert!(hasher.finalize_into_sized(&mut output).is_ok());
857 }
858 }
859
860 #[test]
861 fn test_finalize_with_random_output_sizes() {
862 let mut hasher = $name::new().unwrap();
863 let input = b"random output sizes test";
864 assert!(hasher.try_update(input).is_ok());
865
866 let sizes = [15, 64, 100, 255, 1024];
867 for &size in &sizes {
868 let mut output = vec![0u8; size];
869 assert!(hasher.finalize_into(&mut output).is_ok());
870 assert_eq!(output.len(), size);
871 }
872 }
873
874 #[test]
875 fn test_finalize_into_exact_varying_exact_sizes() {
876 let mut hasher = $name::new().unwrap();
877 let input = b"varying exact sizes finalize test";
878 assert!(hasher.try_update(input).is_ok());
879
880 let sizes = [32, 64, 128, 256];
881 for size in sizes {
882 let mut output = vec![0u8; size];
883 assert!(hasher.finalize_into(output.as_mut_slice()).is_ok());
884 assert_eq!(output.len(), size);
885 }
886 }
887
888 #[test]
889 fn test_finalize_after_finalize_with_empty_input() {
890 let mut hasher = $name::new().unwrap();
891
892 let mut output1 = [0u8; 64];
893 assert!(hasher.finalize_into(&mut output1).is_ok());
894
895 let mut output2 = [0u8; 64];
896 assert!(hasher.finalize_into(&mut output2).is_ok());
897
898 assert_eq!(output1, output2);
899 }
900
901 #[test]
902 fn test_finalize_into_exact_with_different_sizes() {
903 let mut hasher = $name::new().unwrap();
904 let inputs = [b"exact size test1", b"exact size test2"];
905
906 for input in inputs {
907 assert!(hasher.try_update(input).is_ok());
908 let mut output = [0u8; $ds];
909 assert!(hasher.finalize_into_sized(&mut output).is_ok());
910 }
911 }
912
913 #[test]
914 fn test_finalize_with_unicode_input() {
915 let mut hasher = $name::new().unwrap();
916 let input = "こんにちは世界".as_bytes(); assert!(hasher.try_update(input).is_ok());
918
919 let mut output = [0u8; 64];
920 assert!(hasher.finalize_into(&mut output).is_ok());
921 assert_eq!(output.len(), 64);
922 }
923
924 #[test]
925 fn test_finalize_with_repeated_updates() {
926 let mut hasher = $name::new().unwrap();
927 let input = b"repeated updates test";
928 for _ in 0..1000 {
929 assert!(hasher.try_update(input).is_ok());
930 }
931
932 let mut output = [0u8; 64];
933 assert!(hasher.finalize_into(&mut output).is_ok());
934 assert_eq!(output.len(), 64);
935 }
936
937 #[test]
938 fn test_finalize_into_sized_after_multiple_updates() {
939 let mut hasher = $name::new().unwrap();
940 let inputs = [b"update1", b"update2", b"update3"];
941 for input in inputs {
942 assert!(hasher.try_update(input).is_ok());
943 }
944
945 let mut output = [0u8; $ds];
946 assert!(hasher.finalize_into_sized(&mut output).is_ok());
947 assert_eq!(output.len(), $ds);
948 }
949
950 #[test]
951 fn test_finalize_with_random_updates_and_finalizes() {
952 use rand::Rng;
953
954 let mut hasher = $name::new().unwrap();
955 let mut rng = rand::thread_rng();
956
957 for _ in 0..100 {
958 let size = rng.gen_range(0..1024);
959 let input: Vec<u8> = (0..size).map(|_| rng.gen()).collect();
960 assert!(hasher.try_update(&input).is_ok());
961
962 let output_size = rng.gen_range(1..2048);
963 let mut output = vec![0u8; output_size];
964 assert!(hasher.finalize_into(&mut output).is_ok());
965 assert_eq!(output.len(), output_size);
966 }
967 }
968
969 #[test]
970 fn test_finalize_after_large_input_multiple_times() {
971 let mut hasher = $name::new().unwrap();
972 let input = vec![3u8; 20_000_000]; assert!(hasher.try_update(&input).is_ok());
974
975 for _ in 0..10 {
976 let mut output = [0u8; 64];
977 assert!(hasher.finalize_into(&mut output).is_ok());
978 }
979 }
980
981 #[test]
982 fn test_finalize_with_special_characters_input() {
983 let mut hasher = $name::new().unwrap();
984 let input = b"sp3c!@l ch@r@ct3rs #test";
985 assert!(hasher.try_update(input).is_ok());
986
987 let mut output = [0u8; 64];
988 assert!(hasher.finalize_into(&mut output).is_ok());
989 assert_eq!(output.len(), 64);
990 }
991
992 #[test]
993 fn test_finalize_after_finalizing_with_large_input() {
994 let mut hasher = $name::new().unwrap();
995 let input = vec![4u8; 50_000_000]; assert!(hasher.try_update(&input).is_ok());
997
998 let mut output = [0u8; 64];
999 assert!(hasher.finalize_into(&mut output).is_ok());
1000
1001 let mut output2 = [0u8; 64];
1003 assert!(hasher.finalize_into(&mut output2).is_ok());
1004
1005 assert_ne!(output, output2);
1007 }
1008
1009 #[test]
1010 fn test_finalize_with_multiple_different_inputs() {
1011 let mut hasher = $name::new().unwrap();
1012 let inputs = [
1013 b"input one".as_slice(),
1014 b"input two".as_slice(),
1015 b"input three".as_slice(),
1016 b"input four".as_slice(),
1017 b"input five".as_slice(),
1018 ];
1019
1020 for input in &inputs {
1021 assert!(hasher.try_update(input).is_ok());
1022 }
1023
1024 let mut output = [0u8; 64];
1025 assert!(hasher.finalize_into(&mut output).is_ok());
1026 assert_eq!(output.len(), 64);
1027 }
1028 }
1029
1030 #[cfg(test)]
1031 mod property_tests {
1032 use super::*;
1033 use digest::{ExtendableOutput, ExtendableOutputReset, XofReader, Update};
1034 use sha3::$name as RcShake;
1035 use proptest::prelude::*;
1036
1037 fn get_rc_hasher() -> RcShake {
1038 RcShake::default()
1039 }
1040
1041 proptest! {
1042 #![proptest_config(ProptestConfig::with_cases(1000))]
1043
1044 #[test]
1045 fn prop_single_update(
1046 input in any::<Vec<u8>>(),
1047 output_size in 1..2048usize
1048 ) {
1049 let mut wolf = $name::new().unwrap();
1050 let mut rc = get_rc_hasher();
1051
1052 assert!(wolf.try_update(&input).is_ok());
1054 rc.update(&input);
1055
1056 let mut wolf_output = vec![0u8; output_size];
1058 assert!(wolf.finalize_into(&mut wolf_output).is_ok());
1059
1060 let mut rc_output = vec![0u8; output_size];
1061 rc.finalize_xof().read(&mut rc_output);
1062
1063 prop_assert_eq!(wolf_output, rc_output);
1065 }
1066
1067 #[test]
1068 fn prop_multiple_updates(
1069 inputs in proptest::collection::vec(any::<Vec<u8>>(), 0..100),
1070 output_size in 1..2048usize
1071 ) {
1072 let mut wolf = $name::new().unwrap();
1073 let mut rc = get_rc_hasher();
1074
1075 for input in &inputs {
1076 assert!(wolf.try_update(input).is_ok());
1077 rc.update(input);
1078 }
1079
1080 let mut wolf_output = vec![0u8; output_size];
1081 assert!(wolf.finalize_into(&mut wolf_output).is_ok());
1082
1083 let mut rc_output = vec![0u8; output_size];
1084 rc.finalize_xof().read(&mut rc_output);
1085
1086 prop_assert_eq!(wolf_output, rc_output);
1088 }
1089
1090 #[test]
1091 fn prop_finalize_idempotent(
1092 input in any::<Vec<u8>>(),
1093 output_size in 1..2048usize
1094 ) {
1095 let mut wolf = $name::new().unwrap();
1096 let mut rc = get_rc_hasher();
1097
1098 assert!(wolf.try_update(&input).is_ok());
1099 rc.update(&input);
1100
1101 let mut wolf_output1 = vec![0u8; output_size];
1102 assert!(wolf.finalize_into(&mut wolf_output1).is_ok());
1103
1104 let mut rc_output1 = vec![0u8; output_size];
1105 rc.finalize_xof_reset().read(&mut rc_output1);
1106
1107 let mut wolf_output2 = vec![0u8; output_size];
1108 assert!(wolf.finalize_into(&mut wolf_output2).is_ok());
1109
1110 let mut rc_output2 = vec![0u8; output_size];
1111 rc.finalize_xof().read(&mut rc_output2);
1112
1113 prop_assert_eq!(wolf_output1, rc_output1);
1115
1116 prop_assert_eq!(wolf_output2, rc_output2);
1118 }
1119
1120 #[test]
1121 fn prop_zero_length_input(
1122 output_size in 1..2048usize
1123 ) {
1124 let mut wolf = $name::new().unwrap();
1125 let mut rc = get_rc_hasher();
1126
1127 let input: Vec<u8> = vec![];
1128 assert!(wolf.try_update(&input).is_ok());
1129 rc.update(&input);
1130
1131 let mut wolf_output = vec![0u8; output_size];
1132 assert!(wolf.finalize_into(&mut wolf_output).is_ok());
1133
1134 let mut rc_output = vec![0u8; output_size];
1135 rc.finalize_xof().read(&mut rc_output);
1136
1137 prop_assert_eq!(wolf_output, rc_output);
1139 }
1140
1141 #[test]
1142 fn prop_variable_output_sizes(
1143 input in any::<Vec<u8>>(),
1144 sizes in proptest::collection::vec(1..2048usize, 1..10)
1145 ) {
1146 let mut wolf = $name::new().unwrap();
1147 let mut rc = get_rc_hasher();
1148
1149 assert!(wolf.try_update(&input).is_ok());
1151 rc.update(&input);
1152
1153 for &size in &sizes {
1154 let mut wolf_output = vec![0u8; size];
1155 assert!(wolf.finalize_into(&mut wolf_output).is_ok());
1156
1157 let mut rc_output = vec![0u8; size];
1158 rc.finalize_xof_reset().read(&mut rc_output);
1159
1160 prop_assert_eq!(wolf_output, rc_output);
1162 }
1163 }
1164 }
1165 }
1166 };
1167}