Change pedersen hash outside the circuit to use window table lookups.

This commit is contained in:
Sean Bowe 2018-07-25 14:46:00 -06:00
parent c2862a4382
commit 821810cd82
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
3 changed files with 91 additions and 3 deletions

23
benches/pedersen_hash.rs Normal file
View File

@ -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::<Vec<_>>();
let personalization = Personalization::MerkleTree(31);
b.iter(|| {
pedersen_hash::<Bls12, _>(personalization, bits.clone(), &params)
});
}

View File

@ -112,6 +112,8 @@ pub trait JubjubParams<E: JubjubEngine>: Sized {
fn scale(&self) -> &E::Fr; fn scale(&self) -> &E::Fr;
/// Returns the generators (for each segment) used in all Pedersen commitments. /// Returns the generators (for each segment) used in all Pedersen commitments.
fn pedersen_hash_generators(&self) -> &[edwards::Point<E, PrimeOrder>]; fn pedersen_hash_generators(&self) -> &[edwards::Point<E, PrimeOrder>];
/// Returns the exp table for Pedersen hashes.
fn pedersen_hash_exp_table(&self) -> &[Vec<Vec<edwards::Point<E, PrimeOrder>>>];
/// Returns the maximum number of chunks per segment of the Pedersen hash. /// Returns the maximum number of chunks per segment of the Pedersen hash.
fn pedersen_hash_chunks_per_generator(&self) -> usize; fn pedersen_hash_chunks_per_generator(&self) -> usize;
/// Returns the pre-computed window tables [-4, 3, 2, 1, 1, 2, 3, 4] of different /// Returns the pre-computed window tables [-4, 3, 2, 1, 1, 2, 3, 4] of different
@ -126,6 +128,9 @@ pub trait JubjubParams<E: JubjubEngine>: Sized {
/// Returns a window table [0, 1, ..., 8] for different magnitudes of some /// Returns a window table [0, 1, ..., 8] for different magnitudes of some
/// fixed generator. /// fixed generator.
fn circuit_generators(&self, FixedGenerators) -> &[Vec<(E::Fr, E::Fr)>]; 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 { impl JubjubEngine for Bls12 {
@ -140,6 +145,7 @@ pub struct JubjubBls12 {
scale: Fr, scale: Fr,
pedersen_hash_generators: Vec<edwards::Point<Bls12, PrimeOrder>>, pedersen_hash_generators: Vec<edwards::Point<Bls12, PrimeOrder>>,
pedersen_hash_exp: Vec<Vec<Vec<edwards::Point<Bls12, PrimeOrder>>>>,
pedersen_circuit_generators: Vec<Vec<Vec<(Fr, Fr)>>>, pedersen_circuit_generators: Vec<Vec<Vec<(Fr, Fr)>>>,
fixed_base_generators: Vec<edwards::Point<Bls12, PrimeOrder>>, fixed_base_generators: Vec<edwards::Point<Bls12, PrimeOrder>>,
@ -154,6 +160,9 @@ impl JubjubParams<Bls12> for JubjubBls12 {
fn pedersen_hash_generators(&self) -> &[edwards::Point<Bls12, PrimeOrder>] { fn pedersen_hash_generators(&self) -> &[edwards::Point<Bls12, PrimeOrder>] {
&self.pedersen_hash_generators &self.pedersen_hash_generators
} }
fn pedersen_hash_exp_table(&self) -> &[Vec<Vec<edwards::Point<Bls12, PrimeOrder>>>] {
&self.pedersen_hash_exp
}
fn pedersen_hash_chunks_per_generator(&self) -> usize { fn pedersen_hash_chunks_per_generator(&self) -> usize {
63 63
} }
@ -171,6 +180,9 @@ impl JubjubParams<Bls12> for JubjubBls12 {
{ {
&self.fixed_base_circuit_generators[base as usize][..] &self.fixed_base_circuit_generators[base as usize][..]
} }
fn pedersen_hash_exp_window_size() -> u32 {
8
}
} }
impl JubjubBls12 { impl JubjubBls12 {
@ -191,6 +203,7 @@ impl JubjubBls12 {
// We'll initialize these below // We'll initialize these below
pedersen_hash_generators: vec![], pedersen_hash_generators: vec![],
pedersen_hash_exp: vec![],
pedersen_circuit_generators: vec![], pedersen_circuit_generators: vec![],
fixed_base_generators: vec![], fixed_base_generators: vec![],
fixed_base_circuit_generators: vec![], fixed_base_circuit_generators: vec![],
@ -258,6 +271,42 @@ impl JubjubBls12 {
tmp_params.pedersen_hash_generators = pedersen_hash_generators; 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 // Create the bases for other parts of the protocol
{ {
let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize]; let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize];

View File

@ -1,6 +1,7 @@
use jubjub::*; use jubjub::*;
use pairing::*; use pairing::*;
#[derive(Copy, Clone)]
pub enum Personalization { pub enum Personalization {
NoteCommitment, NoteCommitment,
MerkleTree(usize) MerkleTree(usize)
@ -31,7 +32,7 @@ pub fn pedersen_hash<E, I>(
let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter()); let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter());
let mut result = edwards::Point::zero(); let mut result = edwards::Point::zero();
let mut generators = params.pedersen_hash_generators().iter(); let mut generators = params.pedersen_hash_exp_table().iter();
loop { loop {
let mut acc = E::Fs::zero(); let mut acc = E::Fs::zero();
@ -78,8 +79,23 @@ pub fn pedersen_hash<E, I>(
break; break;
} }
let mut tmp = generators.next().expect("we don't have enough generators").clone(); let mut table: &[Vec<edwards::Point<E, _>>] = &generators.next().expect("we don't have enough generators");
tmp = tmp.mul(acc, params); 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); result = result.add(&tmp, params);
} }