Merge pull request #272 from zcash/configure-api-changes

`Circuit` API changes
This commit is contained in:
str4d 2021-06-01 17:14:39 +01:00 committed by GitHub
commit 845bf724ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 355 additions and 135 deletions

View File

@ -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());

View File

@ -162,16 +162,20 @@ impl<F: FieldExt> SpreadTableChip<F> {
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 {

View File

@ -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<F>> for Region<'
}
impl<'r, F: FieldExt> Region<'r, F> {
/// Enables a selector at the given offset.
pub(crate) fn enable_selector<A, AR>(
&mut self,
annotation: A,
selector: &Selector,
offset: usize,
) -> Result<(), Error>
where
A: Fn() -> AR,
AR: Into<String>,
{
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.

View File

@ -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<F: FieldExt>: 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<F: FieldExt> RegionLayouter<F> 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<F> + 'a> SingleChipLayouterRegion<'r, '
impl<'r, 'a, F: FieldExt, CS: Assignment<F> + 'a> RegionLayouter<F>
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),

View File

@ -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<F: Field + Group> Assignment<F> for MockProver<F> {
fn exit_region(&mut self) {}
fn enable_selector<A, AR>(
&mut self,
annotation: A,
selector: &Selector,
row: usize,
) -> Result<(), Error>
where
A: FnOnce() -> AR,
AR: Into<String>,
{
// 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<V, A, AR>(
&mut self,
_: A,
@ -295,47 +310,47 @@ impl<F: FieldExt> MockProver<F> {
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<T>, Rotation)],
cells: &'a [Vec<F>],
) -> 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<T>, Rotation)],
cells: &'a [Vec<F>],
) -> 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 =

View File

@ -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<F: Field> Assignment<F> for Graph {
// Do nothing; we don't care about regions in this context.
}
fn enable_selector<A, AR>(&mut self, _: A, _: &Selector, _: usize) -> Result<(), Error>
where
A: FnOnce() -> AR,
AR: Into<String>,
{
// Do nothing; we don't care about cells in this context.
Ok(())
}
fn assign_advice<V, A, AR>(
&mut self,
_: A,

View File

@ -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<F: Field> Assignment<F> for Layout {
self.current_region = None;
}
fn enable_selector<A, AR>(
&mut self,
annotation: A,
selector: &Selector,
row: usize,
) -> Result<(), Error>
where
A: FnOnce() -> AR,
AR: Into<String>,
{
// Selectors are just fixed columns.
self.assign_fixed(annotation, selector.0, row, || Ok(F::one()))
}
fn assign_advice<V, A, AR>(
&mut self,
_: A,

View File

@ -175,19 +175,12 @@ impl TryFrom<Column<Any>> for Column<Instance> {
/// }
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Selector(Column<Fixed>);
pub struct Selector(pub(crate) Column<Fixed>);
impl Selector {
/// Enable this selector at the given offset within the given region.
pub fn enable<F: FieldExt>(&self, region: &mut Region<F>, 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<F: Field> {
/// [`Layouter::assign_region`]: crate::circuit::Layouter#method.assign_region
fn exit_region(&mut self);
/// Enables a selector at the given row.
fn enable_selector<A, AR>(
&mut self,
annotation: A,
selector: &Selector,
row: usize,
) -> Result<(), Error>
where
A: FnOnce() -> AR,
AR: Into<String>;
/// Assign an advice column value (witness)
fn assign_advice<V, A, AR>(
&mut self,
@ -460,6 +464,43 @@ impl<F> Mul<F> for Expression<F> {
#[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<Any>,
rotation: Rotation,
}
impl<Col: Into<Column<Any>>> From<(Col, Rotation)> for VirtualCell {
fn from((column, rotation): (Col, Rotation)) -> Self {
VirtualCell {
column: column.into(),
rotation,
}
}
}
#[derive(Clone, Debug)]
pub(crate) struct Gate<F: Field> {
name: &'static str,
poly: Expression<F>,
/// We track queried selectors separately from other cells, so that we can use them to
/// trigger debug checks on gates.
queried_selectors: Vec<VirtualCell>,
queried_cells: Vec<VirtualCell>,
}
impl<F: Field> Gate<F> {
pub(crate) fn name(&self) -> &'static str {
self.name
}
pub(crate) fn poly(&self) -> &Expression<F> {
&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<F: Field> {
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<F>)>,
pub(crate) gates: Vec<Gate<F>>,
pub(crate) advice_queries: Vec<(Column<Advice>, Rotation)>,
pub(crate) instance_queries: Vec<(Column<Instance>, Rotation)>,
pub(crate) fixed_queries: Vec<(Column<Fixed>, Rotation)>,
@ -495,12 +536,12 @@ pub struct PinnedConstraintSystem<'a, F: Field> {
lookups: &'a Vec<lookup::Argument<F>>,
}
struct PinnedGates<'a, F: Field>(&'a Vec<(&'static str, Expression<F>)>);
struct PinnedGates<'a, F: Field>(&'a Vec<Gate<F>>);
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<F: Field> ConstraintSystem<F> {
}
/// 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<F>],
table_expressions: &[Expression<F>],
table_map: impl FnOnce(&mut VirtualCells<'_, F>) -> Vec<(Expression<F>, Expression<F>)>,
) -> 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<F> {
Expression::Fixed(self.query_fixed_index(selector.0, at))
}
fn query_fixed_index(&mut self, column: Column<Fixed>, at: Rotation) -> usize {
// Return existing query, if it exists
for (index, fixed_query) in self.fixed_queries.iter().enumerate() {
@ -593,11 +629,6 @@ impl<F: Field> ConstraintSystem<F> {
index
}
/// Query a fixed column at a relative position
pub fn query_fixed(&mut self, column: Column<Fixed>, at: Rotation) -> Expression<F> {
Expression::Fixed(self.query_fixed_index(column, at))
}
pub(crate) fn query_advice_index(&mut self, column: Column<Advice>, at: Rotation) -> usize {
// Return existing query, if it exists
for (index, advice_query) in self.advice_queries.iter().enumerate() {
@ -613,11 +644,6 @@ impl<F: Field> ConstraintSystem<F> {
index
}
/// Query an advice column at a relative position
pub fn query_advice(&mut self, column: Column<Advice>, at: Rotation) -> Expression<F> {
Expression::Advice(self.query_advice_index(column, at))
}
fn query_instance_index(&mut self, column: Column<Instance>, at: Rotation) -> usize {
// Return existing query, if it exists
for (index, instance_query) in self.instance_queries.iter().enumerate() {
@ -633,11 +659,6 @@ impl<F: Field> ConstraintSystem<F> {
index
}
/// Query an instance column at a relative position
pub fn query_instance(&mut self, column: Column<Instance>, at: Rotation) -> Expression<F> {
Expression::Instance(self.query_instance_index(column, at))
}
fn query_any_index(&mut self, column: Column<Any>, at: Rotation) -> usize {
match column.column_type() {
Any::Advice => self.query_advice_index(Column::<Advice>::try_from(column).unwrap(), at),
@ -648,21 +669,6 @@ impl<F: Field> ConstraintSystem<F> {
}
}
/// Query an Any column at a relative position
pub fn query_any(&mut self, column: Column<Any>, at: Rotation) -> Expression<F> {
match column.column_type() {
Any::Advice => Expression::Advice(
self.query_advice_index(Column::<Advice>::try_from(column).unwrap(), at),
),
Any::Fixed => Expression::Fixed(
self.query_fixed_index(Column::<Fixed>::try_from(column).unwrap(), at),
),
Any::Instance => Expression::Instance(
self.query_instance_index(Column::<Instance>::try_from(column).unwrap(), at),
),
}
}
pub(crate) fn get_advice_query_index(&self, column: Column<Advice>, at: Rotation) -> usize {
for (index, advice_query) in self.advice_queries.iter().enumerate() {
if advice_query == &(column, at) {
@ -708,9 +714,22 @@ impl<F: Field> ConstraintSystem<F> {
}
/// Create a new gate
pub fn create_gate(&mut self, name: &'static str, f: impl FnOnce(&mut Self) -> Expression<F>) {
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<F>,
) {
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<F: Field> ConstraintSystem<F> {
// 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<F>,
queried_selectors: Vec<VirtualCell>,
queried_cells: Vec<VirtualCell>,
}
impl<'a, F: Field> VirtualCells<'a, F> {
fn new(meta: &'a mut ConstraintSystem<F>) -> 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<F> {
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<Fixed>, at: Rotation) -> Expression<F> {
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<Advice>, at: Rotation) -> Expression<F> {
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<Instance>, at: Rotation) -> Expression<F> {
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<Any>, at: Rotation) -> Expression<F> {
self.queried_cells.push((column, at).into());
match column.column_type() {
Any::Advice => Expression::Advice(
self.meta
.query_advice_index(Column::<Advice>::try_from(column).unwrap(), at),
),
Any::Fixed => Expression::Fixed(
self.meta
.query_fixed_index(Column::<Fixed>::try_from(column).unwrap(), at),
),
Any::Instance => Expression::Instance(
self.meta
.query_instance_index(Column::<Instance>::try_from(column).unwrap(), at),
),
}
}
}

View File

@ -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<F: Field> Assignment<F> for Assembly<F> {
// Do nothing; we don't care about regions in this context.
}
fn enable_selector<A, AR>(
&mut self,
annotation: A,
selector: &Selector,
row: usize,
) -> Result<(), Error>
where
A: FnOnce() -> AR,
AR: Into<String>,
{
// 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<V, A, AR>(
&mut self,
_: A,

View File

@ -11,11 +11,14 @@ pub(crate) struct Argument<F: Field> {
}
impl<F: Field> Argument<F> {
pub fn new(input_expressions: &[Expression<F>], table_expressions: &[Expression<F>]) -> 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<F>, Expression<F>)>) -> 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,
}
}

View File

@ -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<A, AR>(
&mut self,
_: A,
_: &Selector,
_: usize,
) -> Result<(), Error>
where
A: FnOnce() -> AR,
AR: Into<String>,
{
// We only care about advice columns here
Ok(())
}
fn assign_advice<V, A, AR>(
&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(),

View File

@ -164,8 +164,8 @@ pub fn verify_proof<'a, C: CurveAffine, E: EncodedChallenge<C>, 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],

View File

@ -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());