sapling_crypto_ce/
group_hash.rs1use 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
81pub 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 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
115pub 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 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
149pub 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 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[..], ¶ms);
194 let generic_point = generic_group_hash::<Bn256, BlakeHasher>(&tag, &personalization[..], ¶ms);
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[..], ¶ms);
210 let generic_point = generic_group_hash::<Bn256, BlakeHasher>(&tag, &personalization[..], ¶ms);
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}