miden_crypto/hash/blake/
mod.rs

1use 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
17// CONSTANTS
18// ================================================================================================
19
20const DIGEST32_BYTES: usize = 32;
21const DIGEST24_BYTES: usize = 24;
22const DIGEST20_BYTES: usize = 20;
23
24// BLAKE3 N-BIT OUTPUT
25// ================================================================================================
26
27/// N-bytes output of a blake3 function.
28///
29/// Note: `N` can't be greater than `32` because [`Digest::as_bytes`] currently supports only 32
30/// bytes.
31#[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        // compile-time assertion
99        assert!(N <= 32, "digest currently supports only 32 bytes!");
100        expand_bytes(&self.0)
101    }
102}
103
104// BLAKE3 256-BIT OUTPUT
105// ================================================================================================
106
107/// 256-bit output blake3 hasher.
108#[derive(Debug, Copy, Clone, Eq, PartialEq)]
109pub struct Blake3_256;
110
111impl Hasher for Blake3_256 {
112    /// Blake3 collision resistance is 128-bits for 32-bytes output.
113    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    /// Returns a hash of the provided sequence of bytes.
160    #[inline(always)]
161    pub fn hash(bytes: &[u8]) -> Blake3Digest<DIGEST32_BYTES> {
162        <Self as Hasher>::hash(bytes)
163    }
164
165    /// Returns a hash of two digests. This method is intended for use in construction of
166    /// Merkle trees and verification of Merkle paths.
167    #[inline(always)]
168    pub fn merge(values: &[Blake3Digest<DIGEST32_BYTES>; 2]) -> Blake3Digest<DIGEST32_BYTES> {
169        <Self as Hasher>::merge(values)
170    }
171
172    /// Returns a hash of the provided field elements.
173    #[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    /// Hashes an iterator of byte slices.
182    #[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// BLAKE3 192-BIT OUTPUT
192// ================================================================================================
193
194/// 192-bit output blake3 hasher.
195#[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    /// Blake3 collision resistance is 96-bits for 24-bytes output.
210    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    /// Returns a hash of the provided sequence of bytes.
248    #[inline(always)]
249    pub fn hash(bytes: &[u8]) -> Blake3Digest<DIGEST24_BYTES> {
250        <Self as Hasher>::hash(bytes)
251    }
252
253    /// Returns a hash of two digests. This method is intended for use in construction of
254    /// Merkle trees and verification of Merkle paths.
255    #[inline(always)]
256    pub fn merge(values: &[Blake3Digest<DIGEST24_BYTES>; 2]) -> Blake3Digest<DIGEST24_BYTES> {
257        <Self as Hasher>::merge(values)
258    }
259
260    /// Returns a hash of the provided field elements.
261    #[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    /// Hashes an iterator of byte slices.
270    #[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// BLAKE3 160-BIT OUTPUT
280// ================================================================================================
281
282/// 160-bit output blake3 hasher.
283#[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    /// Blake3 collision resistance is 80-bits for 20-bytes output.
298    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    /// Returns a hash of the provided sequence of bytes.
336    #[inline(always)]
337    pub fn hash(bytes: &[u8]) -> Blake3Digest<DIGEST20_BYTES> {
338        <Self as Hasher>::hash(bytes)
339    }
340
341    /// Returns a hash of two digests. This method is intended for use in construction of
342    /// Merkle trees and verification of Merkle paths.
343    #[inline(always)]
344    pub fn merge(values: &[Blake3Digest<DIGEST20_BYTES>; 2]) -> Blake3Digest<DIGEST20_BYTES> {
345        <Self as Hasher>::merge(values)
346    }
347
348    /// Returns a hash of the provided field elements.
349    #[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    /// Hashes an iterator of byte slices.
358    #[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
367// HELPER FUNCTIONS
368// ================================================================================================
369
370/// Zero-copy ref shrink to array.
371fn shrink_bytes<const M: usize, const N: usize>(bytes: &[u8; M]) -> &[u8; N] {
372    // compile-time assertion
373    assert!(M >= N, "N should fit in M so it can be safely transmuted into a smaller slice!");
374    // safety: bytes len is asserted
375    unsafe { transmute(bytes) }
376}
377
378/// Hash the elements into bytes and shrink the output.
379fn hash_elements<const N: usize, E>(elements: &[E]) -> [u8; N]
380where
381    E: FieldElement<BaseField = Felt>,
382{
383    // don't leak assumptions from felt and check its actual implementation.
384    // this is a compile-time branch so it is for free
385    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        // BLAKE3 rate is 64 bytes - so, we can absorb 64 bytes into the state in a single
391        // permutation. we move the elements into the hasher via the buffer to give the CPU
392        // a chance to process multiple element-to-byte conversions in parallel
393        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
411/// Owned bytes expansion.
412fn expand_bytes<const M: usize, const N: usize>(bytes: &[u8; M]) -> [u8; N] {
413    // compile-time assertion
414    assert!(M <= N, "M should fit in N so M can be expanded!");
415    // this branch is constant so it will be optimized to be either one of the variants in release
416    // mode
417    if M == N {
418        // safety: the sizes are checked to be the same
419        unsafe { transmute_copy(bytes) }
420    } else {
421        let mut expanded = [0u8; N];
422        expanded[..M].copy_from_slice(bytes);
423        expanded
424    }
425}
426
427// Cast the slice into contiguous bytes.
428fn prepare_merge<const N: usize, D>(args: &[D; N]) -> &[u8]
429where
430    D: Deref<Target = [u8]>,
431{
432    // compile-time assertion
433    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    // safety: the values are tested to be contiguous
437    let bytes = unsafe { from_raw_parts(values, len) };
438    debug_assert_eq!(args[0].deref(), &bytes[..len / N]);
439    bytes
440}