From d8534e1c50a52769bdf1edcd3c06c16160251055 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 10 Feb 2021 19:36:25 +0800 Subject: [PATCH 01/10] Pass Expressions to meta.lookup() --- examples/circuit-layout.rs | 8 ++++++-- src/dev.rs | 25 ++++++++++++++++++------- src/plonk.rs | 8 ++++++-- src/plonk/circuit.rs | 20 ++++++++------------ src/plonk/lookup.rs | 13 +++++++------ src/plonk/lookup/prover.rs | 33 ++++++++++++++++++++------------- src/plonk/lookup/verifier.rs | 21 +++++++++++---------- 7 files changed, 76 insertions(+), 52 deletions(-) diff --git a/examples/circuit-layout.rs b/examples/circuit-layout.rs index 045e50e3..ccd93380 100644 --- a/examples/circuit-layout.rs +++ b/examples/circuit-layout.rs @@ -283,8 +283,12 @@ fn main() { * ... ... ... 0 0 * ] */ - meta.lookup(&[a.into()], &[sl.into()]); - meta.lookup(&[a.into(), b.into()], &[sl.into(), sl2.into()]); + let a_ = meta.query_any(a.into(), Rotation::cur()); + let b_ = meta.query_any(b.into(), Rotation::cur()); + let sl_ = meta.query_any(sl.into(), Rotation::cur()); + let sl2_ = meta.query_any(sl2.into(), Rotation::cur()); + meta.lookup(&[a_.clone()], &[sl_.clone()]); + meta.lookup(&[a_, b_], &[sl_, sl2_]); meta.create_gate("Combined add-mult", |meta| { let d = meta.query_advice(d, Rotation::next()); diff --git a/src/dev.rs b/src/dev.rs index 02950bf2..f11e3fb2 100644 --- a/src/dev.rs +++ b/src/dev.rs @@ -5,8 +5,8 @@ use ff::Field; use crate::{ arithmetic::{FieldExt, Group}, plonk::{ - permutation, Advice, Any, Assignment, Circuit, Column, ColumnType, ConstraintSystem, Error, - Fixed, + permutation, Advice, Assignment, Circuit, Column, ColumnType, ConstraintSystem, Error, + Expression, Fixed, }, poly::Rotation, }; @@ -143,7 +143,7 @@ pub enum VerifyFailure { /// ); /// ``` #[derive(Debug)] -pub struct MockProver { +pub struct MockProver { n: u32, cs: ConstraintSystem, @@ -316,10 +316,21 @@ impl MockProver { // Check that all lookups exist in their respective tables. for (lookup_index, lookup) in self.cs.lookups.iter().enumerate() { for input_row in 0..n { - let load = |column: &Column, row| match column.column_type() { - Any::Fixed => self.fixed[column.index()][row as usize], - Any::Advice => self.advice[column.index()][row as usize], - Any::Instance => self.instance[column.index()][row as usize], + let load = |column: &Expression, row| match column { + Expression::Fixed(index) => { + let column_index = self.cs.fixed_queries[*index].0.index(); + self.fixed[column_index][row as usize] + } + Expression::Advice(index) => { + let column_index = self.cs.advice_queries[*index].0.index(); + self.advice[column_index][row as usize] + } + Expression::Instance(index) => { + let column_index = self.cs.instance_queries[*index].0.index(); + self.instance[column_index][row as usize] + } + // TODO: other Expression variants + _ => unreachable!(), }; let inputs: Vec<_> = lookup diff --git a/src/plonk.rs b/src/plonk.rs index 80a05bcf..38f9ab44 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -467,8 +467,12 @@ fn test_proving() { * ... ... ... 0 0 * ] */ - meta.lookup(&[a.into()], &[sl.into()]); - meta.lookup(&[a.into(), b.into()], &[sl.into(), sl2.into()]); + let a_ = meta.query_any(a.into(), Rotation::cur()); + let b_ = meta.query_any(b.into(), Rotation::cur()); + let sl_ = meta.query_any(sl.into(), Rotation::cur()); + let sl2_ = meta.query_any(sl2.into(), Rotation::cur()); + meta.lookup(&[a_.clone()], &[sl_.clone()]); + meta.lookup(&[a_, b_], &[sl_, sl2_]); meta.create_gate("Combined add-mult", |meta| { let d = meta.query_advice(d, Rotation::next()); diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index bb664847..61b4ed7c 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -15,8 +15,10 @@ pub trait ColumnType: 'static + Sized + std::fmt::Debug {} /// A column with an index and type #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub struct Column { - index: usize, - column_type: C, + /// Index of column + pub index: usize, + /// Type of column + pub column_type: C, } impl Column { @@ -362,7 +364,7 @@ pub(crate) struct PointIndex(pub usize); /// This is a description of the circuit environment, such as the gate, column and /// permutation arrangements. #[derive(Debug, Clone)] -pub struct ConstraintSystem { +pub struct ConstraintSystem { pub(crate) num_fixed_columns: usize, pub(crate) num_advice_columns: usize, pub(crate) num_instance_columns: usize, @@ -377,7 +379,7 @@ pub struct ConstraintSystem { // Vector of lookup arguments, where each corresponds to a sequence of // input columns and a sequence of table columns involved in the lookup. - pub(crate) lookups: Vec, + pub(crate) lookups: Vec>, } /// Represents the minimal parameters that determine a `ConstraintSystem`. @@ -456,19 +458,13 @@ impl ConstraintSystem { /// columns are not the same. pub fn lookup( &mut self, - input_columns: &[Column], - table_columns: &[Column], + input_columns: &[Expression], + table_columns: &[Expression], ) -> usize { assert_eq!(input_columns.len(), table_columns.len()); let index = self.lookups.len(); - for input in input_columns { - self.query_any_index(*input, Rotation::cur()); - } - for table in table_columns { - self.query_any_index(*table, Rotation::cur()); - } self.lookups .push(lookup::Argument::new(input_columns, table_columns)); diff --git a/src/plonk/lookup.rs b/src/plonk/lookup.rs index acb76ff7..6755d056 100644 --- a/src/plonk/lookup.rs +++ b/src/plonk/lookup.rs @@ -1,16 +1,17 @@ -use super::circuit::{Any, Column}; +use super::circuit::Expression; +use ff::Field; pub(crate) mod prover; pub(crate) mod verifier; #[derive(Clone, Debug)] -pub(crate) struct Argument { - pub input_columns: Vec>, - pub table_columns: Vec>, +pub(crate) struct Argument { + pub input_columns: Vec>, + pub table_columns: Vec>, } -impl Argument { - pub fn new(input_columns: &[Column], table_columns: &[Column]) -> Self { +impl Argument { + pub fn new(input_columns: &[Expression], table_columns: &[Expression]) -> Self { assert_eq!(input_columns.len(), table_columns.len()); Argument { input_columns: input_columns.to_vec(), diff --git a/src/plonk/lookup/prover.rs b/src/plonk/lookup/prover.rs index 00783224..3b6ad940 100644 --- a/src/plonk/lookup/prover.rs +++ b/src/plonk/lookup/prover.rs @@ -1,5 +1,5 @@ use super::super::{ - circuit::{Any, Column}, + circuit::{Advice, Aux, Column, Expression, Fixed}, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, Error, ProvingKey, }; use super::Argument; @@ -57,7 +57,7 @@ pub(in crate::plonk) struct Evaluated { constructed: Constructed, } -impl Argument { +impl Argument { /// Given a Lookup with input columns [A_0, A_1, ..., A_{m-1}] and table columns /// [S_0, S_1, ..., S_{m-1}], this method /// - constructs A_compressed = \theta^{m-1} A_0 + theta^{m-2} A_1 + ... + \theta A_{m-2} + A_{m-1} @@ -82,20 +82,27 @@ impl Argument { transcript: &mut T, ) -> Result, Error> { // Closure to get values of columns and compress them - let compress_columns = |columns: &[Column]| { + let compress_columns = |columns: &[Expression]| { // Values of input columns involved in the lookup let (unpermuted_columns, unpermuted_cosets): (Vec<_>, Vec<_>) = columns .iter() - .map(|&column| { - let (values, cosets) = match column.column_type() { - Any::Advice => (advice_values, advice_cosets), - Any::Fixed => (fixed_values, fixed_cosets), - Any::Instance => (instance_values, instance_cosets), - }; - ( - &values[column.index()], - &cosets[pk.vk.cs.get_any_query_index(column, Rotation::cur())], - ) + .map(|column| { + match column { + Expression::Advice(index) => { + let column_index = pk.vk.cs.advice_queries[*index].0.index(); + (&advice_values[column_index], &advice_cosets[*index]) + } + Expression::Fixed(index) => { + let column_index = pk.vk.cs.fixed_queries[*index].0.index(); + (&fixed_values[column_index], &fixed_cosets[*index]) + } + Expression::Instance(index) => { + let column_index = pk.vk.cs.instance_queries[*index].0.index(); + (&instance_values[column_index], &instance_cosets[*index]) + } + // TODO: other Expression variants + _ => unreachable!(), + } }) .unzip(); diff --git a/src/plonk/lookup/verifier.rs b/src/plonk/lookup/verifier.rs index 50581eef..9be04cf8 100644 --- a/src/plonk/lookup/verifier.rs +++ b/src/plonk/lookup/verifier.rs @@ -1,9 +1,9 @@ use std::iter; -use super::super::circuit::{Any, Column}; +use super::super::circuit::{Advice, Aux, Column, Expression, Fixed}; use super::Argument; use crate::{ - arithmetic::CurveAffine, + arithmetic::{CurveAffine, FieldExt}, plonk::{ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, Error, VerifyingKey}, poly::{multiopen::VerifierQuery, Rotation}, transcript::TranscriptRead, @@ -29,7 +29,7 @@ pub struct Evaluated { permuted_table_eval: C::Scalar, } -impl Argument { +impl Argument { pub(in crate::plonk) fn read_permuted_commitments>( &self, transcript: &mut T, @@ -101,7 +101,7 @@ impl Evaluated { &'a self, vk: &'a VerifyingKey, l_0: C::Scalar, - argument: &'a Argument, + argument: &'a Argument, theta: ChallengeTheta, beta: ChallengeBeta, gamma: ChallengeGamma, @@ -116,15 +116,16 @@ impl Evaluated { * &(self.permuted_input_eval + &*beta) * &(self.permuted_table_eval + &*gamma); - let compress_columns = |columns: &[Column]| { + let compress_columns = |columns: &[Expression]| { columns .iter() .map(|column| { - let index = vk.cs.get_any_query_index(*column, Rotation::cur()); - match column.column_type() { - Any::Advice => advice_evals[index], - Any::Fixed => fixed_evals[index], - Any::Instance => instance_evals[index], + match column { + Expression::Advice(index) => advice_evals[*index], + Expression::Fixed(index) => fixed_evals[*index], + Expression::Instance(index) => instance_evals[*index], + // TODO: other Expression variants + _ => unreachable!(), } }) .fold(C::Scalar::zero(), |acc, eval| acc * &*theta + &eval) From aca6de61f8de2672caaffdab074197eadbff3526 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 10 Feb 2021 22:57:08 +0800 Subject: [PATCH 02/10] Evaluate Expressions and all variants Co-authored-by: Jack Grigg --- src/plonk.rs | 2 +- src/plonk/circuit.rs | 6 +-- src/plonk/lookup/prover.rs | 99 +++++++++++++++++++++++------------- src/plonk/lookup/verifier.rs | 18 +++---- src/plonk/prover.rs | 4 +- src/plonk/verifier.rs | 1 - 6 files changed, 78 insertions(+), 52 deletions(-) diff --git a/src/plonk.rs b/src/plonk.rs index 38f9ab44..205613b5 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -472,7 +472,7 @@ fn test_proving() { let sl_ = meta.query_any(sl.into(), Rotation::cur()); let sl2_ = meta.query_any(sl2.into(), Rotation::cur()); meta.lookup(&[a_.clone()], &[sl_.clone()]); - meta.lookup(&[a_, b_], &[sl_, sl2_]); + meta.lookup(&[a_ + b_], &[sl_ + sl2_]); meta.create_gate("Combined add-mult", |meta| { let d = meta.query_advice(d, Rotation::next()); diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index 61b4ed7c..d4d8631e 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -15,10 +15,8 @@ pub trait ColumnType: 'static + Sized + std::fmt::Debug {} /// A column with an index and type #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub struct Column { - /// Index of column - pub index: usize, - /// Type of column - pub column_type: C, + index: usize, + column_type: C, } impl Column { diff --git a/src/plonk/lookup/prover.rs b/src/plonk/lookup/prover.rs index 3b6ad940..55304331 100644 --- a/src/plonk/lookup/prover.rs +++ b/src/plonk/lookup/prover.rs @@ -1,6 +1,6 @@ use super::super::{ - circuit::{Advice, Aux, Column, Expression, Fixed}, - ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, Error, ProvingKey, + circuit::Expression, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, Error, + ProvingKey, }; use super::Argument; use crate::{ @@ -13,20 +13,24 @@ use crate::{ transcript::TranscriptWrite, }; use ff::Field; -use std::{collections::BTreeMap, iter}; +use std::{ + collections::BTreeMap, + iter, + ops::{Mul, MulAssign}, +}; #[derive(Debug)] -pub(in crate::plonk) struct Permuted<'a, C: CurveAffine> { - unpermuted_input_columns: Vec<&'a Polynomial>, - unpermuted_input_cosets: Vec<&'a Polynomial>, +pub(in crate::plonk) struct Permuted { + unpermuted_input_columns: Vec>, + unpermuted_input_cosets: Vec>, permuted_input_column: Polynomial, permuted_input_poly: Polynomial, permuted_input_coset: Polynomial, permuted_input_inv_coset: Polynomial, permuted_input_blind: Blind, permuted_input_commitment: C, - unpermuted_table_columns: Vec<&'a Polynomial>, - unpermuted_table_cosets: Vec<&'a Polynomial>, + unpermuted_table_columns: Vec>, + unpermuted_table_cosets: Vec>, permuted_table_column: Polynomial, permuted_table_poly: Polynomial, permuted_table_coset: Polynomial, @@ -35,8 +39,8 @@ pub(in crate::plonk) struct Permuted<'a, C: CurveAffine> { } #[derive(Debug)] -pub(in crate::plonk) struct Committed<'a, C: CurveAffine> { - permuted: Permuted<'a, C>, +pub(in crate::plonk) struct Committed { + permuted: Permuted, product_poly: Polynomial, product_coset: Polynomial, product_inv_coset: Polynomial, @@ -67,7 +71,7 @@ impl Argument { /// - constructs Permuted struct using permuted_input_value = A', and /// permuted_table_column = S'. /// The Permuted struct is used to update the Lookup, and is then returned. - pub(in crate::plonk) fn commit_permuted<'a, C: CurveAffine, T: TranscriptWrite>( + pub(in crate::plonk) fn commit_permuted<'a, C, T: TranscriptWrite>( &self, pk: &ProvingKey, params: &Params, @@ -80,31 +84,56 @@ impl Argument { fixed_cosets: &'a [Polynomial], instance_cosets: &'a [Polynomial], transcript: &mut T, - ) -> Result, Error> { + ) -> Result, Error> + where + C: CurveAffine, + C::Projective: Mul + MulAssign, + { // Closure to get values of columns and compress them - let compress_columns = |columns: &[Expression]| { + let compress_columns = |columns: &[Expression]| { // Values of input columns involved in the lookup - let (unpermuted_columns, unpermuted_cosets): (Vec<_>, Vec<_>) = columns + let unpermuted_columns: Vec<_> = columns .iter() .map(|column| { - match column { - Expression::Advice(index) => { - let column_index = pk.vk.cs.advice_queries[*index].0.index(); - (&advice_values[column_index], &advice_cosets[*index]) - } - Expression::Fixed(index) => { - let column_index = pk.vk.cs.fixed_queries[*index].0.index(); - (&fixed_values[column_index], &fixed_cosets[*index]) - } - Expression::Instance(index) => { - let column_index = pk.vk.cs.instance_queries[*index].0.index(); - (&instance_values[column_index], &instance_cosets[*index]) - } - // TODO: other Expression variants - _ => unreachable!(), - } + column.evaluate( + &|index| { + let column_index = pk.vk.cs.fixed_queries[index].0.index(); + fixed_values[column_index].clone() + }, + &|index| { + let column_index = pk.vk.cs.advice_queries[index].0.index(); + advice_values[column_index].clone() + }, + &|index| { + let column_index = pk.vk.cs.instance_queries[index].0.index(); + instance_values[column_index].clone() + }, + &|a, b| a + &b, + &|a, b| { + let a = &mut a.clone(); + for (a_, b_) in a.iter_mut().zip(b.iter()) { + *a_ *= b_; + } + a.clone() + }, + &|a, scalar| a * scalar, + ) }) - .unzip(); + .collect(); + + let unpermuted_cosets: Vec<_> = columns + .iter() + .map(|column| { + column.evaluate( + &|index| fixed_cosets[index].clone(), + &|index| advice_cosets[index].clone(), + &|index| instance_cosets[index].clone(), + &|a, b| a + &b, + &|a, b| a * &b, + &|a, scalar| a * scalar, + ) + }) + .collect(); // Compressed version of columns let compressed_column = unpermuted_columns @@ -185,7 +214,7 @@ impl Argument { } } -impl<'a, C: CurveAffine> Permuted<'a, C> { +impl Permuted { /// Given a Lookup with input columns, table columns, and the permuted /// input column and permuted table column, this method constructs the /// grand product polynomial over the lookup. The grand product polynomial @@ -199,7 +228,7 @@ impl<'a, C: CurveAffine> Permuted<'a, C> { beta: ChallengeBeta, gamma: ChallengeGamma, transcript: &mut T, - ) -> Result, Error> { + ) -> Result, Error> { // Goal is to compute the products of fractions // // Numerator: (\theta^{m-1} a_0(\omega^i) + \theta^{m-2} a_1(\omega^i) + ... + \theta a_{m-2}(\omega^i) + a_{m-1}(\omega^i) + \beta) @@ -327,7 +356,7 @@ impl<'a, C: CurveAffine> Permuted<'a, C> { .write_point(product_commitment) .map_err(|_| Error::TranscriptError)?; - Ok(Committed::<'a, C> { + Ok(Committed:: { permuted: self, product_poly: z, product_coset, @@ -338,7 +367,7 @@ impl<'a, C: CurveAffine> Permuted<'a, C> { } } -impl<'a, C: CurveAffine> Committed<'a, C> { +impl<'a, C: CurveAffine> Committed { /// Given a Lookup with input columns, table columns, permuted input /// column, permuted table column, and grand product polynomial, this /// method constructs constraints that must hold between these values. diff --git a/src/plonk/lookup/verifier.rs b/src/plonk/lookup/verifier.rs index 9be04cf8..14dee34c 100644 --- a/src/plonk/lookup/verifier.rs +++ b/src/plonk/lookup/verifier.rs @@ -1,6 +1,6 @@ use std::iter; -use super::super::circuit::{Advice, Aux, Column, Expression, Fixed}; +use super::super::circuit::Expression; use super::Argument; use crate::{ arithmetic::{CurveAffine, FieldExt}, @@ -99,7 +99,6 @@ impl Committed { impl Evaluated { pub(in crate::plonk) fn expressions<'a>( &'a self, - vk: &'a VerifyingKey, l_0: C::Scalar, argument: &'a Argument, theta: ChallengeTheta, @@ -120,13 +119,14 @@ impl Evaluated { columns .iter() .map(|column| { - match column { - Expression::Advice(index) => advice_evals[*index], - Expression::Fixed(index) => fixed_evals[*index], - Expression::Instance(index) => instance_evals[*index], - // TODO: other Expression variants - _ => unreachable!(), - } + column.evaluate( + &|index| fixed_evals[index], + &|index| advice_evals[index], + &|index| instance_evals[index], + &|a, b| a + &b, + &|a, b| a * &b, + &|a, scalar| a * scalar, + ) }) .fold(C::Scalar::zero(), |acc, eval| acc * &*theta + &eval) }; diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 15ec08b0..ed43f5b4 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -246,7 +246,7 @@ pub fn create_proof, ConcreteCircuit: Circ // Sample theta challenge for keeping lookup columns linearly independent let theta = ChallengeTheta::get(transcript); - let lookups: Vec>> = instance + let lookups: Vec>> = instance .iter() .zip(advice.iter()) .map(|(instance, advice)| -> Result, Error> { @@ -307,7 +307,7 @@ pub fn create_proof, ConcreteCircuit: Circ }) .collect::, _>>()?; - let lookups: Vec>> = lookups + let lookups: Vec>> = lookups .into_iter() .map(|lookups| -> Result, _> { // Construct and commit to products for each lookup diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index f1f09d2e..c854901c 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -201,7 +201,6 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( .zip(vk.cs.lookups.iter()) .flat_map(move |(p, argument)| { p.expressions( - vk, l_0, argument, theta, From 2f2de13887045645b14c73051aab908807ddb11c Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 12 Feb 2021 09:40:53 +0800 Subject: [PATCH 03/10] Calculate required degree of lookup --- src/plonk.rs | 2 +- src/plonk/lookup.rs | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/plonk.rs b/src/plonk.rs index 205613b5..4e147d1d 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -472,7 +472,7 @@ fn test_proving() { let sl_ = meta.query_any(sl.into(), Rotation::cur()); let sl2_ = meta.query_any(sl2.into(), Rotation::cur()); meta.lookup(&[a_.clone()], &[sl_.clone()]); - meta.lookup(&[a_ + b_], &[sl_ + sl2_]); + meta.lookup(&[a_ * b_], &[sl_ * sl2_]); meta.create_gate("Combined add-mult", |meta| { let d = meta.query_advice(d, Rotation::next()); diff --git a/src/plonk/lookup.rs b/src/plonk/lookup.rs index 6755d056..e632c082 100644 --- a/src/plonk/lookup.rs +++ b/src/plonk/lookup.rs @@ -25,7 +25,7 @@ impl Argument { // degree 2: // l_0(X) * (1 - z'(X)) = 0 // - // degree 3: + // degree (1 + input_degree + table_degree): // z'(X) (a'(X) + \beta) (s'(X) + \gamma) // - z'(\omega^{-1} X) (\theta^{m-1} a_0(X) + ... + a_{m-1}(X) + \beta) (\theta^{m-1} s_0(X) + ... + s_{m-1}(X) + \gamma) // @@ -34,6 +34,15 @@ impl Argument { // // degree 2: // (a′(X)−s′(X))⋅(a′(X)−a′(\omega{-1} X)) = 0 - 3 + let mut input_degree = 1; + for expr in self.input_columns.iter() { + input_degree = std::cmp::max(input_degree, expr.degree()); + } + let mut table_degree = 1; + for expr in self.table_columns.iter() { + table_degree = std::cmp::max(table_degree, expr.degree()); + } + + 1 + input_degree + table_degree } } From 8e56b415fbd4927884db625d89381a9e76817d68 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Fri, 12 Feb 2021 10:24:55 +0800 Subject: [PATCH 04/10] Rename column -> expression for lookups --- src/dev.rs | 42 ++++--- src/plonk/circuit.rs | 16 +-- src/plonk/lookup.rs | 18 +-- src/plonk/lookup/prover.rs | 207 ++++++++++++++++++----------------- src/plonk/lookup/verifier.rs | 12 +- 5 files changed, 157 insertions(+), 138 deletions(-) diff --git a/src/dev.rs b/src/dev.rs index f11e3fb2..57264494 100644 --- a/src/dev.rs +++ b/src/dev.rs @@ -316,30 +316,38 @@ impl MockProver { // Check that all lookups exist in their respective tables. for (lookup_index, lookup) in self.cs.lookups.iter().enumerate() { for input_row in 0..n { - let load = |column: &Expression, row| match column { - Expression::Fixed(index) => { - let column_index = self.cs.fixed_queries[*index].0.index(); - self.fixed[column_index][row as usize] - } - Expression::Advice(index) => { - let column_index = self.cs.advice_queries[*index].0.index(); - self.advice[column_index][row as usize] - } - Expression::Instance(index) => { - let column_index = self.cs.instance_queries[*index].0.index(); - self.instance[column_index][row as usize] - } - // TODO: other Expression variants - _ => unreachable!(), + let load = |expression: &Expression, row| { + expression.evaluate( + &|index| { + let column_index = self.cs.fixed_queries[index].0.index(); + self.fixed[column_index][row as usize] + }, + &|index| { + let column_index = self.cs.advice_queries[index].0.index(); + self.advice[column_index][row as usize] + }, + &|index| { + let column_index = self.cs.instance_queries[index].0.index(); + self.instance[column_index][row as usize] + }, + &|a, b| a + b, + &|a, b| a * b, + &|a, scalar| a * scalar, + ) }; let inputs: Vec<_> = lookup - .input_columns + .input_expressions .iter() .map(|c| load(c, input_row)) .collect(); if !(0..n) - .map(|table_row| lookup.table_columns.iter().map(move |c| load(c, table_row))) + .map(|table_row| { + lookup + .table_expressions + .iter() + .map(move |c| load(c, table_row)) + }) .any(|table_row| table_row.eq(inputs.iter().cloned())) { return Err(VerifyFailure::Lookup { diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index d4d8631e..4b984941 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -376,7 +376,7 @@ pub struct ConstraintSystem { pub(crate) permutations: Vec, // Vector of lookup arguments, where each corresponds to a sequence of - // input columns and a sequence of table columns involved in the lookup. + // input expressions and a sequence of table expressions involved in the lookup. pub(crate) lookups: Vec>, } @@ -451,20 +451,20 @@ impl ConstraintSystem { index } - /// Add a lookup argument for some input columns and table columns. - /// The function will panic if the number of input columns and table - /// columns are not the same. + /// Add a lookup argument for some input expressions and table expressions. + /// The function will panic if the number of input expressions and table + /// expressions are not the same. pub fn lookup( &mut self, - input_columns: &[Expression], - table_columns: &[Expression], + input_expressions: &[Expression], + table_expressions: &[Expression], ) -> usize { - assert_eq!(input_columns.len(), table_columns.len()); + assert_eq!(input_expressions.len(), table_expressions.len()); let index = self.lookups.len(); self.lookups - .push(lookup::Argument::new(input_columns, table_columns)); + .push(lookup::Argument::new(input_expressions, table_expressions)); index } diff --git a/src/plonk/lookup.rs b/src/plonk/lookup.rs index e632c082..c3a9f936 100644 --- a/src/plonk/lookup.rs +++ b/src/plonk/lookup.rs @@ -6,21 +6,21 @@ pub(crate) mod verifier; #[derive(Clone, Debug)] pub(crate) struct Argument { - pub input_columns: Vec>, - pub table_columns: Vec>, + pub input_expressions: Vec>, + pub table_expressions: Vec>, } impl Argument { - pub fn new(input_columns: &[Expression], table_columns: &[Expression]) -> Self { - assert_eq!(input_columns.len(), table_columns.len()); + pub fn new(input_expressions: &[Expression], table_expressions: &[Expression]) -> Self { + assert_eq!(input_expressions.len(), table_expressions.len()); Argument { - input_columns: input_columns.to_vec(), - table_columns: table_columns.to_vec(), + input_expressions: input_expressions.to_vec(), + table_expressions: table_expressions.to_vec(), } } pub(crate) fn required_degree(&self) -> usize { - assert_eq!(self.input_columns.len(), self.table_columns.len()); + assert_eq!(self.input_expressions.len(), self.table_expressions.len()); // degree 2: // l_0(X) * (1 - z'(X)) = 0 @@ -35,11 +35,11 @@ impl Argument { // degree 2: // (a′(X)−s′(X))⋅(a′(X)−a′(\omega{-1} X)) = 0 let mut input_degree = 1; - for expr in self.input_columns.iter() { + for expr in self.input_expressions.iter() { input_degree = std::cmp::max(input_degree, expr.degree()); } let mut table_degree = 1; - for expr in self.table_columns.iter() { + for expr in self.table_expressions.iter() { table_degree = std::cmp::max(table_degree, expr.degree()); } diff --git a/src/plonk/lookup/prover.rs b/src/plonk/lookup/prover.rs index 55304331..e707a02c 100644 --- a/src/plonk/lookup/prover.rs +++ b/src/plonk/lookup/prover.rs @@ -21,17 +21,17 @@ use std::{ #[derive(Debug)] pub(in crate::plonk) struct Permuted { - unpermuted_input_columns: Vec>, + unpermuted_input_expressions: Vec>, unpermuted_input_cosets: Vec>, - permuted_input_column: Polynomial, + permuted_input_expression: Polynomial, permuted_input_poly: Polynomial, permuted_input_coset: Polynomial, permuted_input_inv_coset: Polynomial, permuted_input_blind: Blind, permuted_input_commitment: C, - unpermuted_table_columns: Vec>, + unpermuted_table_expressions: Vec>, unpermuted_table_cosets: Vec>, - permuted_table_column: Polynomial, + permuted_table_expression: Polynomial, permuted_table_poly: Polynomial, permuted_table_coset: Polynomial, permuted_table_blind: Blind, @@ -62,14 +62,14 @@ pub(in crate::plonk) struct Evaluated { } impl Argument { - /// Given a Lookup with input columns [A_0, A_1, ..., A_{m-1}] and table columns + /// Given a Lookup with input expressions [A_0, A_1, ..., A_{m-1}] and table expressions /// [S_0, S_1, ..., S_{m-1}], this method /// - constructs A_compressed = \theta^{m-1} A_0 + theta^{m-2} A_1 + ... + \theta A_{m-2} + A_{m-1} /// and S_compressed = \theta^{m-1} S_0 + theta^{m-2} S_1 + ... + \theta S_{m-2} + S_{m-1}, - /// - permutes A_compressed and S_compressed using permute_column_pair() helper, + /// - permutes A_compressed and S_compressed using permute_expression_pair() helper, /// obtaining A' and S', and /// - constructs Permuted struct using permuted_input_value = A', and - /// permuted_table_column = S'. + /// permuted_table_expression = S'. /// The Permuted struct is used to update the Lookup, and is then returned. pub(in crate::plonk) fn commit_permuted<'a, C, T: TranscriptWrite>( &self, @@ -89,13 +89,13 @@ impl Argument { C: CurveAffine, C::Projective: Mul + MulAssign, { - // Closure to get values of columns and compress them - let compress_columns = |columns: &[Expression]| { - // Values of input columns involved in the lookup - let unpermuted_columns: Vec<_> = columns + // Closure to get values of expressions and compress them + let compress_expressions = |expressions: &[Expression]| { + // Values of input expressions involved in the lookup + let unpermuted_expressions: Vec<_> = expressions .iter() - .map(|column| { - column.evaluate( + .map(|expression| { + expression.evaluate( &|index| { let column_index = pk.vk.cs.fixed_queries[index].0.index(); fixed_values[column_index].clone() @@ -121,10 +121,10 @@ impl Argument { }) .collect(); - let unpermuted_cosets: Vec<_> = columns + let unpermuted_cosets: Vec<_> = expressions .iter() - .map(|column| { - column.evaluate( + .map(|expression| { + expression.evaluate( &|index| fixed_cosets[index].clone(), &|index| advice_cosets[index].clone(), &|index| instance_cosets[index].clone(), @@ -135,41 +135,50 @@ impl Argument { }) .collect(); - // Compressed version of columns - let compressed_column = unpermuted_columns + // Compressed version of expressions + let compressed_expression = unpermuted_expressions .iter() - .fold(domain.empty_lagrange(), |acc, column| acc * *theta + column); + .fold(domain.empty_lagrange(), |acc, expression| { + acc * *theta + expression + }); - (unpermuted_columns, unpermuted_cosets, compressed_column) + ( + unpermuted_expressions, + unpermuted_cosets, + compressed_expression, + ) }; - // Closure to construct commitment to column of values - let commit_column = |column: &Polynomial| { - let poly = pk.vk.domain.lagrange_to_coeff(column.clone()); + // Closure to construct commitment to vector of values + let commit_values = |values: &Polynomial| { + let poly = pk.vk.domain.lagrange_to_coeff(values.clone()); let blind = Blind(C::Scalar::rand()); - let commitment = params.commit_lagrange(&column, blind).to_affine(); + let commitment = params.commit_lagrange(&values, blind).to_affine(); (poly, blind, commitment) }; - // Get values of input columns involved in the lookup and compress them - let (unpermuted_input_columns, unpermuted_input_cosets, compressed_input_column) = - compress_columns(&self.input_columns); + // Get values of input expressions involved in the lookup and compress them + let (unpermuted_input_expressions, unpermuted_input_cosets, compressed_input_expression) = + compress_expressions(&self.input_expressions); - // Get values of table columns involved in the lookup and compress them - let (unpermuted_table_columns, unpermuted_table_cosets, compressed_table_column) = - compress_columns(&self.table_columns); + // Get values of table expressions involved in the lookup and compress them + let (unpermuted_table_expressions, unpermuted_table_cosets, compressed_table_expression) = + compress_expressions(&self.table_expressions); - // Permute compressed (InputColumn, TableColumn) pair - let (permuted_input_column, permuted_table_column) = - permute_column_pair::(domain, &compressed_input_column, &compressed_table_column)?; + // Permute compressed (InputExpression, TableExpression) pair + let (permuted_input_expression, permuted_table_expression) = permute_expression_pair::( + domain, + &compressed_input_expression, + &compressed_table_expression, + )?; - // Commit to permuted input column + // Commit to permuted input expression let (permuted_input_poly, permuted_input_blind, permuted_input_commitment) = - commit_column(&permuted_input_column); + commit_values(&permuted_input_expression); - // Commit to permuted table column + // Commit to permuted table expression let (permuted_table_poly, permuted_table_blind, permuted_table_commitment) = - commit_column(&permuted_table_column); + commit_values(&permuted_table_expression); // Hash permuted input commitment transcript @@ -195,17 +204,17 @@ impl Argument { .coeff_to_extended(permuted_table_poly.clone(), Rotation::cur()); Ok(Permuted { - unpermuted_input_columns, + unpermuted_input_expressions, unpermuted_input_cosets, - permuted_input_column, + permuted_input_expression, permuted_input_poly, permuted_input_coset, permuted_input_inv_coset, permuted_input_blind, permuted_input_commitment, - unpermuted_table_columns, + unpermuted_table_expressions, unpermuted_table_cosets, - permuted_table_column, + permuted_table_expression, permuted_table_poly, permuted_table_coset, permuted_table_blind, @@ -215,8 +224,8 @@ impl Argument { } impl Permuted { - /// Given a Lookup with input columns, table columns, and the permuted - /// input column and permuted table column, this method constructs the + /// Given a Lookup with input expressions, table expressions, and the permuted + /// input expression and permuted table expression, this method constructs the /// grand product polynomial over the lookup. The grand product polynomial /// is used to populate the Product struct. The Product struct is /// added to the Lookup and finally returned by the method. @@ -235,18 +244,18 @@ impl Permuted { // * (\theta^{m-1} s_0(\omega^i) + \theta^{m-2} s_1(\omega^i) + ... + \theta s_{m-2}(\omega^i) + s_{m-1}(\omega^i) + \gamma) // Denominator: (a'(\omega^i) + \beta) (s'(\omega^i) + \gamma) // - // where a_j(X) is the jth input column in this lookup, - // where a'(X) is the compression of the permuted input columns, - // s_j(X) is the jth table column in this lookup, - // s'(X) is the compression of the permuted table columns, - // and i is the ith row of the column. + // where a_j(X) is the jth input expression in this lookup, + // where a'(X) is the compression of the permuted input expressions, + // s_j(X) is the jth table expression in this lookup, + // s'(X) is the compression of the permuted table expressions, + // and i is the ith row of the expression. let mut lookup_product = vec![C::Scalar::zero(); params.n as usize]; - // Denominator uses the permuted input column and permuted table column + // Denominator uses the permuted input expression and permuted table expression parallelize(&mut lookup_product, |lookup_product, start| { for ((lookup_product, permuted_input_value), permuted_table_value) in lookup_product .iter_mut() - .zip(self.permuted_input_column[start..].iter()) - .zip(self.permuted_table_column[start..].iter()) + .zip(self.permuted_input_expression[start..].iter()) + .zip(self.permuted_table_expression[start..].iter()) { *lookup_product = (*beta + permuted_input_value) * &(*gamma + permuted_table_value); } @@ -263,18 +272,18 @@ impl Permuted { for (i, product) in product.iter_mut().enumerate() { let i = i + start; - // Compress unpermuted input columns + // Compress unpermuted input expressions let mut input_term = C::Scalar::zero(); - for unpermuted_input_column in self.unpermuted_input_columns.iter() { + for unpermuted_input_expression in self.unpermuted_input_expressions.iter() { input_term *= &*theta; - input_term += &unpermuted_input_column[i]; + input_term += &unpermuted_input_expression[i]; } - // Compress unpermuted table columns + // Compress unpermuted table expressions let mut table_term = C::Scalar::zero(); - for unpermuted_table_column in self.unpermuted_table_columns.iter() { + for unpermuted_table_expression in self.unpermuted_table_expressions.iter() { table_term *= &*theta; - table_term += &unpermuted_table_column[i]; + table_term += &unpermuted_table_expression[i]; } *product *= &(input_term + &*beta); @@ -288,12 +297,12 @@ impl Permuted { // * (\theta^{m-1} s_0(\omega^i) + \theta^{m-2} s_1(\omega^i) + ... + \theta s_{m-2}(\omega^i) + s_{m-1}(\omega^i) + \gamma) // Denominator: (a'(\omega^i) + \beta) (s'(\omega^i) + \gamma) // - // where there are m input columns and m table columns, - // a_j(\omega^i) is the jth input column in this lookup, - // a'j(\omega^i) is the permuted input column, - // s_j(\omega^i) is the jth table column in this lookup, - // s'(\omega^i) is the permuted table column, - // and i is the ith row of the column. + // where there are m input expressions and m table expressions, + // a_j(\omega^i) is the jth input expression in this lookup, + // a'j(\omega^i) is the permuted input expression, + // s_j(\omega^i) is the jth table expression in this lookup, + // s'(\omega^i) is the permuted table expression, + // and i is the ith row of the expression. // Compute the evaluations of the lookup product polynomial // over our domain, starting with z[0] = 1 @@ -319,21 +328,21 @@ impl Permuted { let prev_idx = (n + i - 1) % n; let mut left = z[i]; - let permuted_input_value = &self.permuted_input_column[i]; + let permuted_input_value = &self.permuted_input_expression[i]; - let permuted_table_value = &self.permuted_table_column[i]; + let permuted_table_value = &self.permuted_table_expression[i]; left *= &(*beta + permuted_input_value); left *= &(*gamma + permuted_table_value); let mut right = z[prev_idx]; let mut input_term = self - .unpermuted_input_columns + .unpermuted_input_expressions .iter() .fold(C::Scalar::zero(), |acc, input| acc * &*theta + &input[i]); let mut table_term = self - .unpermuted_table_columns + .unpermuted_table_expressions .iter() .fold(C::Scalar::zero(), |acc, table| acc * &*theta + &table[i]); @@ -368,8 +377,8 @@ impl Permuted { } impl<'a, C: CurveAffine> Committed { - /// Given a Lookup with input columns, table columns, permuted input - /// column, permuted table column, and grand product polynomial, this + /// Given a Lookup with input expressions, table expressions, permuted input + /// expression, permuted table expression, and grand product polynomial, this /// method constructs constraints that must hold between these values. /// This method returns the constraints as a vector of polynomials in /// the extended evaluation domain. @@ -412,14 +421,14 @@ impl<'a, C: CurveAffine> Committed { for (i, right) in right.iter_mut().enumerate() { let i = i + start; - // Compress the unpermuted input columns + // Compress the unpermuted input expressions let mut input_term = C::Scalar::zero(); for input in permuted.unpermuted_input_cosets.iter() { input_term *= &*theta; input_term += &input[i]; } - // Compress the unpermuted table columns + // Compress the unpermuted table expressions let mut table_term = C::Scalar::zero(); for table in permuted.unpermuted_table_cosets.iter() { table_term *= &*theta; @@ -434,15 +443,15 @@ impl<'a, C: CurveAffine> Committed { Some(left - &right) }) - // Check that the first values in the permuted input column and permuted - // fixed column are the same. + // Check that the first values in the permuted input expression and permuted + // fixed expression are the same. // l_0(X) * (a'(X) - s'(X)) = 0 .chain(Some( (permuted.permuted_input_coset.clone() - &permuted.permuted_table_coset) * &pk.l0, )) - // Check that each value in the permuted lookup input column is either + // Check that each value in the permuted lookup input expression is either // equal to the value above it, or the value at the same index in the - // permuted table column. + // permuted table expression. // (a′(X)−s′(X))⋅(a′(X)−a′(\omega{-1} X)) = 0 .chain(Some( (permuted.permuted_input_coset.clone() - &permuted.permuted_table_coset) @@ -538,39 +547,41 @@ impl Evaluated { } } -type ColumnPair = (Polynomial, Polynomial); +type ExpressionPair = (Polynomial, Polynomial); -/// Given a column of input values A and a column of table values S, +/// Given a vector of input values A and a vector of table values S, /// this method permutes A and S to produce A' and S', such that: /// - like values in A' are vertically adjacent to each other; and /// - the first row in a sequence of like values in A' is the row /// that has the corresponding value in S'. /// This method returns (A', S') if no errors are encountered. -fn permute_column_pair( +fn permute_expression_pair( domain: &EvaluationDomain, - input_column: &Polynomial, - table_column: &Polynomial, -) -> Result, Error> { - let mut permuted_input_column = input_column.clone(); + input_expression: &Polynomial, + table_expression: &Polynomial, +) -> Result, Error> { + let mut permuted_input_expression = input_expression.clone(); - // Sort input lookup column values - permuted_input_column.sort(); + // Sort input lookup expression values + permuted_input_expression.sort(); - // A BTreeMap of each unique element in the table column and its count + // A BTreeMap of each unique element in the table expression and its count let mut leftover_table_map: BTreeMap = - table_column.iter().fold(BTreeMap::new(), |mut acc, coeff| { - *acc.entry(*coeff).or_insert(0) += 1; - acc - }); - let mut permuted_table_coeffs = vec![C::Scalar::zero(); table_column.len()]; + table_expression + .iter() + .fold(BTreeMap::new(), |mut acc, coeff| { + *acc.entry(*coeff).or_insert(0) += 1; + acc + }); + let mut permuted_table_coeffs = vec![C::Scalar::zero(); table_expression.len()]; - let mut repeated_input_rows = permuted_input_column + let mut repeated_input_rows = permuted_input_expression .iter() .zip(permuted_table_coeffs.iter_mut()) .enumerate() .filter_map(|(row, (input_value, table_value))| { - // If this is the first occurence of `input_value` in the input column - if row == 0 || *input_value != permuted_input_column[row - 1] { + // If this is the first occurence of `input_value` in the input expression + if row == 0 || *input_value != permuted_input_expression[row - 1] { *table_value = *input_value; // Remove one instance of input_value from leftover_table_map if let Some(count) = leftover_table_map.get_mut(&input_value) { @@ -596,11 +607,11 @@ fn permute_column_pair( } assert!(repeated_input_rows.is_empty()); - let mut permuted_table_column = domain.empty_lagrange(); + let mut permuted_table_expression = domain.empty_lagrange(); parallelize( - &mut permuted_table_column, - |permuted_table_column, start| { - for (permuted_table_value, permuted_table_coeff) in permuted_table_column + &mut permuted_table_expression, + |permuted_table_expression, start| { + for (permuted_table_value, permuted_table_coeff) in permuted_table_expression .iter_mut() .zip(permuted_table_coeffs[start..].iter()) { @@ -609,5 +620,5 @@ fn permute_column_pair( }, ); - Ok((permuted_input_column, permuted_table_column)) + Ok((permuted_input_expression, permuted_table_expression)) } diff --git a/src/plonk/lookup/verifier.rs b/src/plonk/lookup/verifier.rs index 14dee34c..9129b8aa 100644 --- a/src/plonk/lookup/verifier.rs +++ b/src/plonk/lookup/verifier.rs @@ -115,11 +115,11 @@ impl Evaluated { * &(self.permuted_input_eval + &*beta) * &(self.permuted_table_eval + &*gamma); - let compress_columns = |columns: &[Expression]| { - columns + let compress_expressions = |expressions: &[Expression]| { + expressions .iter() - .map(|column| { - column.evaluate( + .map(|expression| { + expression.evaluate( &|index| fixed_evals[index], &|index| advice_evals[index], &|index| instance_evals[index], @@ -131,8 +131,8 @@ impl Evaluated { .fold(C::Scalar::zero(), |acc, eval| acc * &*theta + &eval) }; let right = self.product_inv_eval - * &(compress_columns(&argument.input_columns) + &*beta) - * &(compress_columns(&argument.table_columns) + &*gamma); + * &(compress_expressions(&argument.input_expressions) + &*beta) + * &(compress_expressions(&argument.table_expressions) + &*gamma); left - &right }; From df2d818891c79e913d3a516b51698199c5cefc2e Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Sun, 14 Feb 2021 23:17:54 +0800 Subject: [PATCH 05/10] Account for Rotations of LagrangeCoeff values --- src/plonk/lookup/prover.rs | 18 ++++++++++++------ src/poly.rs | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/plonk/lookup/prover.rs b/src/plonk/lookup/prover.rs index e707a02c..634845fa 100644 --- a/src/plonk/lookup/prover.rs +++ b/src/plonk/lookup/prover.rs @@ -97,16 +97,22 @@ impl Argument { .map(|expression| { expression.evaluate( &|index| { - let column_index = pk.vk.cs.fixed_queries[index].0.index(); - fixed_values[column_index].clone() + let query = pk.vk.cs.fixed_queries[index]; + let column_index = query.0.index(); + let rotation = query.1; + fixed_values[column_index].clone().rotate(rotation) }, &|index| { - let column_index = pk.vk.cs.advice_queries[index].0.index(); - advice_values[column_index].clone() + let query = pk.vk.cs.advice_queries[index]; + let column_index = query.0.index(); + let rotation = query.1; + advice_values[column_index].clone().rotate(rotation) }, &|index| { - let column_index = pk.vk.cs.instance_queries[index].0.index(); - instance_values[column_index].clone() + let query = pk.vk.cs.instance_queries[index]; + let column_index = query.0.index(); + let rotation = query.1; + instance_values[column_index].clone().rotate(rotation) }, &|a, b| a + &b, &|a, b| { diff --git a/src/poly.rs b/src/poly.rs index 5ac1462c..e39ba9d9 100644 --- a/src/poly.rs +++ b/src/poly.rs @@ -187,6 +187,22 @@ impl<'a, F: Field> Mul<&'a Polynomial> } } +impl<'a, F: Field> Polynomial { + /// Rotates the values in a Lagrange basis polynomial by `Rotation` + pub fn rotate(&self, rotation: Rotation) -> Polynomial { + let mut values = self.values.clone(); + if rotation.0 < 0 { + values.rotate_right((-rotation.0) as usize); + } else { + values.rotate_left(rotation.0 as usize); + } + Polynomial { + values, + _marker: PhantomData, + } + } +} + impl<'a, F: Field, B: Basis> Mul for Polynomial { type Output = Polynomial; From 6a7f869f66f90b809e00b8d816aa3d8852c8bb27 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 16 Feb 2021 17:16:47 +0800 Subject: [PATCH 06/10] Clippy fixes --- src/dev.rs | 6 +++--- src/plonk/lookup/prover.rs | 16 +++++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/dev.rs b/src/dev.rs index 57264494..1020c37c 100644 --- a/src/dev.rs +++ b/src/dev.rs @@ -341,15 +341,15 @@ impl MockProver { .iter() .map(|c| load(c, input_row)) .collect(); - if !(0..n) + let lookup_passes = (0..n) .map(|table_row| { lookup .table_expressions .iter() .map(move |c| load(c, table_row)) }) - .any(|table_row| table_row.eq(inputs.iter().cloned())) - { + .any(|table_row| table_row.eq(inputs.iter().cloned())); + if !lookup_passes { return Err(VerifyFailure::Lookup { lookup_index, row: input_row as usize, diff --git a/src/plonk/lookup/prover.rs b/src/plonk/lookup/prover.rs index 634845fa..7b559c0c 100644 --- a/src/plonk/lookup/prover.rs +++ b/src/plonk/lookup/prover.rs @@ -116,11 +116,17 @@ impl Argument { }, &|a, b| a + &b, &|a, b| { - let a = &mut a.clone(); - for (a_, b_) in a.iter_mut().zip(b.iter()) { - *a_ *= b_; - } - a.clone() + let mut modified_a = vec![C::Scalar::one(); params.n as usize]; + parallelize(&mut modified_a, |modified_a, start| { + for ((modified_a, a), b) in modified_a + .iter_mut() + .zip(a[start..].iter()) + .zip(b[start..].iter()) + { + *modified_a *= *a * b; + } + }); + pk.vk.domain.lagrange_from_vec(modified_a) }, &|a, scalar| a * scalar, ) From 4bf46fc34908169e6bd6045cfaee10009ce9e084 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Sat, 13 Feb 2021 18:36:29 +0800 Subject: [PATCH 07/10] Add Expression::Const variant --- src/dev.rs | 2 ++ src/plonk/circuit.rs | 10 ++++++++++ src/plonk/lookup/prover.rs | 2 ++ src/plonk/lookup/verifier.rs | 1 + src/plonk/prover.rs | 1 + src/plonk/verifier.rs | 1 + src/poly/domain.rs | 17 +++++++++++++++++ 7 files changed, 34 insertions(+) diff --git a/src/dev.rs b/src/dev.rs index 1020c37c..7bdbcee3 100644 --- a/src/dev.rs +++ b/src/dev.rs @@ -296,6 +296,7 @@ impl MockProver { } if gate.evaluate( + &|scalar| scalar, &load(n, row, &self.cs.fixed_queries, &self.fixed), &load(n, row, &self.cs.advice_queries, &self.advice), &load(n, row, &self.cs.instance_queries, &self.instance), @@ -318,6 +319,7 @@ impl MockProver { for input_row in 0..n { let load = |expression: &Expression, row| { expression.evaluate( + &|scalar| scalar, &|index| { let column_index = self.cs.fixed_queries[index].0.index(); self.fixed[column_index][row as usize] diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index 4b984941..dc84cbb1 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -224,6 +224,8 @@ pub trait Circuit { /// Low-degree expression representing an identity that must hold over the committed columns. #[derive(Clone, Debug)] pub enum Expression { + /// This is a constant polynomial + Const(F), /// This is a fixed column queried at a certain relative location Fixed(usize), /// This is an advice (witness) column queried at a certain relative location @@ -243,6 +245,7 @@ impl Expression { /// operations. pub fn evaluate( &self, + const_column: &impl Fn(F) -> T, fixed_column: &impl Fn(usize) -> T, advice_column: &impl Fn(usize) -> T, instance_column: &impl Fn(usize) -> T, @@ -251,11 +254,13 @@ impl Expression { scaled: &impl Fn(T, F) -> T, ) -> T { match self { + Expression::Const(scalar) => const_column(*scalar), Expression::Fixed(index) => fixed_column(*index), Expression::Advice(index) => advice_column(*index), Expression::Instance(index) => instance_column(*index), Expression::Sum(a, b) => { let a = a.evaluate( + const_column, fixed_column, advice_column, instance_column, @@ -264,6 +269,7 @@ impl Expression { scaled, ); let b = b.evaluate( + const_column, fixed_column, advice_column, instance_column, @@ -275,6 +281,7 @@ impl Expression { } Expression::Product(a, b) => { let a = a.evaluate( + const_column, fixed_column, advice_column, instance_column, @@ -283,6 +290,7 @@ impl Expression { scaled, ); let b = b.evaluate( + const_column, fixed_column, advice_column, instance_column, @@ -294,6 +302,7 @@ impl Expression { } Expression::Scaled(a, f) => { let a = a.evaluate( + const_column, fixed_column, advice_column, instance_column, @@ -309,6 +318,7 @@ impl Expression { /// Compute the degree of this polynomial pub fn degree(&self) -> usize { match self { + Expression::Const(_) => 0, Expression::Fixed(_) => 1, Expression::Advice(_) => 1, Expression::Instance(_) => 1, diff --git a/src/plonk/lookup/prover.rs b/src/plonk/lookup/prover.rs index 7b559c0c..a574a17b 100644 --- a/src/plonk/lookup/prover.rs +++ b/src/plonk/lookup/prover.rs @@ -96,6 +96,7 @@ impl Argument { .iter() .map(|expression| { expression.evaluate( + &|scalar| pk.vk.domain.const_lagrange(scalar), &|index| { let query = pk.vk.cs.fixed_queries[index]; let column_index = query.0.index(); @@ -137,6 +138,7 @@ impl Argument { .iter() .map(|expression| { expression.evaluate( + &|scalar| pk.vk.domain.const_extended(scalar), &|index| fixed_cosets[index].clone(), &|index| advice_cosets[index].clone(), &|index| instance_cosets[index].clone(), diff --git a/src/plonk/lookup/verifier.rs b/src/plonk/lookup/verifier.rs index 9129b8aa..e0c779b1 100644 --- a/src/plonk/lookup/verifier.rs +++ b/src/plonk/lookup/verifier.rs @@ -120,6 +120,7 @@ impl Evaluated { .iter() .map(|expression| { expression.evaluate( + &|scalar| scalar, &|index| fixed_evals[index], &|index| advice_evals[index], &|index| instance_evals[index], diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index ed43f5b4..a4597f72 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -373,6 +373,7 @@ pub fn create_proof, ConcreteCircuit: Circ // Custom constraints .chain(meta.gates.iter().map(move |(_, poly)| { poly.evaluate( + &|scalar| pk.vk.domain.const_extended(scalar), &|index| pk.fixed_cosets[index].clone(), &|index| advice.advice_cosets[index].clone(), &|index| instance.instance_cosets[index].clone(), diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index c854901c..38f7485f 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -168,6 +168,7 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead>( // Evaluate the circuit using the custom gates provided .chain(vk.cs.gates.iter().map(move |(_, poly)| { poly.evaluate( + &|scalar| scalar, &|index| fixed_evals[index], &|index| advice_evals[index], &|index| instance_evals[index], diff --git a/src/poly/domain.rs b/src/poly/domain.rs index c6bd2ced..2976ac30 100644 --- a/src/poly/domain.rs +++ b/src/poly/domain.rs @@ -177,6 +177,14 @@ impl EvaluationDomain { } } + /// Returns a constant polynomial in the Lagrange coefficient basis + pub fn const_lagrange(&self, scalar: G) -> Polynomial { + Polynomial { + values: vec![scalar; self.n as usize], + _marker: PhantomData, + } + } + /// Returns an empty (zero) polynomial in the extended Lagrange coefficient /// basis pub fn empty_extended(&self) -> Polynomial { @@ -186,6 +194,15 @@ impl EvaluationDomain { } } + /// Returns a constant polynomial in the extended Lagrange coefficient + /// basis + pub fn const_extended(&self, scalar: G) -> Polynomial { + Polynomial { + values: vec![scalar; self.extended_len()], + _marker: PhantomData, + } + } + /// This takes us from an n-length vector into the coefficient form. /// /// This function will panic if the provided vector is not the correct From d29246b49b4cbe2ed60778ed3cebfa561f0c5dfc Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Sun, 14 Feb 2021 08:48:44 +0800 Subject: [PATCH 08/10] Rename const_* -> constant_* --- src/plonk/circuit.rs | 18 +++++++++--------- src/plonk/lookup/prover.rs | 4 ++-- src/plonk/prover.rs | 2 +- src/poly/domain.rs | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index dc84cbb1..8f959cfc 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -225,7 +225,7 @@ pub trait Circuit { #[derive(Clone, Debug)] pub enum Expression { /// This is a constant polynomial - Const(F), + Constant(F), /// This is a fixed column queried at a certain relative location Fixed(usize), /// This is an advice (witness) column queried at a certain relative location @@ -245,7 +245,7 @@ impl Expression { /// operations. pub fn evaluate( &self, - const_column: &impl Fn(F) -> T, + constant: &impl Fn(F) -> T, fixed_column: &impl Fn(usize) -> T, advice_column: &impl Fn(usize) -> T, instance_column: &impl Fn(usize) -> T, @@ -254,13 +254,13 @@ impl Expression { scaled: &impl Fn(T, F) -> T, ) -> T { match self { - Expression::Const(scalar) => const_column(*scalar), + Expression::Constant(scalar) => constant(*scalar), Expression::Fixed(index) => fixed_column(*index), Expression::Advice(index) => advice_column(*index), Expression::Instance(index) => instance_column(*index), Expression::Sum(a, b) => { let a = a.evaluate( - const_column, + constant, fixed_column, advice_column, instance_column, @@ -269,7 +269,7 @@ impl Expression { scaled, ); let b = b.evaluate( - const_column, + constant, fixed_column, advice_column, instance_column, @@ -281,7 +281,7 @@ impl Expression { } Expression::Product(a, b) => { let a = a.evaluate( - const_column, + constant, fixed_column, advice_column, instance_column, @@ -290,7 +290,7 @@ impl Expression { scaled, ); let b = b.evaluate( - const_column, + constant, fixed_column, advice_column, instance_column, @@ -302,7 +302,7 @@ impl Expression { } Expression::Scaled(a, f) => { let a = a.evaluate( - const_column, + constant, fixed_column, advice_column, instance_column, @@ -318,7 +318,7 @@ impl Expression { /// Compute the degree of this polynomial pub fn degree(&self) -> usize { match self { - Expression::Const(_) => 0, + Expression::Constant(_) => 0, Expression::Fixed(_) => 1, Expression::Advice(_) => 1, Expression::Instance(_) => 1, diff --git a/src/plonk/lookup/prover.rs b/src/plonk/lookup/prover.rs index a574a17b..5abe7727 100644 --- a/src/plonk/lookup/prover.rs +++ b/src/plonk/lookup/prover.rs @@ -96,7 +96,7 @@ impl Argument { .iter() .map(|expression| { expression.evaluate( - &|scalar| pk.vk.domain.const_lagrange(scalar), + &|scalar| pk.vk.domain.constant_lagrange(scalar), &|index| { let query = pk.vk.cs.fixed_queries[index]; let column_index = query.0.index(); @@ -138,7 +138,7 @@ impl Argument { .iter() .map(|expression| { expression.evaluate( - &|scalar| pk.vk.domain.const_extended(scalar), + &|scalar| pk.vk.domain.constant_extended(scalar), &|index| fixed_cosets[index].clone(), &|index| advice_cosets[index].clone(), &|index| instance_cosets[index].clone(), diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index a4597f72..8d1c0553 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -373,7 +373,7 @@ pub fn create_proof, ConcreteCircuit: Circ // Custom constraints .chain(meta.gates.iter().map(move |(_, poly)| { poly.evaluate( - &|scalar| pk.vk.domain.const_extended(scalar), + &|scalar| pk.vk.domain.constant_extended(scalar), &|index| pk.fixed_cosets[index].clone(), &|index| advice.advice_cosets[index].clone(), &|index| instance.instance_cosets[index].clone(), diff --git a/src/poly/domain.rs b/src/poly/domain.rs index 2976ac30..ce530c20 100644 --- a/src/poly/domain.rs +++ b/src/poly/domain.rs @@ -178,7 +178,7 @@ impl EvaluationDomain { } /// Returns a constant polynomial in the Lagrange coefficient basis - pub fn const_lagrange(&self, scalar: G) -> Polynomial { + pub fn constant_lagrange(&self, scalar: G) -> Polynomial { Polynomial { values: vec![scalar; self.n as usize], _marker: PhantomData, @@ -196,7 +196,7 @@ impl EvaluationDomain { /// Returns a constant polynomial in the extended Lagrange coefficient /// basis - pub fn const_extended(&self, scalar: G) -> Polynomial { + pub fn constant_extended(&self, scalar: G) -> Polynomial { Polynomial { values: vec![scalar; self.extended_len()], _marker: PhantomData, From 81af4e43d1da1222ac0ebb67274cfa6e8f57c035 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Thu, 18 Feb 2021 15:48:20 -0700 Subject: [PATCH 09/10] Update pinned verification key to account for circuit changes --- src/plonk.rs | 54 +++++++++++++++++++++----------------------- src/plonk/circuit.rs | 2 +- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/plonk.rs b/src/plonk.rs index 4e147d1d..bb9fd31f 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -909,39 +909,37 @@ fn test_proving() { ], lookups: [ Argument { - input_columns: [ - Column { - index: 1, - column_type: Advice, - }, + input_expressions: [ + Advice( + 0, + ), ], - table_columns: [ - Column { - index: 6, - column_type: Fixed, - }, + table_expressions: [ + Fixed( + 0, + ), ], }, Argument { - input_columns: [ - Column { - index: 1, - column_type: Advice, - }, - Column { - index: 2, - column_type: Advice, - }, + input_expressions: [ + Product( + Advice( + 0, + ), + Advice( + 1, + ), + ), ], - table_columns: [ - Column { - index: 6, - column_type: Fixed, - }, - Column { - index: 7, - column_type: Fixed, - }, + table_expressions: [ + Product( + Fixed( + 0, + ), + Fixed( + 1, + ), + ), ], }, ], diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index 8f959cfc..f9e38b27 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -401,7 +401,7 @@ pub struct PinnedConstraintSystem<'a, F: Field> { instance_queries: &'a Vec<(Column, Rotation)>, fixed_queries: &'a Vec<(Column, Rotation)>, permutations: &'a Vec, - lookups: &'a Vec, + lookups: &'a Vec>, } struct PinnedGates<'a, F: Field>(&'a Vec<(&'static str, Expression)>); From 0316019a9422146fbd75e221163d643443c0e458 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Thu, 18 Feb 2021 16:25:00 -0700 Subject: [PATCH 10/10] Add test for polynomial rotation in Lagrange form. --- src/poly/domain.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/poly/domain.rs b/src/poly/domain.rs index ce530c20..338f1a67 100644 --- a/src/poly/domain.rs +++ b/src/poly/domain.rs @@ -413,3 +413,40 @@ pub struct PinnedEvaluationDomain<'a, G: Group> { extended_k: &'a u32, omega: &'a G::Scalar, } + +#[test] +fn test_rotate() { + use crate::arithmetic::eval_polynomial; + use crate::pasta::pallas::Scalar; + let domain = EvaluationDomain::::new(1, 3); + + let mut poly = domain.empty_lagrange(); + assert_eq!(poly.len(), 8); + for value in poly.iter_mut() { + *value = Scalar::rand(); + } + + let poly_rotated_cur = poly.rotate(Rotation::cur()); + let poly_rotated_next = poly.rotate(Rotation::next()); + let poly_rotated_prev = poly.rotate(Rotation::prev()); + + let poly = domain.lagrange_to_coeff(poly); + let poly_rotated_cur = domain.lagrange_to_coeff(poly_rotated_cur); + let poly_rotated_next = domain.lagrange_to_coeff(poly_rotated_next); + let poly_rotated_prev = domain.lagrange_to_coeff(poly_rotated_prev); + + let x = Scalar::rand(); + + assert_eq!( + eval_polynomial(&poly[..], x), + eval_polynomial(&poly_rotated_cur[..], x) + ); + assert_eq!( + eval_polynomial(&poly[..], x * domain.omega), + eval_polynomial(&poly_rotated_next[..], x) + ); + assert_eq!( + eval_polynomial(&poly[..], x * domain.omega_inv), + eval_polynomial(&poly_rotated_prev[..], x) + ); +}