miden_crypto/hash/blake/
mod.rs1use core::mem::size_of;
2
3use super::{
4 HasherExt,
5 digest::{Digest, Digest192, Digest256},
6};
7use crate::{Felt, field::BasedVectorSpace};
8
9#[cfg(test)]
10mod tests;
11
12pub use p3_blake3::Blake3 as Blake3Hasher;
17
18pub type Blake3Digest<const N: usize> = Digest<N>;
23
24#[derive(Debug, Copy, Clone, Eq, PartialEq)]
29pub struct Blake3_256;
30
31impl HasherExt for Blake3_256 {
32 type Digest = Digest256;
33
34 fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
35 let mut hasher = blake3::Hasher::new();
36 for slice in slices {
37 hasher.update(slice);
38 }
39 Digest::new(hasher.finalize().into())
40 }
41}
42
43impl Blake3_256 {
44 pub const COLLISION_RESISTANCE: u32 = 128;
46
47 pub fn hash(bytes: &[u8]) -> Digest256 {
48 Digest::new(blake3::hash(bytes).into())
49 }
50
51 pub fn merge(values: &[Digest256; 2]) -> Digest256 {
55 Self::hash(Digest::digests_as_bytes(values))
56 }
57
58 pub fn merge_many(values: &[Digest256]) -> Digest256 {
59 Digest::new(blake3::hash(Digest::digests_as_bytes(values)).into())
60 }
61
62 pub fn merge_with_int(seed: Digest256, value: u64) -> Digest256 {
63 let mut hasher = blake3::Hasher::new();
64 hasher.update(seed.as_bytes());
65 hasher.update(&value.to_le_bytes());
66 Digest::new(hasher.finalize().into())
67 }
68
69 #[inline(always)]
71 pub fn hash_elements<E: BasedVectorSpace<Felt>>(elements: &[E]) -> Digest256 {
72 Digest::new(hash_elements(elements))
73 }
74
75 #[inline(always)]
77 pub fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Digest256 {
78 <Self as HasherExt>::hash_iter(slices)
79 }
80}
81
82#[derive(Debug, Copy, Clone, Eq, PartialEq)]
87pub struct Blake3_192;
88
89impl HasherExt for Blake3_192 {
90 type Digest = Digest192;
91
92 fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
93 let mut hasher = blake3::Hasher::new();
94 for slice in slices {
95 hasher.update(slice);
96 }
97 Digest::new(shrink_array(hasher.finalize().into()))
98 }
99}
100
101impl Blake3_192 {
102 pub const COLLISION_RESISTANCE: u32 = 96;
104
105 pub fn hash(bytes: &[u8]) -> Digest192 {
106 Digest::new(shrink_array(blake3::hash(bytes).into()))
107 }
108
109 pub fn merge_many(values: &[Digest192]) -> Digest192 {
111 let bytes = Digest::digests_as_bytes(values);
112 Digest::new(shrink_array(blake3::hash(bytes).into()))
113 }
114
115 pub fn merge(values: &[Digest192; 2]) -> Digest192 {
116 Self::hash(Digest::digests_as_bytes(values))
117 }
118
119 pub fn merge_with_int(seed: Digest192, value: u64) -> Digest192 {
120 let mut hasher = blake3::Hasher::new();
121 hasher.update(seed.as_bytes());
122 hasher.update(&value.to_le_bytes());
123 Digest::new(shrink_array(hasher.finalize().into()))
124 }
125
126 #[inline(always)]
128 pub fn hash_elements<E: BasedVectorSpace<Felt>>(elements: &[E]) -> Digest192 {
129 Digest::new(hash_elements(elements))
130 }
131
132 #[inline(always)]
134 pub fn hash_iter<'a>(slices: impl Iterator<Item = &'a [u8]>) -> Digest192 {
135 <Self as HasherExt>::hash_iter(slices)
136 }
137}
138
139fn hash_elements<const N: usize, E>(elements: &[E]) -> [u8; N]
144where
145 E: BasedVectorSpace<Felt>,
146{
147 let digest = {
148 const FELT_BYTES: usize = size_of::<u64>();
149 const { assert!(FELT_BYTES == 8, "buffer arithmetic assumes 8-byte field elements") };
150
151 let mut hasher = blake3::Hasher::new();
152 let mut buf = [0_u8; 64];
154 let mut buf_offset = 0;
155
156 for elem in elements.iter() {
157 for &felt in E::as_basis_coefficients_slice(elem) {
158 buf[buf_offset..buf_offset + FELT_BYTES]
159 .copy_from_slice(&felt.as_canonical_u64().to_le_bytes());
160 buf_offset += FELT_BYTES;
161
162 if buf_offset == 64 {
163 hasher.update(&buf);
164 buf_offset = 0;
165 }
166 }
167 }
168
169 if buf_offset > 0 {
170 hasher.update(&buf[..buf_offset]);
171 }
172
173 hasher.finalize()
174 };
175
176 shrink_array(digest.into())
177}
178
179fn shrink_array<const M: usize, const N: usize>(source: [u8; M]) -> [u8; N] {
183 const {
184 assert!(M >= N, "size of destination should be smaller or equal than source");
185 }
186 core::array::from_fn(|i| source[i])
187}