From edc4adc32c0644972247328eb566a650055e325e Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Wed, 7 Feb 2018 13:33:09 -0700 Subject: [PATCH] Implementation of fixed-base Edwards scalar multiplication in the circuit. --- src/circuit/mont.rs | 97 ++++++++++++++++++++++++++++++++++++++++++++- src/jubjub/mod.rs | 11 +++++ 2 files changed, 106 insertions(+), 2 deletions(-) diff --git a/src/circuit/mont.rs b/src/circuit/mont.rs index 666129f..37995fb 100644 --- a/src/circuit/mont.rs +++ b/src/circuit/mont.rs @@ -17,7 +17,12 @@ use super::num::AllocatedNum; use ::jubjub::{ JubjubEngine, - JubjubParams + JubjubParams, + FixedGenerators +}; + +use super::lookup::{ + lookup3_xy }; use super::boolean::Boolean; @@ -36,6 +41,56 @@ impl Clone for EdwardsPoint { } } +/// Perform a fixed-base scalar multiplication with +/// `by` being in little-endian bit order. `by` must +/// be a multiple of 3. +pub fn fixed_base_multiplication( + mut cs: CS, + base: FixedGenerators, + by: &[Boolean], + params: &E::Params +) -> Result, SynthesisError> + where CS: ConstraintSystem, + E: JubjubEngine, + Var: Copy +{ + // We're going to chunk the scalar into 3-bit windows, + // so let's force the caller to supply the right number + // of bits for our lookups. + assert!(by.len() % 3 == 0); + + // Represents the result of the multiplication + let mut result = None; + + for (i, (chunk, window)) in by.chunks(3) + .zip(params.circuit_generators(base).iter()) + .enumerate() + { + let (x, y) = lookup3_xy( + cs.namespace(|| format!("window table lookup {}", i)), + chunk, + window + )?; + + let p = EdwardsPoint { + x: x, + y: y + }; + + if result.is_none() { + result = Some(p); + } else { + result = Some(result.unwrap().add( + cs.namespace(|| format!("addition {}", i)), + &p, + params + )?); + } + } + + Ok(result.get()?.clone()) +} + impl EdwardsPoint { /// This extracts the x-coordinate, which is an injective /// encoding for elements of the prime order subgroup. @@ -615,13 +670,16 @@ mod test { use ::jubjub::{ montgomery, edwards, - JubjubBls12 + JubjubBls12, + JubjubParams, + FixedGenerators }; use ::jubjub::fs::Fs; use super::{ MontgomeryPoint, EdwardsPoint, AllocatedNum, + fixed_base_multiplication }; use super::super::boolean::{ Boolean, @@ -731,6 +789,41 @@ mod test { assert!(p.double(&mut cs, params).is_err()); } + #[test] + fn test_edwards_fixed_base_multiplication() { + let params = &JubjubBls12::new(); + let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); + + for _ in 0..100 { + let mut cs = TestConstraintSystem::::new(); + + let p = params.generator(FixedGenerators::NoteCommitmentRandomization); + let s = Fs::rand(rng); + let q = p.mul(s, params); + let (x1, y1) = q.into_xy(); + + let mut s_bits = BitIterator::new(s.into_repr()).collect::>(); + s_bits.reverse(); + s_bits.truncate(Fs::NUM_BITS as usize); + + let s_bits = s_bits.into_iter() + .enumerate() + .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)).unwrap()) + .map(|v| Boolean::from(v)) + .collect::>(); + + let q = fixed_base_multiplication( + cs.namespace(|| "multiplication"), + FixedGenerators::NoteCommitmentRandomization, + &s_bits, + params + ).unwrap(); + + assert_eq!(q.x.get_value().unwrap(), x1); + assert_eq!(q.y.get_value().unwrap(), y1); + } + } + #[test] fn test_edwards_multiplication() { let params = &JubjubBls12::new(); diff --git a/src/jubjub/mod.rs b/src/jubjub/mod.rs index 9055b98..0a53660 100644 --- a/src/jubjub/mod.rs +++ b/src/jubjub/mod.rs @@ -49,6 +49,8 @@ pub trait JubjubParams: Sized { fn pedersen_circuit_generators(&self) -> &[Vec>]; fn fixed_base_chunks_per_generator(&self) -> usize; + fn generator(&self, base: FixedGenerators) -> &edwards::Point; + fn circuit_generators(&self, FixedGenerators) -> &[Vec<(E::Fr, E::Fr)>]; } pub enum Unknown { } @@ -63,6 +65,7 @@ impl JubjubEngine for Bls12 { /// Fixed generators of the Jubjub curve of unknown /// exponent. +#[derive(Copy, Clone)] pub enum FixedGenerators { NoteCommitmentRandomization = 0, Max = 1 @@ -98,6 +101,14 @@ impl JubjubParams for JubjubBls12 { fn pedersen_circuit_generators(&self) -> &[Vec>] { &self.pedersen_circuit_generators } + fn generator(&self, base: FixedGenerators) -> &edwards::Point + { + &self.fixed_base_generators[base as usize] + } + fn circuit_generators(&self, base: FixedGenerators) -> &[Vec<(Fr, Fr)>] + { + &self.fixed_base_circuit_generators[base as usize][..] + } } impl JubjubBls12 {