From 821810cd8248df1ede0865e4abc8f280dd6ce8fc Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Wed, 25 Jul 2018 14:46:00 -0600 Subject: [PATCH] Change pedersen hash outside the circuit to use window table lookups. --- benches/pedersen_hash.rs | 23 +++++++++++++++++++ src/jubjub/mod.rs | 49 ++++++++++++++++++++++++++++++++++++++++ src/pedersen_hash.rs | 22 +++++++++++++++--- 3 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 benches/pedersen_hash.rs diff --git a/benches/pedersen_hash.rs b/benches/pedersen_hash.rs new file mode 100644 index 0000000..c5968de --- /dev/null +++ b/benches/pedersen_hash.rs @@ -0,0 +1,23 @@ +#![feature(test)] + +extern crate rand; +extern crate test; +extern crate pairing; +extern crate sapling_crypto; + +use rand::{Rand, thread_rng}; +use pairing::bls12_381::Bls12; +use sapling_crypto::jubjub::JubjubBls12; +use sapling_crypto::pedersen_hash::{pedersen_hash, Personalization}; + +#[bench] +fn bench_pedersen_hash(b: &mut test::Bencher) { + let params = JubjubBls12::new(); + let rng = &mut thread_rng(); + let bits = (0..510).map(|_| bool::rand(rng)).collect::>(); + let personalization = Personalization::MerkleTree(31); + + b.iter(|| { + pedersen_hash::(personalization, bits.clone(), ¶ms) + }); +} diff --git a/src/jubjub/mod.rs b/src/jubjub/mod.rs index 80a7986..51a000a 100644 --- a/src/jubjub/mod.rs +++ b/src/jubjub/mod.rs @@ -112,6 +112,8 @@ pub trait JubjubParams: Sized { fn scale(&self) -> &E::Fr; /// Returns the generators (for each segment) used in all Pedersen commitments. fn pedersen_hash_generators(&self) -> &[edwards::Point]; + /// Returns the exp table for Pedersen hashes. + fn pedersen_hash_exp_table(&self) -> &[Vec>>]; /// Returns the maximum number of chunks per segment of the Pedersen hash. fn pedersen_hash_chunks_per_generator(&self) -> usize; /// Returns the pre-computed window tables [-4, 3, 2, 1, 1, 2, 3, 4] of different @@ -126,6 +128,9 @@ pub trait JubjubParams: Sized { /// Returns a window table [0, 1, ..., 8] for different magnitudes of some /// fixed generator. fn circuit_generators(&self, FixedGenerators) -> &[Vec<(E::Fr, E::Fr)>]; + /// Returns the window size for exponentiation of Pedersen hash generators + /// outside the circuit + fn pedersen_hash_exp_window_size() -> u32; } impl JubjubEngine for Bls12 { @@ -140,6 +145,7 @@ pub struct JubjubBls12 { scale: Fr, pedersen_hash_generators: Vec>, + pedersen_hash_exp: Vec>>>, pedersen_circuit_generators: Vec>>, fixed_base_generators: Vec>, @@ -154,6 +160,9 @@ impl JubjubParams for JubjubBls12 { fn pedersen_hash_generators(&self) -> &[edwards::Point] { &self.pedersen_hash_generators } + fn pedersen_hash_exp_table(&self) -> &[Vec>>] { + &self.pedersen_hash_exp + } fn pedersen_hash_chunks_per_generator(&self) -> usize { 63 } @@ -171,6 +180,9 @@ impl JubjubParams for JubjubBls12 { { &self.fixed_base_circuit_generators[base as usize][..] } + fn pedersen_hash_exp_window_size() -> u32 { + 8 + } } impl JubjubBls12 { @@ -191,6 +203,7 @@ impl JubjubBls12 { // We'll initialize these below pedersen_hash_generators: vec![], + pedersen_hash_exp: vec![], pedersen_circuit_generators: vec![], fixed_base_generators: vec![], fixed_base_circuit_generators: vec![], @@ -258,6 +271,42 @@ impl JubjubBls12 { tmp_params.pedersen_hash_generators = pedersen_hash_generators; } + // Create the exp table for the Pedersen hash generators + { + let mut pedersen_hash_exp = vec![]; + + for g in &tmp_params.pedersen_hash_generators { + let mut g = g.clone(); + + let window = JubjubBls12::pedersen_hash_exp_window_size(); + + let mut tables = vec![]; + + let mut num_bits = 0; + while num_bits <= fs::Fs::NUM_BITS { + let mut table = Vec::with_capacity(1 << window); + + let mut base = edwards::Point::zero(); + + for _ in 0..(1 << window) { + table.push(base.clone()); + base = base.add(&g, &tmp_params); + } + + tables.push(table); + num_bits += window; + + for _ in 0..window { + g = g.double(&tmp_params); + } + } + + pedersen_hash_exp.push(tables); + } + + tmp_params.pedersen_hash_exp = pedersen_hash_exp; + } + // Create the bases for other parts of the protocol { let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize]; diff --git a/src/pedersen_hash.rs b/src/pedersen_hash.rs index 5c3bb90..0590a5c 100644 --- a/src/pedersen_hash.rs +++ b/src/pedersen_hash.rs @@ -1,6 +1,7 @@ use jubjub::*; use pairing::*; +#[derive(Copy, Clone)] pub enum Personalization { NoteCommitment, MerkleTree(usize) @@ -31,7 +32,7 @@ pub fn pedersen_hash( let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter()); let mut result = edwards::Point::zero(); - let mut generators = params.pedersen_hash_generators().iter(); + let mut generators = params.pedersen_hash_exp_table().iter(); loop { let mut acc = E::Fs::zero(); @@ -78,8 +79,23 @@ pub fn pedersen_hash( break; } - let mut tmp = generators.next().expect("we don't have enough generators").clone(); - tmp = tmp.mul(acc, params); + let mut table: &[Vec>] = &generators.next().expect("we don't have enough generators"); + let window = JubjubBls12::pedersen_hash_exp_window_size(); + let window_mask = (1 << window) - 1; + + let mut acc = acc.into_repr(); + + let mut tmp = edwards::Point::zero(); + + while !acc.is_zero() { + let i = (acc.as_ref()[0] & window_mask) as usize; + + tmp = tmp.add(&table[0][i], params); + + acc.shr(window); + table = &table[1..]; + } + result = result.add(&tmp, params); }