1#[cfg(feature = "alloc")]
49use alloc::vec::Vec;
50
51use crate::classic::crypto_generichash::{
52 GenericHashState, crypto_generichash, crypto_generichash_final, crypto_generichash_init,
53 crypto_generichash_update,
54};
55use crate::constants::{CRYPTO_GENERICHASH_BYTES, CRYPTO_GENERICHASH_KEYBYTES};
56use crate::error::Error;
57use crate::types::*;
58
59pub type Hash = StackByteArray<CRYPTO_GENERICHASH_BYTES>;
61pub type Key = StackByteArray<CRYPTO_GENERICHASH_KEYBYTES>;
63
64#[cfg(any(
65 all(feature = "protected", any(unix, windows)),
66 all(doc, not(doctest), feature = "std")
67))]
68#[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "protected")))]
69pub mod protected {
70 use super::*;
87 pub use crate::protected::*;
88
89 pub type Key = HeapByteArray<CRYPTO_GENERICHASH_KEYBYTES>;
92 pub type Hash = HeapByteArray<CRYPTO_GENERICHASH_BYTES>;
95}
96
97#[derive(Clone)]
112pub struct GenericHash<const KEY_LENGTH: usize, const OUTPUT_LENGTH: usize> {
113 state: GenericHashState,
114}
115
116pub type DefaultGenericHash = GenericHash<CRYPTO_GENERICHASH_KEYBYTES, CRYPTO_GENERICHASH_BYTES>;
120
121impl<const KEY_LENGTH: usize, const OUTPUT_LENGTH: usize> GenericHash<KEY_LENGTH, OUTPUT_LENGTH> {
122 pub fn new<Key: ByteArray<KEY_LENGTH>>(key: Option<&Key>) -> Result<Self, Error> {
129 Ok(Self {
130 state: crypto_generichash_init(key.map(|k| k.as_slice()), OUTPUT_LENGTH)?,
131 })
132 }
133
134 pub fn update<Input: Bytes + ?Sized>(&mut self, input: &Input) {
136 crypto_generichash_update(&mut self.state, input.as_slice())
137 }
138
139 pub fn finalize<Output: NewByteArray<OUTPUT_LENGTH>>(self) -> Result<Output, Error> {
146 let mut output = Output::new_byte_array();
147
148 crypto_generichash_final(self.state, output.as_mut_slice())?;
149
150 Ok(output)
151 }
152
153 #[cfg(feature = "alloc")]
161 pub fn finalize_to_vec(self) -> Result<Vec<u8>, Error> {
162 Ok(self.finalize::<StackByteArray<OUTPUT_LENGTH>>()?.to_vec())
163 }
164
165 pub fn hash<
191 Output: NewByteArray<OUTPUT_LENGTH>,
192 Input: Bytes + ?Sized,
193 Key: ByteArray<KEY_LENGTH>,
194 >(
195 input: &Input,
196 key: Option<&Key>,
197 ) -> Result<Output, Error> {
198 let mut output = Output::new_byte_array();
199 crypto_generichash(
200 output.as_mut_slice(),
201 input.as_slice(),
202 key.map(|k| k.as_slice()),
203 )?;
204 Ok(output)
205 }
206
207 #[cfg(feature = "alloc")]
213 pub fn hash_to_vec<Input: Bytes + ?Sized, Key: ByteArray<KEY_LENGTH>>(
214 input: &Input,
215 key: Option<&Key>,
216 ) -> Result<Vec<u8>, Error> {
217 Ok(Self::hash::<StackByteArray<OUTPUT_LENGTH>, _, _>(input, key)?.to_vec())
218 }
219}
220
221#[cfg(all(test, feature = "alloc"))]
222mod tests {
223 use super::*;
224
225 #[test]
226 fn test_generichash() {
227 use base64::Engine as _;
228 use base64::engine::general_purpose;
229
230 let mut hasher = DefaultGenericHash::new::<Key>(None).expect("new hash failed");
231 hasher.update(b"hello");
232
233 let output: Hash = hasher.finalize().expect("finalize failed");
234
235 assert_eq!(
236 general_purpose::STANDARD.encode(&output),
237 "Mk3PAn3UowqTLEQfNlol6GsXPe+kuOWJSCU0cbgbcs8="
238 );
239
240 let mut hasher = DefaultGenericHash::new::<Key>(None).expect("new hash failed");
241 hasher.update(b"hello");
242
243 let output = hasher.finalize_to_vec().expect("finalize failed");
244
245 assert_eq!(
246 general_purpose::STANDARD.encode(output),
247 "Mk3PAn3UowqTLEQfNlol6GsXPe+kuOWJSCU0cbgbcs8="
248 );
249 }
250
251 #[test]
252 fn test_generichash_onetime() {
253 use base64::Engine as _;
254 use base64::engine::general_purpose;
255
256 let output: Hash =
257 GenericHash::hash(b"hello", Some(b"a very secret key")).expect("hash failed");
258
259 assert_eq!(
260 general_purpose::STANDARD.encode(&output),
261 "AECDe+XJsB6nOkbCsbS/OPXdzpcRm3AolW/Bg1LFY9A="
262 );
263
264 let output: Hash =
265 DefaultGenericHash::hash::<_, _, Key>(b"hello", None).expect("hash failed");
266
267 assert_eq!(
268 general_purpose::STANDARD.encode(&output),
269 "Mk3PAn3UowqTLEQfNlol6GsXPe+kuOWJSCU0cbgbcs8="
270 );
271
272 let output =
273 DefaultGenericHash::hash_to_vec::<_, Key>(b"hello", None).expect("hash failed");
274
275 assert_eq!(
276 general_purpose::STANDARD.encode(output),
277 "Mk3PAn3UowqTLEQfNlol6GsXPe+kuOWJSCU0cbgbcs8="
278 );
279 }
280 #[test]
281 fn test_generichash_clone_mid_stream() {
282 let key = Key::from(&[0x5au8; CRYPTO_GENERICHASH_KEYBYTES]);
283 let message: Vec<u8> = (0..300u16).map(|i| (i * 31 % 251) as u8).collect();
285 for key in [None, Some(&key)] {
286 for split in [0, 5, 128, 129, 300] {
287 let expected: Hash =
288 GenericHash::hash(message.as_slice(), key).expect("hash failed");
289
290 let mut hasher = DefaultGenericHash::new(key).expect("new hash failed");
291 hasher.update(&message[..split]);
292 let mut copy = hasher.clone();
293 hasher.update(&message[split..]);
294 copy.update(&message[split..]);
295
296 let original: Hash = hasher.finalize().expect("finalize failed");
297 let cloned: Hash = copy.finalize().expect("finalize failed");
298 assert_eq!(original, expected);
299 assert_eq!(cloned, expected);
300 }
301 }
302
303 let mut hasher = DefaultGenericHash::new(Some(&key)).expect("new hash failed");
305 hasher.update(b"shared prefix ");
306 let mut copy = hasher.clone();
307 hasher.update(b"one");
308 copy.update(b"two");
309 let one: Hash = hasher.finalize().expect("finalize failed");
310 let two: Hash = copy.finalize().expect("finalize failed");
311 let expected_one: Hash =
312 GenericHash::hash(b"shared prefix one", Some(&key)).expect("hash failed");
313 let expected_two: Hash =
314 GenericHash::hash(b"shared prefix two", Some(&key)).expect("hash failed");
315 assert_eq!(one, expected_one);
316 assert_eq!(two, expected_two);
317 }
318
319 #[test]
320 fn test_generichash_onetime_empty() {
321 use base64::Engine as _;
322 use base64::engine::general_purpose;
323
324 let output = DefaultGenericHash::hash_to_vec::<_, Key>(&[], None).expect("hash failed");
325
326 assert_eq!(
327 general_purpose::STANDARD.encode(output),
328 "DldRwCblQ7Loqy6wYJnaodHl30d3j3eH+qtFzfEv46g="
329 );
330 }
331
332 #[test]
333 fn test_vectors() {
334 let test_vec = |input, key, hash| {
335 let input = hex::decode(input).expect("decode input");
336 let key: [u8; 64] = hex::decode(key)
337 .expect("decode key")
338 .try_into()
339 .expect("64-byte key");
340 let expected_hash = hex::decode(hash).expect("decode hash");
341
342 let hash: [u8; 64] =
343 GenericHash::<64, 64>::hash(&input, Some(&key)).expect("hash failed");
344
345 assert_eq!(expected_hash, hash);
346 };
347
348 test_vec("", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568");
349 test_vec("00", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", "961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd");
350 test_vec("0001", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", "da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965");
351 test_vec("000102", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", "33d0825dddf7ada99b0e7e307104ad07ca9cfd9692214f1561356315e784f3e5a17e364ae9dbb14cb2036df932b77f4b292761365fb328de7afdc6d8998f5fc1");
352 test_vec("00010203", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", "beaa5a3d08f3807143cf621d95cd690514d0b49efff9c91d24b59241ec0eefa5f60196d407048bba8d2146828ebcb0488d8842fd56bb4f6df8e19c4b4daab8ac");
353 test_vec("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfc", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", "a6213743568e3b3158b9184301f3690847554c68457cb40fc9a4b8cfd8d4a118c301a07737aeda0f929c68913c5f51c80394f53bff1c3e83b2e40ca97eba9e15");
354 test_vec("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfd", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", "d444bfa2362a96df213d070e33fa841f51334e4e76866b8139e8af3bb3398be2dfaddcbc56b9146de9f68118dc5829e74b0c28d7711907b121f9161cb92b69a9");
355 test_vec("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461");
356 }
357
358 use crate::constants::{CRYPTO_GENERICHASH_BYTES_MAX, CRYPTO_GENERICHASH_KEYBYTES_MAX};
359
360 const FOX: &[u8] = b"The quick brown fox jumps over the lazy dog";
361
362 const FOX_KAT: [(usize, usize, &str); 5] = [
365 (16, 0, "249df9a49f517ddcd37f5c897620ec73"),
366 (
367 64,
368 0,
369 concat!(
370 "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673",
371 "f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918",
372 ),
373 ),
374 (16, 16, "fb80e606c7e3d993cbf7117a60f630a0"),
375 (
376 32,
377 32,
378 "5d9461aff732d77d0cc98725ea29298c914fd5193b4c08ec9e3ad6b28c3e2faf",
379 ),
380 (
381 64,
382 64,
383 concat!(
384 "1d58d71414d24752db3274afdc483fc0f4c68317c4c2f6a31e09de9437ba02cc",
385 "ab8c8585790a52b0d476f7920c0e1397d1aec9e52f3df3feae76f7d6223ce5cf",
386 ),
387 ),
388 ];
389
390 fn sequential_key<const LENGTH: usize>() -> StackByteArray<LENGTH> {
391 StackByteArray::from(core::array::from_fn::<u8, LENGTH, _>(|i| i as u8))
392 }
393
394 fn assert_fox<const KEY_LENGTH: usize, const OUTPUT_LENGTH: usize>(
397 key: Option<&StackByteArray<KEY_LENGTH>>,
398 expected: &str,
399 ) {
400 let expected = hex::decode(expected).expect("hex");
401 let output: StackByteArray<OUTPUT_LENGTH> =
402 GenericHash::<KEY_LENGTH, OUTPUT_LENGTH>::hash(FOX, key).expect("hash");
403 assert_eq!(output.as_slice(), expected.as_slice());
404 assert_eq!(
405 GenericHash::<KEY_LENGTH, OUTPUT_LENGTH>::hash_to_vec(&FOX, key).expect("hash"),
406 expected
407 );
408
409 for parts in [
410 vec![FOX],
411 vec![&FOX[..1], &FOX[1..]],
412 vec![&[][..], &FOX[..20], &FOX[20..40], &FOX[40..], &[][..]],
413 ] {
414 let mut hasher = GenericHash::<KEY_LENGTH, OUTPUT_LENGTH>::new(key).expect("new");
415 for part in &parts {
416 hasher.update(*part);
417 }
418 let output: StackByteArray<OUTPUT_LENGTH> = hasher.finalize().expect("finalize");
419 assert_eq!(output.as_slice(), expected.as_slice());
420 }
421 }
422
423 #[test]
424 fn min_and_max_output_and_key_lengths_match_libsodium_known_answers() {
425 assert_fox::<CRYPTO_GENERICHASH_KEYBYTES, 16>(None, FOX_KAT[0].2);
426 assert_fox::<CRYPTO_GENERICHASH_KEYBYTES, 64>(None, FOX_KAT[1].2);
427 assert_fox::<16, 16>(Some(&sequential_key::<16>()), FOX_KAT[2].2);
428 assert_fox::<32, 32>(Some(&sequential_key::<32>()), FOX_KAT[3].2);
429 assert_fox::<64, 64>(Some(&sequential_key::<64>()), FOX_KAT[4].2);
430
431 let unkeyed16 = hex::decode(FOX_KAT[0].2).expect("hex");
434 let keyed16 = hex::decode(FOX_KAT[2].2).expect("hex");
435 let unkeyed64 = hex::decode(FOX_KAT[1].2).expect("hex");
436 assert_ne!(unkeyed16, keyed16);
437 assert_ne!(unkeyed16, &unkeyed64[..16]);
438 }
439
440 #[test]
445 fn output_and_key_lengths_follow_libsodium_ranges() {
446 let empty_key: Hash =
447 GenericHash::<0, 32>::hash(FOX, Some(&sequential_key::<0>())).expect("empty key");
448 let default_unkeyed: Hash =
449 DefaultGenericHash::hash::<_, _, Key>(FOX, None).expect("unkeyed");
450 assert_eq!(empty_key, default_unkeyed);
451
452 assert!(matches!(
453 GenericHash::<CRYPTO_GENERICHASH_KEYBYTES, 0>::new::<Key>(None),
454 Err(Error::InvalidLength {
455 context: crate::ErrorContext::Output,
456 actual: 0,
457 ..
458 })
459 ));
460 let too_long: Result<StackByteArray<{ CRYPTO_GENERICHASH_BYTES_MAX + 1 }>, Error> =
461 GenericHash::<CRYPTO_GENERICHASH_KEYBYTES, { CRYPTO_GENERICHASH_BYTES_MAX + 1 }>::hash::<
462 _,
463 _,
464 Key,
465 >(FOX, None);
466 assert!(matches!(
467 too_long,
468 Err(Error::InvalidLength {
469 context: crate::ErrorContext::Output,
470 actual: 65,
471 ..
472 })
473 ));
474
475 let long_key = sequential_key::<{ CRYPTO_GENERICHASH_KEYBYTES_MAX + 1 }>();
476 assert!(matches!(
477 GenericHash::<{ CRYPTO_GENERICHASH_KEYBYTES_MAX + 1 }, 32>::new(Some(&long_key)),
478 Err(Error::InvalidLength {
479 context: crate::ErrorContext::Blake2bKey,
480 actual: 65,
481 ..
482 })
483 ));
484 let rejected: Result<Hash, Error> =
485 GenericHash::<{ CRYPTO_GENERICHASH_KEYBYTES_MAX + 1 }, 32>::hash(FOX, Some(&long_key));
486 assert!(matches!(
487 rejected,
488 Err(Error::InvalidLength {
489 context: crate::ErrorContext::Blake2bKey,
490 actual: 65,
491 ..
492 })
493 ));
494 }
495
496 #[cfg(all(feature = "protected", any(unix, windows)))]
497 #[test]
498 fn locked_key_input_and_output_match_stack_types() {
499 use crate::generichash::protected::*;
500
501 let input = HeapBytes::from_slice_into_readonly_locked(FOX).expect("lock input");
502 let key = sequential_key::<CRYPTO_GENERICHASH_KEYBYTES>();
503 let locked_key =
504 protected::Key::from_slice_into_readonly_locked(key.as_slice()).expect("lock key");
505 let expected = hex::decode(FOX_KAT[3].2).expect("hex");
506
507 let hash: Locked<protected::Hash> =
508 GenericHash::hash(&input, Some(&locked_key)).expect("hash");
509 assert_eq!(hash.as_slice(), expected.as_slice());
510 let stack: Hash = GenericHash::hash(FOX, Some(&key)).expect("hash");
511 assert_eq!(stack.as_slice(), hash.as_slice());
512
513 let mut hasher = DefaultGenericHash::new(Some(&locked_key)).expect("new");
514 hasher.update(&input);
515 let hash: Locked<protected::Hash> = hasher.finalize().expect("finalize");
516 assert_eq!(hash.as_slice(), expected.as_slice());
517
518 let unkeyed: Locked<protected::Hash> =
519 DefaultGenericHash::hash::<_, _, protected::Key>(&input, None).expect("hash");
520 let stack_unkeyed: Hash = DefaultGenericHash::hash::<_, _, Key>(FOX, None).expect("hash");
521 assert_eq!(unkeyed.as_slice(), stack_unkeyed.as_slice());
522 assert_ne!(unkeyed.as_slice(), expected.as_slice());
523 }
524
525 #[cfg(dryoc_native_tests)]
526 #[test]
527 fn keyed_and_unkeyed_hashes_match_libsodium_at_length_bounds() {
528 fn sodium_hash(input: &[u8], key: Option<&[u8]>, outlen: usize) -> Vec<u8> {
529 crate::native_test_util::generichash(outlen, input, key).expect("libsodium hash")
530 }
531
532 for (outlen, keylen, _) in FOX_KAT {
533 let key: Vec<u8> = (0..keylen as u8).collect();
534 let key = (keylen > 0).then_some(key.as_slice());
535 let expected = sodium_hash(FOX, key, outlen);
536 let actual = match (keylen, outlen) {
537 (0, 16) => GenericHash::<64, 16>::hash_to_vec(&FOX, None::<&StackByteArray<64>>),
538 (0, 64) => GenericHash::<64, 64>::hash_to_vec(&FOX, None::<&StackByteArray<64>>),
539 (16, 16) => GenericHash::<16, 16>::hash_to_vec(&FOX, Some(&sequential_key::<16>())),
540 (32, 32) => GenericHash::<32, 32>::hash_to_vec(&FOX, Some(&sequential_key::<32>())),
541 (64, 64) => GenericHash::<64, 64>::hash_to_vec(&FOX, Some(&sequential_key::<64>())),
542 _ => unreachable!(),
543 }
544 .expect("hash");
545 assert_eq!(actual, expected);
546 }
547
548 let expected = sodium_hash(FOX, Some(&[0u8][..]), 1);
551 assert_eq!(
552 GenericHash::<1, 1>::hash_to_vec(&FOX, Some(&sequential_key::<1>())).expect("hash"),
553 expected
554 );
555 let key: Vec<u8> = (0..15).collect();
556 let expected = sodium_hash(FOX, Some(&key), 15);
557 let mut hasher = GenericHash::<15, 15>::new(Some(&sequential_key::<15>())).expect("new");
558 hasher.update(FOX);
559 assert_eq!(hasher.finalize_to_vec().expect("finalize"), expected);
560
561 let key = sequential_key::<CRYPTO_GENERICHASH_KEYBYTES>();
563 for len in [0, 1, 127, 128, 129, 255, 256, 257] {
564 let input: Vec<u8> = (0..len).map(|i| (i * 7 % 251) as u8).collect();
565 let expected = sodium_hash(&input, Some(key.as_slice()), CRYPTO_GENERICHASH_BYTES);
566 assert_eq!(
567 DefaultGenericHash::hash_to_vec(&input, Some(&key)).expect("hash"),
568 expected
569 );
570 let expected = sodium_hash(&input, None, CRYPTO_GENERICHASH_BYTES);
571 assert_eq!(
572 DefaultGenericHash::hash_to_vec::<_, Key>(&input, None).expect("hash"),
573 expected
574 );
575 }
576 }
577}