Skip to main content

sapling_crypto_ce/
baby_pedersen_hash.rs

1use babyjubjub::*;
2use bellman::pairing::ff::{Field, PrimeField, PrimeFieldRepr};
3
4#[derive(Copy, Clone)]
5pub enum Personalization {
6    NoteCommitment,
7    MerkleTree(usize)
8}
9
10impl Personalization {
11    pub fn get_bits(&self) -> Vec<bool> {
12        match *self {
13            Personalization::NoteCommitment =>
14                vec![true, true, true, true, true, true],
15            Personalization::MerkleTree(num) => {
16                assert!(num < 62);
17
18                (0..6).map(|i| (num >> i) & 1 == 1).collect()
19            }
20        }
21    }
22}
23
24pub fn pedersen_hash<E, I>(
25    personalization: Personalization,
26    bits: I,
27    params: &E::Params
28) -> edwards::Point<E, PrimeOrder>
29    where I: IntoIterator<Item=bool>,
30          E: JubjubEngine
31{
32    let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter());
33
34    let mut result = edwards::Point::zero();
35    let mut generators = params.pedersen_hash_exp_table().iter();
36
37    loop {
38        let mut acc = E::Fs::zero();
39        let mut cur = E::Fs::one();
40        let mut chunks_remaining = params.pedersen_hash_chunks_per_generator();
41        let mut encountered_bits = false;
42
43        // Grab three bits from the input
44        while let Some(a) = bits.next() {
45            encountered_bits = true;
46
47            let b = bits.next().unwrap_or(false);
48            let c = bits.next().unwrap_or(false);
49
50            // Start computing this portion of the scalar
51            let mut tmp = cur;
52            if a {
53                tmp.add_assign(&cur);
54            }
55            cur.double(); // 2^1 * cur
56            if b {
57                tmp.add_assign(&cur);
58            }
59
60            // conditionally negate
61            if c {
62                tmp.negate();
63            }
64
65            acc.add_assign(&tmp);
66
67            chunks_remaining -= 1;
68
69            if chunks_remaining == 0 {
70                break;
71            } else {
72                cur.double(); // 2^2 * cur
73                cur.double(); // 2^3 * cur
74                cur.double(); // 2^4 * cur
75            }
76        }
77
78        if !encountered_bits {
79            break;
80        }
81
82        let mut table: &[Vec<edwards::Point<E, _>>] = &generators.next().expect("we don't have enough generators");
83        let window = JubjubBn256::pedersen_hash_exp_window_size();
84        let window_mask = (1 << window) - 1;
85
86        let mut acc = acc.into_repr();
87        
88        let mut tmp = edwards::Point::zero();
89
90        while !acc.is_zero() {
91            let i = (acc.as_ref()[0] & window_mask) as usize;
92
93            tmp = tmp.add(&table[0][i], params);
94
95            acc.shr(window);
96            table = &table[1..];
97        }
98
99        result = result.add(&tmp, params);
100    }
101
102    result
103}