diff --git a/src/dev.rs b/src/dev.rs index f11e3fb..5726449 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 d4d8631..4b98494 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 e632c08..c3a9f93 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 5530433..e707a02 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 14dee34..9129b8a 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 };