Merge pull request #79 from ebfull/pedersen-hash-performance
Improve Pedersen hash performance
This commit is contained in:
commit
b70d6e66fc
|
@ -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(), ¶ms)
|
||||||
|
});
|
||||||
|
}
|
|
@ -355,12 +355,72 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn double(&self, params: &E::Params) -> Self {
|
pub fn double(&self, _: &E::Params) -> Self {
|
||||||
// Point addition is unified and complete.
|
// See "Twisted Edwards Curves Revisited"
|
||||||
// There are dedicated formulae, but we do
|
// Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson
|
||||||
// not implement these now.
|
// Section 3.3
|
||||||
|
// http://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd
|
||||||
|
|
||||||
self.add(self, params)
|
// A = X1^2
|
||||||
|
let mut a = self.x;
|
||||||
|
a.square();
|
||||||
|
|
||||||
|
// B = Y1^2
|
||||||
|
let mut b = self.y;
|
||||||
|
b.square();
|
||||||
|
|
||||||
|
// C = 2*Z1^2
|
||||||
|
let mut c = self.z;
|
||||||
|
c.square();
|
||||||
|
c.double();
|
||||||
|
|
||||||
|
// D = a*A
|
||||||
|
// = -A
|
||||||
|
let mut d = a;
|
||||||
|
d.negate();
|
||||||
|
|
||||||
|
// E = (X1+Y1)^2 - A - B
|
||||||
|
let mut e = self.x;
|
||||||
|
e.add_assign(&self.y);
|
||||||
|
e.square();
|
||||||
|
e.add_assign(&d); // -A = D
|
||||||
|
e.sub_assign(&b);
|
||||||
|
|
||||||
|
// G = D+B
|
||||||
|
let mut g = d;
|
||||||
|
g.add_assign(&b);
|
||||||
|
|
||||||
|
// F = G-C
|
||||||
|
let mut f = g;
|
||||||
|
f.sub_assign(&c);
|
||||||
|
|
||||||
|
// H = D-B
|
||||||
|
let mut h = d;
|
||||||
|
h.sub_assign(&b);
|
||||||
|
|
||||||
|
// X3 = E*F
|
||||||
|
let mut x3 = e;
|
||||||
|
x3.mul_assign(&f);
|
||||||
|
|
||||||
|
// Y3 = G*H
|
||||||
|
let mut y3 = g;
|
||||||
|
y3.mul_assign(&h);
|
||||||
|
|
||||||
|
// T3 = E*H
|
||||||
|
let mut t3 = e;
|
||||||
|
t3.mul_assign(&h);
|
||||||
|
|
||||||
|
// Z3 = F*G
|
||||||
|
let mut z3 = f;
|
||||||
|
z3.mul_assign(&g);
|
||||||
|
|
||||||
|
Point {
|
||||||
|
x: x3,
|
||||||
|
y: y3,
|
||||||
|
t: t3,
|
||||||
|
z: z3,
|
||||||
|
_marker: PhantomData
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&self, other: &Self, params: &E::Params) -> Self
|
pub fn add(&self, other: &Self, params: &E::Params) -> Self
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue