Skip to main content

filecoin_hashers/
blake2s.rs

1use std::fmt::{self, Debug, Formatter};
2use std::hash::Hasher as StdHasher;
3use std::panic::panic_any;
4
5use anyhow::ensure;
6use bellperson::{
7    gadgets::{
8        blake2s::blake2s as blake2s_circuit, boolean::Boolean, multipack, num::AllocatedNum,
9    },
10    ConstraintSystem, SynthesisError,
11};
12use blake2s_simd::{Hash as Blake2sHash, Params as Blake2s, State};
13use blstrs::Scalar as Fr;
14use ff::{Field, PrimeField};
15use merkletree::{
16    hash::{Algorithm, Hashable},
17    merkle::Element,
18};
19use rand::RngCore;
20use serde::{Deserialize, Serialize};
21
22use crate::types::{Domain, HashFunction, Hasher};
23
24#[derive(Default, Copy, Clone, PartialEq, Eq, Debug)]
25pub struct Blake2sHasher {}
26
27impl Hasher for Blake2sHasher {
28    type Domain = Blake2sDomain;
29    type Function = Blake2sFunction;
30
31    fn name() -> String {
32        "Blake2sHasher".into()
33    }
34}
35
36#[derive(Clone)]
37pub struct Blake2sFunction(State);
38
39impl Default for Blake2sFunction {
40    fn default() -> Self {
41        Blake2sFunction(Blake2s::new().hash_length(32).to_state())
42    }
43}
44
45impl PartialEq for Blake2sFunction {
46    fn eq(&self, other: &Self) -> bool {
47        format!("{:?}", self) == format!("{:?}", other)
48    }
49}
50
51impl Eq for Blake2sFunction {}
52
53impl Debug for Blake2sFunction {
54    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
55        write!(f, "Blake2sFunction({:?})", self.0)
56    }
57}
58
59impl StdHasher for Blake2sFunction {
60    #[inline]
61    fn write(&mut self, msg: &[u8]) {
62        self.0.update(msg);
63    }
64
65    #[inline]
66    fn finish(&self) -> u64 {
67        unreachable!("unused by Function -- should never be called")
68    }
69}
70
71#[derive(
72    Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Default, Serialize, Deserialize, Hash,
73)]
74pub struct Blake2sDomain(pub [u8; 32]);
75
76impl AsRef<Blake2sDomain> for Blake2sDomain {
77    fn as_ref(&self) -> &Self {
78        self
79    }
80}
81
82impl Blake2sDomain {
83    pub fn trim_to_fr32(&mut self) {
84        // strip last two bits, to ensure result is in Fr.
85        self.0[31] &= 0b0011_1111;
86    }
87}
88
89impl AsRef<[u8]> for Blake2sDomain {
90    fn as_ref(&self) -> &[u8] {
91        &self.0[..]
92    }
93}
94
95impl Hashable<Blake2sFunction> for Blake2sDomain {
96    fn hash(&self, state: &mut Blake2sFunction) {
97        state.write(self.as_ref())
98    }
99}
100
101impl From<Fr> for Blake2sDomain {
102    fn from(val: Fr) -> Self {
103        Blake2sDomain(val.to_repr())
104    }
105}
106
107impl Element for Blake2sDomain {
108    fn byte_len() -> usize {
109        32
110    }
111
112    fn from_slice(bytes: &[u8]) -> Self {
113        match Blake2sDomain::try_from_bytes(bytes) {
114            Ok(res) => res,
115            Err(err) => panic_any(err),
116        }
117    }
118
119    fn copy_to_slice(&self, bytes: &mut [u8]) {
120        bytes.copy_from_slice(&self.0);
121    }
122}
123
124impl From<Blake2sDomain> for Fr {
125    fn from(val: Blake2sDomain) -> Self {
126        Fr::from_repr_vartime(val.0).expect("from_repr failure")
127    }
128}
129
130impl Domain for Blake2sDomain {
131    fn into_bytes(&self) -> Vec<u8> {
132        self.0.to_vec()
133    }
134
135    fn try_from_bytes(raw: &[u8]) -> anyhow::Result<Self> {
136        ensure!(
137            raw.len() == 32 && u32::from(raw[31]) <= Fr::NUM_BITS,
138            "invalid amount of bytes"
139        );
140
141        let mut res = Blake2sDomain::default();
142        res.0.copy_from_slice(&raw[0..32]);
143        Ok(res)
144    }
145
146    fn write_bytes(&self, dest: &mut [u8]) -> anyhow::Result<()> {
147        ensure!(dest.len() >= 32, "too many bytes");
148        dest[0..32].copy_from_slice(&self.0[..]);
149        Ok(())
150    }
151
152    fn random<R: RngCore>(rng: &mut R) -> Self {
153        // generating an Fr and converting it, to ensure we stay in the field
154        Fr::random(rng).into()
155    }
156}
157
158#[allow(clippy::from_over_into)]
159impl Into<Blake2sDomain> for Blake2sHash {
160    fn into(self) -> Blake2sDomain {
161        let mut res = Blake2sDomain::default();
162        res.0[..].copy_from_slice(self.as_ref());
163        res.trim_to_fr32();
164
165        res
166    }
167}
168
169impl HashFunction<Blake2sDomain> for Blake2sFunction {
170    fn hash(data: &[u8]) -> Blake2sDomain {
171        Blake2s::new()
172            .hash_length(32)
173            .to_state()
174            .update(data)
175            .finalize()
176            .into()
177    }
178
179    fn hash2(a: &Blake2sDomain, b: &Blake2sDomain) -> Blake2sDomain {
180        Blake2s::new()
181            .hash_length(32)
182            .to_state()
183            .update(a.as_ref())
184            .update(b.as_ref())
185            .finalize()
186            .into()
187    }
188
189    fn hash_multi_leaf_circuit<Arity, CS: ConstraintSystem<Fr>>(
190        mut cs: CS,
191        leaves: &[AllocatedNum<Fr>],
192        _height: usize,
193    ) -> Result<AllocatedNum<Fr>, SynthesisError> {
194        let mut bits = Vec::with_capacity(leaves.len() * Fr::CAPACITY as usize);
195        for (i, leaf) in leaves.iter().enumerate() {
196            bits.extend_from_slice(
197                &leaf.to_bits_le(cs.namespace(|| format!("{}_num_into_bits", i)))?,
198            );
199            while bits.len() % 8 != 0 {
200                bits.push(Boolean::Constant(false));
201            }
202        }
203        Self::hash_circuit(cs, &bits)
204    }
205
206    fn hash_leaf_bits_circuit<CS: ConstraintSystem<Fr>>(
207        cs: CS,
208        left: &[Boolean],
209        right: &[Boolean],
210        _height: usize,
211    ) -> Result<AllocatedNum<Fr>, SynthesisError> {
212        let mut preimage: Vec<Boolean> = vec![];
213
214        preimage.extend_from_slice(left);
215        while !preimage.len().is_multiple_of(8) {
216            preimage.push(Boolean::Constant(false));
217        }
218
219        preimage.extend_from_slice(right);
220        while !preimage.len().is_multiple_of(8) {
221            preimage.push(Boolean::Constant(false));
222        }
223
224        Self::hash_circuit(cs, &preimage[..])
225    }
226
227    fn hash_circuit<CS: ConstraintSystem<Fr>>(
228        mut cs: CS,
229        bits: &[Boolean],
230    ) -> Result<AllocatedNum<Fr>, SynthesisError> {
231        let personalization = vec![0u8; 8];
232        let alloc_bits = blake2s_circuit(cs.namespace(|| "hash"), bits, &personalization)?;
233
234        multipack::pack_bits(cs.namespace(|| "pack"), &alloc_bits)
235    }
236
237    fn hash2_circuit<CS>(
238        mut cs: CS,
239        a_num: &AllocatedNum<Fr>,
240        b_num: &AllocatedNum<Fr>,
241    ) -> Result<AllocatedNum<Fr>, SynthesisError>
242    where
243        CS: ConstraintSystem<Fr>,
244    {
245        // Allocate as booleans
246        let a = a_num.to_bits_le(cs.namespace(|| "a_bits"))?;
247        let b = b_num.to_bits_le(cs.namespace(|| "b_bits"))?;
248
249        let mut preimage: Vec<Boolean> = vec![];
250
251        preimage.extend_from_slice(&a);
252        while !preimage.len().is_multiple_of(8) {
253            preimage.push(Boolean::Constant(false));
254        }
255
256        preimage.extend_from_slice(&b);
257        while !preimage.len().is_multiple_of(8) {
258            preimage.push(Boolean::Constant(false));
259        }
260
261        Self::hash_circuit(cs, &preimage[..])
262    }
263}
264
265impl Algorithm<Blake2sDomain> for Blake2sFunction {
266    #[inline]
267    fn hash(&mut self) -> Blake2sDomain {
268        self.0.clone().finalize().into()
269    }
270
271    #[inline]
272    fn reset(&mut self) {
273        self.0 = Blake2s::new().hash_length(32).to_state()
274    }
275
276    fn leaf(&mut self, leaf: Blake2sDomain) -> Blake2sDomain {
277        leaf
278    }
279
280    fn node(&mut self, left: Blake2sDomain, right: Blake2sDomain, _height: usize) -> Blake2sDomain {
281        left.hash(self);
282        right.hash(self);
283        self.hash()
284    }
285
286    fn multi_node(&mut self, parts: &[Blake2sDomain], _height: usize) -> Blake2sDomain {
287        for part in parts {
288            part.hash(self)
289        }
290        self.hash()
291    }
292}
293
294impl From<[u8; 32]> for Blake2sDomain {
295    #[inline]
296    fn from(val: [u8; 32]) -> Self {
297        Blake2sDomain(val)
298    }
299}
300
301impl From<Blake2sDomain> for [u8; 32] {
302    #[inline]
303    fn from(val: Blake2sDomain) -> Self {
304        val.0
305    }
306}