From 7edffe0197e0c1d81b39ec46193328de9381658e Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Sat, 22 Aug 2020 16:10:27 -0600 Subject: [PATCH] Allow commitments to generic advice wire polynomials --- src/plonk.rs | 74 +++++++++++++++++++++++++++++++++++++++++-- src/plonk/circuit.rs | 36 ++++++++++++++++++--- src/plonk/prover.rs | 48 +++++++++++++++++++++++++--- src/plonk/srs.rs | 45 +++++++++++++++++++++++--- src/plonk/verifier.rs | 5 +++ 5 files changed, 191 insertions(+), 17 deletions(-) diff --git a/src/plonk.rs b/src/plonk.rs index 97eba66..9385609 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -42,15 +42,21 @@ pub struct SRS { sd_commitment: C, sm_commitment: C, domain: EvaluationDomain, + + fixed_commitments: Vec, + fixed_polys: Vec<(Vec, Vec)>, + meta: MetaCircuit, } /// This is an object which represents a (Turbo)PLONK proof. +// This structure must never allow points at infinity. #[derive(Debug, Clone)] pub struct Proof { a_commitment: C, b_commitment: C, c_commitment: C, d_commitment: C, + advice_commitments: Vec, h_commitments: Vec, a_eval_x: C::Scalar, b_eval_x: C::Scalar, @@ -77,6 +83,8 @@ pub enum Error { IncompatibleParams, /// The constraint system is not satisfied. ConstraintSystemFailure, + /// Out of bounds index passed to a backend + BoundsFailure, } fn hash_point>( @@ -103,7 +111,16 @@ fn test_proving() { // Initialize the polynomial commitment parameters let params: Params = Params::new::>(K); - struct MyConfig {} + struct MyConfig { + a: Wire, + b: Wire, + c: Wire, + + sa: Wire, + sb: Wire, + sc: Wire, + sm: Wire, + } struct MyCircuit { a: Option, } @@ -112,7 +129,24 @@ fn test_proving() { type Config = MyConfig; fn configure(meta: &mut MetaCircuit) -> MyConfig { - MyConfig {} + let a = meta.advice_wire(); + let b = meta.advice_wire(); + let c = meta.advice_wire(); + + let sa = meta.fixed_wire(); + let sb = meta.fixed_wire(); + let sc = meta.fixed_wire(); + let sm = meta.fixed_wire(); + + MyConfig { + a, + b, + c, + sa, + sb, + sc, + sm, + } } fn synthesize( @@ -137,6 +171,42 @@ fn test_proving() { //cs.copy(c, e); } + // Similar to the above... + let mut row = 0; + for _ in 0..10 { + cs.assign(Variable(config.a, row), || { + self.a.ok_or(Error::SynthesisError) + })?; + cs.assign(Variable(config.b, row), || { + self.a.ok_or(Error::SynthesisError) + })?; + let a_squared = self.a.map(|a| a.square()); + cs.assign(Variable(config.c, row), || { + self.a.ok_or(Error::SynthesisError) + })?; + // Multiplication gate + cs.assign(Variable(config.sa, row), || Ok(Field::zero()))?; + cs.assign(Variable(config.sb, row), || Ok(Field::zero()))?; + cs.assign(Variable(config.sc, row), || Ok(Field::one()))?; + cs.assign(Variable(config.sm, row), || Ok(Field::one()))?; + row += 1; + + cs.assign(Variable(config.a, row), || { + self.a.ok_or(Error::SynthesisError) + })?; + cs.assign(Variable(config.b, row), || { + a_squared.ok_or(Error::SynthesisError) + })?; + let fin = a_squared.and_then(|a_squared| self.a.map(|a| a + a_squared)); + cs.assign(Variable(config.c, row), || fin.ok_or(Error::SynthesisError))?; + // Addition gate + cs.assign(Variable(config.sa, row), || Ok(Field::one()))?; + cs.assign(Variable(config.sb, row), || Ok(Field::one()))?; + cs.assign(Variable(config.sc, row), || Ok(Field::one()))?; + cs.assign(Variable(config.sm, row), || Ok(Field::zero()))?; + row += 1; + } + Ok(()) } } diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index f016b6b..3f4f872 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -6,7 +6,7 @@ use crate::arithmetic::Field; /// This represents a PLONK wire, which could be a fixed (selector) wire or an /// advice wire. -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub enum Wire { /// A wires A, @@ -16,15 +16,23 @@ pub enum Wire { C, /// D wires D, + /// Fixed wires + Fixed(usize), + /// Advice wires + Advice(usize), } /// Represents a pointer to a value in the constraint system. #[derive(Clone, Debug)] -pub struct Variable(pub(crate) Wire, pub(crate) usize); +pub struct Variable(pub Wire, pub usize); /// This trait allows a [`Circuit`] to direct some backend to assign a witness /// for a constraint system. pub trait ConstraintSystem { + /// Assign a wire value + fn assign(&mut self, var: Variable, to: impl FnOnce() -> Result) + -> Result<(), Error>; + /// Creates a gate. fn create_gate( &mut self, @@ -131,8 +139,8 @@ impl Mul for Polynomial { /// permutation arrangements. #[derive(Debug, Clone)] pub struct MetaCircuit { - // num_fixed_wires: usize, - // num_advice_wires: usize, + pub(crate) num_fixed_wires: usize, + pub(crate) num_advice_wires: usize, // permutations: Vec>, // gates: Vec, // queries: HashSet<(Wire, usize)>, @@ -141,6 +149,24 @@ pub struct MetaCircuit { impl Default for MetaCircuit { fn default() -> MetaCircuit { - MetaCircuit {} + MetaCircuit { + num_fixed_wires: 0, + num_advice_wires: 0, + } + } +} + +impl MetaCircuit { + /// Allocate a new fixed wire + pub fn fixed_wire(&mut self) -> Wire { + let tmp = Wire::Fixed(self.num_fixed_wires); + self.num_fixed_wires += 1; + tmp + } + /// Allocate a new advice wire + pub fn advice_wire(&mut self) -> Wire { + let tmp = Wire::Advice(self.num_advice_wires); + self.num_advice_wires += 1; + tmp } } diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index f6016cf..b99e015 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -1,5 +1,5 @@ use super::{ - circuit::{Circuit, ConstraintSystem, MetaCircuit, Wire, Variable}, + circuit::{Circuit, ConstraintSystem, MetaCircuit, Variable, Wire}, hash_point, Error, Proof, SRS, }; use crate::arithmetic::{ @@ -31,9 +31,29 @@ impl Proof { sc: Vec, sd: Vec, sm: Vec, + advice: Vec>, } impl ConstraintSystem for WitnessCollection { + fn assign( + &mut self, + var: Variable, + to: impl FnOnce() -> Result, + ) -> Result<(), Error> { + // We only care about advice wires here. + match var.0 { + Wire::Advice(index) => { + *self + .advice + .get_mut(index) + .and_then(|v| v.get_mut(var.1)) + .ok_or(Error::BoundsFailure)? = to()?; + } + _ => {} + } + Ok(()) + } + fn create_gate( &mut self, sa: F, @@ -66,6 +86,9 @@ impl Proof { // } } + let mut meta = MetaCircuit::default(); + let config = ConcreteCircuit::configure(&mut meta); + let mut witness = WitnessCollection { a: vec![], b: vec![], @@ -76,12 +99,9 @@ impl Proof { sc: vec![], sd: vec![], sm: vec![], + advice: vec![vec![C::Scalar::zero(); params.n as usize]; meta.num_advice_wires], }; - let mut meta = MetaCircuit::default(); - - let config = ConcreteCircuit::configure(&mut meta); - // Synthesize the circuit to obtain the witness and other information. circuit.synthesize(&mut witness, config)?; @@ -115,10 +135,21 @@ impl Proof { let c_commitment = params.commit_lagrange(&witness.c, c_blind).to_affine(); let d_commitment = params.commit_lagrange(&witness.d, d_blind).to_affine(); + let advice_blinds = vec![C::Scalar::one(); witness.advice.len()]; // TODO: not random + let advice_commitments = witness + .advice + .iter() + .zip(advice_blinds.iter()) + .map(|(poly, blind)| params.commit_lagrange(poly, *blind).to_affine()) + .collect(); + hash_point(&mut transcript, &a_commitment)?; hash_point(&mut transcript, &b_commitment)?; hash_point(&mut transcript, &c_commitment)?; hash_point(&mut transcript, &d_commitment)?; + for commitment in &advice_commitments { + hash_point(&mut transcript, commitment)?; + } let domain = &srs.domain; @@ -127,6 +158,12 @@ impl Proof { let (c_coset, c_poly) = domain.obtain_coset(witness.c); let (d_coset, d_poly) = domain.obtain_coset(witness.d); + let advice_polys: Vec<_> = witness + .advice + .into_iter() + .map(|poly| domain.obtain_coset(poly)) + .collect(); + // (a * sa) + (b * sb) + (a * sm * b) + (d * sd) - (c * sc) let mut h_poly = Vec::with_capacity(a_coset.len()); for ((((((((a, b), c), d), sa), sb), sc), sd), sm) in a_coset @@ -253,6 +290,7 @@ impl Proof { b_commitment, c_commitment, d_commitment, + advice_commitments, h_commitments, a_eval_x, b_eval_x, diff --git a/src/plonk/srs.rs b/src/plonk/srs.rs index c61f8cb..1c2e3b6 100644 --- a/src/plonk/srs.rs +++ b/src/plonk/srs.rs @@ -1,5 +1,5 @@ use super::{ - circuit::{Circuit, ConstraintSystem, MetaCircuit, Wire, Variable}, + circuit::{Circuit, ConstraintSystem, MetaCircuit, Variable, Wire}, domain::EvaluationDomain, Error, GATE_DEGREE, SRS, }; @@ -19,9 +19,28 @@ impl SRS { sc: Vec, sd: Vec, sm: Vec, + fixed: Vec>, } impl ConstraintSystem for Assembly { + fn assign( + &mut self, + var: Variable, + to: impl FnOnce() -> Result, + ) -> Result<(), Error> { + // We only care about fixed wires here. + match var.0 { + Wire::Fixed(index) => { + *self + .fixed + .get_mut(index) + .and_then(|v| v.get_mut(var.1)) + .ok_or(Error::BoundsFailure)? = to()?; + } + _ => {} + } + Ok(()) + } fn create_gate( &mut self, sa: F, @@ -46,18 +65,18 @@ impl SRS { } } + let mut meta = MetaCircuit::default(); + let config = ConcreteCircuit::configure(&mut meta); + let mut assembly: Assembly = Assembly { sa: vec![], sb: vec![], sc: vec![], sd: vec![], sm: vec![], + fixed: vec![vec![C::Scalar::zero(); params.n as usize]; meta.num_fixed_wires], }; - let mut meta = MetaCircuit::default(); - - let config = ConcreteCircuit::configure(&mut meta); - // Synthesize the circuit to obtain SRS circuit.synthesize(&mut assembly, config)?; @@ -84,6 +103,12 @@ impl SRS { .commit_lagrange(&assembly.sm, C::Scalar::one()) .to_affine(); + let fixed_commitments = assembly + .fixed + .iter() + .map(|poly| params.commit_lagrange(poly, C::Scalar::one()).to_affine()) + .collect(); + let domain = EvaluationDomain::new(GATE_DEGREE, params.k); let sa = domain.obtain_coset(assembly.sa); @@ -92,6 +117,12 @@ impl SRS { let sd = domain.obtain_coset(assembly.sd); let sm = domain.obtain_coset(assembly.sm); + let fixed_polys = assembly + .fixed + .into_iter() + .map(|poly| domain.obtain_coset(poly)) + .collect(); + Ok(SRS { sa, sb, @@ -104,6 +135,10 @@ impl SRS { sd_commitment, sm_commitment, domain, + + fixed_commitments, + fixed_polys, + meta, }) } } diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index 4759fd4..e155cb1 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -22,6 +22,11 @@ impl Proof { hash_point(&mut transcript, &self.d_commitment) .expect("proof cannot contain points at infinity"); + for commitment in &self.advice_commitments { + hash_point(&mut transcript, commitment) + .expect("proof cannot contain points at infinity"); + } + for c in &self.h_commitments { hash_point(&mut transcript, c).expect("proof cannot contain points at infinity"); }