From 0caf1d20878f82dbe5ba9b47533759248c6f9404 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 18 Sep 2020 00:33:42 +0800 Subject: [PATCH 01/11] Provide aux_commitments to verifier and aux_lagrange_polys to prover --- src/plonk.rs | 1 + src/plonk/circuit.rs | 21 +++++++++++++----- src/plonk/prover.rs | 50 +++++++++++++++++++++++++++++++++++++++++++ src/plonk/verifier.rs | 18 ++++++++++++++++ 4 files changed, 85 insertions(+), 5 deletions(-) diff --git a/src/plonk.rs b/src/plonk.rs index ac5ac13..4559c0f 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -50,6 +50,7 @@ pub struct Proof { permutation_product_inv_evals: Vec, permutation_evals: Vec>, advice_evals: Vec, + aux_evals: Vec, fixed_evals: Vec, h_evals: Vec, f_commitment: C, diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index 8ec8e3d..301eff8 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -14,6 +14,10 @@ pub struct FixedWire(pub usize); #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct AdviceWire(pub usize); +/// This represents a wire which has an externally assigned value +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct AuxWire(pub usize); + /// This trait allows a [`Circuit`] to direct some backend to assign a witness /// for a constraint system. pub trait Assignment { @@ -68,6 +72,8 @@ pub enum Expression { Fixed(usize), /// This is an advice (witness) wire queried at a certain relative location Advice(usize), + /// This is an auxiliary (external) wire queried at a certain relative location + Aux(usize), /// This is the sum of two polynomials Sum(Box>, Box>), /// This is the product of two polynomials @@ -83,6 +89,7 @@ impl Expression { &self, fixed_wire: &impl Fn(usize) -> T, advice_wire: &impl Fn(usize) -> T, + aux_wire: &impl Fn(usize) -> T, sum: &impl Fn(T, T) -> T, product: &impl Fn(T, T) -> T, scaled: &impl Fn(T, F) -> T, @@ -90,18 +97,19 @@ impl Expression { match self { Expression::Fixed(index) => fixed_wire(*index), Expression::Advice(index) => advice_wire(*index), + Expression::Aux(index) => aux_wire(*index), Expression::Sum(a, b) => { - let a = a.evaluate(fixed_wire, advice_wire, sum, product, scaled); - let b = b.evaluate(fixed_wire, advice_wire, sum, product, scaled); + let a = a.evaluate(fixed_wire, advice_wire, aux_wire, sum, product, scaled); + let b = b.evaluate(fixed_wire, advice_wire, aux_wire, sum, product, scaled); sum(a, b) } Expression::Product(a, b) => { - let a = a.evaluate(fixed_wire, advice_wire, sum, product, scaled); - let b = b.evaluate(fixed_wire, advice_wire, sum, product, scaled); + let a = a.evaluate(fixed_wire, advice_wire, aux_wire, sum, product, scaled); + let b = b.evaluate(fixed_wire, advice_wire, aux_wire, sum, product, scaled); product(a, b) } Expression::Scaled(a, f) => { - let a = a.evaluate(fixed_wire, advice_wire, sum, product, scaled); + let a = a.evaluate(fixed_wire, advice_wire, aux_wire, sum, product, scaled); scaled(a, *f) } } @@ -112,6 +120,7 @@ impl Expression { match self { Expression::Fixed(_) => 1, Expression::Advice(_) => 1, + Expression::Aux(_) => 1, Expression::Sum(a, b) => max(a.degree(), b.degree()), Expression::Product(a, b) => a.degree() + b.degree(), Expression::Scaled(poly, _) => poly.degree(), @@ -153,6 +162,7 @@ pub struct ConstraintSystem { pub(crate) num_advice_wires: usize, pub(crate) gates: Vec>, pub(crate) advice_queries: Vec<(AdviceWire, Rotation)>, + pub(crate) aux_queries: Vec<(AuxWire, Rotation)>, pub(crate) fixed_queries: Vec<(FixedWire, Rotation)>, // Mapping from a witness vector rotation to the index in the point vector. @@ -179,6 +189,7 @@ impl Default for ConstraintSystem { gates: vec![], fixed_queries: Vec::new(), advice_queries: Vec::new(), + aux_queries: Vec::new(), rotations, permutations: Vec::new(), } diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 93c6942..999a82f 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -24,6 +24,7 @@ impl Proof { params: &Params, srs: &SRS, circuit: &ConcreteCircuit, + aux_lagrange_polys: Vec>, ) -> Result { struct WitnessCollection { advice: Vec>, @@ -125,6 +126,35 @@ impl Proof { }) .collect(); + // Compute commitments to auxiliary wire polynomials + let aux_commitments_projective: Vec<_> = aux_lagrange_polys + .iter() + .map(|poly| params.commit_lagrange(poly, Blind::default())) + .collect(); + let mut aux_commitments = vec![C::zero(); aux_commitments_projective.len()]; + C::Projective::batch_to_affine(&aux_commitments_projective, &mut aux_commitments); + let aux_commitments = aux_commitments; + drop(aux_commitments_projective); + + for commitment in &aux_commitments { + hash_point(&mut transcript, commitment)?; + } + + let aux_polys: Vec<_> = aux_lagrange_polys + .clone() + .into_iter() + .map(|poly| domain.lagrange_to_coeff(poly)) + .collect(); + + let aux_cosets: Vec<_> = meta + .aux_queries + .iter() + .map(|&(wire, at)| { + let poly = aux_polys[wire.0].clone(); + domain.coeff_to_extended(poly, at) + }) + .collect(); + // Sample x_0 challenge let x_0: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); @@ -253,6 +283,7 @@ impl Proof { let evaluation = poly.evaluate( &|index| srs.fixed_cosets[index].clone(), &|index| advice_cosets[index].clone(), + &|index| aux_cosets[index].clone(), &|a, b| a + &b, &|a, b| a * &b, &|a, scalar| a * scalar, @@ -355,6 +386,12 @@ impl Proof { .map(|&(wire, at)| eval_polynomial(&advice_polys[wire.0], domain.rotate_omega(x_3, at))) .collect(); + let aux_evals: Vec<_> = meta + .aux_queries + .iter() + .map(|&(wire, at)| eval_polynomial(&aux_polys[wire.0], domain.rotate_omega(x_3, at))) + .collect(); + let fixed_evals: Vec<_> = meta .fixed_queries .iter() @@ -396,6 +433,7 @@ impl Proof { // Hash each advice evaluation for eval in advice_evals .iter() + .chain(aux_evals.iter()) .chain(fixed_evals.iter()) .chain(h_evals.iter()) .chain(permutation_product_evals.iter()) @@ -451,6 +489,17 @@ impl Proof { ); } + for (query_index, &(wire, ref at)) in meta.aux_queries.iter().enumerate() { + let point_index = (*meta.rotations.get(at).unwrap()).0; + + accumulate( + point_index, + &aux_polys[wire.0], + Blind::default(), + aux_evals[query_index], + ); + } + for (query_index, &(wire, ref at)) in meta.fixed_queries.iter().enumerate() { let point_index = (*meta.rotations.get(at).unwrap()).0; @@ -595,6 +644,7 @@ impl Proof { permutation_evals, advice_evals, fixed_evals, + aux_evals, h_evals, f_commitment, q_evals, diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index a9ae739..6c2cf75 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -13,6 +13,7 @@ impl<'a, C: CurveAffine> Proof { params: &'a Params, srs: &SRS, mut msm: MSM<'a, C>, + aux_commitments: Vec, ) -> Result, Error> { // Scale the MSM by a random factor to ensure that if the existing MSM // has is_zero() == false then this argument won't be able to interfere @@ -28,6 +29,12 @@ impl<'a, C: CurveAffine> Proof { .expect("proof cannot contain points at infinity"); } + // Hash the external auxiliary commitments into the transcript + for commitment in &aux_commitments { + hash_point(&mut transcript, commitment) + .expect("proof cannot contain points at infinity"); + } + // Sample x_0 challenge let x_0: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); @@ -59,6 +66,7 @@ impl<'a, C: CurveAffine> Proof { for eval in self .advice_evals .iter() + .chain(self.aux_evals.iter()) .chain(self.fixed_evals.iter()) .chain(self.h_evals.iter()) .chain(self.permutation_product_evals.iter()) @@ -80,6 +88,7 @@ impl<'a, C: CurveAffine> Proof { let evaluation: C::Scalar = poly.evaluate( &|index| self.fixed_evals[index], &|index| self.advice_evals[index], + &|index| self.aux_evals[index], &|a, b| a + &b, &|a, b| a * &b, &|a, scalar| a * &scalar, @@ -172,6 +181,15 @@ impl<'a, C: CurveAffine> Proof { ); } + for (query_index, &(wire, ref at)) in srs.cs.aux_queries.iter().enumerate() { + let point_index = (*srs.cs.rotations.get(at).unwrap()).0; + accumulate( + point_index, + aux_commitments[wire.0], + self.aux_evals[query_index], + ); + } + for (query_index, &(wire, ref at)) in srs.cs.fixed_queries.iter().enumerate() { let point_index = (*srs.cs.rotations.get(at).unwrap()).0; accumulate( From a257308ba2cac1d1a99fa71b787161a4c68008bd Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 18 Sep 2020 01:07:19 +0800 Subject: [PATCH 02/11] Add aux wires to ConstraintSystem --- src/plonk.rs | 12 +++++++++++- src/plonk/circuit.rs | 35 +++++++++++++++++++++++++++++++++++ src/plonk/verifier.rs | 5 +++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/plonk.rs b/src/plonk.rs index 4559c0f..d223173 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -262,6 +262,8 @@ fn test_proving() { let c = meta.advice_wire(); let d = meta.advice_wire(); + let x = meta.aux_wire(); + let perm = meta.permutation(&[a, b, c]); let perm2 = meta.permutation(&[a, b, c]); @@ -269,6 +271,7 @@ fn test_proving() { let sa = meta.fixed_wire(); let sb = meta.fixed_wire(); let sc = meta.fixed_wire(); + let sx = meta.fixed_wire(); meta.create_gate(|meta| { let d = meta.query_advice(d, 1); @@ -278,12 +281,19 @@ fn test_proving() { let b = meta.query_advice(b, 0); let c = meta.query_advice(c, 0); + let x = meta.query_advice(x, 0); + let sa = meta.query_fixed(sa, 0); let sb = meta.query_fixed(sb, 0); let sc = meta.query_fixed(sc, 0); let sm = meta.query_fixed(sm, 0); - a.clone() * sa + b.clone() * sb + a * b * sm + (c * sc * (-F::one())) + sf * (d * e) + a.clone() * sa + + b.clone() * sb + + a * b * sm + + (c * sc * (-F::one())) + + sf * (d * e) + + (x * sx * (-F::one())) }); PLONKConfig { diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index 301eff8..5330a1b 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -160,6 +160,7 @@ pub(crate) struct PointIndex(pub usize); pub struct ConstraintSystem { pub(crate) num_fixed_wires: usize, pub(crate) num_advice_wires: usize, + pub(crate) num_aux_wires: usize, pub(crate) gates: Vec>, pub(crate) advice_queries: Vec<(AdviceWire, Rotation)>, pub(crate) aux_queries: Vec<(AuxWire, Rotation)>, @@ -186,6 +187,7 @@ impl Default for ConstraintSystem { ConstraintSystem { num_fixed_wires: 0, num_advice_wires: 0, + num_aux_wires: 0, gates: vec![], fixed_queries: Vec::new(), advice_queries: Vec::new(), @@ -266,6 +268,32 @@ impl ConstraintSystem { Expression::Advice(self.query_advice_index(wire, at)) } + fn query_aux_index(&mut self, wire: AuxWire, at: i32) -> usize { + let at = Rotation(at); + { + let len = self.rotations.len(); + self.rotations.entry(at).or_insert(PointIndex(len)); + } + + // Return existing query, if it exists + for (index, aux_query) in self.aux_queries.iter().enumerate() { + if aux_query == &(wire, at) { + return index; + } + } + + // Make a new query + let index = self.aux_queries.len(); + self.aux_queries.push((wire, at)); + + index + } + + /// Query an auxiliary wire at a relative position + pub fn query_aux(&mut self, wire: AuxWire, at: i32) -> Expression { + Expression::Aux(self.query_aux_index(wire, at)) + } + /// Create a new gate pub fn create_gate(&mut self, f: impl FnOnce(&mut Self) -> Expression) { let poly = f(self); @@ -285,4 +313,11 @@ impl ConstraintSystem { self.num_advice_wires += 1; tmp } + + /// Allocate a new auxiliary wire + pub fn aux_wire(&mut self) -> AuxWire { + let tmp = AuxWire(self.num_aux_wires); + self.num_aux_wires += 1; + tmp + } } diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index 6c2cf75..6c7c239 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -15,6 +15,11 @@ impl<'a, C: CurveAffine> Proof { mut msm: MSM<'a, C>, aux_commitments: Vec, ) -> Result, Error> { + // Check that aux_commitments matches the expected number of aux_wires + if aux_commitments.len() != srs.cs.num_aux_wires { + return Err(Error::IncompatibleParams); + } + // Scale the MSM by a random factor to ensure that if the existing MSM // has is_zero() == false then this argument won't be able to interfere // with it to make it true, with high probability. From 0bdcbb6c670c39ab170f7baf733785314e67717e Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 18 Sep 2020 01:33:31 +0800 Subject: [PATCH 03/11] Introduce Wire enum for use in permutations --- src/plonk/circuit.rs | 21 ++++++++++-- src/plonk/prover.rs | 78 +++++++++++++++++++++++++++++++++----------- 2 files changed, 77 insertions(+), 22 deletions(-) diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index 5330a1b..5758804 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -18,6 +18,17 @@ pub struct AdviceWire(pub usize); #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct AuxWire(pub usize); +/// An enum over all wire types, to be used in permutations +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum Wire { + /// Fixed wire + Fixed(FixedWire), + /// Advice wire + Advice(AdviceWire), + /// Auxiliary wire + Aux(AuxWire), +} + /// This trait allows a [`Circuit`] to direct some backend to assign a witness /// for a constraint system. pub trait Assignment { @@ -176,7 +187,7 @@ pub struct ConstraintSystem { // enforced between advice wire values in A, B and C, and another // permutation between wires (B, C, D) which allows the same with D instead // of A. - pub(crate) permutations: Vec>, + pub(crate) permutations: Vec>, } impl Default for ConstraintSystem { @@ -200,7 +211,7 @@ impl Default for ConstraintSystem { impl ConstraintSystem { /// Add a permutation argument for some advice wires - pub fn permutation(&mut self, wires: &[AdviceWire]) -> usize { + pub fn permutation(&mut self, wires: &[Wire]) -> usize { let index = self.permutations.len(); if index == 0 { let at = Rotation(-1); @@ -209,7 +220,11 @@ impl ConstraintSystem { } let wires = wires .iter() - .map(|&wire| (wire, self.query_advice_index(wire, 0))) + .map(|&wire| match wire { + Wire::Advice(wire) => (Wire::Advice(wire), self.query_advice_index(wire, 0)), + Wire::Aux(wire) => (Wire::Aux(wire), self.query_aux_index(wire, 0)), + Wire::Fixed(wire) => (Wire::Fixed(wire), self.query_fixed_index(wire, 0)), + }) .collect(); self.permutations.push(wires); diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 999a82f..eb6fd08 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -1,5 +1,5 @@ use super::{ - circuit::{AdviceWire, Assignment, Circuit, ConstraintSystem, FixedWire}, + circuit::{AdviceWire, Assignment, Circuit, ConstraintSystem, FixedWire, Wire}, hash_point, Error, Proof, SRS, }; use crate::arithmetic::{ @@ -182,15 +182,34 @@ impl Proof { // Iterate over each wire of the permutation for (&(wire, _), permuted_wire_values) in wires.iter().zip(permuted_values.iter()) { - parallelize(&mut modified_advice, |modified_advice, start| { - for ((modified_advice, advice_value), permuted_advice_value) in modified_advice - .iter_mut() - .zip(witness.advice[wire.0][start..].iter()) - .zip(permuted_wire_values[start..].iter()) - { - *modified_advice *= &(x_0 * permuted_advice_value + &x_1 + advice_value); + match wire { + Wire::Advice(wire) => { + parallelize(&mut modified_advice, |modified_advice, start| { + for ((modified_advice, advice_value), permuted_advice_value) in + modified_advice + .iter_mut() + .zip(witness.advice[wire.0][start..].iter()) + .zip(permuted_wire_values[start..].iter()) + { + *modified_advice *= + &(x_0 * permuted_advice_value + &x_1 + advice_value); + } + }); } - }); + Wire::Aux(wire) => { + parallelize(&mut modified_advice, |modified_aux, start| { + for ((modified_aux, aux_value), permuted_aux_value) in modified_aux + .iter_mut() + .zip(aux_lagrange_polys[wire.0][start..].iter()) + .zip(permuted_wire_values[start..].iter()) + { + *modified_aux *= &(x_0 * permuted_aux_value + &x_1 + aux_value); + } + }); + } + // TODO: implement for fixed wires + _ => unreachable!(), + } } permutation_modified_advice.push(modified_advice); @@ -214,17 +233,38 @@ impl Proof { let mut deltaomega = C::Scalar::one(); for &(wire, _) in wires.iter() { let omega = domain.get_omega(); - parallelize(&mut modified_advice, |modified_advice, start| { - let mut deltaomega = deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]); - for (modified_advice, advice_value) in modified_advice - .iter_mut() - .zip(witness.advice[wire.0][start..].iter()) - { - // Multiply by p_j(\omega^i) + \delta^j \omega^i \beta - *modified_advice *= &(deltaomega * &x_0 + &x_1 + advice_value); - deltaomega *= ω + match wire { + Wire::Advice(wire) => { + parallelize(&mut modified_advice, |modified_advice, start| { + let mut deltaomega = + deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]); + for (modified_advice, advice_value) in modified_advice + .iter_mut() + .zip(witness.advice[wire.0][start..].iter()) + { + // Multiply by p_j(\omega^i) + \delta^j \omega^i \beta + *modified_advice *= &(deltaomega * &x_0 + &x_1 + advice_value); + deltaomega *= ω + } + }); } - }); + Wire::Aux(wire) => { + parallelize(&mut modified_advice, |modified_advice, start| { + let mut deltaomega = + deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]); + for (modified_advice, advice_value) in modified_advice + .iter_mut() + .zip(aux_lagrange_polys[wire.0][start..].iter()) + { + // Multiply by p_j(\omega^i) + \delta^j \omega^i \beta + *modified_advice *= &(deltaomega * &x_0 + &x_1 + advice_value); + deltaomega *= ω + } + }); + } + // TODO: implement for fixed wires + _ => unreachable!(), + } deltaomega *= &C::Scalar::DELTA; } From 9482202a983f7772dc157fdd9c6ad583af1577f9 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 18 Sep 2020 12:02:48 +0800 Subject: [PATCH 04/11] Update PLONK test_proving() example --- src/plonk.rs | 134 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 20 deletions(-) diff --git a/src/plonk.rs b/src/plonk.rs index d223173..a96d24a 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -92,8 +92,8 @@ fn hash_point>( #[test] fn test_proving() { - use crate::arithmetic::{EqAffine, Field, Fp, Fq}; - use crate::poly::commitment::Params; + use crate::arithmetic::{Curve, EqAffine, Field, Fp, Fq}; + use crate::poly::commitment::{Blind, Params}; use crate::transcript::DummyHash; use std::marker::PhantomData; const K: u32 = 5; @@ -102,6 +102,14 @@ fn test_proving() { #[derive(Copy, Clone, Debug)] pub struct Variable(AdviceWire, usize); + /// This represents an auxiliary wire at a certain row in the ConstraintSystem + #[derive(Copy, Clone, Debug)] + pub struct AuxVariable(AuxWire, usize); + + /// This represents a wire at a certain row in the ConstraintSystem + #[derive(Copy, Clone, Debug)] + pub struct PermVariable(Wire, usize); + // Initialize the polynomial commitment parameters let params: Params = Params::new::>(K); @@ -112,10 +120,13 @@ fn test_proving() { d: AdviceWire, e: AdviceWire, + x: AuxWire, + sa: FixedWire, sb: FixedWire, sc: FixedWire, sm: FixedWire, + sx: FixedWire, perm: usize, perm2: usize, @@ -128,11 +139,15 @@ fn test_proving() { fn raw_add(&mut self, f: F) -> Result<(Variable, Variable, Variable), Error> where F: FnOnce() -> Result<(FF, FF, FF), Error>; - fn copy(&mut self, a: Variable, b: Variable) -> Result<(), Error>; + fn copy(&mut self, a: PermVariable, b: PermVariable) -> Result<(), Error>; + fn raw_aux(&mut self, f: F) -> Result<(Variable, AuxVariable), Error> + where + F: FnOnce() -> Result<(FF, FF), Error>; } struct MyCircuit { a: Option, + x: Option, } struct StandardPLONK<'a, F: Field, CS: Assignment + 'a> { @@ -230,17 +245,31 @@ fn test_proving() { Variable(self.config.c, index), )) } - fn copy(&mut self, left: Variable, right: Variable) -> Result<(), Error> { + fn copy(&mut self, left: PermVariable, right: PermVariable) -> Result<(), Error> { let left_wire = match left.0 { - x if x == self.config.a => 0, - x if x == self.config.b => 1, - x if x == self.config.c => 2, + Wire::Advice(wire) => match wire { + x if x == self.config.a => 0, + x if x == self.config.b => 1, + x if x == self.config.c => 2, + _ => unreachable!(), + }, + Wire::Aux(wire) => match wire { + x if x == self.config.x => 3, + _ => unreachable!(), + }, _ => unreachable!(), }; let right_wire = match right.0 { - x if x == self.config.a => 0, - x if x == self.config.b => 1, - x if x == self.config.c => 2, + Wire::Advice(wire) => match wire { + x if x == self.config.a => 0, + x if x == self.config.b => 1, + x if x == self.config.c => 2, + _ => unreachable!(), + }, + Wire::Aux(wire) => match wire { + x if x == self.config.x => 3, + _ => unreachable!(), + }, _ => unreachable!(), }; @@ -249,6 +278,24 @@ fn test_proving() { self.cs .copy(self.config.perm2, left_wire, left.1, right_wire, right.1) } + fn raw_aux(&mut self, f: F) -> Result<(Variable, AuxVariable), Error> + where + F: FnOnce() -> Result<(FF, FF), Error>, + { + let index = self.current_gate; + self.current_gate += 1; + let mut value = None; + self.cs.assign_advice(self.config.a, index, || { + value = Some(f()?); + Ok(value.ok_or(Error::SynthesisError)?.0) + })?; + self.cs + .assign_fixed(self.config.sx, index, || Ok(FF::zero()))?; + Ok(( + Variable(self.config.a, index), + AuxVariable(self.config.x, index), + )) + } } impl Circuit for MyCircuit { @@ -264,8 +311,18 @@ fn test_proving() { let x = meta.aux_wire(); - let perm = meta.permutation(&[a, b, c]); - let perm2 = meta.permutation(&[a, b, c]); + let perm = meta.permutation(&[ + Wire::Advice(a), + Wire::Advice(b), + Wire::Advice(c), + Wire::Aux(x), + ]); + let perm2 = meta.permutation(&[ + Wire::Advice(a), + Wire::Advice(b), + Wire::Advice(c), + Wire::Aux(x), + ]); let sm = meta.fixed_wire(); let sa = meta.fixed_wire(); @@ -281,12 +338,13 @@ fn test_proving() { let b = meta.query_advice(b, 0); let c = meta.query_advice(c, 0); - let x = meta.query_advice(x, 0); + let x = meta.query_aux(x, 0); let sa = meta.query_fixed(sa, 0); let sb = meta.query_fixed(sb, 0); let sc = meta.query_fixed(sc, 0); let sm = meta.query_fixed(sm, 0); + let sx = meta.query_fixed(sx, 0); a.clone() * sa + b.clone() * sb @@ -302,10 +360,12 @@ fn test_proving() { c, d, e, + x, sa, sb, sc, sm, + sx, perm, perm2, } @@ -336,9 +396,25 @@ fn test_proving() { fin.ok_or(Error::SynthesisError)?, )) })?; - cs.copy(a0, a1)?; - cs.copy(b1, c0)?; + cs.copy( + PermVariable(Wire::Advice(a0.0), a0.1), + PermVariable(Wire::Advice(a1.0), a1.1), + )?; + cs.copy( + PermVariable(Wire::Advice(b1.0), b1.1), + PermVariable(Wire::Advice(c0.0), c0.1), + )?; } + let (_, x) = cs.raw_aux(|| { + Ok(( + self.x.ok_or(Error::SynthesisError)?, + self.x.ok_or(Error::SynthesisError)?, + )) + })?; + cs.copy( + PermVariable(Wire::Aux(x.0), x.1), + PermVariable(Wire::Aux(x.0), x.1), + )?; Ok(()) } @@ -346,21 +422,39 @@ fn test_proving() { let circuit: MyCircuit = MyCircuit { a: Some(Fp::random()), + + // TODO: use meaningful value from recursion + x: Some(Fp::random()), }; - let empty_circuit: MyCircuit = MyCircuit { a: None }; + let empty_circuit: MyCircuit = MyCircuit { a: None, x: None }; // Initialize the SRS let srs = SRS::generate(¶ms, &empty_circuit).expect("SRS generation should not fail"); + // TODO: use meaningful value from recursion + let aux_lagrange_polys = vec![srs.domain.empty_lagrange(); srs.cs.num_aux_wires]; + + // TODO: use meaningful value from recursion + let mut aux_commitments: Vec = vec![]; + for poly in &aux_lagrange_polys { + let commitment = params.commit_lagrange(poly, Blind::default()); + aux_commitments.push(commitment.to_affine()); + } + for _ in 0..100 { // Create a proof - let proof = Proof::create::, DummyHash, _>(¶ms, &srs, &circuit) - .expect("proof generation should not fail"); + let proof = Proof::create::, DummyHash, _>( + ¶ms, + &srs, + &circuit, + aux_lagrange_polys.clone(), + ) + .expect("proof generation should not fail"); let msm = params.empty_msm(); let guard = proof - .verify::, DummyHash>(¶ms, &srs, msm) + .verify::, DummyHash>(¶ms, &srs, msm, aux_commitments.clone()) .unwrap(); { let msm = guard.clone().use_challenges(); @@ -374,7 +468,7 @@ fn test_proving() { let msm = guard.clone().use_challenges(); assert!(msm.clone().is_zero()); let guard = proof - .verify::, DummyHash>(¶ms, &srs, msm) + .verify::, DummyHash>(¶ms, &srs, msm, aux_commitments.clone()) .unwrap(); { let msm = guard.clone().use_challenges(); From fd094fccd87e89a97b1e67b0b45f5aa2db83cdc7 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 18 Sep 2020 20:18:52 +0800 Subject: [PATCH 05/11] Add aux_commitments and aux_evals to test_proving() example --- src/plonk.rs | 30 +++++++++++++++++++++--------- src/poly/commitment.rs | 5 +++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/plonk.rs b/src/plonk.rs index a96d24a..afe16d8 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -420,20 +420,13 @@ fn test_proving() { } } - let circuit: MyCircuit = MyCircuit { - a: Some(Fp::random()), - - // TODO: use meaningful value from recursion - x: Some(Fp::random()), - }; - let empty_circuit: MyCircuit = MyCircuit { a: None, x: None }; // Initialize the SRS let srs = SRS::generate(¶ms, &empty_circuit).expect("SRS generation should not fail"); // TODO: use meaningful value from recursion - let aux_lagrange_polys = vec![srs.domain.empty_lagrange(); srs.cs.num_aux_wires]; + let mut aux_lagrange_polys = vec![srs.domain.empty_lagrange(); srs.cs.num_aux_wires]; // TODO: use meaningful value from recursion let mut aux_commitments: Vec = vec![]; @@ -443,6 +436,14 @@ fn test_proving() { } for _ in 0..100 { + // Generate circuit + let circuit: MyCircuit = MyCircuit { + a: Some(Fp::random()), + + // TODO: use meaningful value from recursion + x: Some(Fp::random()), + }; + // Create a proof let proof = Proof::create::, DummyHash, _>( ¶ms, @@ -477,7 +478,18 @@ fn test_proving() { { let g = guard.compute_g(); let (msm, _) = guard.clone().use_g(g); - assert!(msm.is_zero()); + assert!(msm.clone().is_zero()); + + let mut g_scalars = vec![Fp::one(); 1 << K]; + if let Some(msm_g_scalars) = msm.get_g_scalars() { + g_scalars = msm_g_scalars; + } + let g_lagrange_poly = srs.domain.lagrange_from_vec(g_scalars.clone()); + aux_lagrange_polys = vec![g_lagrange_poly.clone(); 1]; + let g_commitment = params + .commit_lagrange(&g_lagrange_poly, Blind::default()) + .to_affine(); + aux_commitments = vec![g_commitment; 1]; } } } diff --git a/src/poly/commitment.rs b/src/poly/commitment.rs index 77ac408..0f08d85 100644 --- a/src/poly/commitment.rs +++ b/src/poly/commitment.rs @@ -124,6 +124,11 @@ impl<'a, C: CurveAffine> MSM<'a, C> { bool::from(best_multiexp(&scalars, &bases).is_zero()) } + + /// Return g_scalars + pub fn get_g_scalars(&self) -> Option> { + self.g_scalars.clone() + } } /// These are the public parameters for the polynomial commitment scheme. From c772801f8f538de51191cd055bc999575173dd70 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 18 Sep 2020 21:02:28 +0800 Subject: [PATCH 06/11] Pass aux_lagrange_polys to prover as a slice --- src/plonk.rs | 2 +- src/plonk/prover.rs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plonk.rs b/src/plonk.rs index afe16d8..1f29f2b 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -449,7 +449,7 @@ fn test_proving() { ¶ms, &srs, &circuit, - aux_lagrange_polys.clone(), + &aux_lagrange_polys.clone(), ) .expect("proof generation should not fail"); diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index eb6fd08..7809f49 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -24,7 +24,7 @@ impl Proof { params: &Params, srs: &SRS, circuit: &ConcreteCircuit, - aux_lagrange_polys: Vec>, + aux_lagrange_polys: &[Polynomial], ) -> Result { struct WitnessCollection { advice: Vec>, @@ -143,7 +143,10 @@ impl Proof { let aux_polys: Vec<_> = aux_lagrange_polys .clone() .into_iter() - .map(|poly| domain.lagrange_to_coeff(poly)) + .map(|poly| { + let lagrange_vec = domain.lagrange_from_vec(poly.to_vec()); + domain.lagrange_to_coeff(lagrange_vec) + }) .collect(); let aux_cosets: Vec<_> = meta From 24fe3fae2990f37a1f8a925cf752ea31db8e1094 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 18 Sep 2020 22:51:48 +0800 Subject: [PATCH 07/11] Remove aux_commitments computation from Prover; remove blinding factor when accumulator aux_evals --- src/plonk.rs | 4 ++-- src/plonk/prover.rs | 16 +--------------- src/plonk/verifier.rs | 6 ------ 3 files changed, 3 insertions(+), 23 deletions(-) diff --git a/src/plonk.rs b/src/plonk.rs index 1f29f2b..92568e5 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -431,7 +431,7 @@ fn test_proving() { // TODO: use meaningful value from recursion let mut aux_commitments: Vec = vec![]; for poly in &aux_lagrange_polys { - let commitment = params.commit_lagrange(poly, Blind::default()); + let commitment = params.commit_lagrange(poly, Blind(Fp::zero())); aux_commitments.push(commitment.to_affine()); } @@ -487,7 +487,7 @@ fn test_proving() { let g_lagrange_poly = srs.domain.lagrange_from_vec(g_scalars.clone()); aux_lagrange_polys = vec![g_lagrange_poly.clone(); 1]; let g_commitment = params - .commit_lagrange(&g_lagrange_poly, Blind::default()) + .commit_lagrange(&g_lagrange_poly, Blind(Fp::zero())) .to_affine(); aux_commitments = vec![g_commitment; 1]; } diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 7809f49..52def2c 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -126,20 +126,6 @@ impl Proof { }) .collect(); - // Compute commitments to auxiliary wire polynomials - let aux_commitments_projective: Vec<_> = aux_lagrange_polys - .iter() - .map(|poly| params.commit_lagrange(poly, Blind::default())) - .collect(); - let mut aux_commitments = vec![C::zero(); aux_commitments_projective.len()]; - C::Projective::batch_to_affine(&aux_commitments_projective, &mut aux_commitments); - let aux_commitments = aux_commitments; - drop(aux_commitments_projective); - - for commitment in &aux_commitments { - hash_point(&mut transcript, commitment)?; - } - let aux_polys: Vec<_> = aux_lagrange_polys .clone() .into_iter() @@ -538,7 +524,7 @@ impl Proof { accumulate( point_index, &aux_polys[wire.0], - Blind::default(), + Blind(C::Scalar::zero()), aux_evals[query_index], ); } diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index 6c7c239..e88554d 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -34,12 +34,6 @@ impl<'a, C: CurveAffine> Proof { .expect("proof cannot contain points at infinity"); } - // Hash the external auxiliary commitments into the transcript - for commitment in &aux_commitments { - hash_point(&mut transcript, commitment) - .expect("proof cannot contain points at infinity"); - } - // Sample x_0 challenge let x_0: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); From e8839a75791c187f8e9f57994fc91fe715553772 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 18 Sep 2020 22:58:40 +0800 Subject: [PATCH 08/11] Refactor wire pattern matching when computing permutation product --- src/plonk/prover.rs | 85 ++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 58 deletions(-) diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 52def2c..15fe884 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -171,34 +171,20 @@ impl Proof { // Iterate over each wire of the permutation for (&(wire, _), permuted_wire_values) in wires.iter().zip(permuted_values.iter()) { - match wire { - Wire::Advice(wire) => { - parallelize(&mut modified_advice, |modified_advice, start| { - for ((modified_advice, advice_value), permuted_advice_value) in - modified_advice - .iter_mut() - .zip(witness.advice[wire.0][start..].iter()) - .zip(permuted_wire_values[start..].iter()) - { - *modified_advice *= - &(x_0 * permuted_advice_value + &x_1 + advice_value); - } - }); + parallelize(&mut modified_advice, |modified_advice, start| { + for ((modified_advice, advice_value), permuted_advice_value) in modified_advice + .iter_mut() + .zip(match wire { + Wire::Advice(wire) => witness.advice[wire.0][start..].iter(), + Wire::Aux(wire) => aux_lagrange_polys[wire.0][start..].iter(), + // TODO: implement for fixed wires + _ => unreachable!(), + }) + .zip(permuted_wire_values[start..].iter()) + { + *modified_advice *= &(x_0 * permuted_advice_value + &x_1 + advice_value); } - Wire::Aux(wire) => { - parallelize(&mut modified_advice, |modified_aux, start| { - for ((modified_aux, aux_value), permuted_aux_value) in modified_aux - .iter_mut() - .zip(aux_lagrange_polys[wire.0][start..].iter()) - .zip(permuted_wire_values[start..].iter()) - { - *modified_aux *= &(x_0 * permuted_aux_value + &x_1 + aux_value); - } - }); - } - // TODO: implement for fixed wires - _ => unreachable!(), - } + }); } permutation_modified_advice.push(modified_advice); @@ -222,38 +208,21 @@ impl Proof { let mut deltaomega = C::Scalar::one(); for &(wire, _) in wires.iter() { let omega = domain.get_omega(); - match wire { - Wire::Advice(wire) => { - parallelize(&mut modified_advice, |modified_advice, start| { - let mut deltaomega = - deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]); - for (modified_advice, advice_value) in modified_advice - .iter_mut() - .zip(witness.advice[wire.0][start..].iter()) - { - // Multiply by p_j(\omega^i) + \delta^j \omega^i \beta - *modified_advice *= &(deltaomega * &x_0 + &x_1 + advice_value); - deltaomega *= ω - } - }); + parallelize(&mut modified_advice, |modified_advice, start| { + let mut deltaomega = deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]); + for (modified_advice, advice_value) in + modified_advice.iter_mut().zip(match wire { + Wire::Advice(wire) => witness.advice[wire.0][start..].iter(), + Wire::Aux(wire) => aux_lagrange_polys[wire.0][start..].iter(), + // TODO: implement for fixed wires + _ => unreachable!(), + }) + { + // Multiply by p_j(\omega^i) + \delta^j \omega^i \beta + *modified_advice *= &(deltaomega * &x_0 + &x_1 + advice_value); + deltaomega *= ω } - Wire::Aux(wire) => { - parallelize(&mut modified_advice, |modified_advice, start| { - let mut deltaomega = - deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]); - for (modified_advice, advice_value) in modified_advice - .iter_mut() - .zip(aux_lagrange_polys[wire.0][start..].iter()) - { - // Multiply by p_j(\omega^i) + \delta^j \omega^i \beta - *modified_advice *= &(deltaomega * &x_0 + &x_1 + advice_value); - deltaomega *= ω - } - }); - } - // TODO: implement for fixed wires - _ => unreachable!(), - } + }); deltaomega *= &C::Scalar::DELTA; } From 73d494a72d27c971dbfcd7153a058fc831b129c9 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Sat, 19 Sep 2020 13:31:56 -0600 Subject: [PATCH 09/11] Various changes, including restoring permutation argument to advice wires only for now. --- src/plonk.rs | 175 ++++++++++++------------------------------ src/plonk/circuit.rs | 21 +---- src/plonk/prover.rs | 75 ++++++++++-------- src/plonk/verifier.rs | 13 +++- 4 files changed, 106 insertions(+), 178 deletions(-) diff --git a/src/plonk.rs b/src/plonk.rs index 92568e5..6def55e 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -102,14 +102,6 @@ fn test_proving() { #[derive(Copy, Clone, Debug)] pub struct Variable(AdviceWire, usize); - /// This represents an auxiliary wire at a certain row in the ConstraintSystem - #[derive(Copy, Clone, Debug)] - pub struct AuxVariable(AuxWire, usize); - - /// This represents a wire at a certain row in the ConstraintSystem - #[derive(Copy, Clone, Debug)] - pub struct PermVariable(Wire, usize); - // Initialize the polynomial commitment parameters let params: Params = Params::new::>(K); @@ -120,13 +112,11 @@ fn test_proving() { d: AdviceWire, e: AdviceWire, - x: AuxWire, - sa: FixedWire, sb: FixedWire, sc: FixedWire, sm: FixedWire, - sx: FixedWire, + sp: FixedWire, perm: usize, perm2: usize, @@ -139,15 +129,14 @@ fn test_proving() { fn raw_add(&mut self, f: F) -> Result<(Variable, Variable, Variable), Error> where F: FnOnce() -> Result<(FF, FF, FF), Error>; - fn copy(&mut self, a: PermVariable, b: PermVariable) -> Result<(), Error>; - fn raw_aux(&mut self, f: F) -> Result<(Variable, AuxVariable), Error> + fn copy(&mut self, a: Variable, b: Variable) -> Result<(), Error>; + fn public_input(&mut self, f: F) -> Result where - F: FnOnce() -> Result<(FF, FF), Error>; + F: FnOnce() -> Result; } struct MyCircuit { a: Option, - x: Option, } struct StandardPLONK<'a, F: Field, CS: Assignment + 'a> { @@ -245,31 +234,17 @@ fn test_proving() { Variable(self.config.c, index), )) } - fn copy(&mut self, left: PermVariable, right: PermVariable) -> Result<(), Error> { + fn copy(&mut self, left: Variable, right: Variable) -> Result<(), Error> { let left_wire = match left.0 { - Wire::Advice(wire) => match wire { - x if x == self.config.a => 0, - x if x == self.config.b => 1, - x if x == self.config.c => 2, - _ => unreachable!(), - }, - Wire::Aux(wire) => match wire { - x if x == self.config.x => 3, - _ => unreachable!(), - }, + x if x == self.config.a => 0, + x if x == self.config.b => 1, + x if x == self.config.c => 2, _ => unreachable!(), }; let right_wire = match right.0 { - Wire::Advice(wire) => match wire { - x if x == self.config.a => 0, - x if x == self.config.b => 1, - x if x == self.config.c => 2, - _ => unreachable!(), - }, - Wire::Aux(wire) => match wire { - x if x == self.config.x => 3, - _ => unreachable!(), - }, + x if x == self.config.a => 0, + x if x == self.config.b => 1, + x if x == self.config.c => 2, _ => unreachable!(), }; @@ -278,23 +253,17 @@ fn test_proving() { self.cs .copy(self.config.perm2, left_wire, left.1, right_wire, right.1) } - fn raw_aux(&mut self, f: F) -> Result<(Variable, AuxVariable), Error> + fn public_input(&mut self, f: F) -> Result where - F: FnOnce() -> Result<(FF, FF), Error>, + F: FnOnce() -> Result, { let index = self.current_gate; self.current_gate += 1; - let mut value = None; - self.cs.assign_advice(self.config.a, index, || { - value = Some(f()?); - Ok(value.ok_or(Error::SynthesisError)?.0) - })?; + self.cs.assign_advice(self.config.a, index, || f())?; self.cs - .assign_fixed(self.config.sx, index, || Ok(FF::zero()))?; - Ok(( - Variable(self.config.a, index), - AuxVariable(self.config.x, index), - )) + .assign_fixed(self.config.sp, index, || Ok(FF::one()))?; + + Ok(Variable(self.config.a, index)) } } @@ -308,27 +277,16 @@ fn test_proving() { let sf = meta.fixed_wire(); let c = meta.advice_wire(); let d = meta.advice_wire(); + let p = meta.aux_wire(); - let x = meta.aux_wire(); - - let perm = meta.permutation(&[ - Wire::Advice(a), - Wire::Advice(b), - Wire::Advice(c), - Wire::Aux(x), - ]); - let perm2 = meta.permutation(&[ - Wire::Advice(a), - Wire::Advice(b), - Wire::Advice(c), - Wire::Aux(x), - ]); + let perm = meta.permutation(&[a, b, c]); + let perm2 = meta.permutation(&[a, b, c]); let sm = meta.fixed_wire(); let sa = meta.fixed_wire(); let sb = meta.fixed_wire(); let sc = meta.fixed_wire(); - let sx = meta.fixed_wire(); + let sp = meta.fixed_wire(); meta.create_gate(|meta| { let d = meta.query_advice(d, 1); @@ -338,20 +296,20 @@ fn test_proving() { let b = meta.query_advice(b, 0); let c = meta.query_advice(c, 0); - let x = meta.query_aux(x, 0); - let sa = meta.query_fixed(sa, 0); let sb = meta.query_fixed(sb, 0); let sc = meta.query_fixed(sc, 0); let sm = meta.query_fixed(sm, 0); - let sx = meta.query_fixed(sx, 0); - a.clone() * sa - + b.clone() * sb - + a * b * sm - + (c * sc * (-F::one())) - + sf * (d * e) - + (x * sx * (-F::one())) + a.clone() * sa + b.clone() * sb + a * b * sm + (c * sc * (-F::one())) + sf * (d * e) + }); + + meta.create_gate(|meta| { + let a = meta.query_advice(a, 0); + let p = meta.query_aux(p, 0); + let sp = meta.query_fixed(sp, 0); + + sp * (a + p * (-F::one())) }); PLONKConfig { @@ -360,12 +318,11 @@ fn test_proving() { c, d, e, - x, sa, sb, sc, sm, - sx, + sp, perm, perm2, } @@ -378,6 +335,8 @@ fn test_proving() { ) -> Result<(), Error> { let mut cs = StandardPLONK::new(cs, config); + let _ = cs.public_input(|| Ok(F::one() + F::one()))?; + for _ in 0..10 { let mut a_squared = None; let (a0, _, c0) = cs.raw_multiply(|| { @@ -396,66 +355,43 @@ fn test_proving() { fin.ok_or(Error::SynthesisError)?, )) })?; - cs.copy( - PermVariable(Wire::Advice(a0.0), a0.1), - PermVariable(Wire::Advice(a1.0), a1.1), - )?; - cs.copy( - PermVariable(Wire::Advice(b1.0), b1.1), - PermVariable(Wire::Advice(c0.0), c0.1), - )?; + cs.copy(a0, a1)?; + cs.copy(b1, c0)?; } - let (_, x) = cs.raw_aux(|| { - Ok(( - self.x.ok_or(Error::SynthesisError)?, - self.x.ok_or(Error::SynthesisError)?, - )) - })?; - cs.copy( - PermVariable(Wire::Aux(x.0), x.1), - PermVariable(Wire::Aux(x.0), x.1), - )?; Ok(()) } } - let empty_circuit: MyCircuit = MyCircuit { a: None, x: None }; + let circuit: MyCircuit = MyCircuit { + a: Some(Fp::random()), + }; + + let empty_circuit: MyCircuit = MyCircuit { a: None }; // Initialize the SRS let srs = SRS::generate(¶ms, &empty_circuit).expect("SRS generation should not fail"); - // TODO: use meaningful value from recursion - let mut aux_lagrange_polys = vec![srs.domain.empty_lagrange(); srs.cs.num_aux_wires]; - - // TODO: use meaningful value from recursion - let mut aux_commitments: Vec = vec![]; - for poly in &aux_lagrange_polys { - let commitment = params.commit_lagrange(poly, Blind(Fp::zero())); - aux_commitments.push(commitment.to_affine()); - } + let mut pubinputs = srs.domain.empty_lagrange(); + pubinputs[0] = Fp::one(); + pubinputs[0] += Fp::one(); + let pubinput = params + .commit_lagrange(&pubinputs, Blind(Field::zero())) + .to_affine(); for _ in 0..100 { - // Generate circuit - let circuit: MyCircuit = MyCircuit { - a: Some(Fp::random()), - - // TODO: use meaningful value from recursion - x: Some(Fp::random()), - }; - // Create a proof let proof = Proof::create::, DummyHash, _>( ¶ms, &srs, &circuit, - &aux_lagrange_polys.clone(), + &[pubinputs.clone()], ) .expect("proof generation should not fail"); let msm = params.empty_msm(); let guard = proof - .verify::, DummyHash>(¶ms, &srs, msm, aux_commitments.clone()) + .verify::, DummyHash>(¶ms, &srs, msm, &[pubinput]) .unwrap(); { let msm = guard.clone().use_challenges(); @@ -469,7 +405,7 @@ fn test_proving() { let msm = guard.clone().use_challenges(); assert!(msm.clone().is_zero()); let guard = proof - .verify::, DummyHash>(¶ms, &srs, msm, aux_commitments.clone()) + .verify::, DummyHash>(¶ms, &srs, msm, &[pubinput]) .unwrap(); { let msm = guard.clone().use_challenges(); @@ -478,18 +414,7 @@ fn test_proving() { { let g = guard.compute_g(); let (msm, _) = guard.clone().use_g(g); - assert!(msm.clone().is_zero()); - - let mut g_scalars = vec![Fp::one(); 1 << K]; - if let Some(msm_g_scalars) = msm.get_g_scalars() { - g_scalars = msm_g_scalars; - } - let g_lagrange_poly = srs.domain.lagrange_from_vec(g_scalars.clone()); - aux_lagrange_polys = vec![g_lagrange_poly.clone(); 1]; - let g_commitment = params - .commit_lagrange(&g_lagrange_poly, Blind(Fp::zero())) - .to_affine(); - aux_commitments = vec![g_commitment; 1]; + assert!(msm.is_zero()); } } } diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index 5758804..5330a1b 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -18,17 +18,6 @@ pub struct AdviceWire(pub usize); #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct AuxWire(pub usize); -/// An enum over all wire types, to be used in permutations -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -pub enum Wire { - /// Fixed wire - Fixed(FixedWire), - /// Advice wire - Advice(AdviceWire), - /// Auxiliary wire - Aux(AuxWire), -} - /// This trait allows a [`Circuit`] to direct some backend to assign a witness /// for a constraint system. pub trait Assignment { @@ -187,7 +176,7 @@ pub struct ConstraintSystem { // enforced between advice wire values in A, B and C, and another // permutation between wires (B, C, D) which allows the same with D instead // of A. - pub(crate) permutations: Vec>, + pub(crate) permutations: Vec>, } impl Default for ConstraintSystem { @@ -211,7 +200,7 @@ impl Default for ConstraintSystem { impl ConstraintSystem { /// Add a permutation argument for some advice wires - pub fn permutation(&mut self, wires: &[Wire]) -> usize { + pub fn permutation(&mut self, wires: &[AdviceWire]) -> usize { let index = self.permutations.len(); if index == 0 { let at = Rotation(-1); @@ -220,11 +209,7 @@ impl ConstraintSystem { } let wires = wires .iter() - .map(|&wire| match wire { - Wire::Advice(wire) => (Wire::Advice(wire), self.query_advice_index(wire, 0)), - Wire::Aux(wire) => (Wire::Aux(wire), self.query_aux_index(wire, 0)), - Wire::Fixed(wire) => (Wire::Fixed(wire), self.query_fixed_index(wire, 0)), - }) + .map(|&wire| (wire, self.query_advice_index(wire, 0))) .collect(); self.permutations.push(wires); diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 15fe884..7c7d514 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -1,5 +1,5 @@ use super::{ - circuit::{AdviceWire, Assignment, Circuit, ConstraintSystem, FixedWire, Wire}, + circuit::{AdviceWire, Assignment, Circuit, ConstraintSystem, FixedWire}, hash_point, Error, Proof, SRS, }; use crate::arithmetic::{ @@ -24,8 +24,12 @@ impl Proof { params: &Params, srs: &SRS, circuit: &ConcreteCircuit, - aux_lagrange_polys: &[Polynomial], + aux: &[Polynomial], ) -> Result { + if aux.len() != srs.cs.num_aux_wires { + return Err(Error::IncompatibleParams); + } + struct WitnessCollection { advice: Vec>, _marker: std::marker::PhantomData, @@ -89,6 +93,38 @@ impl Proof { // Create a transcript for obtaining Fiat-Shamir challenges. let mut transcript = HBase::init(C::Base::one()); + // Compute commitments to aux wire polynomials + let aux_commitments_projective: Vec<_> = aux + .iter() + .map(|poly| params.commit_lagrange(poly, Blind(C::Scalar::zero()))) // TODO: bad blind? + .collect(); + let mut aux_commitments = vec![C::zero(); aux_commitments_projective.len()]; + C::Projective::batch_to_affine(&aux_commitments_projective, &mut aux_commitments); + let aux_commitments = aux_commitments; + drop(aux_commitments_projective); + + for commitment in &aux_commitments { + hash_point(&mut transcript, commitment)?; + } + + let aux_polys: Vec<_> = aux + .clone() + .into_iter() + .map(|poly| { + let lagrange_vec = domain.lagrange_from_vec(poly.to_vec()); + domain.lagrange_to_coeff(lagrange_vec) + }) + .collect(); + + let aux_cosets: Vec<_> = meta + .aux_queries + .iter() + .map(|&(wire, at)| { + let poly = aux_polys[wire.0].clone(); + domain.coeff_to_extended(poly, at) + }) + .collect(); + // Compute commitments to advice wire polynomials let advice_blinds: Vec<_> = witness .advice @@ -126,24 +162,6 @@ impl Proof { }) .collect(); - let aux_polys: Vec<_> = aux_lagrange_polys - .clone() - .into_iter() - .map(|poly| { - let lagrange_vec = domain.lagrange_from_vec(poly.to_vec()); - domain.lagrange_to_coeff(lagrange_vec) - }) - .collect(); - - let aux_cosets: Vec<_> = meta - .aux_queries - .iter() - .map(|&(wire, at)| { - let poly = aux_polys[wire.0].clone(); - domain.coeff_to_extended(poly, at) - }) - .collect(); - // Sample x_0 challenge let x_0: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); @@ -174,12 +192,7 @@ impl Proof { parallelize(&mut modified_advice, |modified_advice, start| { for ((modified_advice, advice_value), permuted_advice_value) in modified_advice .iter_mut() - .zip(match wire { - Wire::Advice(wire) => witness.advice[wire.0][start..].iter(), - Wire::Aux(wire) => aux_lagrange_polys[wire.0][start..].iter(), - // TODO: implement for fixed wires - _ => unreachable!(), - }) + .zip(witness.advice[wire.0][start..].iter()) .zip(permuted_wire_values[start..].iter()) { *modified_advice *= &(x_0 * permuted_advice_value + &x_1 + advice_value); @@ -210,13 +223,9 @@ impl Proof { let omega = domain.get_omega(); parallelize(&mut modified_advice, |modified_advice, start| { let mut deltaomega = deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]); - for (modified_advice, advice_value) in - modified_advice.iter_mut().zip(match wire { - Wire::Advice(wire) => witness.advice[wire.0][start..].iter(), - Wire::Aux(wire) => aux_lagrange_polys[wire.0][start..].iter(), - // TODO: implement for fixed wires - _ => unreachable!(), - }) + for (modified_advice, advice_value) in modified_advice + .iter_mut() + .zip(witness.advice[wire.0][start..].iter()) { // Multiply by p_j(\omega^i) + \delta^j \omega^i \beta *modified_advice *= &(deltaomega * &x_0 + &x_1 + advice_value); diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index e88554d..b10d4a8 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -13,10 +13,13 @@ impl<'a, C: CurveAffine> Proof { params: &'a Params, srs: &SRS, mut msm: MSM<'a, C>, - aux_commitments: Vec, + aux_commitments: &[C], ) -> Result, Error> { // Check that aux_commitments matches the expected number of aux_wires - if aux_commitments.len() != srs.cs.num_aux_wires { + // and self.aux_evals + if aux_commitments.len() != srs.cs.num_aux_wires + || self.aux_evals.len() != srs.cs.num_aux_wires + { return Err(Error::IncompatibleParams); } @@ -28,6 +31,12 @@ impl<'a, C: CurveAffine> Proof { // Create a transcript for obtaining Fiat-Shamir challenges. let mut transcript = HBase::init(C::Base::one()); + // Hash the aux (external) commitments into the transcript + for commitment in aux_commitments { + hash_point(&mut transcript, commitment) + .expect("proof cannot contain points at infinity"); // TODO + } + // Hash the prover's advice commitments into the transcript for commitment in &self.advice_commitments { hash_point(&mut transcript, commitment) From 6620817d81f7a6e1f369e8777bff6a9b2343e086 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Sat, 19 Sep 2020 13:47:37 -0600 Subject: [PATCH 10/11] Return errors from verifier instead of assuming points aren't at infinity in the proof. --- src/plonk/verifier.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index b10d4a8..0200e93 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -33,14 +33,12 @@ impl<'a, C: CurveAffine> Proof { // Hash the aux (external) commitments into the transcript for commitment in aux_commitments { - hash_point(&mut transcript, commitment) - .expect("proof cannot contain points at infinity"); // TODO + hash_point(&mut transcript, commitment)?; } // Hash the prover's advice commitments into the transcript for commitment in &self.advice_commitments { - hash_point(&mut transcript, commitment) - .expect("proof cannot contain points at infinity"); + hash_point(&mut transcript, commitment)?; } // Sample x_0 challenge @@ -51,7 +49,7 @@ impl<'a, C: CurveAffine> Proof { // Hash each permutation product commitment for c in &self.permutation_product_commitments { - hash_point(&mut transcript, c).expect("proof cannot contain points at infinity"); + hash_point(&mut transcript, c)?; } // Sample x_2 challenge, which keeps the gates linearly independent. @@ -59,7 +57,7 @@ impl<'a, C: CurveAffine> Proof { // Obtain a commitment to h(X) in the form of multiple pieces of degree n - 1 for c in &self.h_commitments { - hash_point(&mut transcript, c).expect("proof cannot contain points at infinity"); + hash_point(&mut transcript, c)?; } // Sample x_3 challenge, which is used to ensure the circuit is @@ -248,8 +246,7 @@ impl<'a, C: CurveAffine> Proof { let x_5: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); // Obtain the commitment to the multi-point quotient polynomial f(X). - hash_point(&mut transcript, &self.f_commitment) - .expect("proof cannot contain points at infinity"); + hash_point(&mut transcript, &self.f_commitment)?; // Sample a challenge x_6 for checking that f(X) was committed to // correctly. From 60aa2918c399c4cf25bc3fb4ffa7b894eb43a327 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Sat, 19 Sep 2020 13:52:33 -0600 Subject: [PATCH 11/11] Remove get_g_scalars() from MSM. --- src/poly/commitment.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/poly/commitment.rs b/src/poly/commitment.rs index 0f08d85..77ac408 100644 --- a/src/poly/commitment.rs +++ b/src/poly/commitment.rs @@ -124,11 +124,6 @@ impl<'a, C: CurveAffine> MSM<'a, C> { bool::from(best_multiexp(&scalars, &bases).is_zero()) } - - /// Return g_scalars - pub fn get_g_scalars(&self) -> Option> { - self.g_scalars.clone() - } } /// These are the public parameters for the polynomial commitment scheme.