wolf_crypto/hash/
api_gen.rs

1
2
3macro_rules! copy_impl {
4    (
5        name: $name:ident,
6        wc: $wc:ty,
7        copy: $copy:ident,
8        finalize_func: $ff:ident
9        $(,)?
10    ) => {
11        impl Clone for $name {
12            #[doc = concat!(
13                "Copy the state of the hash (calls the `", stringify!($copy), "` function)"
14            )]
15            #[doc = ""]
16            #[doc = "# Returns"]
17            #[doc = ""]
18            #[doc = concat!(
19                "A distinct new instance of `", stringify!($name), "`, with the same state as the ",
20                "hasher that was cloned."
21            )]
22            #[doc = ""]
23            #[doc = "# Example"]
24            #[doc = ""]
25            #[doc = "```"]
26            #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
27            #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
28            #[doc = ""]
29            #[doc = "assert!(hasher.update_sized(b\"hello world\").is_ok());"]
30            #[doc = ""]
31            #[doc = "let mut cloned = hasher.clone();"]
32            #[doc = "assert_eq!("]
33            #[doc = concat!("    cloned.", stringify!($ff), "().unwrap(),")]
34            #[doc = concat!("    hasher.", stringify!($ff), "().unwrap(),")]
35            #[doc = "    \"The two hashers should have the same output\""]
36            #[doc = ");"]
37            #[doc = "```"]
38            fn clone(&self) -> Self {
39                // Fairly opaque in docs for return type of the copy function. Here's the
40                // source, and the only place in which this returns a non-zero status.
41
42                // static int wc_Sha3Copy(wc_Sha3* src, wc_Sha3* dst)
43                // {
44                //     int ret = 0;
45                //
46                //     if (src == NULL || dst == NULL)
47                //         return BAD_FUNC_ARG;
48                //
49                //     XMEMCPY(dst, src, sizeof(wc_Sha3));
50                //     /* ... */
51                //     return ret;
52                // }
53
54                // This is the same general implementation for all of the Copy implementations, see:
55                // -- https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/sha256.c#L2527
56                // -- https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/sha.c#L1117
57                // -- https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/sha512.c#L1870
58                // -- https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/src/md5.c#L541
59
60                // So, the only way that this fails is if src is null or dst is null. This is
61                // significant as it plays into deciding if this needs to be feature gated by
62                // `panic_api`.
63
64                // So, we know src is non-null, and we know the dst is non-null. This is due to
65                // rust's memory safety guarantees. For as long as our $name instance is scope,
66                // the associated memory is not prematurely freed. So, this should be infallible,
67                // and thus fine to include in the API without the feature gate.
68
69                // ---------------------- Non-const pointer considerations ---------------------
70                // Another dangerous part of this API is that the pointer for src is not declared
71                // as const. This could have been simply been due to a slight oversight or
72                // with the goal consistency, perhaps even future proofing to ensure if they do
73                // eventually mutate it (which would not make much sense in a copy impl) they do
74                // not violate semantic versioning.
75                //
76                // I have reviewed all Copy implementations, including all possible paths (even
77                // those not included with the current wolf-crypto-sys build). There is absolutely
78                // no mutation of the source pointer. This is in our update checklist, whenever
79                // we update wolfcrypt this assumption is audited as a pre-requisite for release.
80                //
81                // The update checklist is at the root of this repository under the name:
82                //   wolfcrypt-update-checklist.org
83
84                let mut inner = ::core::mem::MaybeUninit::<$wc>::uninit();
85
86                // we assert that the result is zero, just to validate our previous claims
87                // in testing (even though most measures applied, ASAN, etc, would catch this).
88
89                unsafe {
90                    // See above commentary as to why this is infallible.
91                    assert_eq!(
92                        $copy(
93                            // See above commentary as to why this is safe.
94                            ::core::ptr::addr_of!(self.inner).cast_mut(),
95                            inner.as_mut_ptr()
96                        ),
97                        0,
98                        concat!(
99                            "Assumption not met, this is a bug, please report this as soon as ",
100                            "possible. The `", stringify!($copy), "` function should have been ",
101                            "infallible under all possible circumstances. But, it has just failed. ",
102                            "This error arises from the `", stringify!($name), "::clone` ",
103                            "implementation."
104                        )
105                    );
106
107                    // See above commentary as to why the $copy operation is infallible, thus
108                    // implying `inner` must be initialized at this point.
109                    Self { inner: inner.assume_init() }
110                }
111            }
112        }
113
114        #[cfg(test)]
115        mod copy_tests {
116            use super::*;
117            use std::thread;
118
119            #[test]
120            fn copied_finalize_equivalent_to_src() {
121                let mut hasher = $name::new().unwrap();
122
123                let input = b"hello world";
124
125                assert!(hasher.try_update(input.as_slice()).is_ok());
126
127                let mut c_hasher = hasher.clone();
128
129                let out = hasher.$ff().unwrap();
130                let c_out = c_hasher.$ff().unwrap();
131
132                assert_eq!(out, c_out);
133            }
134
135            #[test]
136            fn multiple_copies_equivalent_finalize() {
137                let mut hasher = $name::new().unwrap();
138                assert!(hasher.try_update(b"hello world").is_ok());
139
140                let hashers: Vec<$name> = (0..10).map(|_| hasher.clone()).collect();
141                let reference = hasher.$ff().unwrap();
142
143                for mut h in hashers.into_iter() {
144                    assert_eq!(h.$ff().unwrap(), reference);
145                }
146            }
147
148            #[test]
149            fn cross_thread_boundary() {
150                let mut hasher = $name::new().unwrap();
151                assert!(hasher.try_update(b"hello").is_ok());
152
153                let cloned = hasher.clone();
154                let handle = thread::spawn(move || {
155                    let mut threaded_hasher = cloned;
156                    assert!(threaded_hasher.try_update(b" world").is_ok());
157                    threaded_hasher.$ff().unwrap()
158                });
159
160                assert!(hasher.try_update(b" world").is_ok());
161                let original_result = hasher.$ff().unwrap();
162                let threaded_result = handle.join().unwrap();
163
164                assert_eq!(
165                    original_result,
166                    threaded_result,
167                    "Hash results should be the same across threads"
168                );
169            }
170
171            #[test]
172            fn deep_clone_with_multiple_updates() {
173                let mut original = $name::new().unwrap();
174                assert!(original.try_update(b"hello").is_ok());
175
176                let mut cloned = original.clone();
177
178                assert!(original.try_update(b" world").is_ok());
179                assert!(cloned.try_update(b" universe").is_ok());
180
181                let original_result = original.$ff().unwrap();
182                let cloned_result = cloned.$ff().unwrap();
183
184                assert_ne!(
185                    original_result, cloned_result,
186                    "Cloned hasher should have independent state"
187                );
188            }
189
190            #[test]
191            fn partial_update_clone() {
192                let mut original = $name::new().unwrap();
193                assert!(original.try_update(b"hel").is_ok());
194
195                let mut cloned = original.clone();
196
197                assert!(original.try_update(b"lo world").is_ok());
198                assert!(cloned.try_update(b"lo world").is_ok());
199
200                let original_result = original.$ff().unwrap();
201                let cloned_result = cloned.$ff().unwrap();
202
203                assert_eq!(
204                    original_result,
205                    cloned_result,
206                    "Partial updates should result in the same hash"
207                );
208            }
209
210            #[test]
211            fn clone_after_finalize() {
212                let mut original = $name::new().unwrap();
213                assert!(original.try_update(b"hello world").is_ok());
214
215                let original_result = original.$ff().unwrap();
216
217                // Clone after finalize (which resets the state)
218                let mut cloned = original.clone();
219
220                // The cloned hasher should now be in a fresh state
221                assert!(cloned.try_update(b"new input").is_ok());
222                let cloned_result = cloned.$ff().unwrap();
223
224                assert_ne!(
225                    original_result, cloned_result,
226                    "Cloned hasher after finalize should be in a fresh state"
227                );
228            }
229
230            #[test]
231            fn multiple_clones_and_updates() {
232                let mut original = $name::new().unwrap();
233                assert!(original.try_update(b"start").is_ok());
234
235                let mut clone1 = original.clone();
236                let mut clone2 = original.clone();
237
238                assert!(original.try_update(b" original").is_ok());
239                assert!(clone1.try_update(b" clone1").is_ok());
240                assert!(clone2.try_update(b" clone2").is_ok());
241
242                let original_result = original.$ff().unwrap();
243                let clone1_result = clone1.$ff().unwrap();
244                let clone2_result = clone2.$ff().unwrap();
245
246                assert_ne!(original_result, clone1_result);
247                assert_ne!(original_result, clone2_result);
248                assert_ne!(clone1_result, clone2_result);
249            }
250        }
251    };
252}
253
254/// Create an API for a hashing function
255macro_rules! make_api {
256    (
257        $(sec_warning: $($warning:literal),*,)?
258        $(anecdote: $anecdote:literal,)?
259        name: $name:ident,
260        wc: $wc:ty,
261        bs: $bs:literal,
262        init: $(= $i_void:ident)? $init:ident $(, heap: $heap:expr, devid: $devId:expr)?,
263        update: $(= $u_void:ident)? $update:ident,
264        finalize: $(= $f_void:ident)? $finalize:ident
265        $(, free: $free:ident)?
266        $(, needs-reset: $nr:ident)?
267        $(, copy: $copy:ident)? $(,)?
268    ) => {
269        #[doc = concat!("The `", stringify!($name), $($anecdote, )? "` hasher.")]
270        #[doc = ""]
271        $(
272            #[doc = "# Security Warning"]
273            #[doc = ""]
274            $(
275                #[doc = $warning]
276            )*
277            #[doc = ""]
278        )?
279        #[doc = "# Example"]
280        #[doc = ""]
281        #[doc = "```"]
282        #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
283        #[doc = ""]
284        #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
285        #[doc = ""]
286        #[doc = "let input = b\"hello world\";"]
287        #[doc = "assert!(hasher.try_update(input.as_slice()).is_ok());"]
288        #[doc = ""]
289        #[doc = "let finalized = hasher.try_finalize().unwrap();"]
290        #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
291        #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($bs), ");")]
292        #[doc = "```"]
293        #[repr(transparent)]
294        pub struct $name {
295            inner: $wc
296        }
297
298        #[allow(unused_mut)] // only for md4 and other very weak hashing algos.
299        impl $name {
300            $(
301                #[doc = "# Security Warning"]
302                #[doc = ""]
303                $(
304                    #[doc = $warning]
305                )*
306                #[doc = ""]
307            )?
308            #[doc = concat!("Create a new `", stringify!($name), "` instance.")]
309            #[doc = ""]
310            #[doc = "# Errors"]
311            #[doc = ""]
312            #[doc = concat!(
313                "If the underlying initialization function fails (`", stringify!($init), "`)"
314            )]
315            #[doc = ""]
316            #[doc = "# Example"]
317            #[doc = ""]
318            #[doc = "```"]
319            #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
320            #[doc = ""]
321            #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
322            #[doc = ""]
323            #[doc = "let input = b\"hello world\";"]
324            #[doc = "assert!(hasher.try_update(input.as_slice()).is_ok());"]
325            #[doc = ""]
326            #[doc = "let finalized = hasher.try_finalize().unwrap();"]
327            #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
328            #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($bs), ");")]
329            #[doc = "```"]
330            pub fn new() -> Result<Self, $crate::error::Unspecified> {
331                unsafe {
332                    let mut res = $crate::opaque_res::Res::new();
333                    let mut inner = ::core::mem::MaybeUninit::<$wc>::uninit();
334
335                    make_api!(
336                        @check res,
337                        $init(inner.as_mut_ptr() $(, $heap, $devId)?)
338                        $(, $i_void)?
339                    );
340
341                    res.unit_err_with(|| Self { inner: inner.assume_init() })
342                }
343            }
344
345            #[doc = concat!(
346                "Update the underlying `", stringify!($wc), "` instance, without performing any ",
347                "safety checks."
348            )]
349            #[doc = ""]
350            #[doc = "# Safety"]
351            #[doc = ""]
352            #[doc = "The length of data is casted to a 32 bit unsigned integer without checking "]
353            #[doc = "for overflows. While it is incredibly unlikely that this overflow will ever"]
354            #[doc = "take place, it is not impossible. Thus this function is marked unsafe."]
355            #[doc = ""]
356            #[doc = "# Arguments"]
357            #[doc = ""]
358            #[doc = "* `data` - The slice to update the underlying hasher state with."]
359            #[doc = ""]
360            #[doc = "# Returns"]
361            #[doc = ""]
362            #[doc = "This function returns the result of the operation."]
363            #[doc = ""]
364            #[doc = "# Example"]
365            #[doc = ""]
366            #[doc = "```"]
367            #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
368            #[doc = ""]
369            #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
370            #[doc = ""]
371            #[doc = "let input = b\"hello world\";"]
372            #[doc = "// SAFETY: The length of `hello world` is 11, which"]
373            #[doc = "// cannot overflow even an 8 bit integer."]
374            #[doc = "let res = unsafe {"]
375            #[doc = "    hasher.update_unchecked(input.as_slice())"]
376            #[doc = "};"]
377            #[doc = "assert!(res.is_ok());"]
378            #[doc = ""]
379            #[doc = "let finalized = hasher.try_finalize().unwrap();"]
380            #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
381            #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($bs), ");")]
382            #[doc = "```"]
383            #[inline]
384            pub unsafe fn update_unchecked(&mut self, data: &[u8]) -> $crate::opaque_res::Res {
385                let mut res = $crate::opaque_res::Res::new();
386
387                make_api!(
388                    @check res,
389                    $update(
390                        ::core::ptr::addr_of_mut!(self.inner),
391                        data.as_ptr(),
392                        data.len() as u32
393                    )
394                    $(, $u_void)?
395                );
396
397                res
398            }
399
400            #[doc = concat!("Update the underlying `", stringify!($wc), "` instance.")]
401            #[doc = ""]
402            #[doc = "# Arguments"]
403            #[doc = ""]
404            #[doc = "* `data` - The slice to update the underlying hasher state with."]
405            #[doc = ""]
406            #[doc = "# Returns"]
407            #[doc = ""]
408            #[doc = "This function returns the result of the operation."]
409            #[doc = ""]
410            #[doc = "# Errors"]
411            #[doc = ""]
412            #[doc = "- If the length of `data` cannot be safely casted to a `u32`."]
413            #[doc = concat!("- If the underlying `", stringify!($update), "` function fails.")]
414            #[doc = ""]
415            #[doc = "# Example"]
416            #[doc = ""]
417            #[doc = "```"]
418            #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
419            #[doc = ""]
420            #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
421            #[doc = ""]
422            #[doc = "let input = b\"hello world\";"]
423            #[doc = "assert!(hasher.try_update(input.as_slice()).is_ok());"]
424            #[doc = ""]
425            #[doc = "let finalized = hasher.try_finalize().unwrap();"]
426            #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
427            #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($bs), ");")]
428            #[doc = "```"]
429            #[doc = ""]
430            #[doc = "**Note**: if the size of the `data` is known at compile time, see "]
431            #[doc = "[`update_sized`] for a slight optimization as the safety checks are done at "]
432            #[doc = "compilation time."]
433            #[doc = ""]
434            #[doc = "[`update_sized`]: Self::update_sized"]
435            #[inline]
436            pub fn try_update(&mut self, data: &[u8]) -> $crate::opaque_res::Res {
437                if !$crate::can_cast_u32(data.len()) {
438                    return $crate::opaque_res::Res::ERR;
439                }
440
441                unsafe { self.update_unchecked(data) }
442            }
443
444            #[doc = concat!(
445                "Update the underlying `", stringify!($wc), "` instance, with the safety checks ",
446                "performed at compilation time."
447            )]
448            #[doc = ""]
449            #[doc = "# Arguments"]
450            #[doc = ""]
451            #[doc = "* `data` - The slice to update the underlying hasher state with."]
452            #[doc = ""]
453            #[doc = "# Returns"]
454            #[doc = ""]
455            #[doc = "This function returns the result of the operation."]
456            #[doc = ""]
457            #[doc = "# Errors"]
458            #[doc = ""]
459            #[doc = "- If the length of `data` cannot be safely casted to a `u32`."]
460            #[doc = concat!("- If the underlying `", stringify!($update), "` function fails.")]
461            #[doc = ""]
462            #[doc = "# Example"]
463            #[doc = ""]
464            #[doc = "```"]
465            #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
466            #[doc = ""]
467            #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
468            #[doc = ""]
469            #[doc = "let input = b\"hello world\";"]
470            #[doc = "assert!(hasher.update_sized(input).is_ok());"]
471            #[doc = ""]
472            #[doc = "let finalized = hasher.try_finalize().unwrap();"]
473            #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
474            #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($bs), ");")]
475            #[doc = "```"]
476            #[doc = ""]
477            #[doc = "**Note**: if the size of the `data` is not known at compile time, see "]
478            #[doc = "[`try_update`] for more flexibility."]
479            #[doc = ""]
480            #[doc = "[`try_update`]: Self::try_update"]
481            #[inline]
482            pub fn update_sized<const C: usize>(&mut self, data: &[u8; C]) -> $crate::opaque_res::Res {
483                if !$crate::const_can_cast_u32::<{ C }>() {
484                    return $crate::opaque_res::Res::ERR;
485                }
486
487                unsafe { self.update_unchecked(data) }
488            }
489            panic_api! {
490            #[doc = concat!(
491                "Update the underlying `", stringify!($wc), "`, panicking under any failure."
492            )]
493            #[doc = ""]
494            #[doc = "# Arguments"]
495            #[doc = ""]
496            #[doc = "* `data` - The slice to update the underlying hasher state with."]
497            #[doc = ""]
498            #[doc = "# Panics"]
499            #[doc = ""]
500            #[doc = "- If the length of `data` cannot be safely casted to a `u32`."]
501            #[doc = concat!("- If the underlying `", stringify!($update), "` function fails.")]
502            #[doc = ""]
503            #[doc = "If a `panic` under any failure is not acceptable for your use case, which "]
504            #[doc = "generally is true, please consider using [`try_update`]."]
505            #[doc = ""]
506            #[doc = "# Example"]
507            #[doc = ""]
508            #[doc = "```"]
509            #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
510            #[doc = ""]
511            #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
512            #[doc = ""]
513            #[doc = "let input = b\"hello world\";"]
514            #[doc = "hasher.update(input.as_slice());"]
515            #[doc = ""]
516            #[doc = "let finalized = hasher.try_finalize().unwrap();"]
517            #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
518            #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($bs), ");")]
519            #[doc = "```"]
520            #[doc = ""]
521            #[doc = "[`try_update`]: Self::try_update"]
522            #[track_caller]
523            pub fn update(&mut self, data: &[u8]) {
524                self.try_update(data).unit_err(())
525                    .expect(concat!("Failed to update hash in `", stringify!($name), "`"))
526            }
527            }
528
529            #[doc = concat!(
530                "Calls the `", stringify!($finalize), "` function, finalizing the hashing of data ",
531                "and resetting the underlying `", stringify!($wc), "` instance's state, without ",
532                "performing any safety checks."
533            )]
534            #[doc = ""]
535            #[doc = "# Safety"]
536            #[doc = ""]
537            #[doc = concat!(
538                "The size of the `output` argument must have a size of at least `", stringify!($bs),
539                "` (the size of the digest)."
540            )]
541            #[doc = ""]
542            #[doc = "# Arguments"]
543            #[doc = ""]
544            #[doc = "* `output` - The buffer to store the output digest in."]
545            #[doc = ""]
546            #[doc = "# Returns"]
547            #[doc = ""]
548            #[doc = "This function returns the result of the operation."]
549            #[doc = ""]
550            #[doc = "# Example"]
551            #[doc = ""]
552            #[doc = "```"]
553            #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
554            #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
555            #[doc = "# let input = b\"hello world\";"]
556            #[doc = "# assert!(hasher.update_sized(input).is_ok());"]
557            #[doc = ""]
558            #[doc = "// Use the hasher ..."]
559            #[doc = ""]
560            #[doc = concat!("let mut output = [0u8; ", stringify!($bs), "];")]
561            #[doc = "// SAFETY: The size of the output is exactly "]
562            #[doc = "// the size of the digest."]
563            #[doc = "let res = unsafe {"]
564            #[doc = "    hasher.finalize_unchecked(output.as_mut_slice())"]
565            #[doc = "};"]
566            #[doc = "assert!(res.is_ok());"]
567            #[doc = "```"]
568            #[inline]
569            pub unsafe fn finalize_unchecked(&mut self, output: &mut [u8]) -> $crate::opaque_res::Res {
570                let mut res = $crate::opaque_res::Res::new();
571
572                make_api!(
573                    @check res,
574                    $finalize(::core::ptr::addr_of_mut!(self.inner), output.as_mut_ptr())
575                    $(, $f_void)?
576                );
577
578                // it just so happens that whenever we do not have a free api, we do not get reset
579                // on finalize. So to make the api consistent we reset manually in this case.
580                make_api! { @needs-reset self, $init, res $(, $nr)? $(, = $i_void)? }
581
582                res
583            }
584
585            #[inline]
586            #[must_use]
587            const fn finalize_predicate(len: usize) -> bool {
588                len >= $bs
589            }
590
591            #[inline]
592            #[must_use]
593            const fn const_finalize_predicate<const S: usize>() -> bool {
594                S >= $bs
595            }
596
597            #[doc = concat!(
598                "Calls the `", stringify!($finalize), "` function, finalizing the hashing of data ",
599                "and resetting the underlying `", stringify!($wc), "` instance's state."
600            )]
601            #[doc = ""]
602            #[doc = "# Arguments"]
603            #[doc = ""]
604            #[doc = "* `output` - The buffer to store the output digest in."]
605            #[doc = ""]
606            #[doc = "# Errors"]
607            #[doc = ""]
608            #[doc = concat!(
609                "- If the size of `output` is less than the digest size (`",
610                stringify!($bs), "`)."
611            )]
612            #[doc = "- If the underlying finalize function fails."]
613            #[doc = ""]
614            #[doc = "# Example"]
615            #[doc = ""]
616            #[doc = "```"]
617            #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
618            #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
619            #[doc = "# let input = b\"hello world\";"]
620            #[doc = "# assert!(hasher.update_sized(input).is_ok());"]
621            #[doc = ""]
622            #[doc = "// Use the hasher ..."]
623            #[doc = ""]
624            #[doc = concat!("let mut output = [0u8; ", stringify!($bs), "];")]
625            #[doc = "let res = hasher.finalize_into(output.as_mut_slice());"]
626            #[doc = "assert!(res.is_ok());"]
627            #[doc = "```"]
628            #[doc = ""]
629            #[doc = "**Note**: if the size of the `output` slice is known at compile time, see"]
630            #[doc = "[`finalize_into_sized`] for a slight optimization as the safety checks are "]
631            #[doc = "done at compilation time. There is also [`finalize_into_exact`] if this size "]
632            #[doc = concat!("is exactly `", stringify!($bs), "` bytes, moving all checks to the ")]
633            #[doc = "type system."]
634            #[doc = ""]
635            #[doc = "[`finalize_into_sized`]: Self::finalize_into_sized"]
636            #[doc = "[`finalize_into_exact`]: Self::finalize_into_exact"]
637            #[inline]
638            pub fn finalize_into(&mut self, output: &mut [u8]) -> $crate::opaque_res::Res {
639                if !Self::finalize_predicate(output.len()) { return $crate::opaque_res::Res::ERR }
640                unsafe { self.finalize_unchecked(output) }
641            }
642
643            #[doc = concat!(
644                "Calls the `", stringify!($finalize), "` function, finalizing the hashing of data ",
645                "and resetting the underlying `", stringify!($wc), "` instance's state, with the ",
646                "safety checks performed at compilation time."
647            )]
648            #[doc = ""]
649            #[doc = "# Arguments"]
650            #[doc = ""]
651            #[doc = "* `output` - The buffer to store the output digest in."]
652            #[doc = ""]
653            #[doc = "# Errors"]
654            #[doc = ""]
655            #[doc = concat!(
656                "- If the size of `output` is less than the digest size (`",
657                stringify!($bs), "`)."
658            )]
659            #[doc = "- If the underlying finalize function fails."]
660            #[doc = ""]
661            #[doc = "# Example"]
662            #[doc = ""]
663            #[doc = "```"]
664            #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
665            #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
666            #[doc = "# let input = b\"hello world\";"]
667            #[doc = "# assert!(hasher.update_sized(input).is_ok());"]
668            #[doc = ""]
669            #[doc = "// Use the hasher ..."]
670            #[doc = ""]
671            #[doc = concat!("let mut output = [0u8; ", stringify!($bs), "];")]
672            #[doc = "let res = hasher.finalize_into_sized(&mut output);"]
673            #[doc = "assert!(res.is_ok());"]
674            #[doc = "```"]
675            #[doc = ""]
676            #[doc = "**Note**: If the size of the output buffer is not known at compilation time "]
677            #[doc = "see [`finalize_into`] for greater flexibility. There is also "]
678            #[doc = "[`finalize_into_exact`] if this size "]
679            #[doc = concat!("is exactly `", stringify!($bs), "` bytes, moving all checks to the ")]
680            #[doc = "type system."]
681            #[doc = ""]
682            #[doc = "[`finalize_into`]: Self::finalize_into"]
683            #[doc = "[`finalize_into_exact`]: Self::finalize_into_exact"]
684            #[inline]
685            pub fn finalize_into_sized<const C: usize>(&mut self, output: &mut [u8; C]) -> $crate::opaque_res::Res {
686                if !Self::const_finalize_predicate::<{ C }>() { return $crate::opaque_res::Res::ERR }
687                unsafe { self.finalize_unchecked(output) }
688            }
689
690            #[doc = concat!(
691                "Calls the `", stringify!($finalize), "` function, finalizing the hashing of data ",
692                "and resetting the underlying `", stringify!($wc), "` instance's state, with the ",
693                "safety checks moved to the type system."
694            )]
695            #[doc = ""]
696            #[doc = "# Arguments"]
697            #[doc = ""]
698            #[doc = "* `output` - The buffer to store the output digest in."]
699            #[doc = ""]
700            #[doc = "# Errors"]
701            #[doc = ""]
702            #[doc = "If the underlying finalize function fails."]
703            #[doc = ""]
704            #[doc = "# Example"]
705            #[doc = ""]
706            #[doc = "```"]
707            #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
708            #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
709            #[doc = "# let input = b\"hello world\";"]
710            #[doc = "# assert!(hasher.update_sized(input).is_ok());"]
711            #[doc = ""]
712            #[doc = "// Use the hasher ..."]
713            #[doc = ""]
714            #[doc = concat!("let mut output = [0u8; ", stringify!($bs), "];")]
715            #[doc = "let res = hasher.finalize_into_exact(&mut output);"]
716            #[doc = "assert!(res.is_ok());"]
717            #[doc = "```"]
718            #[doc = ""]
719            #[doc = "**Note**: If the size of the output buffer is not known at compilation time "]
720            #[doc = "see [`finalize_into`] for greater flexibility. If the size is known at "]
721            #[doc = concat!("compilation time, but not exactly `", stringify!($bs), "` bytes, ")]
722            #[doc = "see [`finalize_into_sized`]."]
723            #[doc = ""]
724            #[doc = "[`finalize_into`]: Self::finalize_into"]
725            #[doc = "[`finalize_into_sized`]: Self::finalize_into_sized"]
726            #[inline]
727            pub fn finalize_into_exact(&mut self, output: &mut [u8; $bs]) -> $crate::opaque_res::Res {
728                unsafe { self.finalize_unchecked(output) }
729            }
730
731            #[doc = concat!(
732                "Calls the `", stringify!($finalize), "` function, finalizing the hashing of ",
733                "data and resetting the underlying `", stringify!($wc), "` instance's state."
734            )]
735            #[doc = ""]
736            #[doc = "# Returns"]
737            #[doc = ""]
738            #[doc = "On success, this returns the output digest."]
739            #[doc = ""]
740            #[doc = "# Errors"]
741            #[doc = ""]
742            #[doc = "If the underlying finalize function fails."]
743            #[doc = ""]
744            #[doc = "# Example"]
745            #[doc = ""]
746            #[doc = "```"]
747            #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
748            #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
749            #[doc = "# let input = b\"hello world\";"]
750            #[doc = "# assert!(hasher.update_sized(input).is_ok());"]
751            #[doc = ""]
752            #[doc = "// Use the hasher ..."]
753            #[doc = ""]
754            #[doc = "let res = hasher.try_finalize().unwrap();"]
755            #[doc = "assert_ne!(res.as_slice(), input.as_slice());"]
756            #[doc = "```"]
757            #[inline]
758            pub fn try_finalize(&mut self) -> Result<[u8; $bs], $crate::error::Unspecified> {
759                let mut buf = [0u8; $bs];
760                self.finalize_into_exact(&mut buf).unit_err(buf)
761            }
762
763            panic_api! {
764            #[doc = concat!(
765                "Calls the `", stringify!($finalize), "` function, finalizing the hashing of ",
766                "data and resetting the underlying `", stringify!($wc), "` instance's state."
767            )]
768            #[doc = ""]
769            #[doc = "# Returns"]
770            #[doc = ""]
771            #[doc = "On success, this returns the output digest."]
772            #[doc = ""]
773            #[doc = "# Panics"]
774            #[doc = ""]
775            #[doc = "If the underlying finalize function fails. If panicking is not acceptable "]
776            #[doc = "for your use case, which generally is true, see [`try_finalize`]."]
777            #[doc = ""]
778            #[doc = "# Example"]
779            #[doc = ""]
780            #[doc = "```"]
781            #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
782            #[doc = concat!("let mut hasher = ", stringify!($name), "::new().unwrap();")]
783            #[doc = "# let input = b\"hello world\";"]
784            #[doc = "# assert!(hasher.update_sized(input).is_ok());"]
785            #[doc = ""]
786            #[doc = "// Use the hasher ..."]
787            #[doc = ""]
788            #[doc = "let res = hasher.try_finalize().unwrap();"]
789            #[doc = "assert_ne!(res.as_slice(), input.as_slice());"]
790            #[doc = "```"]
791            #[doc = ""]
792            #[doc = "[`try_finalize`]: Self::try_finalize"]
793            #[track_caller]
794            pub fn finalize(&mut self) -> [u8; $bs] {
795                self.try_finalize().expect(concat!(
796                    "Failed to finalize in `", stringify!($name), "`"
797                ))
798            }
799            }
800        }
801
802        // SAFETY:
803        // All methods which mutate the underlying state require a mutable reference,
804        // the only way to obtain a mutable reference across thread boundaries is via
805        // synchronization or unsafe in Rust (which then would be the user's responsibility).
806        unsafe impl Send for $name {}
807
808        // SAFETY:
809        // There is no providing of interior mutability, all methods which mutate the underlying
810        // state require a mutable reference, thus making this safe to mark `Sync`.
811        unsafe impl Sync for $name {}
812
813        // only implement if free was provided, as some hashing functions do not have this API.
814        $(
815        impl Drop for $name {
816            #[doc = concat!(
817                "Calls the `", stringify!($free), "` function, cleaning up after itself."
818            )]
819            #[inline]
820            fn drop(&mut self) {
821                unsafe { $free(::core::ptr::addr_of_mut!(self.inner)) }
822            }
823        }
824        )?
825
826        $(copy_impl! {
827            name: $name,
828            wc: $wc,
829            copy: $copy,
830            finalize_func: try_finalize
831        })?
832
833        #[cfg(test)]
834        mod unit_tests {
835            use super::*;
836            use digest::Digest;
837
838            #[test]
839            fn reset_behavior() {
840                let mut hasher = $name::new().unwrap();
841
842                let input = b"hello world";
843                assert!(hasher.try_update(input.as_slice()).is_ok());
844
845                let _ = hasher.try_finalize().unwrap();
846
847                // hasher2 and hasher when hashing more data should have the same digest due to the
848                // implicit reset behavior of all finalize functions in wolfcrypt.
849                let mut hasher2 = $name::new().unwrap();
850
851                let sec_inp = b"goodbye world";
852                assert!(hasher.try_update(sec_inp.as_slice()).is_ok());
853                assert!(hasher2.try_update(sec_inp.as_slice()).is_ok());
854
855                let r_out = hasher.try_finalize().unwrap();
856                let out = hasher2.try_finalize().unwrap();
857
858                assert_eq!(r_out.as_slice(), out.as_slice());
859            }
860
861            #[test]
862            fn rust_crypto_equivalence() {
863                let mut wolf = $name::new().unwrap();
864                let mut rc = <make_api!(@rc $name $(, $heap, $devId)?)>::new();
865
866                let inp = b"hello world";
867
868                assert!(wolf.try_update(inp.as_slice()).is_ok());
869                rc.update(inp.as_slice());
870
871                let rc_out = rc.finalize();
872                let wolf_out = wolf.try_finalize().unwrap();
873
874                assert_eq!(rc_out.as_slice(), wolf_out.as_slice());
875            }
876
877            #[test]
878            fn rust_crypto_reset_equivalence() {
879                let mut wolf = $name::new().unwrap();
880                let mut rc = <make_api!(@rc $name $(, $heap, $devId)?)>::new();
881
882                let inp = b"hello world";
883
884                assert!(wolf.try_update(inp.as_slice()).is_ok());
885                rc.update(inp.as_slice());
886
887                let f_rc_out = rc.finalize_reset();
888                let f_wolf_out = wolf.try_finalize().unwrap();
889
890                assert_eq!(f_rc_out.as_slice(), f_wolf_out.as_slice());
891
892                let s_inp = b"goodbye world";
893
894                assert!(wolf.try_update(s_inp.as_slice()).is_ok());
895                rc.update(s_inp.as_slice());
896
897                let s_rc_out = rc.finalize();
898                let s_wolf_out = wolf.try_finalize().unwrap();
899
900                assert_eq!(s_rc_out.as_slice(), s_wolf_out.as_slice());
901            }
902
903            #[test]
904            fn hash_finalize_hash_finalize() {
905                let mut hasher = $name::new().unwrap();
906                let inp = b"hello world";
907
908                assert!(hasher.try_update(inp.as_slice()).is_ok());
909
910                let f_out = hasher.try_finalize().unwrap();
911
912                assert!(hasher.try_update(inp.as_slice()).is_ok());
913
914                let s_out = hasher.try_finalize().unwrap();
915                assert_eq!(s_out, f_out);
916            }
917
918            #[test]
919            fn just_finalize() {
920                let mut hasher = $name::new().unwrap();
921                assert!(hasher.try_finalize().is_ok());
922            }
923
924            #[test]
925            fn rust_crypto_just_finalize_equivalence() {
926                let mut wolf = $name::new().unwrap();
927                let rc = <make_api!(@rc $name $(, $heap, $devId)?)>::new();
928
929                let w_out = wolf.try_finalize().unwrap();
930                let rc_out = rc.finalize();
931
932                assert_eq!(w_out.as_slice(), rc_out.as_slice());
933            }
934
935            #[test]
936            fn hash_empty() {
937                let input = [0u8; 0];
938                let mut hasher = $name::new().unwrap();
939
940                assert!(hasher.try_update(input.as_slice()).is_ok());
941                assert!(hasher.try_finalize().is_ok());
942            }
943
944            #[test]
945            fn rust_crypto_hash_empty_equivalence() {
946                let mut wolf = $name::new().unwrap();
947                let mut rc = <make_api!(@rc $name $(, $heap, $devId)?)>::new();
948
949                let input = [0u8; 0];
950
951                assert!(wolf.try_update(input.as_slice()).is_ok());
952                rc.update(input.as_slice());
953
954                let w_out = wolf.try_finalize().unwrap();
955                let rc_out = rc.finalize();
956
957                assert_eq!(w_out.as_slice(), rc_out.as_slice());
958            }
959
960            #[test]
961            fn finalize_into_predicate() {
962                let mut hasher = $name::new().unwrap();
963                let mut small_out = [0u8; $bs - 4];
964
965                assert!(hasher.finalize_into(small_out.as_mut_slice()).is_err());
966            }
967
968            #[test]
969            fn finalize_into_sized_predicate() {
970                let mut hasher = $name::new().unwrap();
971                let mut small_out = [0u8; $bs - 4];
972
973                assert!(hasher.finalize_into_sized(&mut small_out).is_err());
974            }
975
976            #[test]
977            fn hash_large() {
978                let input = [7u8; 32_768];
979                let mut hasher = $name::new().unwrap();
980
981                assert!(hasher.try_update(input.as_slice()).is_ok());
982                assert!(hasher.try_finalize().is_ok());
983            }
984
985            #[test]
986            fn rust_crypto_hash_large_equivalence() {
987                let input = [7u8; 32_768];
988                let mut wolf = $name::new().unwrap();
989                let mut rc = <make_api!(@rc $name $(, $heap, $devId)?)>::new();
990
991                assert!(wolf.try_update(input.as_slice()).is_ok());
992                rc.update(input.as_slice());
993
994                let w_out = wolf.try_finalize().unwrap();
995                let rc_out = rc.finalize();
996
997                assert_eq!(w_out.as_slice(), rc_out.as_slice());
998            }
999
1000            #[test]
1001            fn hash_massive() {
1002                let input = [7u8; 131_072];
1003                let mut hasher = $name::new().unwrap();
1004
1005                assert!(hasher.try_update(input.as_slice()).is_ok());
1006                assert!(hasher.try_finalize().is_ok());
1007            }
1008
1009            #[test]
1010            fn rust_crypto_hash_massive_equivalence() {
1011                let input = [7u8; 131_072];
1012                let mut wolf = $name::new().unwrap();
1013                let mut rc = <make_api!(@rc $name $(, $heap, $devId)?)>::new();
1014
1015                assert!(wolf.try_update(input.as_slice()).is_ok());
1016                rc.update(input.as_slice());
1017
1018                let w_out = wolf.try_finalize().unwrap();
1019                let rc_out = rc.finalize();
1020
1021                assert_eq!(w_out.as_slice(), rc_out.as_slice());
1022            }
1023
1024            #[test]
1025            fn hash_one_mb() {
1026                // probably do not want to put this on the stack
1027                let input = vec![7u8; 1_048_576];
1028
1029                let mut hasher = $name::new().unwrap();
1030
1031                assert!(hasher.try_update(input.as_slice()).is_ok());
1032                assert!(hasher.try_finalize().is_ok());
1033            }
1034
1035            #[test]
1036            fn rust_crypto_hash_mb_equivalence() {
1037                let input = vec![7u8; 1_048_576];
1038                let mut wolf = $name::new().unwrap();
1039                let mut rc = <make_api!(@rc $name $(, $heap, $devId)?)>::new();
1040
1041                assert!(wolf.try_update(input.as_slice()).is_ok());
1042                rc.update(input.as_slice());
1043
1044                let w_out = wolf.try_finalize().unwrap();
1045                let rc_out = rc.finalize();
1046
1047                assert_eq!(w_out.as_slice(), rc_out.as_slice());
1048            }
1049        }
1050
1051        #[cfg(test)]
1052        mod property_tests {
1053            use super::*;
1054            use digest::Digest;
1055            use crate::aes::test_utils::{BoundList, AnyList};
1056            use proptest::prelude::*;
1057
1058            proptest! {
1059                #![proptest_config(ProptestConfig::with_cases(100_000 / $bs))]
1060
1061                #[test]
1062                fn rust_crypto_eq_wolf_single_update(
1063                    input in any::<BoundList<1024>>()
1064                ) {
1065                    let mut wolf = $name::new().unwrap();
1066                    let mut rc = <make_api!(@rc $name $(, $heap, $devId)?)>::new();
1067
1068                    prop_assert!(wolf.try_update(input.as_slice()).is_ok());
1069                    rc.update(input.as_slice());
1070
1071                    let finalized = wolf.try_finalize().unwrap();
1072                    let rc_finalized = rc.finalize();
1073
1074                    prop_assert_eq!(finalized.as_slice(), rc_finalized.as_slice());
1075                }
1076            }
1077
1078            proptest! {
1079                #![proptest_config(ProptestConfig::with_cases(50_000 / $bs))]
1080
1081                #[test]
1082                fn rust_crypto_eq_wolf_arb_updates(
1083                    inputs in any::<AnyList<32, BoundList<512>>>()
1084                ) {
1085                    let mut wolf = $name::new().unwrap();
1086                    let mut rc = <make_api!(@rc $name $(, $heap, $devId)?)>::new();
1087
1088                    for input in inputs.as_slice().iter() {
1089                        prop_assert!(wolf.try_update(input.as_slice()).is_ok());
1090                        rc.update(input.as_slice());
1091                    }
1092
1093                    let finalized = wolf.try_finalize().unwrap();
1094                    let rc_finalized = rc.finalize();
1095
1096                    prop_assert_eq!(finalized.as_slice(), rc_finalized.as_slice());
1097                }
1098
1099                #[test]
1100                fn rust_crypto_arb_reset_equivalence(
1101                    inputs in any::<AnyList<32, BoundList<512>>>()
1102                ) {
1103                    let mut wolf = $name::new().unwrap();
1104                    let mut rc = <make_api!(@rc $name $(, $heap, $devId)?)>::new();
1105
1106                    for input in inputs.as_slice().iter() {
1107                        prop_assert!(wolf.try_update(input.as_slice()).is_ok());
1108                        rc.update(input.as_slice());
1109
1110                        let w_out = wolf.try_finalize().unwrap();
1111                        let rc_out = rc.finalize_reset();
1112
1113                        prop_assert_eq!(w_out.as_slice(), rc_out.as_slice());
1114                    }
1115
1116                    let finalized = wolf.try_finalize().unwrap();
1117                    let rc_finalized = rc.finalize();
1118
1119                    prop_assert_eq!(finalized.as_slice(), rc_finalized.as_slice());
1120                }
1121            }
1122
1123            proptest! {
1124                #[test]
1125                fn arb_massive(
1126                    input in proptest::collection::vec(any::<u8>(), 65536..=524_288)
1127                ) {
1128                    let mut wolf = $name::new().unwrap();
1129
1130                    prop_assert!(wolf.try_update(input.as_slice()).is_ok());
1131                    prop_assert!(wolf.try_finalize().is_ok());
1132                }
1133
1134                #[test]
1135                fn rust_crypto_arb_massive_equivalence(
1136                    input in proptest::collection::vec(any::<u8>(), 65536..=524_288)
1137                ) {
1138                    let mut wolf = $name::new().unwrap();
1139                    let mut rc = <make_api!(@rc $name $(, $heap, $devId)?)>::new();
1140
1141                    prop_assert!(wolf.try_update(input.as_slice()).is_ok());
1142                    rc.update(input.as_slice());
1143
1144                    let finalized = wolf.try_finalize().unwrap();
1145                    let rc_finalized = rc.finalize();
1146
1147                    prop_assert_eq!(finalized.as_slice(), rc_finalized.as_slice());
1148                }
1149            }
1150        }
1151    };
1152
1153    (@check $res:ident, $expr:expr, void) => {
1154        $expr
1155    };
1156    (@check $res:ident, $expr:expr) => {
1157        $res.ensure_0($expr)
1158    };
1159
1160    (@needs-reset $this:ident, $init:ident, $res:ident $(, = $void:ident)?) => {};
1161    (@needs-reset $this:ident, $init:ident, $res:ident, true $(, = $void:ident)?) => {
1162        make_api! (@check $res, $init(::core::ptr::addr_of_mut!($this.inner)) $(, $void)? )
1163    };
1164
1165    // rust-crypto to test against, convenient that I used the same naming convention by accident.
1166    (@rc $name:ident, $heap:expr, $devId:expr) => {
1167        sha3::$name
1168    };
1169    (@rc Md5) => {
1170        md5::Md5
1171    };
1172    (@rc Md4) => {
1173        md4::Md4
1174    };
1175    (@rc RipeMd) => {
1176        ripemd::Ripemd160
1177    };
1178    (@rc Sha) => {
1179        sha1::Sha1
1180    };
1181    (@rc $name:ident) => {
1182        sha2::$name
1183    };
1184}
1185