1use std::cmp::Ordering;
2use std::hash::{Hash as StdHash, Hasher as StdHasher};
3use std::panic::panic_any;
4
5use anyhow::ensure;
6use bellperson::{
7 gadgets::{boolean::Boolean, num::AllocatedNum},
8 ConstraintSystem, SynthesisError,
9};
10use blstrs::Scalar as Fr;
11use ff::{Field, PrimeField};
12use generic_array::typenum::{marker_traits::Unsigned, U2};
13use merkletree::{
14 hash::{Algorithm as LightAlgorithm, Hashable},
15 merkle::Element,
16};
17use neptune::{circuit::poseidon_hash, poseidon::Poseidon};
18use rand::RngCore;
19use serde::{Deserialize, Serialize};
20
21use crate::types::{
22 Domain, HashFunction, Hasher, PoseidonArity, PoseidonMDArity, POSEIDON_CONSTANTS_16,
23 POSEIDON_CONSTANTS_2, POSEIDON_CONSTANTS_4, POSEIDON_CONSTANTS_8, POSEIDON_MD_CONSTANTS,
24};
25
26#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
27pub struct PoseidonHasher {}
28
29impl Hasher for PoseidonHasher {
30 type Domain = PoseidonDomain;
31 type Function = PoseidonFunction;
32
33 fn name() -> String {
34 "poseidon_hasher".into()
35 }
36}
37
38#[derive(Copy, Clone, Debug, PartialEq, Eq)]
39pub struct PoseidonFunction(Fr);
40
41impl Default for PoseidonFunction {
42 fn default() -> PoseidonFunction {
43 PoseidonFunction(Fr::ZERO)
44 }
45}
46
47impl Hashable<PoseidonFunction> for Fr {
48 fn hash(&self, state: &mut PoseidonFunction) {
49 state.write(&self.to_repr());
50 }
51}
52
53impl Hashable<PoseidonFunction> for PoseidonDomain {
54 fn hash(&self, state: &mut PoseidonFunction) {
55 state.write(&self.0);
56 }
57}
58
59#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize)]
60pub struct PoseidonDomain(<Fr as PrimeField>::Repr);
61
62impl AsRef<PoseidonDomain> for PoseidonDomain {
63 fn as_ref(&self) -> &PoseidonDomain {
64 self
65 }
66}
67
68impl StdHash for PoseidonDomain {
69 fn hash<H: StdHasher>(&self, state: &mut H) {
70 StdHash::hash(&self.0, state);
71 }
72}
73
74impl PartialEq for PoseidonDomain {
75 fn eq(&self, other: &Self) -> bool {
76 self.0 == other.0
77 }
78}
79
80impl Eq for PoseidonDomain {}
81
82impl Ord for PoseidonDomain {
83 #[inline(always)]
84 fn cmp(&self, other: &PoseidonDomain) -> Ordering {
85 (self.0).cmp(&other.0)
86 }
87}
88
89impl PartialOrd for PoseidonDomain {
90 #[inline(always)]
91 fn partial_cmp(&self, other: &PoseidonDomain) -> Option<Ordering> {
92 Some(self.cmp(other))
93 }
94}
95
96impl AsRef<[u8]> for PoseidonDomain {
97 #[inline]
98 fn as_ref(&self) -> &[u8] {
99 &self.0
100 }
101}
102
103impl Domain for PoseidonDomain {
104 fn into_bytes(&self) -> Vec<u8> {
105 self.0.to_vec()
106 }
107
108 fn try_from_bytes(raw: &[u8]) -> anyhow::Result<Self> {
109 ensure!(
110 raw.len() == PoseidonDomain::byte_len(),
111 "invalid amount of bytes"
112 );
113 let mut repr = <Fr as PrimeField>::Repr::default();
114 repr.copy_from_slice(raw);
115 Ok(PoseidonDomain(repr))
116 }
117
118 fn write_bytes(&self, dest: &mut [u8]) -> anyhow::Result<()> {
119 ensure!(
120 dest.len() == PoseidonDomain::byte_len(),
121 "invalid amount of bytes"
122 );
123 dest.copy_from_slice(&self.0);
124 Ok(())
125 }
126
127 fn random<R: RngCore>(rng: &mut R) -> Self {
128 Fr::random(rng).into()
130 }
131}
132
133impl Element for PoseidonDomain {
134 fn byte_len() -> usize {
135 32
136 }
137
138 fn from_slice(bytes: &[u8]) -> Self {
139 match PoseidonDomain::try_from_bytes(bytes) {
140 Ok(res) => res,
141 Err(err) => panic_any(err),
142 }
143 }
144
145 fn copy_to_slice(&self, bytes: &mut [u8]) {
146 bytes.copy_from_slice(&self.0);
147 }
148}
149
150impl StdHasher for PoseidonFunction {
151 #[inline]
152 fn write(&mut self, msg: &[u8]) {
153 self.0 = Fr::from_repr_vartime(shared_hash(msg).0).expect("from_repr failure");
154 }
155
156 #[inline]
157 fn finish(&self) -> u64 {
158 unimplemented!()
159 }
160}
161
162fn shared_hash(data: &[u8]) -> PoseidonDomain {
163 let preimage = data
166 .chunks(32)
167 .map(|chunk| {
168 Fr::from_repr_vartime(PoseidonDomain::from_slice(chunk).0).expect("from_repr failure")
169 })
170 .collect::<Vec<_>>();
171
172 shared_hash_frs(&preimage).into()
173}
174
175fn shared_hash_frs(preimage: &[Fr]) -> Fr {
176 match preimage.len() {
177 2 => {
178 let mut p = Poseidon::new_with_preimage(preimage, &POSEIDON_CONSTANTS_2);
179 p.hash()
180 }
181 4 => {
182 let mut p = Poseidon::new_with_preimage(preimage, &POSEIDON_CONSTANTS_4);
183 p.hash()
184 }
185 8 => {
186 let mut p = Poseidon::new_with_preimage(preimage, &POSEIDON_CONSTANTS_8);
187 p.hash()
188 }
189 16 => {
190 let mut p = Poseidon::new_with_preimage(preimage, &POSEIDON_CONSTANTS_16);
191 p.hash()
192 }
193
194 _ => panic_any(format!(
195 "Unsupported arity for Poseidon hasher: {}",
196 preimage.len()
197 )),
198 }
199}
200
201impl HashFunction<PoseidonDomain> for PoseidonFunction {
202 fn hash(data: &[u8]) -> PoseidonDomain {
203 shared_hash(data)
204 }
205
206 fn hash2(a: &PoseidonDomain, b: &PoseidonDomain) -> PoseidonDomain {
207 let mut p =
208 Poseidon::new_with_preimage(&[(*a).into(), (*b).into()][..], &*POSEIDON_CONSTANTS_2);
209 let fr: Fr = p.hash();
210 fr.into()
211 }
212
213 fn hash_md(input: &[PoseidonDomain]) -> PoseidonDomain {
214 assert!(input.len() > 1, "hash_md needs more than one element.");
215 let arity = PoseidonMDArity::to_usize();
216
217 let mut p = Poseidon::new(&*POSEIDON_MD_CONSTANTS);
218
219 let fr_input = input
220 .iter()
221 .map(|x| Fr::from_repr_vartime(x.0).expect("from_repr failure"))
222 .collect::<Vec<_>>();
223
224 fr_input[1..]
225 .chunks(arity - 1)
226 .fold(fr_input[0], |acc, elts| {
227 p.reset();
228 p.input(acc).expect("input failure"); elts.iter().for_each(|elt| {
230 let _ = p.input(*elt).expect("input failure");
231 });
232 p.hash()
233 })
234 .into()
235 }
236
237 fn hash_leaf_circuit<CS: ConstraintSystem<Fr>>(
238 cs: CS,
239 left: &AllocatedNum<Fr>,
240 right: &AllocatedNum<Fr>,
241 _height: usize,
242 ) -> Result<AllocatedNum<Fr>, SynthesisError> {
243 let preimage = vec![left.clone(), right.clone()];
244
245 poseidon_hash::<CS, Fr, U2>(cs, preimage, U2::PARAMETERS())
246 }
247
248 fn hash_multi_leaf_circuit<Arity: 'static + PoseidonArity, CS: ConstraintSystem<Fr>>(
249 cs: CS,
250 leaves: &[AllocatedNum<Fr>],
251 _height: usize,
252 ) -> Result<AllocatedNum<Fr>, SynthesisError> {
253 let params = Arity::PARAMETERS();
254 poseidon_hash::<CS, Fr, Arity>(cs, leaves.to_vec(), params)
255 }
256
257 fn hash_md_circuit<CS: ConstraintSystem<Fr>>(
258 cs: &mut CS,
259 elements: &[AllocatedNum<Fr>],
260 ) -> Result<AllocatedNum<Fr>, SynthesisError> {
261 let params = PoseidonMDArity::PARAMETERS();
262 let arity = PoseidonMDArity::to_usize();
263
264 let mut hash = elements[0].clone();
265 let mut preimage = vec![hash.clone(); arity]; for (hash_num, elts) in elements[1..].chunks(arity - 1).enumerate() {
267 preimage[0] = hash;
268 for (i, elt) in elts.iter().enumerate() {
269 preimage[i + 1] = elt.clone();
270 }
271 #[allow(clippy::needless_range_loop)]
273 for i in (elts.len() + 1)..arity {
274 preimage[i] =
275 AllocatedNum::alloc(cs.namespace(|| format!("padding {}", i)), || Ok(Fr::ZERO))
276 .expect("alloc failure");
277 }
278 let cs = cs.namespace(|| format!("hash md {}", hash_num));
279 hash = poseidon_hash::<_, Fr, PoseidonMDArity>(cs, preimage.clone(), params)?.clone();
280 }
281
282 Ok(hash)
283 }
284
285 fn hash_circuit<CS: ConstraintSystem<Fr>>(
286 _cs: CS,
287 _bits: &[Boolean],
288 ) -> Result<AllocatedNum<Fr>, SynthesisError> {
289 unimplemented!();
290 }
291
292 fn hash2_circuit<CS>(
293 cs: CS,
294 a: &AllocatedNum<Fr>,
295 b: &AllocatedNum<Fr>,
296 ) -> Result<AllocatedNum<Fr>, SynthesisError>
297 where
298 CS: ConstraintSystem<Fr>,
299 {
300 let preimage = vec![a.clone(), b.clone()];
301 poseidon_hash::<CS, Fr, U2>(cs, preimage, U2::PARAMETERS())
302 }
303}
304
305impl LightAlgorithm<PoseidonDomain> for PoseidonFunction {
306 #[inline]
307 fn hash(&mut self) -> PoseidonDomain {
308 self.0.into()
309 }
310
311 #[inline]
312 fn reset(&mut self) {
313 self.0 = Fr::ZERO;
314 }
315
316 fn leaf(&mut self, leaf: PoseidonDomain) -> PoseidonDomain {
317 leaf
318 }
319
320 fn node(
321 &mut self,
322 left: PoseidonDomain,
323 right: PoseidonDomain,
324 _height: usize,
325 ) -> PoseidonDomain {
326 shared_hash_frs(&[
327 Fr::from_repr_vartime(left.0).expect("from_repr failure"),
328 Fr::from_repr_vartime(right.0).expect("from_repr failure"),
329 ])
330 .into()
331 }
332
333 fn multi_node(&mut self, parts: &[PoseidonDomain], _height: usize) -> PoseidonDomain {
334 match parts.len() {
335 1 | 2 | 4 | 8 | 16 => shared_hash_frs(
336 &parts
337 .iter()
338 .enumerate()
339 .map(|(i, x)| {
340 if let Some(fr) = Fr::from_repr_vartime(x.0) {
341 fr
342 } else {
343 panic_any(format!("from_repr failure at {}", i));
344 }
345 })
346 .collect::<Vec<_>>(),
347 )
348 .into(),
349 arity => panic_any(format!("unsupported arity {}", arity)),
350 }
351 }
352}
353
354impl From<Fr> for PoseidonDomain {
355 #[inline]
356 fn from(val: Fr) -> Self {
357 PoseidonDomain(val.to_repr())
358 }
359}
360
361impl From<[u8; 32]> for PoseidonDomain {
362 #[inline]
363 fn from(val: [u8; 32]) -> Self {
364 PoseidonDomain(val)
365 }
366}
367
368impl From<PoseidonDomain> for [u8; 32] {
369 #[inline]
370 fn from(val: PoseidonDomain) -> Self {
371 val.0
372 }
373}
374
375impl From<PoseidonDomain> for Fr {
376 #[inline]
377 fn from(val: PoseidonDomain) -> Self {
378 Fr::from_repr_vartime(val.0).expect("from_repr failure")
379 }
380}
381
382#[cfg(test)]
383mod tests {
384 use super::*;
385
386 use bellperson::util_cs::test_cs::TestConstraintSystem;
387 use merkletree::{merkle::MerkleTree, store::VecStore};
388
389 fn u64s_to_u8s(u64s: [u64; 4]) -> [u8; 32] {
390 let mut bytes = [0u8; 32];
391 bytes[..8].copy_from_slice(&u64s[0].to_le_bytes());
392 bytes[8..16].copy_from_slice(&u64s[1].to_le_bytes());
393 bytes[16..24].copy_from_slice(&u64s[2].to_le_bytes());
394 bytes[24..].copy_from_slice(&u64s[3].to_le_bytes());
395 bytes
396 }
397
398 #[test]
399 fn test_path() {
400 let values = [
401 PoseidonDomain(Fr::ONE.to_repr()),
402 PoseidonDomain(Fr::ONE.to_repr()),
403 PoseidonDomain(Fr::ONE.to_repr()),
404 PoseidonDomain(Fr::ONE.to_repr()),
405 ];
406
407 let t = MerkleTree::<PoseidonDomain, PoseidonFunction, VecStore<_>, U2>::new(
408 values.iter().copied(),
409 )
410 .expect("merkle tree new failure");
411
412 let p = t.gen_proof(0).expect("gen_proof failure"); assert_eq!(*p.path(), vec![0, 0]);
415 assert!(p
416 .validate::<PoseidonFunction>()
417 .expect("failed to validate"));
418 }
419
420 #[test]
428 fn test_poseidon_hasher() {
429 let leaves = [
430 PoseidonDomain(Fr::ONE.to_repr()),
431 PoseidonDomain(Fr::ZERO.to_repr()),
432 PoseidonDomain(Fr::ZERO.to_repr()),
433 PoseidonDomain(Fr::ONE.to_repr()),
434 ];
435
436 let t = MerkleTree::<PoseidonDomain, PoseidonFunction, VecStore<_>, U2>::new(
437 leaves.iter().copied(),
438 )
439 .expect("merkle tree new failure");
440
441 assert_eq!(t.leafs(), 4);
442
443 let mut a = PoseidonFunction::default();
444
445 assert_eq!(t.read_at(0).expect("read_at failure"), leaves[0]);
446 assert_eq!(t.read_at(1).expect("read_at failure"), leaves[1]);
447 assert_eq!(t.read_at(2).expect("read_at failure"), leaves[2]);
448 assert_eq!(t.read_at(3).expect("read_at failure"), leaves[3]);
449
450 let i1 = a.node(leaves[0], leaves[1], 0);
451 a.reset();
452 let i2 = a.node(leaves[2], leaves[3], 0);
453 a.reset();
454
455 assert_eq!(t.read_at(4).expect("read_at failure"), i1);
456 assert_eq!(t.read_at(5).expect("read_at failure"), i2);
457
458 let root = a.node(i1, i2, 1);
459 a.reset();
460
461 assert_eq!(
462 t.read_at(4).expect("read_at failure").0,
463 u64s_to_u8s([
464 0xb339ff6079800b5e,
465 0xec5907b3dc3094af,
466 0x93c003cc74a24f26,
467 0x042f94ffbe786bc3,
468 ]),
469 );
470
471 let expected = u64s_to_u8s([
472 0xefbb8be3e291e671,
473 0x77cc72b8cb2b5ad2,
474 0x30eb6385ae6b74ae,
475 0x1effebb7b26ad9eb,
476 ]);
477 let actual = t.read_at(6).expect("read_at failure").0;
478
479 assert_eq!(actual, expected);
480 assert_eq!(t.read_at(6).expect("read_at failure"), root);
481 }
482
483 #[test]
484 fn test_as_ref() {
485 let cases: Vec<[u64; 4]> = vec![
486 [0, 0, 0, 0],
487 [
488 14963070332212552755,
489 2414807501862983188,
490 16116531553419129213,
491 6357427774790868134,
492 ],
493 ];
494
495 for case in cases.into_iter() {
496 let val = PoseidonDomain(u64s_to_u8s(case));
497
498 for _ in 0..100 {
499 assert_eq!(val.into_bytes(), val.into_bytes());
500 }
501
502 let raw: &[u8] = val.as_ref();
503
504 for (limb, bytes) in case.iter().zip(raw.chunks(8)) {
505 assert_eq!(&limb.to_le_bytes(), bytes);
506 }
507 }
508 }
509
510 #[test]
511 fn test_serialize() {
512 let val = PoseidonDomain(u64s_to_u8s([1, 2, 3, 4]));
513
514 let ser = serde_json::to_string(&val)
515 .expect("Failed to serialize `PoseidonDomain` element to JSON string");
516 let val_back = serde_json::from_str(&ser)
517 .expect("Failed to deserialize JSON string to `PoseidonnDomain`");
518
519 assert_eq!(val, val_back);
520 }
521
522 #[test]
523 fn test_hash_md() {
524 let n = 71;
526 let data = vec![PoseidonDomain(Fr::ONE.to_repr()); n];
527 let hashed = PoseidonFunction::hash_md(&data);
528
529 assert_eq!(
530 hashed,
531 PoseidonDomain(u64s_to_u8s([
532 0x351c54133b332c90,
533 0xc26f6d625f4e8195,
534 0x5fd9623643ed9622,
535 0x59f42220e09ff6f7,
536 ]))
537 );
538 }
539 #[test]
540 fn test_hash_md_circuit() {
541 let n = 71;
543 let data = vec![PoseidonDomain(Fr::ONE.to_repr()); n];
544
545 let mut cs = TestConstraintSystem::<Fr>::new();
546 let circuit_data = (0..n)
547 .map(|n| {
548 AllocatedNum::alloc(cs.namespace(|| format!("input {}", n)), || Ok(Fr::ONE))
549 .expect("alloc failure")
550 })
551 .collect::<Vec<_>>();
552
553 let hashed = PoseidonFunction::hash_md(&data);
554 let hashed_fr = Fr::from_repr_vartime(hashed.0).expect("from_repr failure");
555
556 let circuit_hashed = PoseidonFunction::hash_md_circuit(&mut cs, circuit_data.as_slice())
557 .expect("hash_md_circuit failure");
558
559 assert!(cs.is_satisfied());
560 let expected_constraints = 2_770;
561 let actual_constraints = cs.num_constraints();
562
563 assert_eq!(expected_constraints, actual_constraints);
564
565 assert_eq!(
566 hashed_fr,
567 circuit_hashed.get_value().expect("get_value failure")
568 );
569 }
570}