1macro_rules! blake_api {
2 (
3 name: $name:ident,
4 wc: $wc:ty,
5 max: $max:literal,
7 init: $init:ident,
8 init_with_key: $init_key:ident,
9 update: $update:ident,
10 final: $final:ident,
11 ll_final: $ll_final:ident,
12 w_loc: $warning:literal $(,)?
13 ) => {
14 #[doc = concat!("The `", stringify!($name), "` hasher.")]
15 #[doc = ""]
16 #[doc = "# Soundness Note"]
17 #[doc = ""]
18 #[doc = concat!(
19 "In the underlying `wolfcrypt` source, the `", stringify!($ll_final),
20 "` function includes a comment "
21 )]
22 #[doc = "[`/* Is this correct? */`][1], which may raise concern about its implementation."]
23 #[doc = "However, we have subjected this Rust API to extensive testing, including property tests"]
24 #[doc = concat!(
25 "against other trusted ", stringify!($name),
26 " implementations, and no failures have been observed."
27 )]
28 #[doc = ""]
29 #[doc = "Furthermore, this comment is not present in the public WolfSSL API, suggesting "]
30 #[doc = "that they may have confidence in their own implementation despite the internal comment."]
31 #[doc = ""]
32 #[doc = "# Const Generic"]
33 #[doc = ""]
34 #[doc = concat!(
35 "* `C` - The length of the ", stringify!($name),
36 " digest to implement, with a maximum length of `", stringify!($max), "`."
37 )]
38 #[doc = ""]
39 #[doc = "# Example"]
40 #[doc = ""]
41 #[doc = "```"]
42 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
43 #[doc = ""]
44 #[doc = concat!(
45 "let mut hasher = ", stringify!($name), "::<", stringify!($max), ">::new().unwrap();"
46 )]
47 #[doc = ""]
48 #[doc = "let input = b\"hello world\";"]
49 #[doc = "assert!(hasher.try_update(input.as_slice()).is_ok());"]
50 #[doc = ""]
51 #[doc = "let finalized = hasher.try_finalize().unwrap();"]
52 #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($max), ");")]
53 #[doc = "```"]
54 #[doc = ""]
55 #[doc = concat!("[1]: ", $warning)]
56 pub struct $name<const C: usize> {
57 inner: $wc
58 }
59
60 impl<const C: usize> $name<C> {
61 #[doc = concat!("Create a new `", stringify!($name), "` instance.")]
62 #[doc = ""]
63 #[doc = "# Errors"]
64 #[doc = ""]
65 #[doc = concat!(
66 "- If the digest length is greater than `", stringify!($max), "` (const generic `C`)"
67 )]
68 #[doc = concat!(
69 "- If the underling initialization function fails (`", stringify!($init), "`)"
70 )]
71 #[doc = ""]
72 #[doc = "# Example"]
73 #[doc = ""]
74 #[doc = "```"]
75 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
76 #[doc = ""]
77 #[doc = concat!(
78 "let mut hasher = ", stringify!($name), "::<", stringify!($max), ">::new().unwrap();"
79 )]
80 #[doc = ""]
81 #[doc = "let input = b\"hello world\";"]
82 #[doc = "assert!(hasher.try_update(input.as_slice()).is_ok());"]
83 #[doc = ""]
84 #[doc = "let finalized = hasher.try_finalize().unwrap();"]
85 #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
86 #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($max), ");")]
87 #[doc = ""]
88 #[doc = concat!("// Maximum `C` is ", stringify!($max))]
89 #[doc = concat!(
90 "assert!(", stringify!($name), "::<{", stringify!($max * 2), "}>::new().is_err());"
91 )]
92 #[doc = "```"]
93 pub fn new() -> Result<Self, $crate::error::Unspecified> {
94 if !$crate::const_lte::<C, { $max }>() { return Err($crate::error::Unspecified); }
95 let mut res = $crate::opaque_res::Res::new();
96
97 unsafe {
98 let mut inner = ::core::mem::MaybeUninit::<$wc>::uninit();
99 res.ensure_0($init(inner.as_mut_ptr(), C as u32));
100 res.unit_err_with(|| Self { inner: inner.assume_init() })
101 }
102 }
103
104 #[inline]
105 unsafe fn new_with_key_unchecked(
106 key: &[u8]
107 ) -> (::core::mem::MaybeUninit<$wc>, $crate::opaque_res::Res) {
108 let mut res = $crate::opaque_res::Res::new();
109 let mut inner = ::core::mem::MaybeUninit::<$wc>::uninit();
110
111 res.ensure_0($init_key(
112 inner.as_mut_ptr(),
113 C as u32,
114 key.as_ptr(),
115 key.len() as u32
116 ));
117
118 (inner, res)
119 }
120
121 #[doc = concat!("Create a new `", stringify!($name), "` instance using a key.")]
122 #[doc = ""]
123 #[doc = concat!(
124 "The key is used to create a keyed ", stringify!($name), " instance, ",
125 "which is suitable for"
126 )]
127 #[doc = "message authentication (MAC) purposes. The output digest length is determined"]
128 #[doc = "by the constant generic parameter `C`."]
129 #[doc = ""]
130 #[doc = "# Errors"]
131 #[doc = ""]
132 #[doc = concat!("- If the digest length `C` is greater than `", stringify!($max), "`.")]
133 #[doc = concat!("- If the key length exceeds `", stringify!($max), "` bytes.")]
134 #[doc = "- If the key is of zero length."]
135 #[doc = concat!(
136 "- If the underlying initialization function (`", stringify!($init_key), "`) fails.\
137 ")]
138 #[doc = ""]
139 #[doc = "# Arguments"]
140 #[doc = ""]
141 #[doc = concat!(
142 "* `key` - A secret key used to initialize the ", stringify!($name),
143 " instance. The length of the key must be less than or equal to ", stringify!($max),
144 " bytes."
145 )]
146 #[doc = ""]
147 #[doc = "# Example"]
148 #[doc = ""]
149 #[doc = "```"]
150 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
151 #[doc = ""]
152 #[doc = "let key = b\"my-secret-key\";"]
153 #[doc = concat!(
154 "let mut hasher = ", stringify!($name), "::<", stringify!($max),
155 ">::new_with_key(key).unwrap();"
156 )]
157 #[doc = ""]
158 #[doc = "let input = b\"hello world\";"]
159 #[doc = "assert!(hasher.try_update(input.as_slice()).is_ok());"]
160 #[doc = ""]
161 #[doc = "let finalized = hasher.try_finalize().unwrap();"]
162 #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
163 #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($max), ");")]
164 #[doc = ""]
165 #[doc = concat!(
166 "// Key length must be less than or equal to ", stringify!($max), " bytes."
167 )]
168 #[doc = concat!("let long_key = [0u8; ", stringify!($max * 2), "];")]
169 #[doc = concat!(
170 "assert!(", stringify!($name), "::<", stringify!($max),
171 ">::new_with_key(&long_key).is_err());"
172 )]
173 #[doc = "```"]
174 pub fn new_with_key(key: &[u8]) -> Result<Self, $crate::error::Unspecified> {
175 if !($crate::const_lte::<C, { $max }>() && $crate::lte::<{ $max }>(key.len())) {
176 return Err($crate::error::Unspecified);
177 }
178
179 unsafe {
180 let (inner, res) = Self::new_with_key_unchecked(key);
181 res.unit_err_with(|| Self { inner: inner.assume_init() })
182 }
183 }
184
185 #[doc = concat!("Create a new `", stringify!($name), "` instance using a fixed-size key.")]
186 #[doc = ""]
187 #[doc = "This function allows you to specify the key as a fixed-size array. It is"]
188 #[doc = "similar to [`new_with_key`] but function preconditions are checked at compile time."]
189 #[doc = ""]
190 #[doc = "# Errors"]
191 #[doc = ""]
192 #[doc = concat!("- If the digest length `C` is greater than `", stringify!($max), "`.")]
193 #[doc = concat!(
194 "- If the key length exceeds `", stringify!($max), "` bytes (compile-time check)."
195 )]
196 #[doc = "- If the key is of zero length."]
197 #[doc = concat!(
198 "- If the underlying initialization function (`", stringify!($init_key), "`) fails."
199 )]
200 #[doc = ""]
201 #[doc = "# Arguments"]
202 #[doc = ""]
203 #[doc = concat!(
204 "- `key`: A fixed-size secret key (length `K`) used to initialize the `",
205 stringify!($name), "` instance. The length of the key must be less than or equal to ",
206 stringify!($max), " bytes."
207 )]
208 #[doc = ""]
209 #[doc = "# Example"]
210 #[doc = ""]
211 #[doc = "```"]
212 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
213 #[doc = ""]
214 #[doc = "let key: [u8; 32] = [0x00; 32];"]
215 #[doc = concat!(
216 "let mut hasher = ", stringify!($name), "::<", stringify!($max),
217 ">::new_with_sized_key(&key).unwrap();"
218 )]
219 #[doc = ""]
220 #[doc = "let input = b\"some data\";"]
221 #[doc = "assert!(hasher.try_update(input.as_slice()).is_ok());"]
222 #[doc = ""]
223 #[doc = "let finalized = hasher.try_finalize().unwrap();"]
224 #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($max), ");")]
225 #[doc = ""]
226 #[doc = concat!(
227 "// Key length must be less than or equal to ", stringify!($max), " bytes."
228 )]
229 #[doc = concat!("let oversized_key = [0u8; ", stringify!($max * 2), "];")]
230 #[doc = concat!(
231 "assert!(", stringify!($name), "::<", stringify!($max),
232 ">::new_with_sized_key(&oversized_key).is_err());"
233 )]
234 #[doc = "```"]
235 #[doc = "[`new_with_key`]: Self::new_with_key"]
236 pub fn new_with_sized_key<const K: usize>(key: &[u8; K]) -> Result<Self, $crate::error::Unspecified> {
237 if !($crate::const_lte::<C, { $max }>() && $crate::const_lte::<K, { $max }>()) {
238 return Err($crate::error::Unspecified);
239 }
240
241 unsafe {
242 let (inner, res) = Self::new_with_key_unchecked(key);
243 res.unit_err_with(|| Self { inner: inner.assume_init() })
244 }
245 }
246
247 #[doc = concat!(
248 "Update the `", stringify!($name),
249 "` instance with the provided data, without performing any safety checks."
250 )]
251 #[doc = ""]
252 #[doc = "# Safety"]
253 #[doc = ""]
254 #[doc = "The length of the data is cast to a 32-bit unsigned integer without checking for"]
255 #[doc = "overflow. While this is unlikely to occur in most practical scenarios, it is not impossible,"]
256 #[doc = "especially with very large slices. Therefore, this function is marked `unsafe`."]
257 #[doc = ""]
258 #[doc = "# Arguments"]
259 #[doc = ""]
260 #[doc = "* `data` - The slice to update the underlying hasher state with."]
261 #[doc = ""]
262 #[doc = "# Returns"]
263 #[doc = ""]
264 #[doc = "This function returns the result of the operation."]
265 #[doc = ""]
266 #[doc = "# Example"]
267 #[doc = ""]
268 #[doc = "```"]
269 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
270 #[doc = ""]
271 #[doc = concat!("let mut hasher = ", stringify!($name), "::<", stringify!($max), ">::new().unwrap();")]
272 #[doc = ""]
273 #[doc = "let input = b\"hello world\";"]
274 #[doc = "// SAFETY: The length of `hello world` is 11, which cannot overflow even an 8-bit integer."]
275 #[doc = "let res = unsafe { hasher.update_unchecked(input.as_slice()) };"]
276 #[doc = "assert!(res.is_ok());"]
277 #[doc = ""]
278 #[doc = "let finalized = hasher.try_finalize().unwrap();"]
279 #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
280 #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($max), ");")]
281 #[doc = "```"]
282 #[inline]
283 pub unsafe fn update_unchecked(&mut self, data: &[u8]) -> $crate::opaque_res::Res {
284 let mut res = $crate::opaque_res::Res::new();
285
286 res.ensure_0($update(
287 ::core::ptr::addr_of_mut!(self.inner),
288 data.as_ptr(),
289 data.len() as u32
290 ));
291
292 res
293 }
294
295 #[doc = concat!("Update the `", stringify!($name), "` instance with the provided data.")]
296 #[doc = ""]
297 #[doc = "# Arguments"]
298 #[doc = ""]
299 #[doc = "* `data` - The slice to update the underlying hasher state with."]
300 #[doc = ""]
301 #[doc = "# Returns"]
302 #[doc = ""]
303 #[doc = "This function returns the result of the operation."]
304 #[doc = ""]
305 #[doc = "# Errors"]
306 #[doc = ""]
307 #[doc = "- If the length of `data` cannot be safely cast to a `u32`."]
308 #[doc = concat!("- If the underlying `", stringify!($update), "` function fails.")]
309 #[doc = ""]
310 #[doc = "# Example"]
311 #[doc = ""]
312 #[doc = "```"]
313 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
314 #[doc = ""]
315 #[doc = concat!("let mut hasher = ", stringify!($name), "::<", stringify!($max), ">::new().unwrap();")]
316 #[doc = ""]
317 #[doc = "let input = b\"hello world\";"]
318 #[doc = "assert!(hasher.try_update(input.as_slice()).is_ok());"]
319 #[doc = ""]
320 #[doc = "let finalized = hasher.try_finalize().unwrap();"]
321 #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
322 #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($max), ");")]
323 #[doc = "```"]
324 #[inline]
325 pub fn try_update(&mut self, data: &[u8]) -> $crate::opaque_res::Res {
326 if !$crate::can_cast_u32(data.len()) { return $crate::opaque_res::Res::ERR }
327 unsafe { self.update_unchecked(data) }
328 }
329
330 #[doc = concat!(
331 "Update the `", stringify!($name),
332 "` instance with the provided data, using compile-time safety checks."
333 )]
334 #[doc = ""]
335 #[doc = "# Arguments"]
336 #[doc = ""]
337 #[doc = "* `data` - The slice to update the underlying hasher state with, where the size of the slice"]
338 #[doc = " is known at compile time."]
339 #[doc = ""]
340 #[doc = "# Returns"]
341 #[doc = ""]
342 #[doc = "This function returns the result of the operation."]
343 #[doc = ""]
344 #[doc = "# Errors"]
345 #[doc = ""]
346 #[doc = "- If the length of `data` cannot be safely cast to a `u32`."]
347 #[doc = concat!("- If the underlying `", stringify!($update), "` function fails.")]
348 #[doc = ""]
349 #[doc = "# Example"]
350 #[doc = ""]
351 #[doc = "```"]
352 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
353 #[doc = ""]
354 #[doc = concat!("let mut hasher = ", stringify!($name), "::<", stringify!($max), ">::new().unwrap();")]
355 #[doc = ""]
356 #[doc = "let input = b\"hello world\";"]
357 #[doc = "assert!(hasher.update_sized(&input).is_ok());"]
358 #[doc = ""]
359 #[doc = "let finalized = hasher.try_finalize().unwrap();"]
360 #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
361 #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($max), ");")]
362 #[doc = "```"]
363 #[inline]
364 pub fn update_sized<const OC: usize>(&mut self, data: &[u8; OC]) -> $crate::opaque_res::Res {
365 if !$crate::const_can_cast_u32::<{ OC }>() { return $crate::opaque_res::Res::ERR }
366 unsafe { self.update_unchecked(data) }
367 }
368
369 panic_api! {
370 #[doc = concat!("Update the `", stringify!($name), "` instance with the provided data, panicking on failure.")]
371 #[doc = ""]
372 #[doc = "# Arguments"]
373 #[doc = ""]
374 #[doc = "* `data` - The slice to update the underlying hasher state with."]
375 #[doc = ""]
376 #[doc = "# Panics"]
377 #[doc = ""]
378 #[doc = "- If the length of `data` cannot be safely cast to a `u32`."]
379 #[doc = concat!("- If the underlying `", stringify!($update), "` function fails.")]
380 #[doc = ""]
381 #[doc = "If a panic is not acceptable for your use case, consider using [`try_update`] instead."]
382 #[doc = ""]
383 #[doc = "# Example"]
384 #[doc = ""]
385 #[doc = "```"]
386 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
387 #[doc = ""]
388 #[doc = concat!("let mut hasher = ", stringify!($name), "::<", stringify!($max), ">::new().unwrap();")]
389 #[doc = ""]
390 #[doc = "let input = b\"hello world\";"]
391 #[doc = "hasher.update(input.as_slice());"]
392 #[doc = ""]
393 #[doc = "let finalized = hasher.try_finalize().unwrap();"]
394 #[doc = "assert_ne!(finalized.as_slice(), input.as_slice());"]
395 #[doc = concat!("assert_eq!(finalized.len(), ", stringify!($max), ");")]
396 #[doc = "```"]
397 #[doc = ""]
398 #[doc = "[`try_update`]: Self::try_update"]
399 #[track_caller]
400 pub fn update(&mut self, data: &[u8]) {
401 self.try_update(data).unit_err(())
402 .expect(concat!("Failed to update hash in `", stringify!($name), "`"))
403 }
404 }
405
406 #[doc = concat!(
407 "Finalize the `", stringify!($name),
408 "` hashing process, writing the output to the provided buffer, without"
409 )]
410 #[doc = "performing safety checks."]
411 #[doc = ""]
412 #[doc = "# Safety"]
413 #[doc = ""]
414 #[doc = "The size of the `output` argument must be at least `C` (the size of the digest)."]
415 #[doc = ""]
416 #[doc = "# Arguments"]
417 #[doc = ""]
418 #[doc = "* `output` - The buffer to store the output digest in."]
419 #[doc = ""]
420 #[doc = "# Returns"]
421 #[doc = ""]
422 #[doc = "This function returns the result of the operation."]
423 #[doc = ""]
424 #[doc = "# Example"]
425 #[doc = ""]
426 #[doc = "```"]
427 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
428 #[doc = concat!("let mut hasher = ", stringify!($name), "::<", stringify!($max), ">::new().unwrap();")]
429 #[doc = ""]
430 #[doc = concat!("let mut output = [0u8; ", stringify!($max), "];")]
431 #[doc = concat!(
432 "// SAFETY: The size of the output buffer is exactly ", stringify!($max),
433 " bytes (the size of the digest)."
434 )]
435 #[doc = "let res = unsafe { hasher.finalize_unchecked(&mut output) };"]
436 #[doc = "assert!(res.is_ok());"]
437 #[doc = "```"]
438 #[inline]
439 pub unsafe fn finalize_unchecked(mut self, output: &mut [u8]) -> $crate::opaque_res::Res {
440 let mut res = $crate::opaque_res::Res::new();
441
442 res.ensure_0($final(
443 ::core::ptr::addr_of_mut!(self.inner),
444 output.as_mut_ptr(),
445 C as u32
446 ));
447
448 res
449 }
450
451 #[doc = concat!(
452 "Finalize the `", stringify!($name),
453 "` hashing process, writing the output to the provided buffer."
454 )]
455 #[doc = ""]
456 #[doc = "# Arguments"]
457 #[doc = ""]
458 #[doc = "* `output` - The buffer to store the output digest in."]
459 #[doc = ""]
460 #[doc = "# Errors"]
461 #[doc = ""]
462 #[doc = "- If the size of `output` is less than `C` (the size of the digest)."]
463 #[doc = "- If the underlying finalize function fails."]
464 #[doc = ""]
465 #[doc = "# Example"]
466 #[doc = ""]
467 #[doc = "```"]
468 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
469 #[doc = concat!("let mut hasher = ", stringify!($name), "::<", stringify!($max), ">::new().unwrap();")]
470 #[doc = ""]
471 #[doc = "// use the hasher ..."]
472 #[doc = ""]
473 #[doc = concat!("let mut output = [0u8; ", stringify!($max), "];")]
474 #[doc = "assert!(hasher.finalize_into(&mut output).is_ok());"]
475 #[doc = "```"]
476 #[inline]
477 pub fn finalize_into(self, output: &mut [u8]) -> $crate::opaque_res::Res {
478 if !$crate::gte::<{ C }>(output.len()) { return $crate::opaque_res::Res::ERR }
479 unsafe { self.finalize_unchecked(output) }
480 }
481
482 #[doc = concat!(
483 "Finalize the `", stringify!($name),
484 "` hashing process, writing the output to a fixed-size buffer, and"
485 )]
486 #[doc = "performing safety checks at compilation time."]
487 #[doc = ""]
488 #[doc = "# Arguments"]
489 #[doc = ""]
490 #[doc = "* `output` - The fixed-size buffer to store the output digest in."]
491 #[doc = ""]
492 #[doc = "# Errors"]
493 #[doc = ""]
494 #[doc = "- If the length of `output` is less than `C` (the size of the digest)."]
495 #[doc = "- If the underlying finalize function fails."]
496 #[doc = ""]
497 #[doc = "# Example"]
498 #[doc = ""]
499 #[doc = "```"]
500 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
501 #[doc = concat!("let mut hasher = ", stringify!($name), "::<", stringify!($max), ">::new().unwrap();")]
502 #[doc = ""]
503 #[doc = "// use the hasher ..."]
504 #[doc = ""]
505 #[doc = concat!("let mut output = [0u8; ", stringify!($max), "];")]
506 #[doc = "assert!(hasher.finalize_into_sized(&mut output).is_ok());"]
507 #[doc = "```"]
508 #[inline]
509 pub fn finalize_into_sized<const OC: usize>(self, output: &mut [u8; OC]) -> $crate::opaque_res::Res {
510 if !$crate::const_gte::<{ OC }, { C }>() { return $crate::opaque_res::Res::ERR }
511 unsafe { self.finalize_unchecked(output) }
512 }
513
514 #[doc = concat!(
515 "Finalize the `", stringify!($name),
516 "` hashing process, writing the output to a buffer with an exact size."
517 )]
518 #[doc = ""]
519 #[doc = "This method is for cases where the size of the output buffer is exactly the same as the"]
520 #[doc = "digest size (`C`). The buffer size is checked at compile time, so no runtime size checks"]
521 #[doc = "are necessary, making this a highly optimized version of finalization."]
522 #[doc = ""]
523 #[doc = "# Arguments"]
524 #[doc = ""]
525 #[doc = "* `output` - The buffer to store the output digest in, with a size exactly equal to the"]
526 #[doc = " digest size (`C`)."]
527 #[doc = ""]
528 #[doc = "# Returns"]
529 #[doc = ""]
530 #[doc = "This function returns the result of the operation."]
531 #[doc = ""]
532 #[doc = "# Example"]
533 #[doc = ""]
534 #[doc = "```"]
535 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
536 #[doc = concat!("let mut hasher = ", stringify!($name), "::<", stringify!($max), ">::new().unwrap();")]
537 #[doc = ""]
538 #[doc = "// use the hasher ..."]
539 #[doc = ""]
540 #[doc = concat!("let mut output = [0u8; ", stringify!($max), "];")]
541 #[doc = "assert!(hasher.finalize_into_exact(&mut output).is_ok());"]
542 #[doc = "```"]
543 #[doc = ""]
544 #[doc = "**Note**: If the size of the output buffer is not exactly `C`, see [`finalize_into`] for"]
545 #[doc = "greater flexibility, or [`finalize_into_sized`] if the size is known at compile time but is"]
546 #[doc = "not exactly `C`."]
547 #[doc = ""]
548 #[doc = "[`finalize_into`]: Self::finalize_into"]
549 #[doc = "[`finalize_into_sized`]: Self::finalize_into_sized"]
550 #[inline]
551 pub fn finalize_into_exact(self, output: &mut [u8; C]) -> $crate::opaque_res::Res {
552 unsafe { self.finalize_unchecked(output) }
553 }
554
555 #[doc = concat!(
556 "Finalize the `", stringify!($name), "` hashing process, returning the result as an array."
557 )]
558 #[doc = ""]
559 #[doc = "# Returns"]
560 #[doc = ""]
561 #[doc = "On success, this returns the output digest as an array."]
562 #[doc = ""]
563 #[doc = "# Errors"]
564 #[doc = ""]
565 #[doc = "If the underlying finalize function fails."]
566 #[doc = ""]
567 #[doc = "# Example"]
568 #[doc = ""]
569 #[doc = "```"]
570 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
571 #[doc = concat!(
572 "let mut hasher = ", stringify!($name), "::<", stringify!($max), ">::new().unwrap();"
573 )]
574 #[doc = ""]
575 #[doc = "// use the hasher ..."]
576 #[doc = ""]
577 #[doc = "let res = hasher.try_finalize().unwrap();"]
578 #[doc = concat!("assert_eq!(res.len(), ", stringify!($max), ");")]
579 #[doc = "```"]
580 #[inline]
581 pub fn try_finalize(self) -> Result<[u8; C], $crate::error::Unspecified> {
582 let mut buf = [0u8; C];
583 self.finalize_into_exact(&mut buf).unit_err(buf)
584 }
585
586 panic_api! {
587 #[doc = concat!(
588 "Finalize the `", stringify!($name),
589 "` hashing process, returning the result as an array, panicking on"
590 )]
591 #[doc = "failure."]
592 #[doc = ""]
593 #[doc = "# Returns"]
594 #[doc = ""]
595 #[doc = "On success, this returns the output digest as an array."]
596 #[doc = ""]
597 #[doc = "# Panics"]
598 #[doc = ""]
599 #[doc = "If the underlying finalize function fails."]
600 #[doc = ""]
601 #[doc = "If panicking is not acceptable for your use case, consider using [`try_finalize`] instead."]
602 #[doc = ""]
603 #[doc = "# Example"]
604 #[doc = ""]
605 #[doc = "```"]
606 #[doc = concat!("use wolf_crypto::hash::", stringify!($name), ";")]
607 #[doc = concat!("let mut hasher = ", stringify!($name), "::<", stringify!($max), ">::new().unwrap();")]
608 #[doc = ""]
609 #[doc = "// use the hasher ..."]
610 #[doc = ""]
611 #[doc = "let res = hasher.finalize();"]
612 #[doc = concat!("assert_eq!(res.len(), ", stringify!($max), ");")]
613 #[doc = "```"]
614 #[doc = ""]
615 #[doc = "[`try_finalize`]: Self::try_finalize"]
616 #[track_caller]
617 pub fn finalize(self) -> [u8; C] {
618 self.try_finalize()
619 .expect(concat!("Failed to finalize in `", stringify!($name), "`"))
620 }
621 }
622 }
623
624 unsafe impl<const C: usize> Send for $name<C> {}
629
630 unsafe impl<const C: usize> Sync for $name<C> {}
634
635 #[cfg(test)]
636 mod unit_tests {
637 use super::*;
638 use digest::Digest;
639
640 #[test]
641 fn rust_crypto_equivalence() {
642 many_blake!($name => |mut wolf, mut rc| {
643 let input = b"hello world";
644
645 assert!(wolf.try_update(input.as_slice()).is_ok());
646 rc.update(input.as_slice());
647
648 let w_out = wolf.try_finalize().unwrap();
649 let rc_out = rc.finalize();
650
651 assert_eq!(w_out.as_slice(), rc_out.as_slice());
652 });
653 }
654
655
656 #[test]
657 fn rust_crypto_partial_update_equivalence() {
658 many_blake!($name => |mut wolf, mut rc| {
659 let input = b"hello w";
660
661 assert!(wolf.try_update(input.as_slice()).is_ok());
662 rc.update(input.as_slice());
663
664 let f = b"orld";
665
666 wolf.update(f.as_slice());
667 rc.update(f.as_slice());
668
669 let w_out = wolf.try_finalize().unwrap();
670 let rc_out = rc.finalize();
671
672 assert_eq!(w_out.as_slice(), rc_out.as_slice());
673 });
674 }
675
676 #[test]
677 fn rust_crypto_empty_equivalence() {
678 many_blake!($name => |mut wolf, mut rc| {
679 let input = b"";
680
681 assert!(wolf.try_update(input.as_slice()).is_ok());
682 rc.update(input.as_slice());
683
684 let w_out = wolf.try_finalize().unwrap();
685 let rc_out = rc.finalize();
686
687 assert_eq!(w_out.as_slice(), rc_out.as_slice());
688 })
689 }
690
691 #[test]
692 fn rust_crypto_1mb_equivalence() {
693 let input = vec![7u8; 1_000_000];
694
695 many_blake!($name => |mut wolf, mut rc| {
696 assert!(wolf.try_update(input.as_slice()).is_ok());
697 rc.update(input.as_slice());
698
699 let w_out = wolf.try_finalize().unwrap();
700 let rc_out = rc.finalize();
701
702 assert_eq!(w_out.as_slice(), rc_out.as_slice());
703 })
704 }
705 }
706
707 #[cfg(test)]
708 mod property_tests {
709 use super::*;
710 use digest::Digest;
711
712 use $crate::aes::test_utils::{BoundList, AnyList};
713 use proptest::prelude::*;
714
715 proptest! {
716 #![proptest_config(ProptestConfig::with_cases(15_000))]
717
718 #[test]
719 fn rust_crypto_eq_wolf_single_update(
720 input in any::<BoundList<1024>>()
721 ) {
722 many_blake!($name => |mut wolf, mut rc| {
723 prop_assert!(wolf.try_update(input.as_slice()).is_ok());
724 rc.update(input.as_slice());
725
726 let finalized = wolf.try_finalize().unwrap();
727 let rc_finalized = rc.finalize();
728
729 prop_assert_eq!(finalized.as_slice(), rc_finalized.as_slice());
730 });
731 }
732 }
733
734 proptest! {
735 #![proptest_config(ProptestConfig::with_cases(5_000))]
736
737 #[test]
740 fn rust_crypto_eq_wolf_arb_updates(
741 inputs in any::<AnyList<32, BoundList<512>>>()
742 ) {
743 many_blake!($name => |mut wolf, mut rc| {
744 for input in inputs.as_slice().iter() {
745 prop_assert!(wolf.try_update(input.as_slice()).is_ok());
746 rc.update(input.as_slice());
747 }
748
749 let finalized = wolf.try_finalize().unwrap();
750 let rc_finalized = rc.finalize();
751
752 prop_assert_eq!(finalized.as_slice(), rc_finalized.as_slice());
753 });
754 }
755 }
756 }
757 };
758}
759
760#[cfg(test)]
761macro_rules! many_blake {
762 (
763 $blake:ident => |mut $wolf:ident, mut $rc:ident $(, $sz:ident)?| $do:expr
764 ) => {{
765 many_blake! { $blake => |mut $wolf is 32, mut $rc is U32 $(, $sz)?| $do }
766 many_blake! { $blake => |mut $wolf is 28, mut $rc is U28 $(, $sz)?| $do }
767 many_blake! { $blake => |mut $wolf is 24, mut $rc is U24 $(, $sz)?| $do }
768 many_blake! { $blake => |mut $wolf is 22, mut $rc is U22 $(, $sz)?| $do }
769 many_blake! { $blake => |mut $wolf is 20, mut $rc is U20 $(, $sz)?| $do }
770 many_blake! { $blake => |mut $wolf is 14, mut $rc is U14 $(, $sz)?| $do }
771 many_blake! { $blake => |mut $wolf is 12, mut $rc is U12 $(, $sz)?| $do }
772 many_blake! { $blake => |mut $wolf is 9, mut $rc is U9 $(, $sz)?| $do }
773 many_blake! { $blake => |mut $wolf is 8, mut $rc is U8 $(, $sz)?| $do }
774 many_blake! { $blake => |mut $wolf is 6, mut $rc is U6 $(, $sz)?| $do }
775 many_blake! { $blake => |mut $wolf is 4, mut $rc is U4 $(, $sz)?| $do }
776 many_blake! { $blake => |mut $wolf is 2, mut $rc is U2 $(, $sz)?| $do }
777 many_blake! { $blake => |mut $wolf is 1, mut $rc is U1 $(, $sz)?| $do }
778 }};
779 (
780 $blake:ident => |mut $wolf:ident is $sz:literal, mut $rc:ident is $rSz:ident $(, $gS:ident)?|
781 $do:expr
782 ) => {{
783 $(let $gS = $sz;)?
784 let mut $wolf = $blake::<{ $sz }>::new().unwrap();
785 let mut $rc = blake2::$blake::<::digest::consts::$rSz>::new();
786 $do
787 }}
788}
789
790#[cfg(test)]
791pub struct KeyedVector {
792 pub input: &'static [u8],
793 pub key: &'static [u8],
794 pub hash: &'static [u8]
795}
796
797#[cfg(test)]
798macro_rules! ingest_blake_vectors {
799 (
800 $(
801 in: $input:literal
802 key: $key:literal
803 hash: $output:literal
804 )*
805 ) => {
806 &[
807 $(
808 $crate::hash::blake_api::KeyedVector {
809 input: &hex_literal::hex!($input),
810 key: &hex_literal::hex!($key),
811 hash: &hex_literal::hex!($output)
812 }
813 ),*
814 ]
815 };
816 ($ident:ident => $($tt:tt)*) => {
817 const $ident: &'static [$crate::hash::blake_api::KeyedVector] = ingest_blake_vectors!(
818 $($tt)*
819 );
820 }
821}