wolf_crypto/hash/
shake_api.rs

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        // SAFETY:
486        // All methods which mutate the underlying state require a mutable reference,
487        // the only way to obtain a mutable reference across thread boundaries is via
488        // synchronization or unsafe in Rust (which then would be the user's responsibility).
489        unsafe impl Send for $name {}
490
491        // SAFETY:
492        // There is no providing of interior mutability, all methods which mutate the underlying
493        // state require a mutable reference, thus making this safe to mark `Sync`.
494        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]; // 10 MB
562                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]; // 10 MB
642                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]; // 10 KB
667                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(); // "Hello, World" in Japanese
917                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]; // 20 MB
973                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]; // 50 MB
996                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                // Finalize again without updates
1002                let mut output2 = [0u8; 64];
1003                assert!(hasher.finalize_into(&mut output2).is_ok());
1004
1005                // Outputs should be different
1006                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                    // Update both hashers
1053                    assert!(wolf.try_update(&input).is_ok());
1054                    rc.update(&input);
1055
1056                    // Finalize both hashers
1057                    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                    // Compare outputs
1064                    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                    // Compare outputs
1087                    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                    // Compare first outputs
1114                    prop_assert_eq!(wolf_output1, rc_output1);
1115
1116                    // Compare second outputs (hash of empty input)
1117                    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                    // Compare outputs
1138                    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                    // Update both hashers
1150                    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                        // Compare outputs
1161                        prop_assert_eq!(wolf_output, rc_output);
1162                    }
1163                }
1164            }
1165        }
1166    };
1167}