winter_crypto/hash/blake/
mod.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6use core::{fmt::Debug, marker::PhantomData};
7
8use math::{FieldElement, StarkField};
9use utils::ByteWriter;
10
11use super::{ByteDigest, ElementHasher, Hasher};
12
13#[cfg(test)]
14mod tests;
15
16// BLAKE3 256-BIT OUTPUT
17// ================================================================================================
18
19/// Implementation of the [Hasher](super::Hasher) trait for BLAKE3 hash function with 256-bit
20/// output.
21#[derive(Debug, PartialEq, Eq)]
22pub struct Blake3_256<B: StarkField>(PhantomData<B>);
23
24impl<B: StarkField> Hasher for Blake3_256<B> {
25    type Digest = ByteDigest<32>;
26
27    const COLLISION_RESISTANCE: u32 = 128;
28
29    fn hash(bytes: &[u8]) -> Self::Digest {
30        ByteDigest(*blake3::hash(bytes).as_bytes())
31    }
32
33    fn merge(values: &[Self::Digest; 2]) -> Self::Digest {
34        ByteDigest(blake3::hash(ByteDigest::digests_as_bytes(values)).into())
35    }
36
37    fn merge_many(values: &[Self::Digest]) -> Self::Digest {
38        ByteDigest(blake3::hash(ByteDigest::digests_as_bytes(values)).into())
39    }
40
41    fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
42        let mut data = [0; 40];
43        data[..32].copy_from_slice(&seed.0);
44        data[32..].copy_from_slice(&value.to_le_bytes());
45        ByteDigest(*blake3::hash(&data).as_bytes())
46    }
47}
48
49impl<B: StarkField> ElementHasher for Blake3_256<B> {
50    type BaseField = B;
51
52    fn hash_elements<E: FieldElement<BaseField = Self::BaseField>>(elements: &[E]) -> Self::Digest {
53        if B::IS_CANONICAL {
54            // when element's internal and canonical representations are the same, we can hash
55            // element bytes directly
56            let bytes = E::elements_as_bytes(elements);
57            ByteDigest(*blake3::hash(bytes).as_bytes())
58        } else {
59            // when elements' internal and canonical representations differ, we need to serialize
60            // them before hashing
61            let mut hasher = BlakeHasher::new();
62            hasher.write_many(elements);
63            ByteDigest(hasher.finalize())
64        }
65    }
66}
67
68// BLAKE3 192-BIT OUTPUT
69// ================================================================================================
70
71/// Implementation of the [Hasher](super::Hasher) trait for BLAKE3 hash function with 192-bit
72/// output.
73#[derive(Debug, PartialEq, Eq)]
74pub struct Blake3_192<B: StarkField>(PhantomData<B>);
75
76impl<B: StarkField> Hasher for Blake3_192<B> {
77    type Digest = ByteDigest<24>;
78
79    const COLLISION_RESISTANCE: u32 = 96;
80
81    fn hash(bytes: &[u8]) -> Self::Digest {
82        let result = blake3::hash(bytes);
83        ByteDigest(result.as_bytes()[..24].try_into().unwrap())
84    }
85
86    fn merge(values: &[Self::Digest; 2]) -> Self::Digest {
87        let result = blake3::hash(ByteDigest::digests_as_bytes(values));
88        ByteDigest(result.as_bytes()[..24].try_into().unwrap())
89    }
90
91    fn merge_many(values: &[Self::Digest]) -> Self::Digest {
92        let result = blake3::hash(ByteDigest::digests_as_bytes(values));
93        ByteDigest(result.as_bytes()[..24].try_into().unwrap())
94    }
95
96    fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
97        let mut data = [0; 32];
98        data[..24].copy_from_slice(&seed.0);
99        data[24..].copy_from_slice(&value.to_le_bytes());
100
101        let result = blake3::hash(&data);
102        ByteDigest(result.as_bytes()[..24].try_into().unwrap())
103    }
104}
105
106impl<B: StarkField> ElementHasher for Blake3_192<B> {
107    type BaseField = B;
108
109    fn hash_elements<E: FieldElement<BaseField = Self::BaseField>>(elements: &[E]) -> Self::Digest {
110        if B::IS_CANONICAL {
111            // when element's internal and canonical representations are the same, we can hash
112            // element bytes directly
113            let bytes = E::elements_as_bytes(elements);
114            let result = blake3::hash(bytes);
115            ByteDigest(result.as_bytes()[..24].try_into().unwrap())
116        } else {
117            // when elements' internal and canonical representations differ, we need to serialize
118            // them before hashing
119            let mut hasher = BlakeHasher::new();
120            hasher.write_many(elements);
121            let result = hasher.finalize();
122            ByteDigest(result[..24].try_into().unwrap())
123        }
124    }
125}
126
127// BLAKE HASHER
128// ================================================================================================
129
130/// Wrapper around BLAKE3 hasher to implement [ByteWriter] trait for it.
131struct BlakeHasher(blake3::Hasher);
132
133impl BlakeHasher {
134    pub fn new() -> Self {
135        Self(blake3::Hasher::new())
136    }
137
138    pub fn finalize(&self) -> [u8; 32] {
139        *self.0.finalize().as_bytes()
140    }
141}
142
143impl ByteWriter for BlakeHasher {
144    fn write_u8(&mut self, value: u8) {
145        self.0.update(&[value]);
146    }
147
148    fn write_bytes(&mut self, values: &[u8]) {
149        self.0.update(values);
150    }
151}