From 73d494a72d27c971dbfcd7153a058fc831b129c9 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Sat, 19 Sep 2020 13:31:56 -0600 Subject: [PATCH] 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 92568e59..6def55e6 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 5758804f..5330a1b3 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 15fe8843..7c7d514a 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 e88554d1..b10d4a89 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)