Skip to main content

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