diff --git a/examples/circuit-layout.rs b/examples/circuit-layout.rs index 14417e8d..0ddfc407 100644 --- a/examples/circuit-layout.rs +++ b/examples/circuit-layout.rs @@ -275,12 +275,18 @@ fn main() { * ... ... ... 0 0 * ] */ - 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.lookup(|meta| { + let a_ = meta.query_any(a.into(), Rotation::cur()); + let sl_ = meta.query_any(sl.into(), Rotation::cur()); + vec![(a_, sl_)] + }); + meta.lookup(|meta| { + 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()); + vec![(a_, sl_), (b_, sl2_)] + }); meta.create_gate("Combined add-mult", |meta| { let d = meta.query_advice(d, Rotation::next()); diff --git a/examples/sha256/table16/spread_table.rs b/examples/sha256/table16/spread_table.rs index 90df3839..9d0ba7da 100644 --- a/examples/sha256/table16/spread_table.rs +++ b/examples/sha256/table16/spread_table.rs @@ -162,16 +162,20 @@ impl SpreadTableChip { let table_dense = meta.fixed_column(); let table_spread = meta.fixed_column(); - let tag_cur = meta.query_advice(input_tag, Rotation::cur()); - let dense_cur = meta.query_advice(input_dense, Rotation::cur()); - let spread_cur = meta.query_advice(input_spread, Rotation::cur()); - let table_tag_cur = meta.query_fixed(table_tag, Rotation::cur()); - let table_dense_cur = meta.query_fixed(table_dense, Rotation::cur()); - let table_spread_cur = meta.query_fixed(table_spread, Rotation::cur()); - meta.lookup( - &[tag_cur, dense_cur, spread_cur], - &[table_tag_cur, table_dense_cur, table_spread_cur], - ); + meta.lookup(|meta| { + let tag_cur = meta.query_advice(input_tag, Rotation::cur()); + let dense_cur = meta.query_advice(input_dense, Rotation::cur()); + let spread_cur = meta.query_advice(input_spread, Rotation::cur()); + let table_tag_cur = meta.query_fixed(table_tag, Rotation::cur()); + let table_dense_cur = meta.query_fixed(table_dense, Rotation::cur()); + let table_spread_cur = meta.query_fixed(table_spread, Rotation::cur()); + + vec![ + (tag_cur, table_tag_cur), + (dense_cur, table_dense_cur), + (spread_cur, table_spread_cur), + ] + }); SpreadTableConfig { input: SpreadInputs { diff --git a/src/circuit.rs b/src/circuit.rs index 4f0bf755..ce50c82e 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -4,7 +4,7 @@ use std::{fmt, marker::PhantomData}; use crate::{ arithmetic::FieldExt, - plonk::{Advice, Any, Column, Error, Fixed, Permutation}, + plonk::{Advice, Any, Column, Error, Fixed, Permutation, Selector}, }; pub mod layouter; @@ -110,6 +110,21 @@ impl<'r, F: FieldExt> From<&'r mut dyn layouter::RegionLayouter> for Region<' } impl<'r, F: FieldExt> Region<'r, F> { + /// Enables a selector at the given offset. + pub(crate) fn enable_selector( + &mut self, + annotation: A, + selector: &Selector, + offset: usize, + ) -> Result<(), Error> + where + A: Fn() -> AR, + AR: Into, + { + self.region + .enable_selector(&|| annotation().into(), selector, offset) + } + /// Assign an advice column value (witness). /// /// Even though `to` has `FnMut` bounds, it is guaranteed to be called at most once. diff --git a/src/circuit/layouter.rs b/src/circuit/layouter.rs index fc414805..563883a3 100644 --- a/src/circuit/layouter.rs +++ b/src/circuit/layouter.rs @@ -7,7 +7,7 @@ use std::marker::PhantomData; use super::{Cell, Layouter, Region, RegionIndex, RegionStart}; use crate::arithmetic::FieldExt; -use crate::plonk::{Advice, Any, Assignment, Column, Error, Fixed, Permutation}; +use crate::plonk::{Advice, Any, Assignment, Column, Error, Fixed, Permutation, Selector}; /// Helper trait for implementing a custom [`Layouter`]. /// @@ -38,6 +38,14 @@ use crate::plonk::{Advice, Any, Assignment, Column, Error, Fixed, Permutation}; /// "logical" columns that are guaranteed to correspond to the chip (and have come from /// `Chip::Config`). pub trait RegionLayouter: fmt::Debug { + /// Enables a selector at the given offset. + fn enable_selector<'v>( + &'v mut self, + annotation: &'v (dyn Fn() -> String + 'v), + selector: &Selector, + offset: usize, + ) -> Result<(), Error>; + /// Assign an advice column value (witness) fn assign_advice<'v>( &'v mut self, @@ -194,6 +202,19 @@ impl RegionShape { } impl RegionLayouter for RegionShape { + fn enable_selector<'v>( + &'v mut self, + _: &'v (dyn Fn() -> String + 'v), + selector: &Selector, + offset: usize, + ) -> Result<(), Error> { + // Track the selector's fixed column as part of the region's shape. + // TODO: Avoid exposing selector internals? + self.columns.insert(selector.0.into()); + self.row_count = cmp::max(self.row_count, offset + 1); + Ok(()) + } + fn assign_advice<'v>( &'v mut self, _: &'v (dyn Fn() -> String + 'v), @@ -267,6 +288,19 @@ impl<'r, 'a, F: FieldExt, CS: Assignment + 'a> SingleChipLayouterRegion<'r, ' impl<'r, 'a, F: FieldExt, CS: Assignment + 'a> RegionLayouter for SingleChipLayouterRegion<'r, 'a, F, CS> { + fn enable_selector<'v>( + &'v mut self, + annotation: &'v (dyn Fn() -> String + 'v), + selector: &Selector, + offset: usize, + ) -> Result<(), Error> { + self.layouter.cs.enable_selector( + annotation, + selector, + *self.layouter.regions[*self.region_index] + offset, + ) + } + fn assign_advice<'v>( &'v mut self, annotation: &'v (dyn Fn() -> String + 'v), diff --git a/src/dev.rs b/src/dev.rs index b6be903a..367f1051 100644 --- a/src/dev.rs +++ b/src/dev.rs @@ -6,7 +6,7 @@ use crate::{ arithmetic::{FieldExt, Group}, plonk::{ permutation, Advice, Any, Assignment, Circuit, Column, ColumnType, ConstraintSystem, Error, - Expression, Fixed, Permutation, + Expression, Fixed, Permutation, Selector, }, poly::Rotation, }; @@ -167,6 +167,21 @@ impl Assignment for MockProver { fn exit_region(&mut self) {} + fn enable_selector( + &mut self, + annotation: A, + selector: &Selector, + row: usize, + ) -> Result<(), Error> + where + A: FnOnce() -> AR, + AR: Into, + { + // Selectors are just fixed columns. + // TODO: Track which gates are enabled by this selector. + self.assign_fixed(annotation, selector.0, row, || Ok(F::one())) + } + fn assign_advice( &mut self, _: A, @@ -295,47 +310,47 @@ impl MockProver { let n = self.n as i32; // Check that all gates are satisfied for all rows. - let gate_errors = - self.cs - .gates - .iter() - .enumerate() - .flat_map(|(gate_index, (gate_name, gate))| { - // We iterate from n..2n so we can just reduce to handle wrapping. - (n..(2 * n)).filter_map(move |row| { - fn load<'a, F: FieldExt, T: ColumnType>( - n: i32, - row: i32, - queries: &'a [(Column, Rotation)], - cells: &'a [Vec], - ) -> impl Fn(usize) -> F + 'a { - move |index| { - let (column, at) = &queries[index]; - let resolved_row = (row + at.0) % n; - cells[column.index()][resolved_row as usize] - } + let gate_errors = self + .cs + .gates + .iter() + .enumerate() + .flat_map(|(gate_index, gate)| { + // We iterate from n..2n so we can just reduce to handle wrapping. + (n..(2 * n)).filter_map(move |row| { + fn load<'a, F: FieldExt, T: ColumnType>( + n: i32, + row: i32, + queries: &'a [(Column, Rotation)], + cells: &'a [Vec], + ) -> impl Fn(usize) -> F + 'a { + move |index| { + let (column, at) = &queries[index]; + let resolved_row = (row + at.0) % n; + cells[column.index()][resolved_row as usize] } + } - 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), - &|a, b| a + &b, - &|a, b| a * &b, - &|a, scalar| a * scalar, - ) == F::zero() - { - None - } else { - Some(VerifyFailure::Gate { - gate_index, - gate_name, - row: (row - n) as usize, - }) - } - }) - }); + if gate.poly().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), + &|a, b| a + &b, + &|a, b| a * &b, + &|a, scalar| a * scalar, + ) == F::zero() + { + None + } else { + Some(VerifyFailure::Gate { + gate_index, + gate_name: gate.name(), + row: (row - n) as usize, + }) + } + }) + }); // Check that all lookups exist in their respective tables. let lookup_errors = diff --git a/src/dev/graph.rs b/src/dev/graph.rs index cce172fd..69588076 100644 --- a/src/dev/graph.rs +++ b/src/dev/graph.rs @@ -2,7 +2,7 @@ use ff::Field; use tabbycat::{AttrList, Edge, GraphBuilder, GraphType, Identity, StmtList}; use crate::plonk::{ - Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Error, Fixed, Permutation, + Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Error, Fixed, Permutation, Selector, }; pub mod layout; @@ -86,6 +86,15 @@ impl Assignment for Graph { // Do nothing; we don't care about regions in this context. } + fn enable_selector(&mut self, _: A, _: &Selector, _: usize) -> Result<(), Error> + where + A: FnOnce() -> AR, + AR: Into, + { + // Do nothing; we don't care about cells in this context. + Ok(()) + } + fn assign_advice( &mut self, _: A, diff --git a/src/dev/graph/layout.rs b/src/dev/graph/layout.rs index 229c7341..ad5f54e6 100644 --- a/src/dev/graph/layout.rs +++ b/src/dev/graph/layout.rs @@ -7,7 +7,7 @@ use std::cmp; use std::collections::HashSet; use crate::plonk::{ - Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Error, Fixed, Permutation, + Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Error, Fixed, Permutation, Selector, }; /// Renders the circuit layout on the given drawing area. @@ -229,6 +229,20 @@ impl Assignment for Layout { self.current_region = None; } + fn enable_selector( + &mut self, + annotation: A, + selector: &Selector, + row: usize, + ) -> Result<(), Error> + where + A: FnOnce() -> AR, + AR: Into, + { + // Selectors are just fixed columns. + self.assign_fixed(annotation, selector.0, row, || Ok(F::one())) + } + fn assign_advice( &mut self, _: A, diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index 0eaa99bd..087e31c4 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -175,19 +175,12 @@ impl TryFrom> for Column { /// } /// ``` #[derive(Clone, Copy, Debug)] -pub struct Selector(Column); +pub struct Selector(pub(crate) Column); impl Selector { /// Enable this selector at the given offset within the given region. pub fn enable(&self, region: &mut Region, offset: usize) -> Result<(), Error> { - // TODO: Ensure that the default for a selector's cells is always zero, if we - // alter the proving system to change the global default. - // TODO: Add Region::enable_selector method to allow the layouter to control the - // selector's assignment. - // https://github.com/zcash/halo2/issues/116 - region - .assign_fixed(|| "", self.0, offset, || Ok(F::one())) - .map(|_| ()) + region.enable_selector(|| "", self, offset) } } @@ -241,6 +234,17 @@ pub trait Assignment { /// [`Layouter::assign_region`]: crate::circuit::Layouter#method.assign_region fn exit_region(&mut self); + /// Enables a selector at the given row. + fn enable_selector( + &mut self, + annotation: A, + selector: &Selector, + row: usize, + ) -> Result<(), Error> + where + A: FnOnce() -> AR, + AR: Into; + /// Assign an advice column value (witness) fn assign_advice( &mut self, @@ -460,6 +464,43 @@ impl Mul for Expression { #[derive(Copy, Clone, Debug)] pub(crate) struct PointIndex(pub usize); +/// A "virtual cell" is a PLONK cell that has been queried at a particular relative offset +/// within a custom gate. +#[derive(Clone, Debug)] +struct VirtualCell { + column: Column, + rotation: Rotation, +} + +impl>> From<(Col, Rotation)> for VirtualCell { + fn from((column, rotation): (Col, Rotation)) -> Self { + VirtualCell { + column: column.into(), + rotation, + } + } +} + +#[derive(Clone, Debug)] +pub(crate) struct Gate { + name: &'static str, + poly: Expression, + /// We track queried selectors separately from other cells, so that we can use them to + /// trigger debug checks on gates. + queried_selectors: Vec, + queried_cells: Vec, +} + +impl Gate { + pub(crate) fn name(&self) -> &'static str { + self.name + } + + pub(crate) fn poly(&self) -> &Expression { + &self.poly + } +} + /// This is a description of the circuit environment, such as the gate, column and /// permutation arrangements. #[derive(Debug, Clone)] @@ -467,7 +508,7 @@ pub struct ConstraintSystem { pub(crate) num_fixed_columns: usize, pub(crate) num_advice_columns: usize, pub(crate) num_instance_columns: usize, - pub(crate) gates: Vec<(&'static str, Expression)>, + pub(crate) gates: Vec>, pub(crate) advice_queries: Vec<(Column, Rotation)>, pub(crate) instance_queries: Vec<(Column, Rotation)>, pub(crate) fixed_queries: Vec<(Column, Rotation)>, @@ -495,12 +536,12 @@ pub struct PinnedConstraintSystem<'a, F: Field> { lookups: &'a Vec>, } -struct PinnedGates<'a, F: Field>(&'a Vec<(&'static str, Expression)>); +struct PinnedGates<'a, F: Field>(&'a Vec>); impl<'a, F: Field> std::fmt::Debug for PinnedGates<'a, F> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { f.debug_list() - .entries(self.0.iter().map(|(_, expr)| expr)) + .entries(self.0.iter().map(|gate| gate.poly())) .finish() } } @@ -556,28 +597,23 @@ impl ConstraintSystem { } /// 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. + /// + /// `table_map` returns a map between input expressions and the table expressions + /// they need to match. pub fn lookup( &mut self, - input_expressions: &[Expression], - table_expressions: &[Expression], + table_map: impl FnOnce(&mut VirtualCells<'_, F>) -> Vec<(Expression, Expression)>, ) -> usize { - assert_eq!(input_expressions.len(), table_expressions.len()); + let mut cells = VirtualCells::new(self); + let table_map = table_map(&mut cells); let index = self.lookups.len(); - self.lookups - .push(lookup::Argument::new(input_expressions, table_expressions)); + self.lookups.push(lookup::Argument::new(table_map)); index } - /// Query a selector at a relative position. - pub fn query_selector(&mut self, selector: Selector, at: Rotation) -> Expression { - Expression::Fixed(self.query_fixed_index(selector.0, at)) - } - fn query_fixed_index(&mut self, column: Column, at: Rotation) -> usize { // Return existing query, if it exists for (index, fixed_query) in self.fixed_queries.iter().enumerate() { @@ -593,11 +629,6 @@ impl ConstraintSystem { index } - /// Query a fixed column at a relative position - pub fn query_fixed(&mut self, column: Column, at: Rotation) -> Expression { - Expression::Fixed(self.query_fixed_index(column, at)) - } - pub(crate) fn query_advice_index(&mut self, column: Column, at: Rotation) -> usize { // Return existing query, if it exists for (index, advice_query) in self.advice_queries.iter().enumerate() { @@ -613,11 +644,6 @@ impl ConstraintSystem { index } - /// Query an advice column at a relative position - pub fn query_advice(&mut self, column: Column, at: Rotation) -> Expression { - Expression::Advice(self.query_advice_index(column, at)) - } - fn query_instance_index(&mut self, column: Column, at: Rotation) -> usize { // Return existing query, if it exists for (index, instance_query) in self.instance_queries.iter().enumerate() { @@ -633,11 +659,6 @@ impl ConstraintSystem { index } - /// Query an instance column at a relative position - pub fn query_instance(&mut self, column: Column, at: Rotation) -> Expression { - Expression::Instance(self.query_instance_index(column, at)) - } - fn query_any_index(&mut self, column: Column, at: Rotation) -> usize { match column.column_type() { Any::Advice => self.query_advice_index(Column::::try_from(column).unwrap(), at), @@ -648,21 +669,6 @@ impl ConstraintSystem { } } - /// Query an Any column at a relative position - pub fn query_any(&mut self, column: Column, at: Rotation) -> Expression { - match column.column_type() { - Any::Advice => Expression::Advice( - self.query_advice_index(Column::::try_from(column).unwrap(), at), - ), - Any::Fixed => Expression::Fixed( - self.query_fixed_index(Column::::try_from(column).unwrap(), at), - ), - Any::Instance => Expression::Instance( - self.query_instance_index(Column::::try_from(column).unwrap(), at), - ), - } - } - pub(crate) fn get_advice_query_index(&self, column: Column, at: Rotation) -> usize { for (index, advice_query) in self.advice_queries.iter().enumerate() { if advice_query == &(column, at) { @@ -708,9 +714,22 @@ impl ConstraintSystem { } /// Create a new gate - pub fn create_gate(&mut self, name: &'static str, f: impl FnOnce(&mut Self) -> Expression) { - let poly = f(self); - self.gates.push((name, poly)); + pub fn create_gate( + &mut self, + name: &'static str, + f: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression, + ) { + let mut cells = VirtualCells::new(self); + let poly = f(&mut cells); + let queried_selectors = cells.queried_selectors; + let queried_cells = cells.queried_cells; + + self.gates.push(Gate { + name, + poly, + queried_selectors, + queried_cells, + }); } /// Allocate a new selector. @@ -775,10 +794,72 @@ impl ConstraintSystem { // Account for each gate to ensure our quotient polynomial is the // correct degree and that our extended domain is the right size. - for (_, poly) in self.gates.iter() { - degree = std::cmp::max(degree, poly.degree()); + for gate in &self.gates { + degree = std::cmp::max(degree, gate.poly().degree()); } degree } } + +/// Exposes the "virtual cells" that can be queried while creating a custom gate or lookup +/// table. +#[derive(Debug)] +pub struct VirtualCells<'a, F: Field> { + meta: &'a mut ConstraintSystem, + queried_selectors: Vec, + queried_cells: Vec, +} + +impl<'a, F: Field> VirtualCells<'a, F> { + fn new(meta: &'a mut ConstraintSystem) -> Self { + VirtualCells { + meta, + queried_selectors: vec![], + queried_cells: vec![], + } + } + + /// Query a selector at a relative position. + pub fn query_selector(&mut self, selector: Selector, at: Rotation) -> Expression { + self.queried_selectors.push((selector.0, at).into()); + Expression::Fixed(self.meta.query_fixed_index(selector.0, at)) + } + + /// Query a fixed column at a relative position + pub fn query_fixed(&mut self, column: Column, at: Rotation) -> Expression { + self.queried_cells.push((column, at).into()); + Expression::Fixed(self.meta.query_fixed_index(column, at)) + } + + /// Query an advice column at a relative position + pub fn query_advice(&mut self, column: Column, at: Rotation) -> Expression { + self.queried_cells.push((column, at).into()); + Expression::Advice(self.meta.query_advice_index(column, at)) + } + + /// Query an instance column at a relative position + pub fn query_instance(&mut self, column: Column, at: Rotation) -> Expression { + self.queried_cells.push((column, at).into()); + Expression::Instance(self.meta.query_instance_index(column, at)) + } + + /// Query an Any column at a relative position + pub fn query_any(&mut self, column: Column, at: Rotation) -> Expression { + self.queried_cells.push((column, at).into()); + match column.column_type() { + Any::Advice => Expression::Advice( + self.meta + .query_advice_index(Column::::try_from(column).unwrap(), at), + ), + Any::Fixed => Expression::Fixed( + self.meta + .query_fixed_index(Column::::try_from(column).unwrap(), at), + ), + Any::Instance => Expression::Instance( + self.meta + .query_instance_index(Column::::try_from(column).unwrap(), at), + ), + } + } +} diff --git a/src/plonk/keygen.rs b/src/plonk/keygen.rs index d903e1fb..e2173b93 100644 --- a/src/plonk/keygen.rs +++ b/src/plonk/keygen.rs @@ -2,7 +2,7 @@ use ff::Field; use group::Curve; use super::{ - circuit::{Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Fixed}, + circuit::{Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Fixed, Selector}, permutation, Error, LagrangeCoeff, Permutation, Polynomial, ProvingKey, VerifyingKey, }; use crate::arithmetic::CurveAffine; @@ -53,6 +53,24 @@ impl Assignment for Assembly { // Do nothing; we don't care about regions in this context. } + fn enable_selector( + &mut self, + annotation: A, + selector: &Selector, + row: usize, + ) -> Result<(), Error> + where + A: FnOnce() -> AR, + AR: Into, + { + // Selectors are just fixed columns. + // TODO: Ensure that the default for a selector's cells is always zero, if we + // alter the proving system to change the global default. + // TODO: Implement selector combining optimization + // https://github.com/zcash/halo2/issues/116 + self.assign_fixed(annotation, selector.0, row, || Ok(F::one())) + } + fn assign_advice( &mut self, _: A, diff --git a/src/plonk/lookup.rs b/src/plonk/lookup.rs index c3a9f936..3fb0df93 100644 --- a/src/plonk/lookup.rs +++ b/src/plonk/lookup.rs @@ -11,11 +11,14 @@ pub(crate) struct Argument { } impl Argument { - pub fn new(input_expressions: &[Expression], table_expressions: &[Expression]) -> Self { - assert_eq!(input_expressions.len(), table_expressions.len()); + /// Constructs a new lookup argument. + /// + /// `table_map` is a sequence of `(input, table)` tuples. + pub fn new(table_map: Vec<(Expression, Expression)>) -> Self { + let (input_expressions, table_expressions) = table_map.into_iter().unzip(); Argument { - input_expressions: input_expressions.to_vec(), - table_expressions: table_expressions.to_vec(), + input_expressions, + table_expressions, } } diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index fa321f4f..43166f59 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -3,7 +3,7 @@ use group::Curve; use std::iter; use super::{ - circuit::{Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Fixed}, + circuit::{Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Fixed, Selector}, lookup, permutation, vanishing, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, ChallengeY, Error, Permutation, ProvingKey, }; @@ -123,6 +123,21 @@ pub fn create_proof< // Do nothing; we don't care about regions in this context. } + fn enable_selector( + &mut self, + _: A, + _: &Selector, + _: usize, + ) -> Result<(), Error> + where + A: FnOnce() -> AR, + AR: Into, + { + // We only care about advice columns here + + Ok(()) + } + fn assign_advice( &mut self, _: A, @@ -373,8 +388,8 @@ pub fn create_proof< |(((advice, instance), permutation_expressions), lookup_expressions)| { iter::empty() // Custom constraints - .chain(meta.gates.iter().map(move |(_, poly)| { - poly.evaluate( + .chain(meta.gates.iter().map(move |gate| { + gate.poly().evaluate( &|scalar| pk.vk.domain.constant_extended(scalar), &|index| pk.fixed_cosets[index].clone(), &|index| advice.advice_cosets[index].clone(), diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index a9f89cca..f755ff6b 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -164,8 +164,8 @@ pub fn verify_proof<'a, C: CurveAffine, E: EncodedChallenge, T: TranscriptRea std::iter::empty() // Evaluate the circuit using the custom gates provided - .chain(vk.cs.gates.iter().map(move |(_, poly)| { - poly.evaluate( + .chain(vk.cs.gates.iter().map(move |gate| { + gate.poly().evaluate( &|scalar| scalar, &|index| fixed_evals[index], &|index| advice_evals[index], diff --git a/tests/plonk_api.rs b/tests/plonk_api.rs index 8665ba77..6e4d3e91 100644 --- a/tests/plonk_api.rs +++ b/tests/plonk_api.rs @@ -277,12 +277,18 @@ fn plonk_api() { * ... ... ... 0 0 * ] */ - 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.lookup(|meta| { + let a_ = meta.query_any(a.into(), Rotation::cur()); + let sl_ = meta.query_any(sl.into(), Rotation::cur()); + vec![(a_, sl_)] + }); + meta.lookup(|meta| { + 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()); + vec![(a_ * b_, sl_ * sl2_)] + }); meta.create_gate("Combined add-mult", |meta| { let d = meta.query_advice(d, Rotation::next());