sapling_crypto_ce/
group_hash.rs

1use jubjub::{
2    JubjubEngine,
3    PrimeOrder,
4    edwards
5};
6
7use bellman::pairing::ff::{
8    PrimeField
9};
10
11use tiny_keccak::{Keccak, Hasher};
12use blake2_rfc::blake2s::Blake2s;
13use constants;
14
15pub trait GroupHasher {
16    fn new(personalization: &[u8]) -> Self;
17    fn update(&mut self, data: &[u8]);
18    fn finalize(&mut self) -> Vec<u8>;
19}
20
21pub struct BlakeHasher {
22    h: Blake2s
23}
24
25impl GroupHasher for BlakeHasher {
26    fn new(personalization: &[u8]) -> Self {
27        let h = Blake2s::with_params(32, &[], &[], personalization);
28
29        Self {
30            h: h
31        }
32    }
33
34    fn update(&mut self, data: &[u8]) {
35        self.h.update(data);
36    }
37
38    fn finalize(&mut self) -> Vec<u8> {
39        use std::mem;
40
41        let new_h = Blake2s::with_params(32, &[], &[], &[]);
42        let h = std::mem::replace(&mut self.h, new_h);
43
44        let result = h.finalize();
45
46        result.as_ref().to_vec().clone()
47    }
48}
49
50pub struct Keccak256Hasher {
51    h: Keccak
52}
53
54impl GroupHasher for Keccak256Hasher {
55    fn new(personalization: &[u8]) -> Self {
56        let mut h = Keccak::v256();
57        h.update(personalization);
58
59        Self {
60            h: h
61        }
62    }
63
64    fn update(&mut self, data: &[u8]) {
65        self.h.update(data);
66    }
67
68    fn finalize(&mut self) -> Vec<u8> {
69        use std::mem;
70
71        let new_h = Keccak::v256();
72        let h = std::mem::replace(&mut self.h, new_h);
73
74        let mut res: [u8; 32] = [0; 32];
75        h.finalize(&mut res);
76
77        res[..].to_vec()
78    }
79}
80
81/// Produces a random point in the Jubjub curve.
82/// The point is guaranteed to be prime order
83/// and not the identity.
84pub fn group_hash<E: JubjubEngine>(
85    tag: &[u8],
86    personalization: &[u8],
87    params: &E::Params
88) -> Option<edwards::Point<E, PrimeOrder>>
89{
90    assert_eq!(personalization.len(), 8);
91
92    // Check to see that scalar field is 255 bits
93    assert!(E::Fr::NUM_BITS == 255);
94
95    let mut h = Blake2s::with_params(32, &[], &[], personalization);
96    h.update(constants::GH_FIRST_BLOCK);
97    h.update(tag);
98    let h = h.finalize().as_ref().to_vec();
99    assert!(h.len() == 32);
100
101    match edwards::Point::<E, _>::read(&h[..], params) {
102        Ok(p) => {
103            let p = p.mul_by_cofactor(params);
104
105            if p != edwards::Point::zero() {
106                Some(p)
107            } else {
108                None
109            }
110        },
111        Err(_) => None
112    }
113}
114
115/// Produces a random point in the Alt Baby Jubjub curve.
116/// The point is guaranteed to be prime order
117/// and not the identity.
118pub fn baby_group_hash<E: JubjubEngine>(
119    tag: &[u8],
120    personalization: &[u8],
121    params: &E::Params
122) -> Option<edwards::Point<E, PrimeOrder>>
123{
124    assert_eq!(personalization.len(), 8);
125
126    // Check to see that scalar field is 255 bits
127    assert!(E::Fr::NUM_BITS == 254);
128
129    let mut h = Blake2s::with_params(32, &[], &[], personalization);
130    h.update(constants::GH_FIRST_BLOCK);
131    h.update(tag);
132    let h = h.finalize().as_ref().to_vec();
133    assert!(h.len() == 32);
134
135    match edwards::Point::<E, _>::read(&h[..], params) {
136        Ok(p) => {
137            let p = p.mul_by_cofactor(params);
138
139            if p != edwards::Point::zero() {
140                Some(p)
141            } else {
142                None
143            }
144        },
145        Err(_) => None
146    }
147}
148
149/// Produces a random point in the Jubjub curve.
150/// The point is guaranteed to be prime order
151/// and not the identity.
152pub fn generic_group_hash<E: JubjubEngine, H: GroupHasher>(
153    tag: &[u8],
154    personalization: &[u8],
155    params: &E::Params
156) -> Option<edwards::Point<E, PrimeOrder>>
157{
158    assert_eq!(personalization.len(), 8);
159
160    // Due to small number of iterations Fr should be close to 255 bits
161    assert!(E::Fr::NUM_BITS == 255 || E::Fr::NUM_BITS == 254);
162
163    let mut h = H::new(personalization);
164    h.update(constants::GH_FIRST_BLOCK);
165    h.update(tag);
166    let h = h.finalize();
167    assert!(h.len() == 32);
168
169    match edwards::Point::<E, _>::read(&h[..], params) {
170        Ok(p) => {
171            let p = p.mul_by_cofactor(params);
172
173            if p != edwards::Point::zero() {
174                Some(p)
175            } else {
176                None
177            }
178        },
179        Err(_) => None
180    }
181}
182
183#[test]
184fn test_generic_hash() {
185    use bellman::pairing::bn256::Bn256;
186    use alt_babyjubjub::JubjubEngine;
187    use alt_babyjubjub::AltJubjubBn256;
188
189    let personalization = b"Hello123";
190    let params = AltJubjubBn256::new();
191    for t in 0u8..=255u8 {
192        let tag = [t];
193        let blake_point = baby_group_hash::<Bn256>(&tag, &personalization[..], &params);
194        let generic_point = generic_group_hash::<Bn256, BlakeHasher>(&tag, &personalization[..], &params);
195        assert!(blake_point == generic_point);
196    }
197}
198
199#[test]
200fn test_export_blake_generators() {
201    use bellman::pairing::bn256::Bn256;
202    use alt_babyjubjub::JubjubEngine;
203    use alt_babyjubjub::AltJubjubBn256;
204
205    let personalization = b"Hello123";
206    let params = AltJubjubBn256::new();
207    for t in 0u8..=255u8 {
208        let tag = [t];
209        let blake_point = baby_group_hash::<Bn256>(&tag, &personalization[..], &params);
210        let generic_point = generic_group_hash::<Bn256, BlakeHasher>(&tag, &personalization[..], &params);
211        assert!(blake_point == generic_point);
212    }
213}
214
215#[test]
216fn blake2s_consistency_test() {
217    let personalization = b"Hello_w!";
218    let tag = b"World_123!";
219    let mut h = Blake2s::with_params(32, &[], &[], personalization);
220    h.update(constants::GH_FIRST_BLOCK);
221    h.update(tag);
222    let h = h.finalize().as_ref().to_vec();
223    let reference = hex!("989e1d96f8d977db95b7fcb59d26fe7f66b4e21e84cdb9387b67aa78ebd07ecf");
224
225    assert_eq!(reference[..], h[..]);
226}