2020-08-22 14:09:47 -07:00
|
|
|
use core::cmp::max;
|
|
|
|
use core::ops::{Add, Mul};
|
2021-02-17 14:15:08 -08:00
|
|
|
use ff::Field;
|
2023-02-22 18:26:43 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
use ff::PrimeField;
|
2021-01-28 16:45:48 -08:00
|
|
|
use std::{
|
2021-02-14 20:46:14 -08:00
|
|
|
convert::TryFrom,
|
2021-01-28 16:45:48 -08:00
|
|
|
ops::{Neg, Sub},
|
|
|
|
};
|
2020-08-22 13:15:39 -07:00
|
|
|
|
2021-12-09 06:52:23 -08:00
|
|
|
use super::{lookup, permutation, Assigned, Error};
|
2022-06-07 16:15:35 -07:00
|
|
|
use crate::{
|
|
|
|
circuit::{Layouter, Region, Value},
|
|
|
|
poly::Rotation,
|
|
|
|
};
|
2020-08-23 12:26:04 -07:00
|
|
|
|
2021-07-24 14:43:15 -07:00
|
|
|
mod compress_selectors;
|
|
|
|
|
2020-11-05 19:25:50 -08:00
|
|
|
/// A column type
|
2021-06-08 03:03:29 -07:00
|
|
|
pub trait ColumnType:
|
|
|
|
'static + Sized + Copy + std::fmt::Debug + PartialEq + Eq + Into<Any>
|
|
|
|
{
|
|
|
|
}
|
2020-11-05 19:25:50 -08:00
|
|
|
|
|
|
|
/// A column with an index and type
|
2021-01-13 06:58:12 -08:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
2020-11-05 19:25:50 -08:00
|
|
|
pub struct Column<C: ColumnType> {
|
2021-02-10 06:57:08 -08:00
|
|
|
index: usize,
|
|
|
|
column_type: C,
|
2020-11-09 08:45:52 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<C: ColumnType> Column<C> {
|
2021-05-27 06:02:13 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
pub(crate) fn new(index: usize, column_type: C) -> Self {
|
|
|
|
Column { index, column_type }
|
|
|
|
}
|
|
|
|
|
2020-11-09 08:45:52 -08:00
|
|
|
pub(crate) fn index(&self) -> usize {
|
|
|
|
self.index
|
|
|
|
}
|
|
|
|
|
2021-11-28 10:42:10 -08:00
|
|
|
/// Type of this column.
|
|
|
|
pub fn column_type(&self) -> &C {
|
2020-11-09 08:45:52 -08:00
|
|
|
&self.column_type
|
|
|
|
}
|
2020-11-05 19:25:50 -08:00
|
|
|
}
|
|
|
|
|
2021-06-08 03:03:29 -07:00
|
|
|
impl<C: ColumnType> Ord for Column<C> {
|
|
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
|
|
// This ordering is consensus-critical! The layouters rely on deterministic column
|
|
|
|
// orderings.
|
2021-10-01 12:54:33 -07:00
|
|
|
match self.column_type.into().cmp(&other.column_type.into()) {
|
2021-06-08 03:03:29 -07:00
|
|
|
// Indices are assigned within column types.
|
2021-10-01 12:54:33 -07:00
|
|
|
std::cmp::Ordering::Equal => self.index.cmp(&other.index),
|
|
|
|
order => order,
|
2021-06-08 03:03:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<C: ColumnType> PartialOrd for Column<C> {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-05 19:25:50 -08:00
|
|
|
/// An advice column
|
2021-01-13 06:58:12 -08:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
2020-11-05 19:25:50 -08:00
|
|
|
pub struct Advice;
|
|
|
|
|
|
|
|
/// A fixed column
|
2021-01-13 06:58:12 -08:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
2020-11-05 19:25:50 -08:00
|
|
|
pub struct Fixed;
|
|
|
|
|
2021-02-14 09:30:36 -08:00
|
|
|
/// An instance column
|
2021-01-13 06:58:12 -08:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
2021-02-14 09:30:36 -08:00
|
|
|
pub struct Instance;
|
2020-11-05 19:25:50 -08:00
|
|
|
|
2021-02-14 09:30:36 -08:00
|
|
|
/// An enum over the Advice, Fixed, Instance structs
|
2021-01-13 06:58:12 -08:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
2020-11-05 19:25:50 -08:00
|
|
|
pub enum Any {
|
|
|
|
/// An Advice variant
|
|
|
|
Advice,
|
|
|
|
/// A Fixed variant
|
|
|
|
Fixed,
|
2021-02-14 09:30:36 -08:00
|
|
|
/// An Instance variant
|
|
|
|
Instance,
|
2020-11-05 19:25:50 -08:00
|
|
|
}
|
|
|
|
|
2021-10-01 12:54:33 -07:00
|
|
|
impl Ord for Any {
|
|
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
|
|
// This ordering is consensus-critical! The layouters rely on deterministic column
|
|
|
|
// orderings.
|
|
|
|
match (self, other) {
|
|
|
|
(Any::Instance, Any::Instance)
|
|
|
|
| (Any::Advice, Any::Advice)
|
|
|
|
| (Any::Fixed, Any::Fixed) => std::cmp::Ordering::Equal,
|
|
|
|
// Across column types, sort Instance < Advice < Fixed.
|
|
|
|
(Any::Instance, Any::Advice)
|
|
|
|
| (Any::Advice, Any::Fixed)
|
|
|
|
| (Any::Instance, Any::Fixed) => std::cmp::Ordering::Less,
|
|
|
|
(Any::Fixed, Any::Instance)
|
|
|
|
| (Any::Fixed, Any::Advice)
|
|
|
|
| (Any::Advice, Any::Instance) => std::cmp::Ordering::Greater,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialOrd for Any {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-05 19:25:50 -08:00
|
|
|
impl ColumnType for Advice {}
|
|
|
|
impl ColumnType for Fixed {}
|
2021-02-14 09:30:36 -08:00
|
|
|
impl ColumnType for Instance {}
|
2020-11-05 19:25:50 -08:00
|
|
|
impl ColumnType for Any {}
|
2020-08-23 12:26:04 -07:00
|
|
|
|
2021-06-08 03:03:29 -07:00
|
|
|
impl From<Advice> for Any {
|
|
|
|
fn from(_: Advice) -> Any {
|
|
|
|
Any::Advice
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Fixed> for Any {
|
|
|
|
fn from(_: Fixed) -> Any {
|
|
|
|
Any::Fixed
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Instance> for Any {
|
|
|
|
fn from(_: Instance) -> Any {
|
|
|
|
Any::Instance
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-05 19:25:50 -08:00
|
|
|
impl From<Column<Advice>> for Column<Any> {
|
|
|
|
fn from(advice: Column<Advice>) -> Column<Any> {
|
|
|
|
Column {
|
2020-11-09 08:45:52 -08:00
|
|
|
index: advice.index(),
|
2020-11-05 19:25:50 -08:00
|
|
|
column_type: Any::Advice,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Column<Fixed>> for Column<Any> {
|
|
|
|
fn from(advice: Column<Fixed>) -> Column<Any> {
|
|
|
|
Column {
|
2020-11-09 08:45:52 -08:00
|
|
|
index: advice.index(),
|
2020-11-05 19:25:50 -08:00
|
|
|
column_type: Any::Fixed,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-14 09:30:36 -08:00
|
|
|
impl From<Column<Instance>> for Column<Any> {
|
|
|
|
fn from(advice: Column<Instance>) -> Column<Any> {
|
2020-11-05 19:25:50 -08:00
|
|
|
Column {
|
2020-11-09 08:45:52 -08:00
|
|
|
index: advice.index(),
|
2021-02-14 09:30:36 -08:00
|
|
|
column_type: Any::Instance,
|
2020-11-05 19:25:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-09 08:39:08 -08:00
|
|
|
impl TryFrom<Column<Any>> for Column<Advice> {
|
|
|
|
type Error = &'static str;
|
|
|
|
|
|
|
|
fn try_from(any: Column<Any>) -> Result<Self, Self::Error> {
|
2020-11-09 08:45:52 -08:00
|
|
|
match any.column_type() {
|
2020-11-10 21:46:18 -08:00
|
|
|
Any::Advice => Ok(Column {
|
|
|
|
index: any.index(),
|
|
|
|
column_type: Advice,
|
|
|
|
}),
|
2020-11-09 08:39:08 -08:00
|
|
|
_ => Err("Cannot convert into Column<Advice>"),
|
2020-11-05 19:25:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-09 08:39:08 -08:00
|
|
|
impl TryFrom<Column<Any>> for Column<Fixed> {
|
|
|
|
type Error = &'static str;
|
|
|
|
|
|
|
|
fn try_from(any: Column<Any>) -> Result<Self, Self::Error> {
|
2020-11-09 08:45:52 -08:00
|
|
|
match any.column_type() {
|
2020-11-10 21:46:18 -08:00
|
|
|
Any::Fixed => Ok(Column {
|
|
|
|
index: any.index(),
|
|
|
|
column_type: Fixed,
|
|
|
|
}),
|
2020-11-09 08:39:08 -08:00
|
|
|
_ => Err("Cannot convert into Column<Fixed>"),
|
2020-11-05 19:25:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-14 09:30:36 -08:00
|
|
|
impl TryFrom<Column<Any>> for Column<Instance> {
|
2020-11-09 08:39:08 -08:00
|
|
|
type Error = &'static str;
|
|
|
|
|
|
|
|
fn try_from(any: Column<Any>) -> Result<Self, Self::Error> {
|
2020-11-09 08:45:52 -08:00
|
|
|
match any.column_type() {
|
2021-02-14 09:30:36 -08:00
|
|
|
Any::Instance => Ok(Column {
|
2020-11-10 21:46:18 -08:00
|
|
|
index: any.index(),
|
2021-02-14 09:30:36 -08:00
|
|
|
column_type: Instance,
|
2020-11-10 21:46:18 -08:00
|
|
|
}),
|
2021-02-14 09:30:36 -08:00
|
|
|
_ => Err("Cannot convert into Column<Instance>"),
|
2020-11-05 19:25:50 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-17 09:33:42 -07:00
|
|
|
|
2021-02-23 15:17:17 -08:00
|
|
|
/// A selector, representing a fixed boolean value per row of the circuit.
|
|
|
|
///
|
|
|
|
/// Selectors can be used to conditionally enable (portions of) gates:
|
|
|
|
/// ```
|
2022-01-20 10:28:44 -08:00
|
|
|
/// use halo2_proofs::poly::Rotation;
|
|
|
|
/// # use halo2_proofs::pasta::Fp;
|
|
|
|
/// # use halo2_proofs::plonk::ConstraintSystem;
|
2021-02-23 15:17:17 -08:00
|
|
|
///
|
|
|
|
/// # let mut meta = ConstraintSystem::<Fp>::default();
|
|
|
|
/// let a = meta.advice_column();
|
|
|
|
/// let b = meta.advice_column();
|
|
|
|
/// let s = meta.selector();
|
|
|
|
///
|
|
|
|
/// meta.create_gate("foo", |meta| {
|
|
|
|
/// let a = meta.query_advice(a, Rotation::prev());
|
|
|
|
/// let b = meta.query_advice(b, Rotation::cur());
|
2021-06-04 08:18:51 -07:00
|
|
|
/// let s = meta.query_selector(s);
|
2021-02-23 15:17:17 -08:00
|
|
|
///
|
|
|
|
/// // On rows where the selector is enabled, a is constrained to equal b.
|
|
|
|
/// // On rows where the selector is disabled, a and b can take any value.
|
2021-05-27 06:44:02 -07:00
|
|
|
/// vec![s * (a - b)]
|
2021-02-23 15:17:17 -08:00
|
|
|
/// });
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Selectors are disabled on all rows by default, and must be explicitly enabled on each
|
|
|
|
/// row when required:
|
|
|
|
/// ```
|
2022-11-29 21:05:37 -08:00
|
|
|
/// use group::ff::Field;
|
2022-06-07 16:15:35 -07:00
|
|
|
/// use halo2_proofs::{
|
|
|
|
/// circuit::{Chip, Layouter, Value},
|
|
|
|
/// plonk::{Advice, Column, Error, Selector},
|
|
|
|
/// };
|
2022-01-20 10:28:44 -08:00
|
|
|
/// # use halo2_proofs::plonk::Fixed;
|
2021-02-23 15:17:17 -08:00
|
|
|
///
|
|
|
|
/// struct Config {
|
|
|
|
/// a: Column<Advice>,
|
|
|
|
/// b: Column<Advice>,
|
|
|
|
/// s: Selector,
|
|
|
|
/// }
|
|
|
|
///
|
2022-11-29 21:05:37 -08:00
|
|
|
/// fn circuit_logic<F: Field, C: Chip<F>>(chip: C, mut layouter: impl Layouter<F>) -> Result<(), Error> {
|
2021-04-27 19:57:51 -07:00
|
|
|
/// let config = chip.config();
|
2021-02-23 15:17:17 -08:00
|
|
|
/// # let config: Config = todo!();
|
|
|
|
/// layouter.assign_region(|| "bar", |mut region| {
|
2022-11-29 21:05:37 -08:00
|
|
|
/// region.assign_advice(|| "a", config.a, 0, || Value::known(F::ONE))?;
|
|
|
|
/// region.assign_advice(|| "a", config.b, 1, || Value::known(F::ONE))?;
|
2021-02-23 15:17:17 -08:00
|
|
|
/// config.s.enable(&mut region, 1)
|
|
|
|
/// })?;
|
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
/// ```
|
2021-05-27 06:03:12 -07:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
2021-07-22 09:07:20 -07:00
|
|
|
pub struct Selector(pub(crate) usize, bool);
|
2021-02-23 15:17:17 -08:00
|
|
|
|
|
|
|
impl Selector {
|
|
|
|
/// Enable this selector at the given offset within the given region.
|
2021-07-21 14:45:36 -07:00
|
|
|
pub fn enable<F: Field>(&self, region: &mut Region<F>, offset: usize) -> Result<(), Error> {
|
2021-05-27 04:43:32 -07:00
|
|
|
region.enable_selector(|| "", self, offset)
|
2021-02-23 15:17:17 -08:00
|
|
|
}
|
2021-07-22 09:07:20 -07:00
|
|
|
|
|
|
|
/// Is this selector "simple"? Simple selectors can only be multiplied
|
|
|
|
/// by expressions that contain no other simple selectors.
|
|
|
|
pub fn is_simple(&self) -> bool {
|
|
|
|
self.1
|
|
|
|
}
|
2021-02-23 15:17:17 -08:00
|
|
|
}
|
|
|
|
|
2023-02-21 08:53:24 -08:00
|
|
|
/// A dynamic table tag
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub struct TableTag(pub(crate) usize);
|
|
|
|
|
|
|
|
impl TableTag {
|
|
|
|
/// The value of a table tag is the table's `index` + 1
|
|
|
|
fn value(&self) -> u64 {
|
|
|
|
self.0 as u64 + 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-28 08:56:09 -07:00
|
|
|
/// Query of fixed column at a certain relative location
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub struct FixedQuery {
|
|
|
|
/// Query index
|
|
|
|
pub(crate) index: usize,
|
|
|
|
/// Column index
|
|
|
|
pub(crate) column_index: usize,
|
|
|
|
/// Rotation of this query
|
|
|
|
pub(crate) rotation: Rotation,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Query of advice column at a certain relative location
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub struct AdviceQuery {
|
|
|
|
/// Query index
|
|
|
|
pub(crate) index: usize,
|
|
|
|
/// Column index
|
|
|
|
pub(crate) column_index: usize,
|
|
|
|
/// Rotation of this query
|
|
|
|
pub(crate) rotation: Rotation,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Query of instance column at a certain relative location
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub struct InstanceQuery {
|
|
|
|
/// Query index
|
|
|
|
pub(crate) index: usize,
|
|
|
|
/// Column index
|
|
|
|
pub(crate) column_index: usize,
|
|
|
|
/// Rotation of this query
|
|
|
|
pub(crate) rotation: Rotation,
|
|
|
|
}
|
|
|
|
|
2021-07-27 07:46:37 -07:00
|
|
|
/// A fixed column of a lookup table.
|
|
|
|
///
|
|
|
|
/// A lookup table can be loaded into this column via [`Layouter::assign_table`]. Columns
|
|
|
|
/// can currently only contain a single table, but they may be used in multiple lookup
|
|
|
|
/// arguments via [`ConstraintSystem::lookup`].
|
|
|
|
///
|
|
|
|
/// Lookup table columns are always "encumbered" by the lookup arguments they are used in;
|
|
|
|
/// they cannot simultaneously be used as general fixed columns.
|
|
|
|
///
|
|
|
|
/// [`Layouter::assign_table`]: crate::circuit::Layouter::assign_table
|
2023-03-21 01:55:12 -07:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
2021-07-27 07:46:37 -07:00
|
|
|
pub struct TableColumn {
|
|
|
|
/// The fixed column that this table column is stored in.
|
|
|
|
///
|
|
|
|
/// # Security
|
|
|
|
///
|
|
|
|
/// This inner column MUST NOT be exposed in the public API, or else chip developers
|
|
|
|
/// can load lookup tables into their circuits without default-value-filling the
|
|
|
|
/// columns, which can cause soundness bugs.
|
|
|
|
inner: Column<Fixed>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TableColumn {
|
|
|
|
pub(crate) fn inner(&self) -> Column<Fixed> {
|
|
|
|
self.inner
|
|
|
|
}
|
2022-07-06 08:29:25 -07:00
|
|
|
|
|
|
|
/// Enable equality on this TableColumn.
|
|
|
|
pub fn enable_equality<F: Field>(&self, meta: &mut ConstraintSystem<F>) {
|
|
|
|
meta.enable_equality(self.inner)
|
|
|
|
}
|
2021-07-27 07:46:37 -07:00
|
|
|
}
|
|
|
|
|
2023-02-21 08:53:24 -08:00
|
|
|
/// `DynamicTable`s are constructed in the configuration phase by `create_dynamic_table`.
|
|
|
|
/// To include a row of a region in a dynamic table use `add_row_to_table` during synthesize.
|
|
|
|
#[cfg_attr(
|
|
|
|
feature = "unstable-dynamic-lookups",
|
|
|
|
derive(Clone, Debug, Eq, PartialEq, Hash)
|
|
|
|
)]
|
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
pub struct DynamicTable {
|
|
|
|
pub(crate) name: String,
|
|
|
|
pub(crate) index: usize,
|
|
|
|
/// Columns contained in this table, excluding the tag column.
|
|
|
|
pub(crate) columns: Vec<Column<Any>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
impl DynamicTable {
|
|
|
|
pub(crate) fn index(&self) -> usize {
|
|
|
|
self.index
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn tag(&self) -> TableTag {
|
|
|
|
TableTag(self.index)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn columns(&self) -> &[Column<Any>] {
|
|
|
|
&self.columns
|
|
|
|
}
|
2023-02-22 18:18:04 -08:00
|
|
|
|
|
|
|
/// Includes a row at `offset` in this dynamic lookup table.
|
|
|
|
pub fn add_row<F>(&self, region: &mut Region<F>, offset: usize) -> Result<(), Error>
|
|
|
|
where
|
|
|
|
F: Field,
|
|
|
|
{
|
|
|
|
region.add_to_lookup(self.tag(), offset)
|
|
|
|
}
|
2023-02-21 08:53:24 -08:00
|
|
|
}
|
|
|
|
|
2020-08-22 13:15:39 -07:00
|
|
|
/// This trait allows a [`Circuit`] to direct some backend to assign a witness
|
|
|
|
/// for a constraint system.
|
2020-09-11 16:18:41 -07:00
|
|
|
pub trait Assignment<F: Field> {
|
2021-01-22 08:43:36 -08:00
|
|
|
/// Creates a new region and enters into it.
|
|
|
|
///
|
|
|
|
/// Panics if we are currently in a region (if `exit_region` was not called).
|
|
|
|
///
|
|
|
|
/// Not intended for downstream consumption; use [`Layouter::assign_region`] instead.
|
|
|
|
///
|
|
|
|
/// [`Layouter::assign_region`]: crate::circuit::Layouter#method.assign_region
|
|
|
|
fn enter_region<NR, N>(&mut self, name_fn: N)
|
|
|
|
where
|
|
|
|
NR: Into<String>,
|
|
|
|
N: FnOnce() -> NR;
|
|
|
|
|
|
|
|
/// Exits the current region.
|
|
|
|
///
|
|
|
|
/// Panics if we are not currently in a region (if `enter_region` was not called).
|
|
|
|
///
|
|
|
|
/// Not intended for downstream consumption; use [`Layouter::assign_region`] instead.
|
|
|
|
///
|
|
|
|
/// [`Layouter::assign_region`]: crate::circuit::Layouter#method.assign_region
|
|
|
|
fn exit_region(&mut self);
|
|
|
|
|
2021-05-27 04:43:32 -07:00
|
|
|
/// 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>;
|
|
|
|
|
2023-02-21 10:08:17 -08:00
|
|
|
/// Adds a row in the provided dynamic lookup table.
|
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
fn add_to_lookup(&mut self, table: TableTag, row: usize) -> Result<(), Error>;
|
|
|
|
|
2021-07-10 07:47:57 -07:00
|
|
|
/// Queries the cell of an instance column at a particular absolute row.
|
|
|
|
///
|
|
|
|
/// Returns the cell's value, if known.
|
2022-06-07 16:15:35 -07:00
|
|
|
fn query_instance(&self, column: Column<Instance>, row: usize) -> Result<Value<F>, Error>;
|
2021-07-08 13:44:01 -07:00
|
|
|
|
2020-11-05 19:13:54 -08:00
|
|
|
/// Assign an advice column value (witness)
|
2021-06-11 08:39:34 -07:00
|
|
|
fn assign_advice<V, VR, A, AR>(
|
2020-08-23 12:26:04 -07:00
|
|
|
&mut self,
|
2021-01-22 08:57:38 -08:00
|
|
|
annotation: A,
|
2020-11-05 19:25:50 -08:00
|
|
|
column: Column<Advice>,
|
2020-08-23 12:26:04 -07:00
|
|
|
row: usize,
|
2021-01-22 08:57:38 -08:00
|
|
|
to: V,
|
|
|
|
) -> Result<(), Error>
|
|
|
|
where
|
2022-06-07 16:15:35 -07:00
|
|
|
V: FnOnce() -> Value<VR>,
|
2021-06-11 08:39:34 -07:00
|
|
|
VR: Into<Assigned<F>>,
|
2021-01-22 08:57:38 -08:00
|
|
|
A: FnOnce() -> AR,
|
|
|
|
AR: Into<String>;
|
2020-08-23 12:26:04 -07:00
|
|
|
|
|
|
|
/// Assign a fixed value
|
2021-06-11 08:39:34 -07:00
|
|
|
fn assign_fixed<V, VR, A, AR>(
|
2020-08-23 12:26:04 -07:00
|
|
|
&mut self,
|
2021-01-22 08:57:38 -08:00
|
|
|
annotation: A,
|
2020-11-05 19:25:50 -08:00
|
|
|
column: Column<Fixed>,
|
2020-08-23 12:26:04 -07:00
|
|
|
row: usize,
|
2021-01-22 08:57:38 -08:00
|
|
|
to: V,
|
|
|
|
) -> Result<(), Error>
|
|
|
|
where
|
2022-06-07 16:15:35 -07:00
|
|
|
V: FnOnce() -> Value<VR>,
|
2021-06-11 08:39:34 -07:00
|
|
|
VR: Into<Assigned<F>>,
|
2021-01-22 08:57:38 -08:00
|
|
|
A: FnOnce() -> AR,
|
|
|
|
AR: Into<String>;
|
2020-08-22 15:10:27 -07:00
|
|
|
|
2021-02-18 23:24:21 -08:00
|
|
|
/// Assign two cells to have the same value
|
2020-08-31 09:01:09 -07:00
|
|
|
fn copy(
|
|
|
|
&mut self,
|
2021-02-18 23:07:08 -08:00
|
|
|
left_column: Column<Any>,
|
2020-08-31 09:01:09 -07:00
|
|
|
left_row: usize,
|
2021-02-18 23:07:08 -08:00
|
|
|
right_column: Column<Any>,
|
2020-08-31 09:01:09 -07:00
|
|
|
right_row: usize,
|
|
|
|
) -> Result<(), Error>;
|
2021-01-22 10:36:42 -08:00
|
|
|
|
2021-07-26 17:34:51 -07:00
|
|
|
/// Fills a fixed `column` starting from the given `row` with value `to`.
|
|
|
|
fn fill_from_row(
|
|
|
|
&mut self,
|
|
|
|
column: Column<Fixed>,
|
|
|
|
row: usize,
|
2022-06-07 16:15:35 -07:00
|
|
|
to: Value<Assigned<F>>,
|
2021-07-26 17:34:51 -07:00
|
|
|
) -> Result<(), Error>;
|
|
|
|
|
2021-01-22 10:36:42 -08:00
|
|
|
/// Creates a new (sub)namespace and enters into it.
|
|
|
|
///
|
|
|
|
/// Not intended for downstream consumption; use [`Layouter::namespace`] instead.
|
|
|
|
///
|
|
|
|
/// [`Layouter::namespace`]: crate::circuit::Layouter#method.namespace
|
|
|
|
fn push_namespace<NR, N>(&mut self, name_fn: N)
|
|
|
|
where
|
|
|
|
NR: Into<String>,
|
|
|
|
N: FnOnce() -> NR;
|
|
|
|
|
|
|
|
/// Exits out of the existing namespace.
|
|
|
|
///
|
|
|
|
/// Not intended for downstream consumption; use [`Layouter::namespace`] instead.
|
|
|
|
///
|
|
|
|
/// [`Layouter::namespace`]: crate::circuit::Layouter#method.namespace
|
|
|
|
fn pop_namespace(&mut self, gadget_name: Option<String>);
|
2020-08-22 13:15:39 -07:00
|
|
|
}
|
|
|
|
|
2021-06-21 11:10:59 -07:00
|
|
|
/// A floor planning strategy for a circuit.
|
|
|
|
///
|
|
|
|
/// The floor planner is chip-agnostic and applies its strategy to the circuit it is used
|
|
|
|
/// within.
|
|
|
|
pub trait FloorPlanner {
|
|
|
|
/// Given the provided `cs`, synthesize the given circuit.
|
|
|
|
///
|
2021-07-20 08:01:38 -07:00
|
|
|
/// `constants` is the list of fixed columns that the layouter may use to assign
|
|
|
|
/// global constant values. These columns will all have been equality-enabled.
|
|
|
|
///
|
2021-06-21 11:10:59 -07:00
|
|
|
/// Internally, a floor planner will perform the following operations:
|
|
|
|
/// - Instantiate a [`Layouter`] for this floor planner.
|
|
|
|
/// - Perform any necessary setup or measurement tasks, which may involve one or more
|
|
|
|
/// calls to `Circuit::default().synthesize(config, &mut layouter)`.
|
|
|
|
/// - Call `circuit.synthesize(config, &mut layouter)` exactly once.
|
|
|
|
fn synthesize<F: Field, CS: Assignment<F>, C: Circuit<F>>(
|
|
|
|
cs: &mut CS,
|
|
|
|
circuit: &C,
|
|
|
|
config: C::Config,
|
2021-07-20 08:01:38 -07:00
|
|
|
constants: Vec<Column<Fixed>>,
|
2021-06-21 11:10:59 -07:00
|
|
|
) -> Result<(), Error>;
|
|
|
|
}
|
|
|
|
|
2020-08-22 13:15:39 -07:00
|
|
|
/// This is a trait that circuits provide implementations for so that the
|
|
|
|
/// backend prover can ask the circuit to synthesize using some given
|
|
|
|
/// [`ConstraintSystem`] implementation.
|
|
|
|
pub trait Circuit<F: Field> {
|
2020-11-05 19:13:54 -08:00
|
|
|
/// This is a configuration object that stores things like columns.
|
2021-02-01 11:05:19 -08:00
|
|
|
type Config: Clone;
|
2021-06-21 11:10:59 -07:00
|
|
|
/// The floor planner used for this circuit. This is an associated type of the
|
|
|
|
/// `Circuit` trait because its behaviour is circuit-critical.
|
|
|
|
type FloorPlanner: FloorPlanner;
|
|
|
|
|
|
|
|
/// Returns a copy of this circuit with no witness values (i.e. all witnesses set to
|
|
|
|
/// `None`). For most circuits, this will be equal to `Self::default()`.
|
|
|
|
fn without_witnesses(&self) -> Self;
|
2020-08-22 14:09:47 -07:00
|
|
|
|
|
|
|
/// The circuit is given an opportunity to describe the exact gate
|
2020-11-05 19:13:54 -08:00
|
|
|
/// arrangement, column arrangement, etc.
|
2020-09-11 16:18:41 -07:00
|
|
|
fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config;
|
2020-08-22 14:09:47 -07:00
|
|
|
|
2020-08-22 13:15:39 -07:00
|
|
|
/// Given the provided `cs`, synthesize the circuit. The concrete type of
|
|
|
|
/// the caller will be different depending on the context, and they may or
|
|
|
|
/// may not expect to have a witness present.
|
2021-06-21 11:10:59 -07:00
|
|
|
fn synthesize(&self, config: Self::Config, layouter: impl Layouter<F>) -> Result<(), Error>;
|
2020-08-22 14:09:47 -07:00
|
|
|
}
|
|
|
|
|
2020-11-05 19:13:54 -08:00
|
|
|
/// Low-degree expression representing an identity that must hold over the committed columns.
|
2022-06-28 08:56:09 -07:00
|
|
|
#[derive(Clone)]
|
2020-09-07 09:22:25 -07:00
|
|
|
pub enum Expression<F> {
|
2021-02-13 02:36:29 -08:00
|
|
|
/// This is a constant polynomial
|
2021-02-13 16:48:44 -08:00
|
|
|
Constant(F),
|
2021-07-21 11:55:19 -07:00
|
|
|
/// This is a virtual selector
|
|
|
|
Selector(Selector),
|
2023-02-21 09:37:35 -08:00
|
|
|
/// A placeholder which will be resolved as a fixed column during optimization.
|
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
TableTag(TableTag),
|
2020-11-05 19:13:54 -08:00
|
|
|
/// This is a fixed column queried at a certain relative location
|
2022-06-28 08:56:09 -07:00
|
|
|
Fixed(FixedQuery),
|
2020-11-05 19:13:54 -08:00
|
|
|
/// This is an advice (witness) column queried at a certain relative location
|
2022-06-28 08:56:09 -07:00
|
|
|
Advice(AdviceQuery),
|
2021-02-14 09:30:36 -08:00
|
|
|
/// This is an instance (external) column queried at a certain relative location
|
2022-06-28 08:56:09 -07:00
|
|
|
Instance(InstanceQuery),
|
2021-07-25 13:24:49 -07:00
|
|
|
/// This is a negated polynomial
|
|
|
|
Negated(Box<Expression<F>>),
|
2020-08-22 14:09:47 -07:00
|
|
|
/// This is the sum of two polynomials
|
2020-09-07 09:22:25 -07:00
|
|
|
Sum(Box<Expression<F>>, Box<Expression<F>>),
|
2020-08-22 14:09:47 -07:00
|
|
|
/// This is the product of two polynomials
|
2020-09-07 09:22:25 -07:00
|
|
|
Product(Box<Expression<F>>, Box<Expression<F>>),
|
2020-08-22 14:09:47 -07:00
|
|
|
/// This is a scaled polynomial
|
2020-09-07 09:22:25 -07:00
|
|
|
Scaled(Box<Expression<F>>, F),
|
2020-08-22 14:09:47 -07:00
|
|
|
}
|
|
|
|
|
2020-09-07 09:22:25 -07:00
|
|
|
impl<F: Field> Expression<F> {
|
2020-08-27 09:10:55 -07:00
|
|
|
/// Evaluate the polynomial using the provided closures to perform the
|
|
|
|
/// operations.
|
2022-09-09 11:15:10 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2020-08-27 09:10:55 -07:00
|
|
|
pub fn evaluate<T>(
|
2020-08-24 07:28:42 -07:00
|
|
|
&self,
|
2021-02-13 16:48:44 -08:00
|
|
|
constant: &impl Fn(F) -> T,
|
2021-07-21 11:55:19 -07:00
|
|
|
selector_column: &impl Fn(Selector) -> T,
|
2023-02-21 09:37:35 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")] table_tag: &impl Fn(TableTag) -> T,
|
2022-06-28 08:56:09 -07:00
|
|
|
fixed_column: &impl Fn(FixedQuery) -> T,
|
|
|
|
advice_column: &impl Fn(AdviceQuery) -> T,
|
|
|
|
instance_column: &impl Fn(InstanceQuery) -> T,
|
2021-07-25 13:24:49 -07:00
|
|
|
negated: &impl Fn(T) -> T,
|
2020-08-24 07:28:42 -07:00
|
|
|
sum: &impl Fn(T, T) -> T,
|
|
|
|
product: &impl Fn(T, T) -> T,
|
|
|
|
scaled: &impl Fn(T, F) -> T,
|
|
|
|
) -> T {
|
|
|
|
match self {
|
2021-02-13 16:48:44 -08:00
|
|
|
Expression::Constant(scalar) => constant(*scalar),
|
2021-07-21 11:55:19 -07:00
|
|
|
Expression::Selector(selector) => selector_column(*selector),
|
2023-02-21 09:37:35 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
Expression::TableTag(tag) => table_tag(*tag),
|
2022-06-28 08:56:09 -07:00
|
|
|
Expression::Fixed(query) => fixed_column(*query),
|
|
|
|
Expression::Advice(query) => advice_column(*query),
|
|
|
|
Expression::Instance(query) => instance_column(*query),
|
2021-07-25 13:24:49 -07:00
|
|
|
Expression::Negated(a) => {
|
|
|
|
let a = a.evaluate(
|
|
|
|
constant,
|
|
|
|
selector_column,
|
2023-02-21 09:37:35 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
table_tag,
|
2021-07-25 13:24:49 -07:00
|
|
|
fixed_column,
|
|
|
|
advice_column,
|
|
|
|
instance_column,
|
|
|
|
negated,
|
|
|
|
sum,
|
|
|
|
product,
|
|
|
|
scaled,
|
|
|
|
);
|
|
|
|
negated(a)
|
|
|
|
}
|
2020-09-07 09:22:25 -07:00
|
|
|
Expression::Sum(a, b) => {
|
2020-11-05 19:13:54 -08:00
|
|
|
let a = a.evaluate(
|
2021-02-13 16:48:44 -08:00
|
|
|
constant,
|
2021-07-21 11:55:19 -07:00
|
|
|
selector_column,
|
2023-02-21 09:37:35 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
table_tag,
|
2020-11-05 19:13:54 -08:00
|
|
|
fixed_column,
|
|
|
|
advice_column,
|
2021-02-14 09:30:36 -08:00
|
|
|
instance_column,
|
2021-07-25 13:24:49 -07:00
|
|
|
negated,
|
2020-11-05 19:13:54 -08:00
|
|
|
sum,
|
|
|
|
product,
|
|
|
|
scaled,
|
|
|
|
);
|
|
|
|
let b = b.evaluate(
|
2021-02-13 16:48:44 -08:00
|
|
|
constant,
|
2021-07-21 11:55:19 -07:00
|
|
|
selector_column,
|
2023-02-21 09:37:35 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
table_tag,
|
2020-11-05 19:13:54 -08:00
|
|
|
fixed_column,
|
|
|
|
advice_column,
|
2021-02-14 09:30:36 -08:00
|
|
|
instance_column,
|
2021-07-25 13:24:49 -07:00
|
|
|
negated,
|
2020-11-05 19:13:54 -08:00
|
|
|
sum,
|
|
|
|
product,
|
|
|
|
scaled,
|
|
|
|
);
|
2020-08-24 07:28:42 -07:00
|
|
|
sum(a, b)
|
|
|
|
}
|
2020-09-07 09:22:25 -07:00
|
|
|
Expression::Product(a, b) => {
|
2020-11-05 19:13:54 -08:00
|
|
|
let a = a.evaluate(
|
2021-02-13 16:48:44 -08:00
|
|
|
constant,
|
2021-07-21 11:55:19 -07:00
|
|
|
selector_column,
|
2023-02-21 09:37:35 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
table_tag,
|
2020-11-05 19:13:54 -08:00
|
|
|
fixed_column,
|
|
|
|
advice_column,
|
2021-02-14 09:30:36 -08:00
|
|
|
instance_column,
|
2021-07-25 13:24:49 -07:00
|
|
|
negated,
|
2020-11-05 19:13:54 -08:00
|
|
|
sum,
|
|
|
|
product,
|
|
|
|
scaled,
|
|
|
|
);
|
|
|
|
let b = b.evaluate(
|
2021-02-13 16:48:44 -08:00
|
|
|
constant,
|
2021-07-21 11:55:19 -07:00
|
|
|
selector_column,
|
2023-02-21 09:37:35 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
table_tag,
|
2020-11-05 19:13:54 -08:00
|
|
|
fixed_column,
|
|
|
|
advice_column,
|
2021-02-14 09:30:36 -08:00
|
|
|
instance_column,
|
2021-07-25 13:24:49 -07:00
|
|
|
negated,
|
2020-11-05 19:13:54 -08:00
|
|
|
sum,
|
|
|
|
product,
|
|
|
|
scaled,
|
|
|
|
);
|
2020-08-24 07:28:42 -07:00
|
|
|
product(a, b)
|
|
|
|
}
|
2020-09-07 09:22:25 -07:00
|
|
|
Expression::Scaled(a, f) => {
|
2020-11-05 19:13:54 -08:00
|
|
|
let a = a.evaluate(
|
2021-02-13 16:48:44 -08:00
|
|
|
constant,
|
2021-07-21 11:55:19 -07:00
|
|
|
selector_column,
|
2023-02-21 09:37:35 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
table_tag,
|
2020-11-05 19:13:54 -08:00
|
|
|
fixed_column,
|
|
|
|
advice_column,
|
2021-02-14 09:30:36 -08:00
|
|
|
instance_column,
|
2021-07-25 13:24:49 -07:00
|
|
|
negated,
|
2020-11-05 19:13:54 -08:00
|
|
|
sum,
|
|
|
|
product,
|
|
|
|
scaled,
|
|
|
|
);
|
2020-08-24 07:28:42 -07:00
|
|
|
scaled(a, *f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-27 09:10:55 -07:00
|
|
|
/// Compute the degree of this polynomial
|
|
|
|
pub fn degree(&self) -> usize {
|
2020-08-22 14:09:47 -07:00
|
|
|
match self {
|
2021-02-13 16:48:44 -08:00
|
|
|
Expression::Constant(_) => 0,
|
2021-07-21 11:55:19 -07:00
|
|
|
Expression::Selector(_) => 1,
|
2023-02-21 09:37:35 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
Expression::TableTag(_) => 1,
|
2021-07-12 11:53:12 -07:00
|
|
|
Expression::Fixed { .. } => 1,
|
|
|
|
Expression::Advice { .. } => 1,
|
|
|
|
Expression::Instance { .. } => 1,
|
2021-07-25 13:24:49 -07:00
|
|
|
Expression::Negated(poly) => poly.degree(),
|
2020-09-07 09:22:25 -07:00
|
|
|
Expression::Sum(a, b) => max(a.degree(), b.degree()),
|
|
|
|
Expression::Product(a, b) => a.degree() + b.degree(),
|
|
|
|
Expression::Scaled(poly, _) => poly.degree(),
|
2020-08-22 14:09:47 -07:00
|
|
|
}
|
|
|
|
}
|
2021-06-10 21:31:27 -07:00
|
|
|
|
|
|
|
/// Square this expression.
|
|
|
|
pub fn square(self) -> Self {
|
|
|
|
self.clone() * self
|
|
|
|
}
|
2021-07-21 13:43:31 -07:00
|
|
|
|
2021-07-24 09:27:50 -07:00
|
|
|
/// Returns whether or not this expression contains a simple `Selector`.
|
2021-07-22 09:07:20 -07:00
|
|
|
fn contains_simple_selector(&self) -> bool {
|
2021-07-21 13:43:31 -07:00
|
|
|
self.evaluate(
|
|
|
|
&|_| false,
|
2021-07-22 09:07:20 -07:00
|
|
|
&|selector| selector.is_simple(),
|
2023-02-21 09:37:35 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
&|_| false,
|
2022-06-28 08:56:09 -07:00
|
|
|
&|_| false,
|
|
|
|
&|_| false,
|
|
|
|
&|_| false,
|
2021-07-25 13:24:49 -07:00
|
|
|
&|a| a,
|
2021-07-21 13:43:31 -07:00
|
|
|
&|a, b| a || b,
|
|
|
|
&|a, b| a || b,
|
|
|
|
&|a, _| a,
|
|
|
|
)
|
|
|
|
}
|
2021-07-22 15:36:28 -07:00
|
|
|
|
|
|
|
/// Extracts a simple selector from this gate, if present
|
|
|
|
fn extract_simple_selector(&self) -> Option<Selector> {
|
|
|
|
let op = |a, b| match (a, b) {
|
|
|
|
(Some(a), None) | (None, Some(a)) => Some(a),
|
|
|
|
(Some(_), Some(_)) => panic!("two simple selectors cannot be in the same expression"),
|
|
|
|
_ => None,
|
|
|
|
};
|
|
|
|
|
|
|
|
self.evaluate(
|
|
|
|
&|_| None,
|
|
|
|
&|selector| {
|
|
|
|
if selector.is_simple() {
|
|
|
|
Some(selector)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
},
|
2023-02-21 09:37:35 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
&|_| None,
|
2022-06-28 08:56:09 -07:00
|
|
|
&|_| None,
|
|
|
|
&|_| None,
|
|
|
|
&|_| None,
|
2021-07-25 13:24:49 -07:00
|
|
|
&|a| a,
|
2021-07-22 15:36:28 -07:00
|
|
|
&op,
|
|
|
|
&op,
|
|
|
|
&|a, _| a,
|
|
|
|
)
|
|
|
|
}
|
2020-08-22 14:09:47 -07:00
|
|
|
}
|
|
|
|
|
2022-06-28 08:56:09 -07:00
|
|
|
impl<F: std::fmt::Debug> std::fmt::Debug for Expression<F> {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
match self {
|
|
|
|
Expression::Constant(scalar) => f.debug_tuple("Constant").field(scalar).finish(),
|
|
|
|
Expression::Selector(selector) => f.debug_tuple("Selector").field(selector).finish(),
|
2023-02-21 09:37:35 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
Expression::TableTag(tag) => f.debug_tuple("TableTag").field(tag).finish(),
|
2022-06-28 08:56:09 -07:00
|
|
|
// Skip enum variant and print query struct directly to maintain backwards compatibility.
|
|
|
|
Expression::Fixed(FixedQuery {
|
|
|
|
index,
|
|
|
|
column_index,
|
|
|
|
rotation,
|
|
|
|
}) => f
|
|
|
|
.debug_struct("Fixed")
|
|
|
|
.field("query_index", index)
|
|
|
|
.field("column_index", column_index)
|
|
|
|
.field("rotation", rotation)
|
|
|
|
.finish(),
|
|
|
|
Expression::Advice(AdviceQuery {
|
|
|
|
index,
|
|
|
|
column_index,
|
|
|
|
rotation,
|
|
|
|
}) => f
|
|
|
|
.debug_struct("Advice")
|
|
|
|
.field("query_index", index)
|
|
|
|
.field("column_index", column_index)
|
|
|
|
.field("rotation", rotation)
|
|
|
|
.finish(),
|
|
|
|
Expression::Instance(InstanceQuery {
|
|
|
|
index,
|
|
|
|
column_index,
|
|
|
|
rotation,
|
|
|
|
}) => f
|
|
|
|
.debug_struct("Instance")
|
|
|
|
.field("query_index", index)
|
|
|
|
.field("column_index", column_index)
|
|
|
|
.field("rotation", rotation)
|
|
|
|
.finish(),
|
|
|
|
Expression::Negated(poly) => f.debug_tuple("Negated").field(poly).finish(),
|
|
|
|
Expression::Sum(a, b) => f.debug_tuple("Sum").field(a).field(b).finish(),
|
|
|
|
Expression::Product(a, b) => f.debug_tuple("Product").field(a).field(b).finish(),
|
|
|
|
Expression::Scaled(poly, scalar) => {
|
|
|
|
f.debug_tuple("Scaled").field(poly).field(scalar).finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-12 08:52:42 -08:00
|
|
|
impl<F: Field> Neg for Expression<F> {
|
2021-01-28 16:45:48 -08:00
|
|
|
type Output = Expression<F>;
|
|
|
|
fn neg(self) -> Self::Output {
|
2021-07-25 13:24:49 -07:00
|
|
|
Expression::Negated(Box::new(self))
|
2021-01-28 16:45:48 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-21 13:43:31 -07:00
|
|
|
impl<F: Field> Add for Expression<F> {
|
2020-09-07 09:22:25 -07:00
|
|
|
type Output = Expression<F>;
|
|
|
|
fn add(self, rhs: Expression<F>) -> Expression<F> {
|
2021-07-22 09:07:20 -07:00
|
|
|
if self.contains_simple_selector() || rhs.contains_simple_selector() {
|
2021-07-24 09:27:50 -07:00
|
|
|
panic!("attempted to use a simple selector in an addition");
|
2021-07-21 13:43:31 -07:00
|
|
|
}
|
2020-09-07 09:22:25 -07:00
|
|
|
Expression::Sum(Box::new(self), Box::new(rhs))
|
2020-08-22 14:09:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-12 08:52:42 -08:00
|
|
|
impl<F: Field> Sub for Expression<F> {
|
2021-01-28 16:45:48 -08:00
|
|
|
type Output = Expression<F>;
|
|
|
|
fn sub(self, rhs: Expression<F>) -> Expression<F> {
|
2021-07-22 09:07:20 -07:00
|
|
|
if self.contains_simple_selector() || rhs.contains_simple_selector() {
|
2021-07-24 09:27:50 -07:00
|
|
|
panic!("attempted to use a simple selector in a subtraction");
|
2021-07-21 13:43:31 -07:00
|
|
|
}
|
2021-01-28 16:45:48 -08:00
|
|
|
Expression::Sum(Box::new(self), Box::new(-rhs))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-21 13:43:31 -07:00
|
|
|
impl<F: Field> Mul for Expression<F> {
|
2020-09-07 09:22:25 -07:00
|
|
|
type Output = Expression<F>;
|
|
|
|
fn mul(self, rhs: Expression<F>) -> Expression<F> {
|
2021-07-22 09:07:20 -07:00
|
|
|
if self.contains_simple_selector() && rhs.contains_simple_selector() {
|
2021-07-24 09:27:50 -07:00
|
|
|
panic!("attempted to multiply two expressions containing simple selectors");
|
2021-07-21 13:43:31 -07:00
|
|
|
}
|
2020-09-07 09:22:25 -07:00
|
|
|
Expression::Product(Box::new(self), Box::new(rhs))
|
2020-08-22 14:09:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-21 13:43:31 -07:00
|
|
|
impl<F: Field> Mul<F> for Expression<F> {
|
2020-09-07 09:22:25 -07:00
|
|
|
type Output = Expression<F>;
|
|
|
|
fn mul(self, rhs: F) -> Expression<F> {
|
|
|
|
Expression::Scaled(Box::new(self), rhs)
|
2020-08-22 14:09:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-27 12:27:24 -07:00
|
|
|
/// Represents an index into a vector where each entry corresponds to a distinct
|
|
|
|
/// point that polynomials are queried at.
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
2020-09-07 09:22:25 -07:00
|
|
|
pub(crate) struct PointIndex(pub usize);
|
2020-08-27 12:27:24 -07:00
|
|
|
|
2021-05-27 04:08:58 -07:00
|
|
|
/// A "virtual cell" is a PLONK cell that has been queried at a particular relative offset
|
|
|
|
/// within a custom gate.
|
2021-05-26 17:27:45 -07:00
|
|
|
#[derive(Clone, Debug)]
|
2021-05-27 06:03:12 -07:00
|
|
|
pub(crate) struct VirtualCell {
|
|
|
|
pub(crate) column: Column<Any>,
|
|
|
|
pub(crate) rotation: Rotation,
|
2021-05-26 17:27:45 -07:00
|
|
|
}
|
|
|
|
|
2021-05-27 04:08:58 -07:00
|
|
|
impl<Col: Into<Column<Any>>> From<(Col, Rotation)> for VirtualCell {
|
2021-05-26 17:27:45 -07:00
|
|
|
fn from((column, rotation): (Col, Rotation)) -> Self {
|
2021-05-27 04:08:58 -07:00
|
|
|
VirtualCell {
|
2021-05-26 17:27:45 -07:00
|
|
|
column: column.into(),
|
|
|
|
rotation,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-03 19:41:06 -07:00
|
|
|
/// An individual polynomial constraint.
|
|
|
|
///
|
|
|
|
/// These are returned by the closures passed to `ConstraintSystem::create_gate`.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Constraint<F: Field> {
|
|
|
|
name: &'static str,
|
|
|
|
poly: Expression<F>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<F: Field> From<Expression<F>> for Constraint<F> {
|
|
|
|
fn from(poly: Expression<F>) -> Self {
|
|
|
|
Constraint { name: "", poly }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<F: Field> From<(&'static str, Expression<F>)> for Constraint<F> {
|
|
|
|
fn from((name, poly): (&'static str, Expression<F>)) -> Self {
|
|
|
|
Constraint { name, poly }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<F: Field> From<Expression<F>> for Vec<Constraint<F>> {
|
|
|
|
fn from(poly: Expression<F>) -> Self {
|
|
|
|
vec![Constraint { name: "", poly }]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add a `Constraints` helper
There are two existing patterns for constructing a gate from a set of
constraints with a common selector:
- Create an iterator of constraints, where each constraint includes the
selector:
```
vec![
("foo", selector.clone() * foo),
("bar", selector.clone() * bar),
("baz", selector * bar),
]
```
This requires the user to write O(n) `selector.clone()` calls.
- Create an iterator of constraints, and then map the selector in:
```
vec![
("foo", foo),
("bar", bar),
("baz", bar),
].into_iter().map(move |(name, poly)| (name, selector.clone() * poly))
```
This looks cleaner overall, but the API is not as intuitive, and it
is messier when the constraints are named.
The `Constraints` struct provides a third, clearer API:
```
Constraints::with_selector(
selector,
vec![
("foo", foo),
("bar", bar),
("baz", bar),
],
)
```
This focuses on the structure of the constraints, and handles the
selector application for the user.
2021-12-02 20:29:11 -08:00
|
|
|
/// A set of polynomial constraints with a common selector.
|
|
|
|
///
|
|
|
|
/// ```
|
2022-11-29 21:05:37 -08:00
|
|
|
/// use group::ff::Field;
|
Add a `Constraints` helper
There are two existing patterns for constructing a gate from a set of
constraints with a common selector:
- Create an iterator of constraints, where each constraint includes the
selector:
```
vec![
("foo", selector.clone() * foo),
("bar", selector.clone() * bar),
("baz", selector * bar),
]
```
This requires the user to write O(n) `selector.clone()` calls.
- Create an iterator of constraints, and then map the selector in:
```
vec![
("foo", foo),
("bar", bar),
("baz", bar),
].into_iter().map(move |(name, poly)| (name, selector.clone() * poly))
```
This looks cleaner overall, but the API is not as intuitive, and it
is messier when the constraints are named.
The `Constraints` struct provides a third, clearer API:
```
Constraints::with_selector(
selector,
vec![
("foo", foo),
("bar", bar),
("baz", bar),
],
)
```
This focuses on the structure of the constraints, and handles the
selector application for the user.
2021-12-02 20:29:11 -08:00
|
|
|
/// use halo2_proofs::{pasta::Fp, plonk::{Constraints, Expression}, poly::Rotation};
|
|
|
|
/// # use halo2_proofs::plonk::ConstraintSystem;
|
|
|
|
///
|
|
|
|
/// # let mut meta = ConstraintSystem::<Fp>::default();
|
|
|
|
/// let a = meta.advice_column();
|
|
|
|
/// let b = meta.advice_column();
|
|
|
|
/// let c = meta.advice_column();
|
|
|
|
/// let s = meta.selector();
|
|
|
|
///
|
|
|
|
/// meta.create_gate("foo", |meta| {
|
|
|
|
/// let next = meta.query_advice(a, Rotation::next());
|
|
|
|
/// let a = meta.query_advice(a, Rotation::cur());
|
|
|
|
/// let b = meta.query_advice(b, Rotation::cur());
|
|
|
|
/// let c = meta.query_advice(c, Rotation::cur());
|
|
|
|
/// let s_ternary = meta.query_selector(s);
|
|
|
|
///
|
2022-11-29 21:05:37 -08:00
|
|
|
/// let one_minus_a = Expression::Constant(Fp::ONE) - a.clone();
|
Add a `Constraints` helper
There are two existing patterns for constructing a gate from a set of
constraints with a common selector:
- Create an iterator of constraints, where each constraint includes the
selector:
```
vec![
("foo", selector.clone() * foo),
("bar", selector.clone() * bar),
("baz", selector * bar),
]
```
This requires the user to write O(n) `selector.clone()` calls.
- Create an iterator of constraints, and then map the selector in:
```
vec![
("foo", foo),
("bar", bar),
("baz", bar),
].into_iter().map(move |(name, poly)| (name, selector.clone() * poly))
```
This looks cleaner overall, but the API is not as intuitive, and it
is messier when the constraints are named.
The `Constraints` struct provides a third, clearer API:
```
Constraints::with_selector(
selector,
vec![
("foo", foo),
("bar", bar),
("baz", bar),
],
)
```
This focuses on the structure of the constraints, and handles the
selector application for the user.
2021-12-02 20:29:11 -08:00
|
|
|
///
|
|
|
|
/// Constraints::with_selector(
|
|
|
|
/// s_ternary,
|
|
|
|
/// std::array::IntoIter::new([
|
|
|
|
/// ("a is boolean", a.clone() * one_minus_a.clone()),
|
|
|
|
/// ("next == a ? b : c", next - (a * b + one_minus_a * c)),
|
|
|
|
/// ]),
|
|
|
|
/// )
|
|
|
|
/// });
|
|
|
|
/// ```
|
2021-12-07 04:18:10 -08:00
|
|
|
///
|
|
|
|
/// Note that the use of `std::array::IntoIter::new` is only necessary if you need to
|
|
|
|
/// support Rust 1.51 or 1.52. If your minimum supported Rust version is 1.53 or greater,
|
|
|
|
/// you can pass an array directly.
|
Add a `Constraints` helper
There are two existing patterns for constructing a gate from a set of
constraints with a common selector:
- Create an iterator of constraints, where each constraint includes the
selector:
```
vec![
("foo", selector.clone() * foo),
("bar", selector.clone() * bar),
("baz", selector * bar),
]
```
This requires the user to write O(n) `selector.clone()` calls.
- Create an iterator of constraints, and then map the selector in:
```
vec![
("foo", foo),
("bar", bar),
("baz", bar),
].into_iter().map(move |(name, poly)| (name, selector.clone() * poly))
```
This looks cleaner overall, but the API is not as intuitive, and it
is messier when the constraints are named.
The `Constraints` struct provides a third, clearer API:
```
Constraints::with_selector(
selector,
vec![
("foo", foo),
("bar", bar),
("baz", bar),
],
)
```
This focuses on the structure of the constraints, and handles the
selector application for the user.
2021-12-02 20:29:11 -08:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Constraints<F: Field, C: Into<Constraint<F>>, Iter: IntoIterator<Item = C>> {
|
|
|
|
selector: Expression<F>,
|
|
|
|
constraints: Iter,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<F: Field, C: Into<Constraint<F>>, Iter: IntoIterator<Item = C>> Constraints<F, C, Iter> {
|
|
|
|
/// Constructs a set of constraints that are controlled by the given selector.
|
|
|
|
///
|
|
|
|
/// Each constraint `c` in `iterator` will be converted into the constraint
|
|
|
|
/// `selector * c`.
|
|
|
|
pub fn with_selector(selector: Expression<F>, constraints: Iter) -> Self {
|
|
|
|
Constraints {
|
|
|
|
selector,
|
|
|
|
constraints,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn apply_selector_to_constraint<F: Field, C: Into<Constraint<F>>>(
|
|
|
|
(selector, c): (Expression<F>, C),
|
|
|
|
) -> Constraint<F> {
|
|
|
|
let constraint: Constraint<F> = c.into();
|
|
|
|
Constraint {
|
|
|
|
name: constraint.name,
|
|
|
|
poly: selector * constraint.poly,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type ApplySelectorToConstraint<F, C> = fn((Expression<F>, C)) -> Constraint<F>;
|
|
|
|
type ConstraintsIterator<F, C, I> = std::iter::Map<
|
|
|
|
std::iter::Zip<std::iter::Repeat<Expression<F>>, I>,
|
|
|
|
ApplySelectorToConstraint<F, C>,
|
|
|
|
>;
|
|
|
|
|
|
|
|
impl<F: Field, C: Into<Constraint<F>>, Iter: IntoIterator<Item = C>> IntoIterator
|
|
|
|
for Constraints<F, C, Iter>
|
|
|
|
{
|
|
|
|
type Item = Constraint<F>;
|
|
|
|
type IntoIter = ConstraintsIterator<F, C, Iter::IntoIter>;
|
|
|
|
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
|
|
std::iter::repeat(self.selector)
|
|
|
|
.zip(self.constraints.into_iter())
|
|
|
|
.map(apply_selector_to_constraint)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-26 17:15:03 -07:00
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub(crate) struct Gate<F: Field> {
|
|
|
|
name: &'static str,
|
2021-06-03 19:41:06 -07:00
|
|
|
constraint_names: Vec<&'static str>,
|
2021-05-27 06:44:02 -07:00
|
|
|
polys: Vec<Expression<F>>,
|
2021-05-27 04:08:58 -07:00
|
|
|
/// We track queried selectors separately from other cells, so that we can use them to
|
|
|
|
/// trigger debug checks on gates.
|
2021-06-04 08:18:51 -07:00
|
|
|
queried_selectors: Vec<Selector>,
|
2021-05-27 04:08:58 -07:00
|
|
|
queried_cells: Vec<VirtualCell>,
|
2021-05-26 17:15:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<F: Field> Gate<F> {
|
|
|
|
pub(crate) fn name(&self) -> &'static str {
|
|
|
|
self.name
|
|
|
|
}
|
|
|
|
|
2021-06-03 19:41:06 -07:00
|
|
|
pub(crate) fn constraint_name(&self, constraint_index: usize) -> &'static str {
|
|
|
|
self.constraint_names[constraint_index]
|
|
|
|
}
|
|
|
|
|
2021-05-27 06:44:02 -07:00
|
|
|
pub(crate) fn polynomials(&self) -> &[Expression<F>] {
|
|
|
|
&self.polys
|
2021-05-26 17:15:03 -07:00
|
|
|
}
|
2021-05-27 06:03:12 -07:00
|
|
|
|
2021-06-04 08:18:51 -07:00
|
|
|
pub(crate) fn queried_selectors(&self) -> &[Selector] {
|
2021-05-27 06:03:12 -07:00
|
|
|
&self.queried_selectors
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn queried_cells(&self) -> &[VirtualCell] {
|
|
|
|
&self.queried_cells
|
|
|
|
}
|
2021-05-26 17:15:03 -07:00
|
|
|
}
|
|
|
|
|
2020-11-05 19:13:54 -08:00
|
|
|
/// This is a description of the circuit environment, such as the gate, column and
|
2020-08-22 14:09:47 -07:00
|
|
|
/// permutation arrangements.
|
|
|
|
#[derive(Debug, Clone)]
|
2021-02-10 03:36:25 -08:00
|
|
|
pub struct ConstraintSystem<F: Field> {
|
2020-11-05 19:13:54 -08:00
|
|
|
pub(crate) num_fixed_columns: usize,
|
|
|
|
pub(crate) num_advice_columns: usize,
|
2021-02-14 09:30:36 -08:00
|
|
|
pub(crate) num_instance_columns: usize,
|
2021-07-21 11:55:19 -07:00
|
|
|
pub(crate) num_selectors: usize,
|
2022-03-16 09:24:53 -07:00
|
|
|
|
|
|
|
/// This is a cached vector that maps virtual selectors to the concrete
|
|
|
|
/// fixed column that they were compressed into. This is just used by dev
|
|
|
|
/// tooling right now.
|
2021-07-21 11:55:19 -07:00
|
|
|
pub(crate) selector_map: Vec<Column<Fixed>>,
|
2023-02-21 08:53:24 -08:00
|
|
|
/// Like selector_map, but for dynamic tables.
|
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
pub(crate) dynamic_table_tag_map: Vec<Column<Fixed>>,
|
|
|
|
|
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
pub(crate) dynamic_tables: Vec<DynamicTable>,
|
2022-03-16 09:24:53 -07:00
|
|
|
|
2021-05-26 17:15:03 -07:00
|
|
|
pub(crate) gates: Vec<Gate<F>>,
|
2020-11-05 19:25:50 -08:00
|
|
|
pub(crate) advice_queries: Vec<(Column<Advice>, Rotation)>,
|
2021-07-09 08:28:45 -07:00
|
|
|
// Contains an integer for each advice column
|
|
|
|
// identifying how many distinct queries it has
|
|
|
|
// so far; should be same length as num_advice_columns.
|
2021-03-02 12:12:51 -08:00
|
|
|
num_advice_queries: Vec<usize>,
|
2021-02-14 09:30:36 -08:00
|
|
|
pub(crate) instance_queries: Vec<(Column<Instance>, Rotation)>,
|
2020-11-05 19:25:50 -08:00
|
|
|
pub(crate) fixed_queries: Vec<(Column<Fixed>, Rotation)>,
|
2020-08-27 12:27:24 -07:00
|
|
|
|
2021-07-02 15:20:36 -07:00
|
|
|
// Permutation argument for performing equality constraints
|
|
|
|
pub(crate) permutation: permutation::Argument,
|
2020-12-01 11:00:59 -08:00
|
|
|
|
|
|
|
// Vector of lookup arguments, where each corresponds to a sequence of
|
2021-02-11 18:24:55 -08:00
|
|
|
// input expressions and a sequence of table expressions involved in the lookup.
|
2021-02-10 03:36:25 -08:00
|
|
|
pub(crate) lookups: Vec<lookup::Argument<F>>,
|
2021-07-12 14:28:16 -07:00
|
|
|
|
2021-07-20 08:01:38 -07:00
|
|
|
// Vector of fixed columns, which can be used to store constant values
|
|
|
|
// that are copied into advice columns.
|
|
|
|
pub(crate) constants: Vec<Column<Fixed>>,
|
|
|
|
|
2021-07-12 14:28:16 -07:00
|
|
|
pub(crate) minimum_degree: Option<usize>,
|
2020-08-22 14:09:47 -07:00
|
|
|
}
|
|
|
|
|
2021-02-17 14:15:08 -08:00
|
|
|
/// Represents the minimal parameters that determine a `ConstraintSystem`.
|
2021-11-23 14:36:27 -08:00
|
|
|
#[allow(dead_code)]
|
2021-02-17 14:15:08 -08:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct PinnedConstraintSystem<'a, F: Field> {
|
|
|
|
num_fixed_columns: &'a usize,
|
|
|
|
num_advice_columns: &'a usize,
|
|
|
|
num_instance_columns: &'a usize,
|
2021-07-21 11:55:19 -07:00
|
|
|
num_selectors: &'a usize,
|
2021-02-17 14:15:08 -08:00
|
|
|
gates: PinnedGates<'a, F>,
|
|
|
|
advice_queries: &'a Vec<(Column<Advice>, Rotation)>,
|
|
|
|
instance_queries: &'a Vec<(Column<Instance>, Rotation)>,
|
|
|
|
fixed_queries: &'a Vec<(Column<Fixed>, Rotation)>,
|
2021-07-02 15:20:36 -07:00
|
|
|
permutation: &'a permutation::Argument,
|
2021-02-18 14:48:20 -08:00
|
|
|
lookups: &'a Vec<lookup::Argument<F>>,
|
2021-07-20 08:01:38 -07:00
|
|
|
constants: &'a Vec<Column<Fixed>>,
|
2021-07-12 14:28:16 -07:00
|
|
|
minimum_degree: &'a Option<usize>,
|
2021-02-17 14:15:08 -08:00
|
|
|
}
|
|
|
|
|
2021-05-26 17:15:03 -07:00
|
|
|
struct PinnedGates<'a, F: Field>(&'a Vec<Gate<F>>);
|
2021-02-17 14:15:08 -08:00
|
|
|
|
|
|
|
impl<'a, F: Field> std::fmt::Debug for PinnedGates<'a, F> {
|
2021-02-17 09:46:20 -08:00
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
2021-02-17 14:15:08 -08:00
|
|
|
f.debug_list()
|
2021-05-27 06:44:02 -07:00
|
|
|
.entries(self.0.iter().flat_map(|gate| gate.polynomials().iter()))
|
2021-02-17 14:15:08 -08:00
|
|
|
.finish()
|
2021-02-17 09:46:20 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-11 16:18:41 -07:00
|
|
|
impl<F: Field> Default for ConstraintSystem<F> {
|
|
|
|
fn default() -> ConstraintSystem<F> {
|
|
|
|
ConstraintSystem {
|
2020-11-05 19:13:54 -08:00
|
|
|
num_fixed_columns: 0,
|
|
|
|
num_advice_columns: 0,
|
2021-02-14 09:30:36 -08:00
|
|
|
num_instance_columns: 0,
|
2021-07-21 11:55:19 -07:00
|
|
|
num_selectors: 0,
|
|
|
|
selector_map: vec![],
|
2023-02-21 08:53:24 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
dynamic_table_tag_map: vec![],
|
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
dynamic_tables: vec![],
|
2020-08-24 07:28:42 -07:00
|
|
|
gates: vec![],
|
2020-08-27 09:10:55 -07:00
|
|
|
fixed_queries: Vec::new(),
|
|
|
|
advice_queries: Vec::new(),
|
2021-03-02 12:12:51 -08:00
|
|
|
num_advice_queries: Vec::new(),
|
2021-02-14 09:30:36 -08:00
|
|
|
instance_queries: Vec::new(),
|
2021-07-02 15:20:36 -07:00
|
|
|
permutation: permutation::Argument::new(),
|
2020-12-01 11:00:59 -08:00
|
|
|
lookups: Vec::new(),
|
2021-07-20 08:01:38 -07:00
|
|
|
constants: vec![],
|
2021-07-12 14:28:16 -07:00
|
|
|
minimum_degree: None,
|
2020-08-22 15:10:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-11 16:18:41 -07:00
|
|
|
impl<F: Field> ConstraintSystem<F> {
|
2021-02-17 14:15:08 -08:00
|
|
|
/// Obtain a pinned version of this constraint system; a structure with the
|
|
|
|
/// minimal parameters needed to determine the rest of the constraint
|
|
|
|
/// system.
|
|
|
|
pub fn pinned(&self) -> PinnedConstraintSystem<'_, F> {
|
|
|
|
PinnedConstraintSystem {
|
|
|
|
num_fixed_columns: &self.num_fixed_columns,
|
|
|
|
num_advice_columns: &self.num_advice_columns,
|
|
|
|
num_instance_columns: &self.num_instance_columns,
|
2021-07-21 11:55:19 -07:00
|
|
|
num_selectors: &self.num_selectors,
|
2021-02-17 14:15:08 -08:00
|
|
|
gates: PinnedGates(&self.gates),
|
|
|
|
fixed_queries: &self.fixed_queries,
|
|
|
|
advice_queries: &self.advice_queries,
|
|
|
|
instance_queries: &self.instance_queries,
|
2021-07-02 15:20:36 -07:00
|
|
|
permutation: &self.permutation,
|
2021-02-17 14:15:08 -08:00
|
|
|
lookups: &self.lookups,
|
2021-07-20 08:01:38 -07:00
|
|
|
constants: &self.constants,
|
2021-07-12 14:28:16 -07:00
|
|
|
minimum_degree: &self.minimum_degree,
|
2021-02-17 14:15:08 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-20 08:01:38 -07:00
|
|
|
/// Enables this fixed column to be used for global constant assignments.
|
|
|
|
///
|
|
|
|
/// # Side-effects
|
|
|
|
///
|
|
|
|
/// The column will be equality-enabled.
|
|
|
|
pub fn enable_constant(&mut self, column: Column<Fixed>) {
|
|
|
|
if !self.constants.contains(&column) {
|
|
|
|
self.constants.push(column);
|
2021-12-15 09:05:31 -08:00
|
|
|
self.enable_equality(column);
|
2021-07-20 08:01:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-02 15:20:36 -07:00
|
|
|
/// Enable the ability to enforce equality over cells in this column
|
2021-12-15 09:05:31 -08:00
|
|
|
pub fn enable_equality<C: Into<Column<Any>>>(&mut self, column: C) {
|
|
|
|
let column = column.into();
|
2021-07-02 15:20:36 -07:00
|
|
|
self.query_any_index(column, Rotation::cur());
|
|
|
|
self.permutation.add_column(column);
|
2020-08-31 09:01:09 -07:00
|
|
|
}
|
|
|
|
|
2021-07-27 07:46:37 -07:00
|
|
|
/// Add a lookup argument for some input expressions and table columns.
|
2021-05-26 16:37:32 -07:00
|
|
|
///
|
2021-07-27 07:46:37 -07:00
|
|
|
/// `table_map` returns a map between input expressions and the table columns
|
2021-05-26 16:37:32 -07:00
|
|
|
/// they need to match.
|
2020-12-01 11:48:19 -08:00
|
|
|
pub fn lookup(
|
|
|
|
&mut self,
|
2021-07-27 07:46:37 -07:00
|
|
|
table_map: impl FnOnce(&mut VirtualCells<'_, F>) -> Vec<(Expression<F>, TableColumn)>,
|
2020-12-01 11:48:19 -08:00
|
|
|
) -> usize {
|
2021-05-27 04:08:58 -07:00
|
|
|
let mut cells = VirtualCells::new(self);
|
2021-07-22 09:28:52 -07:00
|
|
|
let table_map = table_map(&mut cells)
|
|
|
|
.into_iter()
|
|
|
|
.map(|(input, table)| {
|
|
|
|
if input.contains_simple_selector() {
|
|
|
|
panic!("expression containing simple selector supplied to lookup argument");
|
|
|
|
}
|
2020-12-02 20:39:44 -08:00
|
|
|
|
2022-07-14 12:08:34 -07:00
|
|
|
let table = cells.query_fixed(table.inner());
|
2021-07-22 09:28:52 -07:00
|
|
|
|
|
|
|
(input, table)
|
|
|
|
})
|
|
|
|
.collect();
|
2021-07-22 09:07:20 -07:00
|
|
|
|
2020-12-01 11:48:19 -08:00
|
|
|
let index = self.lookups.len();
|
|
|
|
|
2021-05-26 16:37:32 -07:00
|
|
|
self.lookups.push(lookup::Argument::new(table_map));
|
2020-12-01 11:48:19 -08:00
|
|
|
|
|
|
|
index
|
|
|
|
}
|
|
|
|
|
2023-02-22 18:26:43 -08:00
|
|
|
/// Add a dynamic lookup argument for some input expressions and table columns.
|
|
|
|
///
|
|
|
|
/// `table_map` returns a map between input expressions and the table columns
|
|
|
|
/// they need to match.
|
|
|
|
///
|
|
|
|
/// `table` must contain all table columns used in table_map.
|
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
pub fn lookup_dynamic(
|
|
|
|
&mut self,
|
|
|
|
table: &DynamicTable,
|
|
|
|
table_map: impl FnOnce(
|
|
|
|
&mut VirtualCells<'_, F>,
|
|
|
|
) -> (Selector, Vec<(Expression<F>, Column<Any>)>),
|
|
|
|
) -> usize
|
|
|
|
where
|
|
|
|
F: PrimeField,
|
|
|
|
{
|
|
|
|
let mut cells = VirtualCells::new(self);
|
|
|
|
let (selector, table_map) = table_map(&mut cells);
|
|
|
|
let selector = cells.query_selector(selector);
|
|
|
|
|
|
|
|
let non_table_columns: Vec<_> = table_map
|
|
|
|
.iter()
|
|
|
|
.map(|(_, c)| c)
|
|
|
|
.filter(|col| !table.columns.contains(col))
|
|
|
|
.collect();
|
|
|
|
if !non_table_columns.is_empty() {
|
|
|
|
panic!(
|
|
|
|
"{:?} does not contain {:?}. Try adding these columns to the dynamic table.",
|
|
|
|
table,
|
|
|
|
non_table_columns.as_slice()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut table_map: Vec<_> = table_map
|
|
|
|
.into_iter()
|
|
|
|
.map(|(input, table)| {
|
|
|
|
if selector.contains_simple_selector() {
|
|
|
|
panic!("selector expression containing simple selector supplied to lookup argument");
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO is this needed
|
|
|
|
if input.contains_simple_selector() {
|
|
|
|
panic!("input expression containing simple selector supplied to lookup argument");
|
|
|
|
}
|
|
|
|
|
|
|
|
let table_query = cells.query_any(table, Rotation::cur());
|
|
|
|
(selector.clone() * input, selector.clone() * table_query)
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
table_map.push((
|
|
|
|
selector.clone() * Expression::Constant(F::from(table.tag().value())),
|
|
|
|
selector * Expression::TableTag(table.tag()),
|
|
|
|
));
|
|
|
|
|
|
|
|
let index = self.lookups.len();
|
|
|
|
|
|
|
|
self.lookups.push(lookup::Argument::new(table_map));
|
|
|
|
|
|
|
|
index
|
|
|
|
}
|
|
|
|
|
2022-07-14 12:08:34 -07:00
|
|
|
fn query_fixed_index(&mut self, column: Column<Fixed>) -> usize {
|
2020-09-03 13:26:00 -07:00
|
|
|
// Return existing query, if it exists
|
|
|
|
for (index, fixed_query) in self.fixed_queries.iter().enumerate() {
|
2022-07-14 12:08:34 -07:00
|
|
|
if fixed_query == &(column, Rotation::cur()) {
|
2020-09-03 13:26:00 -07:00
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make a new query
|
2020-08-27 09:10:55 -07:00
|
|
|
let index = self.fixed_queries.len();
|
2022-07-14 12:08:34 -07:00
|
|
|
self.fixed_queries.push((column, Rotation::cur()));
|
2020-08-27 09:10:55 -07:00
|
|
|
|
2020-09-03 13:26:00 -07:00
|
|
|
index
|
|
|
|
}
|
|
|
|
|
2020-12-23 08:45:16 -08:00
|
|
|
pub(crate) fn query_advice_index(&mut self, column: Column<Advice>, at: Rotation) -> usize {
|
2020-09-03 13:26:00 -07:00
|
|
|
// Return existing query, if it exists
|
|
|
|
for (index, advice_query) in self.advice_queries.iter().enumerate() {
|
2020-11-05 19:13:54 -08:00
|
|
|
if advice_query == &(column, at) {
|
2020-09-03 13:26:00 -07:00
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make a new query
|
2020-08-27 09:10:55 -07:00
|
|
|
let index = self.advice_queries.len();
|
2020-11-05 19:13:54 -08:00
|
|
|
self.advice_queries.push((column, at));
|
2021-03-02 12:12:51 -08:00
|
|
|
self.num_advice_queries[column.index] += 1;
|
2020-08-27 09:10:55 -07:00
|
|
|
|
2020-09-02 12:15:40 -07:00
|
|
|
index
|
|
|
|
}
|
|
|
|
|
2021-02-14 09:30:36 -08:00
|
|
|
fn query_instance_index(&mut self, column: Column<Instance>, at: Rotation) -> usize {
|
2020-09-17 10:07:19 -07:00
|
|
|
// Return existing query, if it exists
|
2021-02-14 09:30:36 -08:00
|
|
|
for (index, instance_query) in self.instance_queries.iter().enumerate() {
|
|
|
|
if instance_query == &(column, at) {
|
2020-09-17 10:07:19 -07:00
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make a new query
|
2021-02-14 09:30:36 -08:00
|
|
|
let index = self.instance_queries.len();
|
|
|
|
self.instance_queries.push((column, at));
|
2020-09-17 10:07:19 -07:00
|
|
|
|
|
|
|
index
|
|
|
|
}
|
|
|
|
|
2020-12-23 08:45:16 -08:00
|
|
|
fn query_any_index(&mut self, column: Column<Any>, at: Rotation) -> usize {
|
2020-11-30 22:35:56 -08:00
|
|
|
match column.column_type() {
|
2020-11-09 08:39:08 -08:00
|
|
|
Any::Advice => self.query_advice_index(Column::<Advice>::try_from(column).unwrap(), at),
|
2022-07-14 12:08:34 -07:00
|
|
|
Any::Fixed => self.query_fixed_index(Column::<Fixed>::try_from(column).unwrap()),
|
2021-02-14 09:30:36 -08:00
|
|
|
Any::Instance => {
|
|
|
|
self.query_instance_index(Column::<Instance>::try_from(column).unwrap(), at)
|
|
|
|
}
|
2020-11-30 22:35:56 -08:00
|
|
|
}
|
2020-11-05 19:36:54 -08:00
|
|
|
}
|
|
|
|
|
2020-12-23 08:45:16 -08:00
|
|
|
pub(crate) fn get_advice_query_index(&self, column: Column<Advice>, at: Rotation) -> usize {
|
2020-11-05 19:25:50 -08:00
|
|
|
for (index, advice_query) in self.advice_queries.iter().enumerate() {
|
|
|
|
if advice_query == &(column, at) {
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-05 19:36:54 -08:00
|
|
|
panic!("get_advice_query_index called for non-existent query");
|
2020-11-05 19:25:50 -08:00
|
|
|
}
|
|
|
|
|
2020-12-23 08:45:16 -08:00
|
|
|
pub(crate) fn get_fixed_query_index(&self, column: Column<Fixed>, at: Rotation) -> usize {
|
2020-11-05 19:25:50 -08:00
|
|
|
for (index, fixed_query) in self.fixed_queries.iter().enumerate() {
|
|
|
|
if fixed_query == &(column, at) {
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
panic!("get_fixed_query_index called for non-existent query");
|
|
|
|
}
|
|
|
|
|
2021-02-14 09:30:36 -08:00
|
|
|
pub(crate) fn get_instance_query_index(&self, column: Column<Instance>, at: Rotation) -> usize {
|
|
|
|
for (index, instance_query) in self.instance_queries.iter().enumerate() {
|
|
|
|
if instance_query == &(column, at) {
|
2020-11-05 19:36:54 -08:00
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-14 09:30:36 -08:00
|
|
|
panic!("get_instance_query_index called for non-existent query");
|
2020-11-05 19:36:54 -08:00
|
|
|
}
|
|
|
|
|
2022-07-14 11:39:23 -07:00
|
|
|
pub(crate) fn get_any_query_index(&self, column: Column<Any>) -> usize {
|
2020-11-10 21:46:18 -08:00
|
|
|
match column.column_type() {
|
2022-07-14 11:39:23 -07:00
|
|
|
Any::Advice => self.get_advice_query_index(
|
|
|
|
Column::<Advice>::try_from(column).unwrap(),
|
|
|
|
Rotation::cur(),
|
|
|
|
),
|
|
|
|
Any::Fixed => self
|
|
|
|
.get_fixed_query_index(Column::<Fixed>::try_from(column).unwrap(), Rotation::cur()),
|
|
|
|
Any::Instance => self.get_instance_query_index(
|
|
|
|
Column::<Instance>::try_from(column).unwrap(),
|
|
|
|
Rotation::cur(),
|
|
|
|
),
|
2020-11-10 21:46:18 -08:00
|
|
|
}
|
2020-11-05 19:36:54 -08:00
|
|
|
}
|
|
|
|
|
2021-07-12 14:28:16 -07:00
|
|
|
/// Sets the minimum degree required by the circuit, which can be set to a
|
|
|
|
/// larger amount than actually needed. This can be used, for example, to
|
|
|
|
/// force the permutation argument to involve more columns in the same set.
|
|
|
|
pub fn set_minimum_degree(&mut self, degree: usize) {
|
|
|
|
self.minimum_degree = Some(degree);
|
|
|
|
}
|
|
|
|
|
2021-06-04 04:59:57 -07:00
|
|
|
/// Creates a new gate.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// A gate is required to contain polynomial constraints. This method will panic if
|
|
|
|
/// `constraints` returns an empty iterator.
|
2021-06-03 19:41:06 -07:00
|
|
|
pub fn create_gate<C: Into<Constraint<F>>, Iter: IntoIterator<Item = C>>(
|
2021-05-26 16:45:55 -07:00
|
|
|
&mut self,
|
|
|
|
name: &'static str,
|
2021-06-04 04:59:57 -07:00
|
|
|
constraints: impl FnOnce(&mut VirtualCells<'_, F>) -> Iter,
|
2021-05-26 16:45:55 -07:00
|
|
|
) {
|
2021-05-27 04:08:58 -07:00
|
|
|
let mut cells = VirtualCells::new(self);
|
2021-06-04 04:59:57 -07:00
|
|
|
let constraints = constraints(&mut cells);
|
2021-05-27 04:08:58 -07:00
|
|
|
let queried_selectors = cells.queried_selectors;
|
|
|
|
let queried_cells = cells.queried_cells;
|
2021-05-26 17:27:45 -07:00
|
|
|
|
2021-06-04 04:59:57 -07:00
|
|
|
let (constraint_names, polys): (_, Vec<_>) = constraints
|
2021-06-03 19:41:06 -07:00
|
|
|
.into_iter()
|
|
|
|
.map(|c| c.into())
|
|
|
|
.map(|c| (c.name, c.poly))
|
|
|
|
.unzip();
|
|
|
|
|
2021-06-04 04:59:57 -07:00
|
|
|
assert!(
|
|
|
|
!polys.is_empty(),
|
|
|
|
"Gates must contain at least one constraint."
|
|
|
|
);
|
|
|
|
|
2021-05-26 17:27:45 -07:00
|
|
|
self.gates.push(Gate {
|
|
|
|
name,
|
2021-06-03 19:41:06 -07:00
|
|
|
constraint_names,
|
2021-05-27 06:44:02 -07:00
|
|
|
polys,
|
2021-05-26 17:27:45 -07:00
|
|
|
queried_selectors,
|
2021-05-27 04:08:58 -07:00
|
|
|
queried_cells,
|
2021-05-26 17:27:45 -07:00
|
|
|
});
|
2020-08-24 07:28:42 -07:00
|
|
|
}
|
|
|
|
|
2021-07-21 11:55:19 -07:00
|
|
|
/// This will compress selectors together depending on their provided
|
|
|
|
/// assignments. This `ConstraintSystem` will then be modified to add new
|
|
|
|
/// fixed columns (representing the actual selectors) and will return the
|
|
|
|
/// polynomials for those columns. Finally, an internal map is updated to
|
|
|
|
/// find which fixed column corresponds with a given `Selector`.
|
|
|
|
///
|
|
|
|
/// Do not call this twice. Yes, this should be a builder pattern instead.
|
2021-07-21 14:45:36 -07:00
|
|
|
pub(crate) fn compress_selectors(mut self, selectors: Vec<Vec<bool>>) -> (Self, Vec<Vec<F>>) {
|
2021-07-24 14:43:15 -07:00
|
|
|
// The number of provided selector assignments must be the number we
|
|
|
|
// counted for this constraint system.
|
2021-07-21 11:55:19 -07:00
|
|
|
assert_eq!(selectors.len(), self.num_selectors);
|
|
|
|
|
2021-07-24 14:43:15 -07:00
|
|
|
// Compute the maximal degree of every selector. We only consider the
|
|
|
|
// expressions in gates, as lookup arguments cannot support simple
|
|
|
|
// selectors. Selectors that are complex or do not appear in any gates
|
|
|
|
// will have degree zero.
|
2021-07-22 15:36:28 -07:00
|
|
|
let mut degrees = vec![0; selectors.len()];
|
|
|
|
for expr in self.gates.iter().flat_map(|gate| gate.polys.iter()) {
|
|
|
|
if let Some(selector) = expr.extract_simple_selector() {
|
2021-07-25 17:39:42 -07:00
|
|
|
degrees[selector.0] = max(degrees[selector.0], expr.degree());
|
2021-07-22 15:36:28 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We will not increase the degree of the constraint system, so we limit
|
|
|
|
// ourselves to the largest existing degree constraint.
|
|
|
|
let max_degree = self.degree();
|
|
|
|
|
|
|
|
let mut new_columns = vec![];
|
2021-07-24 14:43:15 -07:00
|
|
|
let (polys, selector_assignment) = compress_selectors::process(
|
|
|
|
selectors
|
|
|
|
.into_iter()
|
|
|
|
.zip(degrees.into_iter())
|
|
|
|
.enumerate()
|
|
|
|
.map(
|
|
|
|
|(i, (activations, max_degree))| compress_selectors::SelectorDescription {
|
|
|
|
selector: i,
|
|
|
|
activations,
|
|
|
|
max_degree,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.collect(),
|
|
|
|
max_degree,
|
|
|
|
|| {
|
|
|
|
let column = self.fixed_column();
|
|
|
|
new_columns.push(column);
|
2022-06-28 08:56:09 -07:00
|
|
|
Expression::Fixed(FixedQuery {
|
2022-07-14 12:08:34 -07:00
|
|
|
index: self.query_fixed_index(column),
|
2021-07-24 14:43:15 -07:00
|
|
|
column_index: column.index,
|
|
|
|
rotation: Rotation::cur(),
|
2022-06-28 08:56:09 -07:00
|
|
|
})
|
2021-07-24 14:43:15 -07:00
|
|
|
},
|
|
|
|
);
|
2021-07-22 15:36:28 -07:00
|
|
|
|
2021-07-24 14:43:15 -07:00
|
|
|
let mut selector_map = vec![None; selector_assignment.len()];
|
|
|
|
let mut selector_replacements = vec![None; selector_assignment.len()];
|
|
|
|
for assignment in selector_assignment {
|
|
|
|
selector_replacements[assignment.selector] = Some(assignment.expression);
|
|
|
|
selector_map[assignment.selector] = Some(new_columns[assignment.combination_index]);
|
2021-07-21 11:55:19 -07:00
|
|
|
}
|
|
|
|
|
2021-07-24 14:43:15 -07:00
|
|
|
self.selector_map = selector_map
|
|
|
|
.into_iter()
|
|
|
|
.map(|a| a.unwrap())
|
|
|
|
.collect::<Vec<_>>();
|
2021-07-22 15:36:28 -07:00
|
|
|
let selector_replacements = selector_replacements
|
2021-07-21 11:55:19 -07:00
|
|
|
.into_iter()
|
2021-07-22 15:36:28 -07:00
|
|
|
.map(|a| a.unwrap())
|
|
|
|
.collect::<Vec<_>>();
|
2021-07-21 11:55:19 -07:00
|
|
|
|
2021-07-21 14:45:36 -07:00
|
|
|
fn replace_selectors<F: Field>(
|
2021-07-21 12:12:05 -07:00
|
|
|
expr: &mut Expression<F>,
|
2021-07-24 14:43:15 -07:00
|
|
|
selector_replacements: &[Expression<F>],
|
2021-07-22 09:07:20 -07:00
|
|
|
must_be_nonsimple: bool,
|
2021-07-21 12:12:05 -07:00
|
|
|
) {
|
|
|
|
*expr = expr.evaluate(
|
2021-07-21 11:55:19 -07:00
|
|
|
&|constant| Expression::Constant(constant),
|
2021-07-22 09:07:20 -07:00
|
|
|
&|selector| {
|
|
|
|
if must_be_nonsimple {
|
2021-07-24 09:27:50 -07:00
|
|
|
// Simple selectors are prohibited from appearing in
|
2021-07-22 09:07:20 -07:00
|
|
|
// expressions in the lookup argument by
|
|
|
|
// `ConstraintSystem`.
|
|
|
|
assert!(!selector.is_simple());
|
|
|
|
}
|
|
|
|
|
2021-07-24 14:43:15 -07:00
|
|
|
selector_replacements[selector.0].clone()
|
2021-07-21 11:55:19 -07:00
|
|
|
},
|
2023-02-21 09:37:35 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
&|query| Expression::TableTag(query),
|
2022-06-28 08:56:09 -07:00
|
|
|
&|query| Expression::Fixed(query),
|
|
|
|
&|query| Expression::Advice(query),
|
|
|
|
&|query| Expression::Instance(query),
|
2021-07-25 13:24:49 -07:00
|
|
|
&|a| -a,
|
2021-07-21 11:55:19 -07:00
|
|
|
&|a, b| a + b,
|
|
|
|
&|a, b| a * b,
|
|
|
|
&|a, f| a * f,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-07-21 12:12:05 -07:00
|
|
|
// Substitute selectors for the real fixed columns in all gates
|
|
|
|
for expr in self.gates.iter_mut().flat_map(|gate| gate.polys.iter_mut()) {
|
2021-07-22 15:36:28 -07:00
|
|
|
replace_selectors(expr, &selector_replacements, false);
|
2021-07-21 12:12:05 -07:00
|
|
|
}
|
|
|
|
|
2021-07-22 09:07:20 -07:00
|
|
|
// Substitute non-simple selectors for the real fixed columns in all
|
|
|
|
// lookup expressions
|
2021-07-21 12:12:05 -07:00
|
|
|
for expr in self.lookups.iter_mut().flat_map(|lookup| {
|
|
|
|
lookup
|
|
|
|
.input_expressions
|
|
|
|
.iter_mut()
|
|
|
|
.chain(lookup.table_expressions.iter_mut())
|
|
|
|
}) {
|
2021-07-22 15:36:28 -07:00
|
|
|
replace_selectors(expr, &selector_replacements, true);
|
2021-07-21 12:12:05 -07:00
|
|
|
}
|
|
|
|
|
2021-07-21 11:55:19 -07:00
|
|
|
(self, polys)
|
|
|
|
}
|
|
|
|
|
2021-07-22 09:07:20 -07:00
|
|
|
/// Allocate a new (simple) selector. Simple selectors cannot be added to
|
|
|
|
/// expressions nor multiplied by other expressions containing simple
|
|
|
|
/// selectors. Also, simple selectors may not appear in lookup argument
|
|
|
|
/// inputs.
|
2021-02-23 15:17:17 -08:00
|
|
|
pub fn selector(&mut self) -> Selector {
|
2021-07-21 11:55:19 -07:00
|
|
|
let index = self.num_selectors;
|
|
|
|
self.num_selectors += 1;
|
2021-07-22 09:07:20 -07:00
|
|
|
Selector(index, true)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Allocate a new complex selector that can appear anywhere
|
|
|
|
/// within expressions.
|
|
|
|
pub fn complex_selector(&mut self) -> Selector {
|
|
|
|
let index = self.num_selectors;
|
|
|
|
self.num_selectors += 1;
|
|
|
|
Selector(index, false)
|
2021-02-23 15:17:17 -08:00
|
|
|
}
|
|
|
|
|
2023-02-22 18:26:43 -08:00
|
|
|
/// Construct a dynamic table consisting of fixed, and advice.
|
|
|
|
/// `name` is solely for debugging.
|
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
pub fn create_dynamic_table(
|
|
|
|
&mut self,
|
|
|
|
name: impl Into<String>,
|
|
|
|
fixed_columns: &[Column<Fixed>],
|
|
|
|
advice_columns: &[Column<Advice>],
|
|
|
|
) -> DynamicTable {
|
|
|
|
let index = self.dynamic_tables.len();
|
|
|
|
let columns: Vec<_> = fixed_columns
|
|
|
|
.iter()
|
|
|
|
.map(|f| Column::<Any>::from(*f))
|
|
|
|
.chain(advice_columns.iter().map(|f| Column::<Any>::from(*f)))
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let table = DynamicTable {
|
|
|
|
name: name.into(),
|
|
|
|
index,
|
|
|
|
columns,
|
|
|
|
};
|
|
|
|
|
|
|
|
self.dynamic_tables.push(table.clone());
|
|
|
|
table
|
|
|
|
}
|
|
|
|
|
2021-07-27 07:46:37 -07:00
|
|
|
/// Allocates a new fixed column that can be used in a lookup table.
|
|
|
|
pub fn lookup_table_column(&mut self) -> TableColumn {
|
|
|
|
TableColumn {
|
|
|
|
inner: self.fixed_column(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-05 19:13:54 -08:00
|
|
|
/// Allocate a new fixed column
|
2020-11-05 19:25:50 -08:00
|
|
|
pub fn fixed_column(&mut self) -> Column<Fixed> {
|
|
|
|
let tmp = Column {
|
|
|
|
index: self.num_fixed_columns,
|
|
|
|
column_type: Fixed,
|
|
|
|
};
|
2020-11-05 19:13:54 -08:00
|
|
|
self.num_fixed_columns += 1;
|
2020-08-22 15:10:27 -07:00
|
|
|
tmp
|
|
|
|
}
|
2020-08-27 09:10:55 -07:00
|
|
|
|
2020-11-05 19:13:54 -08:00
|
|
|
/// Allocate a new advice column
|
2020-11-05 19:25:50 -08:00
|
|
|
pub fn advice_column(&mut self) -> Column<Advice> {
|
|
|
|
let tmp = Column {
|
|
|
|
index: self.num_advice_columns,
|
|
|
|
column_type: Advice,
|
|
|
|
};
|
2020-11-05 19:13:54 -08:00
|
|
|
self.num_advice_columns += 1;
|
2021-03-02 12:12:51 -08:00
|
|
|
self.num_advice_queries.push(0);
|
2020-08-22 15:10:27 -07:00
|
|
|
tmp
|
2020-08-22 14:09:47 -07:00
|
|
|
}
|
2020-09-17 10:07:19 -07:00
|
|
|
|
2021-02-14 09:30:36 -08:00
|
|
|
/// Allocate a new instance column
|
|
|
|
pub fn instance_column(&mut self) -> Column<Instance> {
|
2020-11-05 19:25:50 -08:00
|
|
|
let tmp = Column {
|
2021-02-14 09:30:36 -08:00
|
|
|
index: self.num_instance_columns,
|
|
|
|
column_type: Instance,
|
2020-11-05 19:25:50 -08:00
|
|
|
};
|
2021-02-14 09:30:36 -08:00
|
|
|
self.num_instance_columns += 1;
|
2020-09-17 10:07:19 -07:00
|
|
|
tmp
|
|
|
|
}
|
2021-02-24 09:19:46 -08:00
|
|
|
|
|
|
|
/// Compute the degree of the constraint system (the maximum degree of all
|
|
|
|
/// constraints).
|
|
|
|
pub fn degree(&self) -> usize {
|
|
|
|
// The permutation argument will serve alongside the gates, so must be
|
|
|
|
// accounted for.
|
2021-07-02 15:20:36 -07:00
|
|
|
let mut degree = self.permutation.required_degree();
|
2021-02-24 09:19:46 -08:00
|
|
|
|
|
|
|
// The lookup argument also serves alongside the gates and must be accounted
|
|
|
|
// for.
|
|
|
|
degree = std::cmp::max(
|
|
|
|
degree,
|
|
|
|
self.lookups
|
|
|
|
.iter()
|
|
|
|
.map(|l| l.required_degree())
|
|
|
|
.max()
|
|
|
|
.unwrap_or(1),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Account for each gate to ensure our quotient polynomial is the
|
|
|
|
// correct degree and that our extended domain is the right size.
|
2021-05-27 06:44:02 -07:00
|
|
|
degree = std::cmp::max(
|
|
|
|
degree,
|
|
|
|
self.gates
|
|
|
|
.iter()
|
|
|
|
.flat_map(|gate| gate.polynomials().iter().map(|poly| poly.degree()))
|
|
|
|
.max()
|
|
|
|
.unwrap_or(0),
|
|
|
|
);
|
2021-02-24 09:19:46 -08:00
|
|
|
|
2021-07-12 14:28:16 -07:00
|
|
|
std::cmp::max(degree, self.minimum_degree.unwrap_or(1))
|
2021-02-24 09:19:46 -08:00
|
|
|
}
|
2021-03-02 12:12:51 -08:00
|
|
|
|
|
|
|
/// Compute the number of blinding factors necessary to perfectly blind
|
|
|
|
/// each of the prover's witness polynomials.
|
|
|
|
pub fn blinding_factors(&self) -> usize {
|
2021-07-09 08:14:52 -07:00
|
|
|
// All of the prover's advice columns are evaluated at no more than
|
2021-03-02 12:12:51 -08:00
|
|
|
let factors = *self.num_advice_queries.iter().max().unwrap_or(&1);
|
2021-07-09 08:14:52 -07:00
|
|
|
// distinct points during gate checks.
|
2021-03-02 12:12:51 -08:00
|
|
|
|
2021-07-14 14:19:26 -07:00
|
|
|
// - The permutation argument witness polynomials are evaluated at most 3 times.
|
|
|
|
// - Each lookup argument has independent witness polynomials, and they are
|
|
|
|
// evaluated at most 2 times.
|
2021-07-02 15:20:36 -07:00
|
|
|
let factors = std::cmp::max(3, factors);
|
2021-03-02 12:12:51 -08:00
|
|
|
|
|
|
|
// Each polynomial is evaluated at most an additional time during
|
2021-07-14 14:19:26 -07:00
|
|
|
// multiopen (at x_3 to produce q_evals):
|
2021-03-02 12:12:51 -08:00
|
|
|
let factors = factors + 1;
|
|
|
|
|
|
|
|
// h(x) is derived by the other evaluations so it does not reveal
|
|
|
|
// anything; in fact it does not even appear in the proof.
|
|
|
|
|
2021-03-03 09:57:13 -08:00
|
|
|
// h(x_3) is also not revealed; the verifier only learns a single
|
|
|
|
// evaluation of a polynomial in x_1 which has h(x_3) and another random
|
2021-07-14 14:19:26 -07:00
|
|
|
// polynomial evaluated at x_3 as coefficients -- this random polynomial
|
|
|
|
// is "random_poly" in the vanishing argument.
|
2021-03-03 09:57:13 -08:00
|
|
|
|
2021-07-02 15:20:36 -07:00
|
|
|
// Add an additional blinding factor as a slight defense against
|
|
|
|
// off-by-one errors.
|
2021-03-02 12:12:51 -08:00
|
|
|
factors + 1
|
|
|
|
}
|
2021-07-09 08:14:52 -07:00
|
|
|
|
|
|
|
/// Returns the minimum necessary rows that need to exist in order to
|
|
|
|
/// account for e.g. blinding factors.
|
|
|
|
pub fn minimum_rows(&self) -> usize {
|
|
|
|
self.blinding_factors() // m blinding factors
|
|
|
|
+ 1 // for l_{-(m + 1)} (l_last)
|
2021-07-10 07:43:01 -07:00
|
|
|
+ 1 // for l_0 (just for extra breathing room for the permutation
|
|
|
|
// argument, to essentially force a separation in the
|
|
|
|
// permutation polynomial between the roles of l_last, l_0
|
|
|
|
// and the interstitial values.)
|
2021-07-09 08:14:52 -07:00
|
|
|
+ 1 // for at least one row
|
|
|
|
}
|
2020-08-22 13:15:39 -07:00
|
|
|
}
|
2021-05-26 16:45:55 -07:00
|
|
|
|
2021-05-27 04:08:58 -07:00
|
|
|
/// Exposes the "virtual cells" that can be queried while creating a custom gate or lookup
|
|
|
|
/// table.
|
2021-05-26 16:45:55 -07:00
|
|
|
#[derive(Debug)]
|
2021-05-27 04:08:58 -07:00
|
|
|
pub struct VirtualCells<'a, F: Field> {
|
2021-05-26 16:45:55 -07:00
|
|
|
meta: &'a mut ConstraintSystem<F>,
|
2021-06-04 08:18:51 -07:00
|
|
|
queried_selectors: Vec<Selector>,
|
2021-05-27 04:08:58 -07:00
|
|
|
queried_cells: Vec<VirtualCell>,
|
2021-05-26 16:45:55 -07:00
|
|
|
}
|
|
|
|
|
2021-05-27 04:08:58 -07:00
|
|
|
impl<'a, F: Field> VirtualCells<'a, F> {
|
2021-05-26 16:45:55 -07:00
|
|
|
fn new(meta: &'a mut ConstraintSystem<F>) -> Self {
|
2021-05-27 04:08:58 -07:00
|
|
|
VirtualCells {
|
2021-05-26 17:27:45 -07:00
|
|
|
meta,
|
|
|
|
queried_selectors: vec![],
|
2021-05-27 04:08:58 -07:00
|
|
|
queried_cells: vec![],
|
2021-05-26 17:27:45 -07:00
|
|
|
}
|
2021-05-26 16:45:55 -07:00
|
|
|
}
|
|
|
|
|
2021-06-04 08:18:51 -07:00
|
|
|
/// Query a selector at the current position.
|
|
|
|
pub fn query_selector(&mut self, selector: Selector) -> Expression<F> {
|
|
|
|
self.queried_selectors.push(selector);
|
2021-07-21 11:55:19 -07:00
|
|
|
Expression::Selector(selector)
|
2021-05-26 16:45:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Query a fixed column at a relative position
|
2022-07-14 12:08:34 -07:00
|
|
|
pub fn query_fixed(&mut self, column: Column<Fixed>) -> Expression<F> {
|
|
|
|
self.queried_cells.push((column, Rotation::cur()).into());
|
2022-06-28 08:56:09 -07:00
|
|
|
Expression::Fixed(FixedQuery {
|
2022-07-14 12:08:34 -07:00
|
|
|
index: self.meta.query_fixed_index(column),
|
2021-07-12 11:53:12 -07:00
|
|
|
column_index: column.index,
|
2022-07-14 12:08:34 -07:00
|
|
|
rotation: Rotation::cur(),
|
2022-06-28 08:56:09 -07:00
|
|
|
})
|
2021-05-26 16:45:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Query an advice column at a relative position
|
|
|
|
pub fn query_advice(&mut self, column: Column<Advice>, at: Rotation) -> Expression<F> {
|
2021-05-27 04:08:58 -07:00
|
|
|
self.queried_cells.push((column, at).into());
|
2022-06-28 08:56:09 -07:00
|
|
|
Expression::Advice(AdviceQuery {
|
|
|
|
index: self.meta.query_advice_index(column, at),
|
2021-07-12 11:53:12 -07:00
|
|
|
column_index: column.index,
|
|
|
|
rotation: at,
|
2022-06-28 08:56:09 -07:00
|
|
|
})
|
2021-05-26 16:45:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Query an instance column at a relative position
|
|
|
|
pub fn query_instance(&mut self, column: Column<Instance>, at: Rotation) -> Expression<F> {
|
2021-05-27 04:08:58 -07:00
|
|
|
self.queried_cells.push((column, at).into());
|
2022-06-28 08:56:09 -07:00
|
|
|
Expression::Instance(InstanceQuery {
|
|
|
|
index: self.meta.query_instance_index(column, at),
|
2021-07-12 11:53:12 -07:00
|
|
|
column_index: column.index,
|
|
|
|
rotation: at,
|
2022-06-28 08:56:09 -07:00
|
|
|
})
|
2021-05-26 16:45:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Query an Any column at a relative position
|
2022-07-14 11:39:23 -07:00
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if query_fixed is called with a non-cur Rotation.
|
2021-12-15 09:05:31 -08:00
|
|
|
pub fn query_any<C: Into<Column<Any>>>(&mut self, column: C, at: Rotation) -> Expression<F> {
|
|
|
|
let column = column.into();
|
2021-05-26 16:45:55 -07:00
|
|
|
match column.column_type() {
|
2021-07-12 11:53:12 -07:00
|
|
|
Any::Advice => self.query_advice(Column::<Advice>::try_from(column).unwrap(), at),
|
2022-07-14 11:39:23 -07:00
|
|
|
Any::Fixed => {
|
|
|
|
if at != Rotation::cur() {
|
|
|
|
panic!("Fixed columns can only be queried at the current rotation");
|
|
|
|
}
|
2022-07-14 12:08:34 -07:00
|
|
|
self.query_fixed(Column::<Fixed>::try_from(column).unwrap())
|
2022-07-14 11:39:23 -07:00
|
|
|
}
|
2021-07-12 11:53:12 -07:00
|
|
|
Any::Instance => self.query_instance(Column::<Instance>::try_from(column).unwrap(), at),
|
2021-05-26 16:45:55 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|