primitives/hashing/
hashing_utils.rs1use blake3;
2use hybrid_array::Array;
3
4use crate::{
5 algebra::field::FieldExtension,
6 constants::CollisionResistanceBytes,
7 types::SessionId,
8};
9
10pub type Digest = Array<u8, CollisionResistanceBytes>;
11
12pub fn hash(slices: &[&[u8]]) -> Digest {
13 let mut hasher = blake3::Hasher::new();
14 for slice in slices {
15 hasher.update(slice);
16 }
17 Into::<[u8; 32]>::into(hasher.finalize()).into()
18}
19
20pub fn hash_into<T: AsRef<[u8]>, I: IntoIterator<Item = T>>(slices: I, out: &mut [u8]) {
21 let mut hasher = blake3::Hasher::new();
22 for slice in slices {
23 hasher.update(slice.as_ref());
24 }
25 hasher.finalize_xof().fill(out.as_mut());
26}
27
28pub fn hash_to_field<T: AsRef<[u8]>, F: FieldExtension>(session_id: &SessionId, message: &T) -> F {
29 let mut hasher = blake3::Hasher::new();
30 let mut output = Array::<u8, F::UniformBytes>::default();
31
32 hasher.update(session_id.as_ref());
33 hasher.update(message.as_ref());
34 hasher.finalize_xof().fill(&mut output);
35
36 F::from_uniform_bytes(&output)
37}
38
39pub fn flatten_slices<T: AsRef<[u8]>>(slices: &[T]) -> Vec<u8> {
40 let total_len = slices.iter().map(|slice| slice.as_ref().len()).sum();
41
42 let mut flattened = Vec::with_capacity(total_len);
43 slices.iter().for_each(|slice| {
44 flattened.extend_from_slice(slice.as_ref());
45 });
46
47 flattened
48}
49
50#[cfg(test)]
51mod tests {
52 use crate::hashing::hash_into;
53
54 #[test]
55 fn test_hash_into_different_results() {
56 let (mut seed0, mut seed1, mut seed2, mut seed3) = ([0; 16], [0; 16], [0; 16], [0; 16]);
57 hash_into([b"0", b"1"], &mut seed0);
58 hash_into([b"0", b"12".as_slice()], &mut seed1);
59 hash_into([b"01", b"12"], &mut seed2);
60 hash_into([b"01", b"1".as_slice()], &mut seed3);
61
62 assert_ne!(seed0, seed1);
63 assert_ne!(seed0, seed2);
64 assert_ne!(seed0, seed3);
65 assert_ne!(seed1, seed2);
66 assert_ne!(seed1, seed3);
67 assert_ne!(seed2, seed3);
68 }
69}