Pedersen hashes with full optimization

This commit is contained in:
Sean Bowe 2018-02-20 17:22:00 -07:00
parent 4fa73efc1e
commit 88bdff6ce9
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
4 changed files with 96 additions and 47 deletions

View File

@ -1,6 +1,9 @@
use pairing::{Engine, Field}; use pairing::{Engine, Field};
use super::*; use super::*;
use super::num::AllocatedNum; use super::num::{
AllocatedNum,
Num
};
use super::boolean::Boolean; use super::boolean::Boolean;
use bellman::{ use bellman::{
ConstraintSystem ConstraintSystem
@ -123,7 +126,7 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
mut cs: CS, mut cs: CS,
bits: &[Boolean], bits: &[Boolean],
coords: &[(E::Fr, E::Fr)] coords: &[(E::Fr, E::Fr)]
) -> Result<(AllocatedNum<E>, AllocatedNum<E>), SynthesisError> ) -> Result<(Num<E>, Num<E>), SynthesisError>
where CS: ConstraintSystem<E> where CS: ConstraintSystem<E>
{ {
assert_eq!(bits.len(), 3); assert_eq!(bits.len(), 3);
@ -145,17 +148,9 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
_ => None _ => None
}; };
// Allocate the x-coordinate resulting from the lookup
let res_x = AllocatedNum::alloc(
cs.namespace(|| "x"),
|| {
Ok(coords[*i.get()?].0)
}
)?;
// Allocate the y-coordinate resulting from the lookup // Allocate the y-coordinate resulting from the lookup
// and conditional negation // and conditional negation
let res_y = AllocatedNum::alloc( let y = AllocatedNum::alloc(
cs.namespace(|| "y"), cs.namespace(|| "y"),
|| { || {
let mut tmp = coords[*i.get()?].1; let mut tmp = coords[*i.get()?].1;
@ -176,15 +171,11 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[0], &bits[1])?; let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[0], &bits[1])?;
cs.enforce( let x = Num::zero()
|| "x-coordinate lookup", .add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00])
|lc| lc + (x_coeffs[0b00], one) .add_bool_with_coeff(one, &bits[0], x_coeffs[0b01])
+ &bits[0].lc::<E>(one, x_coeffs[0b01]) .add_bool_with_coeff(one, &bits[1], x_coeffs[0b10])
+ &bits[1].lc::<E>(one, x_coeffs[0b10]) .add_bool_with_coeff(one, &precomp, x_coeffs[0b11]);
+ &precomp.lc::<E>(one, x_coeffs[0b11]),
|lc| lc + one,
|lc| lc + res_x.get_variable()
);
let y_lc = precomp.lc::<E>(one, y_coeffs[0b11]) + let y_lc = precomp.lc::<E>(one, y_coeffs[0b11]) +
&bits[1].lc::<E>(one, y_coeffs[0b10]) + &bits[1].lc::<E>(one, y_coeffs[0b10]) +
@ -195,10 +186,10 @@ pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
|| "y-coordinate lookup", || "y-coordinate lookup",
|lc| lc + &y_lc + &y_lc, |lc| lc + &y_lc + &y_lc,
|lc| lc + &bits[2].lc::<E>(one, E::Fr::one()), |lc| lc + &bits[2].lc::<E>(one, E::Fr::one()),
|lc| lc + &y_lc - res_y.get_variable() |lc| lc + &y_lc - y.get_variable()
); );
Ok((res_x, res_y)) Ok((x, y.into()))
} }
#[cfg(test)] #[cfg(test)]

View File

@ -12,7 +12,10 @@ use super::{
Assignment Assignment
}; };
use super::num::AllocatedNum; use super::num::{
AllocatedNum,
Num
};
use ::jubjub::{ use ::jubjub::{
JubjubEngine, JubjubEngine,
@ -470,8 +473,8 @@ impl<E: JubjubEngine> EdwardsPoint<E> {
} }
pub struct MontgomeryPoint<E: Engine> { pub struct MontgomeryPoint<E: Engine> {
x: AllocatedNum<E>, x: Num<E>,
y: AllocatedNum<E> y: Num<E>
} }
impl<E: JubjubEngine> MontgomeryPoint<E> { impl<E: JubjubEngine> MontgomeryPoint<E> {
@ -504,9 +507,9 @@ impl<E: JubjubEngine> MontgomeryPoint<E> {
cs.enforce( cs.enforce(
|| "u computation", || "u computation",
|lc| lc + self.y.get_variable(), |lc| lc + &self.y.lc(E::Fr::one()),
|lc| lc + u.get_variable(), |lc| lc + u.get_variable(),
|lc| lc + (*params.scale(), self.x.get_variable()) |lc| lc + &self.x.lc(*params.scale())
); );
// Compute v = (x - 1) / (x + 1) // Compute v = (x - 1) / (x + 1)
@ -531,10 +534,10 @@ impl<E: JubjubEngine> MontgomeryPoint<E> {
let one = CS::one(); let one = CS::one();
cs.enforce( cs.enforce(
|| "v computation", || "v computation",
|lc| lc + self.x.get_variable() |lc| lc + &self.x.lc(E::Fr::one())
+ one, + one,
|lc| lc + v.get_variable(), |lc| lc + v.get_variable(),
|lc| lc + self.x.get_variable() |lc| lc + &self.x.lc(E::Fr::one())
- one, - one,
); );
@ -549,8 +552,8 @@ impl<E: JubjubEngine> MontgomeryPoint<E> {
/// on the curve. Useful for constants and /// on the curve. Useful for constants and
/// window table lookups. /// window table lookups.
pub fn interpret_unchecked( pub fn interpret_unchecked(
x: AllocatedNum<E>, x: Num<E>,
y: AllocatedNum<E> y: Num<E>
) -> Self ) -> Self
{ {
MontgomeryPoint { MontgomeryPoint {
@ -590,13 +593,13 @@ impl<E: JubjubEngine> MontgomeryPoint<E> {
cs.enforce( cs.enforce(
|| "evaluate lambda", || "evaluate lambda",
|lc| lc + other.x.get_variable() |lc| lc + &other.x.lc(E::Fr::one())
- self.x.get_variable(), - &self.x.lc(E::Fr::one()),
|lc| lc + lambda.get_variable(), |lc| lc + lambda.get_variable(),
|lc| lc + other.y.get_variable() |lc| lc + &other.y.lc(E::Fr::one())
- self.y.get_variable() - &self.y.lc(E::Fr::one())
); );
// Compute x'' = lambda^2 - A - x - x' // Compute x'' = lambda^2 - A - x - x'
@ -617,8 +620,8 @@ impl<E: JubjubEngine> MontgomeryPoint<E> {
|lc| lc + lambda.get_variable(), |lc| lc + lambda.get_variable(),
|lc| lc + lambda.get_variable(), |lc| lc + lambda.get_variable(),
|lc| lc + (*params.montgomery_a(), one) |lc| lc + (*params.montgomery_a(), one)
+ self.x.get_variable() + &self.x.lc(E::Fr::one())
+ other.x.get_variable() + &other.x.lc(E::Fr::one())
+ xprime.get_variable() + xprime.get_variable()
); );
@ -636,18 +639,18 @@ impl<E: JubjubEngine> MontgomeryPoint<E> {
// y' + y = lambda(x - x') // y' + y = lambda(x - x')
cs.enforce( cs.enforce(
|| "evaluate yprime", || "evaluate yprime",
|lc| lc + self.x.get_variable() |lc| lc + &self.x.lc(E::Fr::one())
- xprime.get_variable(), - xprime.get_variable(),
|lc| lc + lambda.get_variable(), |lc| lc + lambda.get_variable(),
|lc| lc + yprime.get_variable() |lc| lc + yprime.get_variable()
+ self.y.get_variable() + &self.y.lc(E::Fr::one())
); );
Ok(MontgomeryPoint { Ok(MontgomeryPoint {
x: xprime, x: xprime.into(),
y: yprime y: yprime.into()
}) })
} }
} }
@ -697,7 +700,7 @@ mod test {
Ok(y) Ok(y)
}).unwrap(); }).unwrap();
let p = MontgomeryPoint::interpret_unchecked(numx, numy); let p = MontgomeryPoint::interpret_unchecked(numx.into(), numy.into());
let q = p.into_edwards(&mut cs, params).unwrap(); let q = p.into_edwards(&mut cs, params).unwrap();
@ -1068,13 +1071,13 @@ mod test {
}).unwrap(); }).unwrap();
let p1 = MontgomeryPoint { let p1 = MontgomeryPoint {
x: num_x0, x: num_x0.into(),
y: num_y0 y: num_y0.into()
}; };
let p2 = MontgomeryPoint { let p2 = MontgomeryPoint {
x: num_x1, x: num_x1.into(),
y: num_y1 y: num_y1.into()
}; };
let p3 = p1.add(cs.namespace(|| "addition"), &p2, params).unwrap(); let p3 = p1.add(cs.namespace(|| "addition"), &p2, params).unwrap();

View File

@ -321,6 +321,61 @@ impl<E: Engine> AllocatedNum<E> {
} }
} }
pub struct Num<E: Engine> {
value: Option<E::Fr>,
lc: LinearCombination<E>
}
impl<E: Engine> From<AllocatedNum<E>> for Num<E> {
fn from(num: AllocatedNum<E>) -> Num<E> {
Num {
value: num.value,
lc: LinearCombination::<E>::zero() + num.variable
}
}
}
impl<E: Engine> Num<E> {
pub fn zero() -> Self {
Num {
value: Some(E::Fr::zero()),
lc: LinearCombination::zero()
}
}
pub fn get_value(&self) -> Option<E::Fr> {
self.value
}
pub fn lc(&self, coeff: E::Fr) -> LinearCombination<E> {
LinearCombination::zero() + (coeff, &self.lc)
}
pub fn add_bool_with_coeff(
self,
one: Variable,
bit: &Boolean,
coeff: E::Fr
) -> Self
{
let newval = match (self.value, bit.get_value()) {
(Some(mut curval), Some(mut bval)) => {
if bval {
curval.add_assign(&coeff);
}
Some(curval)
},
_ => None
};
Num {
value: newval,
lc: self.lc + &bit.lc(one, coeff)
}
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use rand::{SeedableRng, Rand, Rng, XorShiftRng}; use rand::{SeedableRng, Rand, Rng, XorShiftRng};

View File

@ -155,7 +155,7 @@ mod test {
).unwrap(); ).unwrap();
assert!(cs.is_satisfied()); assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 1549); assert_eq!(cs.num_constraints(), 1377);
} }
#[test] #[test]