sapling_crypto_ce/alt_babyjubjub/
mod.rs1use bellman::pairing::ff::{
41 Field,
42 PrimeField,
43};
44
45use group_hash::{baby_group_hash, generic_group_hash};
46
47use constants;
48
49use bellman::pairing::bn256::{
50 Bn256,
51 Fr
52};
53
54pub use super::jubjub::{
55 Unknown,
56 PrimeOrder,
57 FixedGenerators,
58 ToUniform,
59 JubjubEngine,
60 JubjubParams,
61 edwards,
62 montgomery
63};
64
65pub mod fs;
74
75#[cfg(test)]
76pub mod tests;
77
78use super::group_hash::GroupHasher;
79
80impl JubjubEngine for Bn256 {
81 type Fs = self::fs::Fs;
82 type Params = AltJubjubBn256;
83}
84#[derive(Clone)]
85pub struct AltJubjubBn256 {
86 edwards_d: Fr,
87 montgomery_a: Fr,
88 montgomery_2a: Fr,
89 scale: Fr,
90
91 pedersen_hash_generators: Vec<edwards::Point<Bn256, PrimeOrder>>,
92 pedersen_hash_exp: Vec<Vec<Vec<edwards::Point<Bn256, PrimeOrder>>>>,
93 pedersen_circuit_generators: Vec<Vec<Vec<(Fr, Fr)>>>,
94
95 fixed_base_generators: Vec<edwards::Point<Bn256, PrimeOrder>>,
96 fixed_base_circuit_generators: Vec<Vec<Vec<(Fr, Fr)>>>,
97}
98
99impl JubjubParams<Bn256> for AltJubjubBn256 {
100 fn edwards_d(&self) -> &Fr { &self.edwards_d }
101 fn montgomery_a(&self) -> &Fr { &self.montgomery_a }
102 fn montgomery_2a(&self) -> &Fr { &self.montgomery_2a }
103 fn scale(&self) -> &Fr { &self.scale }
104 fn pedersen_hash_generators(&self) -> &[edwards::Point<Bn256, PrimeOrder>] {
105 &self.pedersen_hash_generators
106 }
107 fn pedersen_hash_exp_table(&self) -> &[Vec<Vec<edwards::Point<Bn256, PrimeOrder>>>] {
108 &self.pedersen_hash_exp
109 }
110 fn pedersen_hash_chunks_per_generator(&self) -> usize {
111 62
112 }
113 fn fixed_base_chunks_per_generator(&self) -> usize {
114 84
115 }
116 fn pedersen_circuit_generators(&self) -> &[Vec<Vec<(Fr, Fr)>>] {
117 &self.pedersen_circuit_generators
118 }
119 fn generator(&self, base: FixedGenerators) -> &edwards::Point<Bn256, PrimeOrder>
120 {
121 &self.fixed_base_generators[base as usize]
122 }
123 fn circuit_generators(&self, base: FixedGenerators) -> &[Vec<(Fr, Fr)>]
124 {
125 &self.fixed_base_circuit_generators[base as usize][..]
126 }
127 fn pedersen_hash_exp_window_size(&self) -> u32 {
128 8
129 }
130}
131
132impl AltJubjubBn256 {
133 pub fn new() -> Self {
134 let montgomery_a = Fr::from_str("168698").unwrap();
135 let mut montgomery_2a = montgomery_a;
136 montgomery_2a.double();
137
138 let mut tmp_params = AltJubjubBn256 {
139 edwards_d: Fr::from_str("12181644023421730124874158521699555681764249180949974110617291017600649128846").unwrap(),
141 montgomery_a: montgomery_a,
143 montgomery_2a: montgomery_2a,
145 scale: Fr::from_str("6360561867910373094066688120553762416144456282423235903351243436111059670888").unwrap(),
147
148 pedersen_hash_generators: vec![],
150 pedersen_hash_exp: vec![],
151 pedersen_circuit_generators: vec![],
152 fixed_base_generators: vec![],
153 fixed_base_circuit_generators: vec![],
154 };
155
156 fn find_group_hash<E: JubjubEngine>(
157 m: &[u8],
158 personalization: &[u8; 8],
159 params: &E::Params
160 ) -> edwards::Point<E, PrimeOrder>
161 {
162 let mut tag = m.to_vec();
163 let i = tag.len();
164 tag.push(0u8);
165
166 loop {
167 let gh = baby_group_hash(
168 &tag,
169 personalization,
170 params
171 );
172
173 assert!(tag[i] != u8::max_value());
175 tag[i] += 1;
176
177 if let Some(gh) = gh {
178 break gh;
179 }
180 }
181 }
182
183 {
185 let mut pedersen_hash_generators = vec![];
186
187 for m in 0..5 {
188 use byteorder::{WriteBytesExt, LittleEndian};
189
190 let mut segment_number = [0u8; 4];
191 (&mut segment_number[0..4]).write_u32::<LittleEndian>(m).unwrap();
192
193 pedersen_hash_generators.push(
194 find_group_hash(
195 &segment_number,
196 constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION,
197 &tmp_params
198 )
199 );
200 }
201
202 for (i, p1) in pedersen_hash_generators.iter().enumerate() {
204 if p1 == &edwards::Point::zero() {
205 panic!("Neutral element!");
206 }
207
208 for p2 in pedersen_hash_generators.iter().skip(i+1) {
209 if p1 == p2 {
210 panic!("Duplicate generator!");
211 }
212 }
213 }
214
215 tmp_params.pedersen_hash_generators = pedersen_hash_generators;
216 }
217
218 {
220 let mut pedersen_hash_exp = vec![];
221
222 for g in &tmp_params.pedersen_hash_generators {
223 let mut g = g.clone();
224
225 let window = tmp_params.pedersen_hash_exp_window_size();
226
227 let mut tables = vec![];
228
229 let mut num_bits = 0;
230 while num_bits <= fs::Fs::NUM_BITS {
231 let mut table = Vec::with_capacity(1 << window);
232
233 let mut base = edwards::Point::zero();
234
235 for _ in 0..(1 << window) {
236 table.push(base.clone());
237 base = base.add(&g, &tmp_params);
238 }
239
240 tables.push(table);
241 num_bits += window;
242
243 for _ in 0..window {
244 g = g.double(&tmp_params);
245 }
246 }
247
248 pedersen_hash_exp.push(tables);
249 }
250
251 tmp_params.pedersen_hash_exp = pedersen_hash_exp;
252 }
253
254 {
256 let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize];
257
258 fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] =
259 find_group_hash(&[], constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION, &tmp_params);
260
261 fixed_base_generators[FixedGenerators::NoteCommitmentRandomness as usize] =
262 find_group_hash(b"r", constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, &tmp_params);
263
264 fixed_base_generators[FixedGenerators::NullifierPosition as usize] =
265 find_group_hash(&[], constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION, &tmp_params);
266
267 fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] =
268 find_group_hash(b"v", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params);
269
270 fixed_base_generators[FixedGenerators::ValueCommitmentRandomness as usize] =
271 find_group_hash(b"r", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params);
272
273 fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] =
274 find_group_hash(&[], constants::SPENDING_KEY_GENERATOR_PERSONALIZATION, &tmp_params);
275
276 for (i, p1) in fixed_base_generators.iter().enumerate() {
278 if p1 == &edwards::Point::zero() {
279 panic!("Neutral element!");
280 }
281
282 for p2 in fixed_base_generators.iter().skip(i+1) {
283 if p1 == p2 {
284 panic!("Duplicate generator!");
285 }
286 }
287 }
288
289 tmp_params.fixed_base_generators = fixed_base_generators;
290 }
291
292 {
295 let mut pedersen_circuit_generators = vec![];
296
297 for gen in tmp_params.pedersen_hash_generators.iter().cloned() {
299 let mut gen = montgomery::Point::from_edwards(&gen, &tmp_params);
300 let mut windows = vec![];
301 for _ in 0..tmp_params.pedersen_hash_chunks_per_generator() {
302 let mut coeffs = vec![];
304 let mut g = gen.clone();
305
306 for _ in 0..4 {
308 coeffs.push(g.into_xy().expect("cannot produce O"));
309 g = g.add(&gen, &tmp_params);
310 }
311 windows.push(coeffs);
312
313 for _ in 0..4 {
315 gen = gen.double(&tmp_params);
316 }
317 }
318 pedersen_circuit_generators.push(windows);
319 }
320
321 tmp_params.pedersen_circuit_generators = pedersen_circuit_generators;
322 }
323
324 {
327 let mut fixed_base_circuit_generators = vec![];
328
329 for mut gen in tmp_params.fixed_base_generators.iter().cloned() {
330 let mut windows = vec![];
331 for _ in 0..tmp_params.fixed_base_chunks_per_generator() {
332 let mut coeffs = vec![(Fr::zero(), Fr::one())];
333 let mut g = gen.clone();
334 for _ in 0..7 {
335 coeffs.push(g.into_xy());
336 g = g.add(&gen, &tmp_params);
337 }
338 windows.push(coeffs);
339
340 gen = g;
342 }
343 fixed_base_circuit_generators.push(windows);
344 }
345
346 tmp_params.fixed_base_circuit_generators = fixed_base_circuit_generators;
347 }
348
349 tmp_params
350 }
351
352 pub fn new_with_hasher<H: GroupHasher>() -> Self {
353 let montgomery_a = Fr::from_str("168698").unwrap();
354 let mut montgomery_2a = montgomery_a;
355 montgomery_2a.double();
356
357 let mut tmp_params = AltJubjubBn256 {
358 edwards_d: Fr::from_str("12181644023421730124874158521699555681764249180949974110617291017600649128846").unwrap(),
360 montgomery_a: montgomery_a,
362 montgomery_2a: montgomery_2a,
364 scale: Fr::from_str("6360561867910373094066688120553762416144456282423235903351243436111059670888").unwrap(),
366
367 pedersen_hash_generators: vec![],
369 pedersen_hash_exp: vec![],
370 pedersen_circuit_generators: vec![],
371 fixed_base_generators: vec![],
372 fixed_base_circuit_generators: vec![],
373 };
374
375 fn find_group_hash<E: JubjubEngine, HH: GroupHasher>(
376 m: &[u8],
377 personalization: &[u8; 8],
378 params: &E::Params
379 ) -> edwards::Point<E, PrimeOrder>
380 {
381 let mut tag = m.to_vec();
382 let i = tag.len();
383 tag.push(0u8);
384
385 loop {
386 let gh = generic_group_hash::<_, HH>(
387 &tag,
388 personalization,
389 params
390 );
391
392 assert!(tag[i] != u8::max_value());
394 tag[i] += 1;
395
396 if let Some(gh) = gh {
397 break gh;
398 }
399 }
400 }
401
402 {
404 let mut pedersen_hash_generators = vec![];
405
406 for m in 0..5 {
407 use byteorder::{WriteBytesExt, LittleEndian};
408
409 let mut segment_number = [0u8; 4];
410 (&mut segment_number[0..4]).write_u32::<LittleEndian>(m).unwrap();
411
412 pedersen_hash_generators.push(
413 find_group_hash::<_, H>(
414 &segment_number,
415 constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION,
416 &tmp_params
417 )
418 );
419 }
420
421 for (i, p1) in pedersen_hash_generators.iter().enumerate() {
423 if p1 == &edwards::Point::zero() {
424 panic!("Neutral element!");
425 }
426
427 for p2 in pedersen_hash_generators.iter().skip(i+1) {
428 if p1 == p2 {
429 panic!("Duplicate generator!");
430 }
431 }
432 }
433
434 tmp_params.pedersen_hash_generators = pedersen_hash_generators;
435 }
436
437 {
439 let mut pedersen_hash_exp = vec![];
440
441 for g in &tmp_params.pedersen_hash_generators {
442 let mut g = g.clone();
443
444 let window = tmp_params.pedersen_hash_exp_window_size();
445
446 let mut tables = vec![];
447
448 let mut num_bits = 0;
449 while num_bits <= fs::Fs::NUM_BITS {
450 let mut table = Vec::with_capacity(1 << window);
451
452 let mut base = edwards::Point::zero();
453
454 for _ in 0..(1 << window) {
455 table.push(base.clone());
456 base = base.add(&g, &tmp_params);
457 }
458
459 tables.push(table);
460 num_bits += window;
461
462 for _ in 0..window {
463 g = g.double(&tmp_params);
464 }
465 }
466
467 pedersen_hash_exp.push(tables);
468 }
469
470 tmp_params.pedersen_hash_exp = pedersen_hash_exp;
471 }
472
473 {
475 let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize];
476
477 fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] =
478 find_group_hash::<_, H>(&[], constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION, &tmp_params);
479
480 fixed_base_generators[FixedGenerators::NoteCommitmentRandomness as usize] =
481 find_group_hash::<_, H>(b"r", constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, &tmp_params);
482
483 fixed_base_generators[FixedGenerators::NullifierPosition as usize] =
484 find_group_hash::<_, H>(&[], constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION, &tmp_params);
485
486 fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] =
487 find_group_hash::<_, H>(b"v", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params);
488
489 fixed_base_generators[FixedGenerators::ValueCommitmentRandomness as usize] =
490 find_group_hash::<_, H>(b"r", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params);
491
492 fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] =
493 find_group_hash::<_, H>(&[], constants::SPENDING_KEY_GENERATOR_PERSONALIZATION, &tmp_params);
494
495 for (i, p1) in fixed_base_generators.iter().enumerate() {
497 if p1 == &edwards::Point::zero() {
498 panic!("Neutral element!");
499 }
500
501 for p2 in fixed_base_generators.iter().skip(i+1) {
502 if p1 == p2 {
503 panic!("Duplicate generator!");
504 }
505 }
506 }
507
508 tmp_params.fixed_base_generators = fixed_base_generators;
509 }
510
511 {
514 let mut pedersen_circuit_generators = vec![];
515
516 for gen in tmp_params.pedersen_hash_generators.iter().cloned() {
518 let mut gen = montgomery::Point::from_edwards(&gen, &tmp_params);
519 let mut windows = vec![];
520 for _ in 0..tmp_params.pedersen_hash_chunks_per_generator() {
521 let mut coeffs = vec![];
523 let mut g = gen.clone();
524
525 for _ in 0..4 {
527 coeffs.push(g.into_xy().expect("cannot produce O"));
528 g = g.add(&gen, &tmp_params);
529 }
530 windows.push(coeffs);
531
532 for _ in 0..4 {
534 gen = gen.double(&tmp_params);
535 }
536 }
537 pedersen_circuit_generators.push(windows);
538 }
539
540 tmp_params.pedersen_circuit_generators = pedersen_circuit_generators;
541 }
542
543 {
546 let mut fixed_base_circuit_generators = vec![];
547
548 for mut gen in tmp_params.fixed_base_generators.iter().cloned() {
549 let mut windows = vec![];
550 for _ in 0..tmp_params.fixed_base_chunks_per_generator() {
551 let mut coeffs = vec![(Fr::zero(), Fr::one())];
552 let mut g = gen.clone();
553 for _ in 0..7 {
554 coeffs.push(g.into_xy());
555 g = g.add(&gen, &tmp_params);
556 }
557 windows.push(coeffs);
558
559 gen = g;
561 }
562 fixed_base_circuit_generators.push(windows);
563 }
564
565 tmp_params.fixed_base_circuit_generators = fixed_base_circuit_generators;
566 }
567
568 tmp_params
569 }
570}
571
572#[test]
573fn test_jubjub_altbn256() {
574 let params = AltJubjubBn256::new();
575
576 tests::test_suite::<Bn256>(¶ms);
577
578 }
599
600#[test]
601fn test_generic_params() {
602 use super::group_hash::BlakeHasher;
603
604 let params = AltJubjubBn256::new();
605 let generic_params = AltJubjubBn256::new_with_hasher::<BlakeHasher>();
606
607 assert!(params.pedersen_hash_generators == generic_params.pedersen_hash_generators);
608 assert!(params.fixed_base_generators == generic_params.fixed_base_generators);
609
610 assert_eq!(params.pedersen_circuit_generators, generic_params.pedersen_circuit_generators);
611 assert_eq!(params.fixed_base_circuit_generators, generic_params.fixed_base_circuit_generators);
612}
613
614#[test]
615fn pretty_print_params_for_blake() {
616 use super::group_hash::BlakeHasher;
617
618 let generic_params = AltJubjubBn256::new_with_hasher::<BlakeHasher>();
619
620 println!("Creating generators using Blake2s");
621
622 println!("Using personalization `{}`", std::str::from_utf8(constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION).unwrap());
623
624 println!("Pedersen hash generators:");
625
626 for (i, e) in generic_params.pedersen_hash_generators.iter().enumerate() {
627 let (x, y) = e.into_xy();
628 println!("Generator {}", i);
629 println!("X = {}", x);
630 println!("Y = {}", y);
631 }
632}
633
634#[test]
635fn pretty_print_params_for_keccak() {
636 use super::group_hash::Keccak256Hasher;
637
638 let generic_params = AltJubjubBn256::new_with_hasher::<Keccak256Hasher>();
639
640 println!("Creating generators using Keccak256 (Ethereum style)");
641
642 println!("Using personalization `{}`", std::str::from_utf8(constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION).unwrap());
643
644 println!("Pedersen hash generators:");
645
646 for (i, e) in generic_params.pedersen_hash_generators.iter().enumerate() {
647 let (x, y) = e.into_xy();
648 println!("Generator {}", i);
649 println!("X = {}", x);
650 println!("Y = {}", y);
651 }
652}