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 let mut inner = ::core::mem::MaybeUninit::<$wc>::uninit();
85
86 unsafe {
90 assert_eq!(
92 $copy(
93 ::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 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 let mut cloned = original.clone();
219
220 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
254macro_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)] 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 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 unsafe impl Send for $name {}
807
808 unsafe impl Sync for $name {}
812
813 $(
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 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 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 (@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