filecoin_hashers/
blake2s.rs1use 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 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 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 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}