miden_crypto/hash/blake/
mod.rs1use alloc::string::String;
2use core::{
3 mem::{size_of, transmute, transmute_copy},
4 ops::Deref,
5 slice::{self, from_raw_parts},
6};
7
8use super::{Digest, ElementHasher, Felt, FieldElement, Hasher, HasherExt};
9use crate::utils::{
10 ByteReader, ByteWriter, Deserializable, DeserializationError, HexParseError, Serializable,
11 bytes_to_hex_string, hex_to_bytes,
12};
13
14#[cfg(test)]
15mod tests;
16
17const DIGEST32_BYTES: usize = 32;
21const DIGEST24_BYTES: usize = 24;
22const DIGEST20_BYTES: usize = 20;
23
24#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
32#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
33#[cfg_attr(feature = "serde", serde(into = "String", try_from = "&str"))]
34pub struct Blake3Digest<const N: usize>([u8; N]);
35
36impl<const N: usize> Blake3Digest<N> {
37 pub fn digests_as_bytes(digests: &[Blake3Digest<N>]) -> &[u8] {
38 let p = digests.as_ptr();
39 let len = digests.len() * N;
40 unsafe { slice::from_raw_parts(p as *const u8, len) }
41 }
42}
43
44impl<const N: usize> Default for Blake3Digest<N> {
45 fn default() -> Self {
46 Self([0; N])
47 }
48}
49
50impl<const N: usize> Deref for Blake3Digest<N> {
51 type Target = [u8];
52
53 fn deref(&self) -> &Self::Target {
54 &self.0
55 }
56}
57
58impl<const N: usize> From<Blake3Digest<N>> for [u8; N] {
59 fn from(value: Blake3Digest<N>) -> Self {
60 value.0
61 }
62}
63
64impl<const N: usize> From<[u8; N]> for Blake3Digest<N> {
65 fn from(value: [u8; N]) -> Self {
66 Self(value)
67 }
68}
69
70impl<const N: usize> From<Blake3Digest<N>> for String {
71 fn from(value: Blake3Digest<N>) -> Self {
72 bytes_to_hex_string(value.as_bytes())
73 }
74}
75
76impl<const N: usize> TryFrom<&str> for Blake3Digest<N> {
77 type Error = HexParseError;
78
79 fn try_from(value: &str) -> Result<Self, Self::Error> {
80 hex_to_bytes(value).map(|v| v.into())
81 }
82}
83
84impl<const N: usize> Serializable for Blake3Digest<N> {
85 fn write_into<W: ByteWriter>(&self, target: &mut W) {
86 target.write_bytes(&self.0);
87 }
88}
89
90impl<const N: usize> Deserializable for Blake3Digest<N> {
91 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
92 source.read_array().map(Self)
93 }
94}
95
96impl<const N: usize> Digest for Blake3Digest<N> {
97 fn as_bytes(&self) -> [u8; 32] {
98 assert!(N <= 32, "digest currently supports only 32 bytes!");
100 expand_bytes(&self.0)
101 }
102}
103
104#[derive(Debug, Copy, Clone, Eq, PartialEq)]
109pub struct Blake3_256;
110
111impl Hasher for Blake3_256 {
112 const COLLISION_RESISTANCE: u32 = 128;
114
115 type Digest = Blake3Digest<32>;
116
117 fn hash(bytes: &[u8]) -> Self::Digest {
118 Blake3Digest(blake3::hash(bytes).into())
119 }
120
121 fn merge(values: &[Self::Digest; 2]) -> Self::Digest {
122 Self::hash(prepare_merge(values))
123 }
124
125 fn merge_many(values: &[Self::Digest]) -> Self::Digest {
126 Blake3Digest(blake3::hash(Blake3Digest::digests_as_bytes(values)).into())
127 }
128
129 fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
130 let mut hasher = blake3::Hasher::new();
131 hasher.update(&seed.0);
132 hasher.update(&value.to_le_bytes());
133 Blake3Digest(hasher.finalize().into())
134 }
135}
136
137impl ElementHasher for Blake3_256 {
138 type BaseField = Felt;
139
140 fn hash_elements<E>(elements: &[E]) -> Self::Digest
141 where
142 E: FieldElement<BaseField = Self::BaseField>,
143 {
144 Blake3Digest(hash_elements(elements))
145 }
146}
147
148impl HasherExt for Blake3_256 {
149 fn hash_iter<'a>(&self, slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
150 let mut hasher = blake3::Hasher::new();
151 for slice in slices {
152 hasher.update(slice);
153 }
154 Blake3Digest(hasher.finalize().into())
155 }
156}
157
158impl Blake3_256 {
159 #[inline(always)]
161 pub fn hash(bytes: &[u8]) -> Blake3Digest<DIGEST32_BYTES> {
162 <Self as Hasher>::hash(bytes)
163 }
164
165 #[inline(always)]
168 pub fn merge(values: &[Blake3Digest<DIGEST32_BYTES>; 2]) -> Blake3Digest<DIGEST32_BYTES> {
169 <Self as Hasher>::merge(values)
170 }
171
172 #[inline(always)]
174 pub fn hash_elements<E>(elements: &[E]) -> Blake3Digest<DIGEST32_BYTES>
175 where
176 E: FieldElement<BaseField = Felt>,
177 {
178 <Self as ElementHasher>::hash_elements(elements)
179 }
180
181 #[inline(always)]
183 pub fn hash_iter<'a>(
184 &self,
185 slices: impl Iterator<Item = &'a [u8]>,
186 ) -> Blake3Digest<DIGEST32_BYTES> {
187 <Self as HasherExt>::hash_iter(self, slices)
188 }
189}
190
191#[derive(Debug, Copy, Clone, Eq, PartialEq)]
196pub struct Blake3_192;
197
198impl HasherExt for Blake3_192 {
199 fn hash_iter<'a>(&self, slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
200 let mut hasher = blake3::Hasher::new();
201 for slice in slices {
202 hasher.update(slice);
203 }
204 Blake3Digest(*shrink_bytes(&hasher.finalize().into()))
205 }
206}
207
208impl Hasher for Blake3_192 {
209 const COLLISION_RESISTANCE: u32 = 96;
211
212 type Digest = Blake3Digest<24>;
213
214 fn hash(bytes: &[u8]) -> Self::Digest {
215 Blake3Digest(*shrink_bytes(&blake3::hash(bytes).into()))
216 }
217
218 fn merge_many(values: &[Self::Digest]) -> Self::Digest {
219 let bytes = Blake3Digest::digests_as_bytes(values);
220 Blake3Digest(*shrink_bytes(&blake3::hash(bytes).into()))
221 }
222
223 fn merge(values: &[Self::Digest; 2]) -> Self::Digest {
224 Self::hash(prepare_merge(values))
225 }
226
227 fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
228 let mut hasher = blake3::Hasher::new();
229 hasher.update(&seed.0);
230 hasher.update(&value.to_le_bytes());
231 Blake3Digest(*shrink_bytes(&hasher.finalize().into()))
232 }
233}
234
235impl ElementHasher for Blake3_192 {
236 type BaseField = Felt;
237
238 fn hash_elements<E>(elements: &[E]) -> Self::Digest
239 where
240 E: FieldElement<BaseField = Self::BaseField>,
241 {
242 Blake3Digest(hash_elements(elements))
243 }
244}
245
246impl Blake3_192 {
247 #[inline(always)]
249 pub fn hash(bytes: &[u8]) -> Blake3Digest<DIGEST24_BYTES> {
250 <Self as Hasher>::hash(bytes)
251 }
252
253 #[inline(always)]
256 pub fn merge(values: &[Blake3Digest<DIGEST24_BYTES>; 2]) -> Blake3Digest<DIGEST24_BYTES> {
257 <Self as Hasher>::merge(values)
258 }
259
260 #[inline(always)]
262 pub fn hash_elements<E>(elements: &[E]) -> Blake3Digest<DIGEST24_BYTES>
263 where
264 E: FieldElement<BaseField = Felt>,
265 {
266 <Self as ElementHasher>::hash_elements(elements)
267 }
268
269 #[inline(always)]
271 pub fn hash_iter<'a>(
272 &self,
273 slices: impl Iterator<Item = &'a [u8]>,
274 ) -> Blake3Digest<DIGEST24_BYTES> {
275 <Self as HasherExt>::hash_iter(self, slices)
276 }
277}
278
279#[derive(Debug, Copy, Clone, Eq, PartialEq)]
284pub struct Blake3_160;
285
286impl HasherExt for Blake3_160 {
287 fn hash_iter<'a>(&self, slices: impl Iterator<Item = &'a [u8]>) -> Self::Digest {
288 let mut hasher = blake3::Hasher::new();
289 for slice in slices {
290 hasher.update(slice);
291 }
292 Blake3Digest(*shrink_bytes(&hasher.finalize().into()))
293 }
294}
295
296impl Hasher for Blake3_160 {
297 const COLLISION_RESISTANCE: u32 = 80;
299
300 type Digest = Blake3Digest<20>;
301
302 fn hash(bytes: &[u8]) -> Self::Digest {
303 Blake3Digest(*shrink_bytes(&blake3::hash(bytes).into()))
304 }
305
306 fn merge(values: &[Self::Digest; 2]) -> Self::Digest {
307 Self::hash(prepare_merge(values))
308 }
309
310 fn merge_many(values: &[Self::Digest]) -> Self::Digest {
311 let bytes = Blake3Digest::digests_as_bytes(values);
312 Blake3Digest(*shrink_bytes(&blake3::hash(bytes).into()))
313 }
314
315 fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
316 let mut hasher = blake3::Hasher::new();
317 hasher.update(&seed.0);
318 hasher.update(&value.to_le_bytes());
319 Blake3Digest(*shrink_bytes(&hasher.finalize().into()))
320 }
321}
322
323impl ElementHasher for Blake3_160 {
324 type BaseField = Felt;
325
326 fn hash_elements<E>(elements: &[E]) -> Self::Digest
327 where
328 E: FieldElement<BaseField = Self::BaseField>,
329 {
330 Blake3Digest(hash_elements(elements))
331 }
332}
333
334impl Blake3_160 {
335 #[inline(always)]
337 pub fn hash(bytes: &[u8]) -> Blake3Digest<DIGEST20_BYTES> {
338 <Self as Hasher>::hash(bytes)
339 }
340
341 #[inline(always)]
344 pub fn merge(values: &[Blake3Digest<DIGEST20_BYTES>; 2]) -> Blake3Digest<DIGEST20_BYTES> {
345 <Self as Hasher>::merge(values)
346 }
347
348 #[inline(always)]
350 pub fn hash_elements<E>(elements: &[E]) -> Blake3Digest<DIGEST20_BYTES>
351 where
352 E: FieldElement<BaseField = Felt>,
353 {
354 <Self as ElementHasher>::hash_elements(elements)
355 }
356
357 #[inline(always)]
359 pub fn hash_iter<'a>(
360 &self,
361 slices: impl Iterator<Item = &'a [u8]>,
362 ) -> Blake3Digest<DIGEST20_BYTES> {
363 <Self as HasherExt>::hash_iter(self, slices)
364 }
365}
366
367fn shrink_bytes<const M: usize, const N: usize>(bytes: &[u8; M]) -> &[u8; N] {
372 assert!(M >= N, "N should fit in M so it can be safely transmuted into a smaller slice!");
374 unsafe { transmute(bytes) }
376}
377
378fn hash_elements<const N: usize, E>(elements: &[E]) -> [u8; N]
380where
381 E: FieldElement<BaseField = Felt>,
382{
383 let digest = if Felt::IS_CANONICAL {
386 blake3::hash(E::elements_as_bytes(elements))
387 } else {
388 let mut hasher = blake3::Hasher::new();
389
390 let mut buf = [0_u8; 64];
394 let mut chunk_iter = E::slice_as_base_elements(elements).chunks_exact(8);
395 for chunk in chunk_iter.by_ref() {
396 for i in 0..8 {
397 buf[i * 8..(i + 1) * 8].copy_from_slice(&chunk[i].as_int().to_le_bytes());
398 }
399 hasher.update(&buf);
400 }
401
402 for element in chunk_iter.remainder() {
403 hasher.update(&element.as_int().to_le_bytes());
404 }
405
406 hasher.finalize()
407 };
408 *shrink_bytes(&digest.into())
409}
410
411fn expand_bytes<const M: usize, const N: usize>(bytes: &[u8; M]) -> [u8; N] {
413 assert!(M <= N, "M should fit in N so M can be expanded!");
415 if M == N {
418 unsafe { transmute_copy(bytes) }
420 } else {
421 let mut expanded = [0u8; N];
422 expanded[..M].copy_from_slice(bytes);
423 expanded
424 }
425}
426
427fn prepare_merge<const N: usize, D>(args: &[D; N]) -> &[u8]
429where
430 D: Deref<Target = [u8]>,
431{
432 assert!(N > 0, "N shouldn't represent an empty slice!");
434 let values = args.as_ptr() as *const u8;
435 let len = size_of::<D>() * N;
436 let bytes = unsafe { from_raw_parts(values, len) };
438 debug_assert_eq!(args[0].deref(), &bytes[..len / N]);
439 bytes
440}