2020-08-22 21:09:47 +00:00
|
|
|
use core::cmp::max;
|
|
|
|
|
use core::ops::{Add, Mul};
|
2021-02-17 22:15:08 +00:00
|
|
|
use ff::Field;
|
2021-01-29 00:45:48 +00:00
|
|
|
use std::{
|
2021-02-15 04:46:14 +00:00
|
|
|
convert::TryFrom,
|
2021-01-29 00:45:48 +00:00
|
|
|
ops::{Neg, Sub},
|
|
|
|
|
};
|
2020-08-22 20:15:39 +00:00
|
|
|
|
2020-12-01 19:00:59 +00:00
|
|
|
use super::{lookup, permutation, Error};
|
2021-02-12 16:52:42 +00:00
|
|
|
use crate::poly::Rotation;
|
2020-08-23 19:26:04 +00:00
|
|
|
|
2020-11-06 03:25:50 +00:00
|
|
|
/// A column type
|
2021-02-11 14:30:26 +00:00
|
|
|
pub trait ColumnType: 'static + Sized + std::fmt::Debug {}
|
2020-11-06 03:25:50 +00:00
|
|
|
|
|
|
|
|
/// A column with an index and type
|
2021-01-13 14:58:12 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
2020-11-06 03:25:50 +00:00
|
|
|
pub struct Column<C: ColumnType> {
|
2020-11-09 16:45:52 +00:00
|
|
|
index: usize,
|
|
|
|
|
column_type: C,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<C: ColumnType> Column<C> {
|
|
|
|
|
pub(crate) fn index(&self) -> usize {
|
|
|
|
|
self.index
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn column_type(&self) -> &C {
|
|
|
|
|
&self.column_type
|
|
|
|
|
}
|
2020-11-06 03:25:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// An advice column
|
2021-01-13 14:58:12 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
2020-11-06 03:25:50 +00:00
|
|
|
pub struct Advice;
|
|
|
|
|
|
|
|
|
|
/// A fixed column
|
2021-01-13 14:58:12 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
2020-11-06 03:25:50 +00:00
|
|
|
pub struct Fixed;
|
|
|
|
|
|
2021-02-14 17:30:36 +00:00
|
|
|
/// An instance column
|
2021-01-13 14:58:12 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
2021-02-14 17:30:36 +00:00
|
|
|
pub struct Instance;
|
2020-11-06 03:25:50 +00:00
|
|
|
|
2021-02-14 17:30:36 +00:00
|
|
|
/// An enum over the Advice, Fixed, Instance structs
|
2021-01-13 14:58:12 +00:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
2020-11-06 03:25:50 +00:00
|
|
|
pub enum Any {
|
|
|
|
|
/// An Advice variant
|
|
|
|
|
Advice,
|
|
|
|
|
/// A Fixed variant
|
|
|
|
|
Fixed,
|
2021-02-14 17:30:36 +00:00
|
|
|
/// An Instance variant
|
|
|
|
|
Instance,
|
2020-11-06 03:25:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ColumnType for Advice {}
|
|
|
|
|
impl ColumnType for Fixed {}
|
2021-02-14 17:30:36 +00:00
|
|
|
impl ColumnType for Instance {}
|
2020-11-06 03:25:50 +00:00
|
|
|
impl ColumnType for Any {}
|
2020-08-23 19:26:04 +00:00
|
|
|
|
2020-11-06 03:25:50 +00:00
|
|
|
impl From<Column<Advice>> for Column<Any> {
|
|
|
|
|
fn from(advice: Column<Advice>) -> Column<Any> {
|
|
|
|
|
Column {
|
2020-11-09 16:45:52 +00:00
|
|
|
index: advice.index(),
|
2020-11-06 03:25:50 +00:00
|
|
|
column_type: Any::Advice,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<Column<Fixed>> for Column<Any> {
|
|
|
|
|
fn from(advice: Column<Fixed>) -> Column<Any> {
|
|
|
|
|
Column {
|
2020-11-09 16:45:52 +00:00
|
|
|
index: advice.index(),
|
2020-11-06 03:25:50 +00:00
|
|
|
column_type: Any::Fixed,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-14 17:30:36 +00:00
|
|
|
impl From<Column<Instance>> for Column<Any> {
|
|
|
|
|
fn from(advice: Column<Instance>) -> Column<Any> {
|
2020-11-06 03:25:50 +00:00
|
|
|
Column {
|
2020-11-09 16:45:52 +00:00
|
|
|
index: advice.index(),
|
2021-02-14 17:30:36 +00:00
|
|
|
column_type: Any::Instance,
|
2020-11-06 03:25:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-09 16:39:08 +00: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 16:45:52 +00:00
|
|
|
match any.column_type() {
|
2020-11-11 05:46:18 +00:00
|
|
|
Any::Advice => Ok(Column {
|
|
|
|
|
index: any.index(),
|
|
|
|
|
column_type: Advice,
|
|
|
|
|
}),
|
2020-11-09 16:39:08 +00:00
|
|
|
_ => Err("Cannot convert into Column<Advice>"),
|
2020-11-06 03:25:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-09 16:39:08 +00: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 16:45:52 +00:00
|
|
|
match any.column_type() {
|
2020-11-11 05:46:18 +00:00
|
|
|
Any::Fixed => Ok(Column {
|
|
|
|
|
index: any.index(),
|
|
|
|
|
column_type: Fixed,
|
|
|
|
|
}),
|
2020-11-09 16:39:08 +00:00
|
|
|
_ => Err("Cannot convert into Column<Fixed>"),
|
2020-11-06 03:25:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-14 17:30:36 +00:00
|
|
|
impl TryFrom<Column<Any>> for Column<Instance> {
|
2020-11-09 16:39:08 +00:00
|
|
|
type Error = &'static str;
|
|
|
|
|
|
|
|
|
|
fn try_from(any: Column<Any>) -> Result<Self, Self::Error> {
|
2020-11-09 16:45:52 +00:00
|
|
|
match any.column_type() {
|
2021-02-14 17:30:36 +00:00
|
|
|
Any::Instance => Ok(Column {
|
2020-11-11 05:46:18 +00:00
|
|
|
index: any.index(),
|
2021-02-14 17:30:36 +00:00
|
|
|
column_type: Instance,
|
2020-11-11 05:46:18 +00:00
|
|
|
}),
|
2021-02-14 17:30:36 +00:00
|
|
|
_ => Err("Cannot convert into Column<Instance>"),
|
2020-11-06 03:25:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-17 16:33:42 +00:00
|
|
|
|
2020-08-22 20:15:39 +00:00
|
|
|
/// This trait allows a [`Circuit`] to direct some backend to assign a witness
|
|
|
|
|
/// for a constraint system.
|
2020-09-11 23:18:41 +00:00
|
|
|
pub trait Assignment<F: Field> {
|
2021-01-22 16:43:36 +00: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);
|
|
|
|
|
|
2020-11-06 03:13:54 +00:00
|
|
|
/// Assign an advice column value (witness)
|
2021-01-22 16:57:38 +00:00
|
|
|
fn assign_advice<V, A, AR>(
|
2020-08-23 19:26:04 +00:00
|
|
|
&mut self,
|
2021-01-22 16:57:38 +00:00
|
|
|
annotation: A,
|
2020-11-06 03:25:50 +00:00
|
|
|
column: Column<Advice>,
|
2020-08-23 19:26:04 +00:00
|
|
|
row: usize,
|
2021-01-22 16:57:38 +00:00
|
|
|
to: V,
|
|
|
|
|
) -> Result<(), Error>
|
|
|
|
|
where
|
|
|
|
|
V: FnOnce() -> Result<F, Error>,
|
|
|
|
|
A: FnOnce() -> AR,
|
|
|
|
|
AR: Into<String>;
|
2020-08-23 19:26:04 +00:00
|
|
|
|
|
|
|
|
/// Assign a fixed value
|
2021-01-22 16:57:38 +00:00
|
|
|
fn assign_fixed<V, A, AR>(
|
2020-08-23 19:26:04 +00:00
|
|
|
&mut self,
|
2021-01-22 16:57:38 +00:00
|
|
|
annotation: A,
|
2020-11-06 03:25:50 +00:00
|
|
|
column: Column<Fixed>,
|
2020-08-23 19:26:04 +00:00
|
|
|
row: usize,
|
2021-01-22 16:57:38 +00:00
|
|
|
to: V,
|
|
|
|
|
) -> Result<(), Error>
|
|
|
|
|
where
|
|
|
|
|
V: FnOnce() -> Result<F, Error>,
|
|
|
|
|
A: FnOnce() -> AR,
|
|
|
|
|
AR: Into<String>;
|
2020-08-22 22:10:27 +00:00
|
|
|
|
2020-11-06 03:13:54 +00:00
|
|
|
/// Assign two advice columns to have the same value
|
2020-08-31 16:01:09 +00:00
|
|
|
fn copy(
|
|
|
|
|
&mut self,
|
|
|
|
|
permutation: usize,
|
2020-11-06 03:13:54 +00:00
|
|
|
left_column: usize,
|
2020-08-31 16:01:09 +00:00
|
|
|
left_row: usize,
|
2020-11-06 03:13:54 +00:00
|
|
|
right_column: usize,
|
2020-08-31 16:01:09 +00:00
|
|
|
right_row: usize,
|
|
|
|
|
) -> Result<(), Error>;
|
2021-01-22 18:36:42 +00: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 20:15:39 +00: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-06 03:13:54 +00:00
|
|
|
/// This is a configuration object that stores things like columns.
|
2021-02-01 19:05:19 +00:00
|
|
|
type Config: Clone;
|
2020-08-22 21:09:47 +00:00
|
|
|
|
|
|
|
|
/// The circuit is given an opportunity to describe the exact gate
|
2020-11-06 03:13:54 +00:00
|
|
|
/// arrangement, column arrangement, etc.
|
2020-09-11 23:18:41 +00:00
|
|
|
fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config;
|
2020-08-22 21:09:47 +00:00
|
|
|
|
2020-08-22 20:15:39 +00: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.
|
2020-09-11 23:18:41 +00:00
|
|
|
fn synthesize(&self, cs: &mut impl Assignment<F>, config: Self::Config) -> Result<(), Error>;
|
2020-08-22 21:09:47 +00:00
|
|
|
}
|
|
|
|
|
|
2020-11-06 03:13:54 +00:00
|
|
|
/// Low-degree expression representing an identity that must hold over the committed columns.
|
2020-08-22 21:09:47 +00:00
|
|
|
#[derive(Clone, Debug)]
|
2020-09-07 16:22:25 +00:00
|
|
|
pub enum Expression<F> {
|
2020-11-06 03:13:54 +00:00
|
|
|
/// This is a fixed column queried at a certain relative location
|
2020-08-27 16:10:55 +00:00
|
|
|
Fixed(usize),
|
2020-11-06 03:13:54 +00:00
|
|
|
/// This is an advice (witness) column queried at a certain relative location
|
2020-08-27 16:10:55 +00:00
|
|
|
Advice(usize),
|
2021-02-14 17:30:36 +00:00
|
|
|
/// This is an instance (external) column queried at a certain relative location
|
|
|
|
|
Instance(usize),
|
2020-08-22 21:09:47 +00:00
|
|
|
/// This is the sum of two polynomials
|
2020-09-07 16:22:25 +00:00
|
|
|
Sum(Box<Expression<F>>, Box<Expression<F>>),
|
2020-08-22 21:09:47 +00:00
|
|
|
/// This is the product of two polynomials
|
2020-09-07 16:22:25 +00:00
|
|
|
Product(Box<Expression<F>>, Box<Expression<F>>),
|
2020-08-22 21:09:47 +00:00
|
|
|
/// This is a scaled polynomial
|
2020-09-07 16:22:25 +00:00
|
|
|
Scaled(Box<Expression<F>>, F),
|
2020-08-22 21:09:47 +00:00
|
|
|
}
|
|
|
|
|
|
2020-09-07 16:22:25 +00:00
|
|
|
impl<F: Field> Expression<F> {
|
2020-08-27 16:10:55 +00:00
|
|
|
/// Evaluate the polynomial using the provided closures to perform the
|
|
|
|
|
/// operations.
|
|
|
|
|
pub fn evaluate<T>(
|
2020-08-24 14:28:42 +00:00
|
|
|
&self,
|
2020-11-06 03:13:54 +00:00
|
|
|
fixed_column: &impl Fn(usize) -> T,
|
|
|
|
|
advice_column: &impl Fn(usize) -> T,
|
2021-02-14 17:30:36 +00:00
|
|
|
instance_column: &impl Fn(usize) -> T,
|
2020-08-24 14:28:42 +00:00
|
|
|
sum: &impl Fn(T, T) -> T,
|
|
|
|
|
product: &impl Fn(T, T) -> T,
|
|
|
|
|
scaled: &impl Fn(T, F) -> T,
|
|
|
|
|
) -> T {
|
|
|
|
|
match self {
|
2020-11-06 03:13:54 +00:00
|
|
|
Expression::Fixed(index) => fixed_column(*index),
|
|
|
|
|
Expression::Advice(index) => advice_column(*index),
|
2021-02-14 17:30:36 +00:00
|
|
|
Expression::Instance(index) => instance_column(*index),
|
2020-09-07 16:22:25 +00:00
|
|
|
Expression::Sum(a, b) => {
|
2020-11-06 03:13:54 +00:00
|
|
|
let a = a.evaluate(
|
|
|
|
|
fixed_column,
|
|
|
|
|
advice_column,
|
2021-02-14 17:30:36 +00:00
|
|
|
instance_column,
|
2020-11-06 03:13:54 +00:00
|
|
|
sum,
|
|
|
|
|
product,
|
|
|
|
|
scaled,
|
|
|
|
|
);
|
|
|
|
|
let b = b.evaluate(
|
|
|
|
|
fixed_column,
|
|
|
|
|
advice_column,
|
2021-02-14 17:30:36 +00:00
|
|
|
instance_column,
|
2020-11-06 03:13:54 +00:00
|
|
|
sum,
|
|
|
|
|
product,
|
|
|
|
|
scaled,
|
|
|
|
|
);
|
2020-08-24 14:28:42 +00:00
|
|
|
sum(a, b)
|
|
|
|
|
}
|
2020-09-07 16:22:25 +00:00
|
|
|
Expression::Product(a, b) => {
|
2020-11-06 03:13:54 +00:00
|
|
|
let a = a.evaluate(
|
|
|
|
|
fixed_column,
|
|
|
|
|
advice_column,
|
2021-02-14 17:30:36 +00:00
|
|
|
instance_column,
|
2020-11-06 03:13:54 +00:00
|
|
|
sum,
|
|
|
|
|
product,
|
|
|
|
|
scaled,
|
|
|
|
|
);
|
|
|
|
|
let b = b.evaluate(
|
|
|
|
|
fixed_column,
|
|
|
|
|
advice_column,
|
2021-02-14 17:30:36 +00:00
|
|
|
instance_column,
|
2020-11-06 03:13:54 +00:00
|
|
|
sum,
|
|
|
|
|
product,
|
|
|
|
|
scaled,
|
|
|
|
|
);
|
2020-08-24 14:28:42 +00:00
|
|
|
product(a, b)
|
|
|
|
|
}
|
2020-09-07 16:22:25 +00:00
|
|
|
Expression::Scaled(a, f) => {
|
2020-11-06 03:13:54 +00:00
|
|
|
let a = a.evaluate(
|
|
|
|
|
fixed_column,
|
|
|
|
|
advice_column,
|
2021-02-14 17:30:36 +00:00
|
|
|
instance_column,
|
2020-11-06 03:13:54 +00:00
|
|
|
sum,
|
|
|
|
|
product,
|
|
|
|
|
scaled,
|
|
|
|
|
);
|
2020-08-24 14:28:42 +00:00
|
|
|
scaled(a, *f)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-27 16:10:55 +00:00
|
|
|
/// Compute the degree of this polynomial
|
|
|
|
|
pub fn degree(&self) -> usize {
|
2020-08-22 21:09:47 +00:00
|
|
|
match self {
|
2020-09-07 16:22:25 +00:00
|
|
|
Expression::Fixed(_) => 1,
|
|
|
|
|
Expression::Advice(_) => 1,
|
2021-02-14 17:30:36 +00:00
|
|
|
Expression::Instance(_) => 1,
|
2020-09-07 16:22:25 +00: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 21:09:47 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-12 16:52:42 +00:00
|
|
|
impl<F: Field> Neg for Expression<F> {
|
2021-01-29 00:45:48 +00:00
|
|
|
type Output = Expression<F>;
|
|
|
|
|
fn neg(self) -> Self::Output {
|
|
|
|
|
Expression::Scaled(Box::new(self), -F::one())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-07 16:22:25 +00:00
|
|
|
impl<F> Add for Expression<F> {
|
|
|
|
|
type Output = Expression<F>;
|
|
|
|
|
fn add(self, rhs: Expression<F>) -> Expression<F> {
|
|
|
|
|
Expression::Sum(Box::new(self), Box::new(rhs))
|
2020-08-22 21:09:47 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-12 16:52:42 +00:00
|
|
|
impl<F: Field> Sub for Expression<F> {
|
2021-01-29 00:45:48 +00:00
|
|
|
type Output = Expression<F>;
|
|
|
|
|
fn sub(self, rhs: Expression<F>) -> Expression<F> {
|
|
|
|
|
Expression::Sum(Box::new(self), Box::new(-rhs))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-07 16:22:25 +00:00
|
|
|
impl<F> Mul for Expression<F> {
|
|
|
|
|
type Output = Expression<F>;
|
|
|
|
|
fn mul(self, rhs: Expression<F>) -> Expression<F> {
|
|
|
|
|
Expression::Product(Box::new(self), Box::new(rhs))
|
2020-08-22 21:09:47 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-07 16:22:25 +00:00
|
|
|
impl<F> Mul<F> for Expression<F> {
|
|
|
|
|
type Output = Expression<F>;
|
|
|
|
|
fn mul(self, rhs: F) -> Expression<F> {
|
|
|
|
|
Expression::Scaled(Box::new(self), rhs)
|
2020-08-22 21:09:47 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-27 19:27:24 +00: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 16:22:25 +00:00
|
|
|
pub(crate) struct PointIndex(pub usize);
|
2020-08-27 19:27:24 +00:00
|
|
|
|
2020-11-06 03:13:54 +00:00
|
|
|
/// This is a description of the circuit environment, such as the gate, column and
|
2020-08-22 21:09:47 +00:00
|
|
|
/// permutation arrangements.
|
|
|
|
|
#[derive(Debug, Clone)]
|
2020-09-11 23:18:41 +00:00
|
|
|
pub struct ConstraintSystem<F> {
|
2020-11-06 03:13:54 +00:00
|
|
|
pub(crate) num_fixed_columns: usize,
|
|
|
|
|
pub(crate) num_advice_columns: usize,
|
2021-02-14 17:30:36 +00:00
|
|
|
pub(crate) num_instance_columns: usize,
|
2021-01-22 19:46:06 +00:00
|
|
|
pub(crate) gates: Vec<(&'static str, Expression<F>)>,
|
2020-11-06 03:25:50 +00:00
|
|
|
pub(crate) advice_queries: Vec<(Column<Advice>, Rotation)>,
|
2021-02-14 17:30:36 +00:00
|
|
|
pub(crate) instance_queries: Vec<(Column<Instance>, Rotation)>,
|
2020-11-06 03:25:50 +00:00
|
|
|
pub(crate) fixed_queries: Vec<(Column<Fixed>, Rotation)>,
|
2020-08-27 19:27:24 +00:00
|
|
|
|
2020-11-07 05:22:33 +00:00
|
|
|
// Vector of permutation arguments, where each corresponds to a sequence of columns
|
2020-09-29 14:51:00 +00:00
|
|
|
// that are involved in a permutation argument.
|
2020-12-01 02:09:03 +00:00
|
|
|
pub(crate) permutations: Vec<permutation::Argument>,
|
2020-12-01 19:00:59 +00:00
|
|
|
|
|
|
|
|
// Vector of lookup arguments, where each corresponds to a sequence of
|
|
|
|
|
// input columns and a sequence of table columns involved in the lookup.
|
|
|
|
|
pub(crate) lookups: Vec<lookup::Argument>,
|
2020-08-22 21:09:47 +00:00
|
|
|
}
|
|
|
|
|
|
2021-02-17 22:15:08 +00:00
|
|
|
/// Represents the minimal parameters that determine a `ConstraintSystem`.
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct PinnedConstraintSystem<'a, F: Field> {
|
|
|
|
|
num_fixed_columns: &'a usize,
|
|
|
|
|
num_advice_columns: &'a usize,
|
|
|
|
|
num_instance_columns: &'a usize,
|
|
|
|
|
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)>,
|
|
|
|
|
permutations: &'a Vec<permutation::Argument>,
|
|
|
|
|
lookups: &'a Vec<lookup::Argument>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct PinnedGates<'a, F: Field>(&'a Vec<(&'static str, Expression<F>)>);
|
|
|
|
|
|
|
|
|
|
impl<'a, F: Field> std::fmt::Debug for PinnedGates<'a, F> {
|
2021-02-17 17:46:20 +00:00
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
2021-02-17 22:15:08 +00:00
|
|
|
f.debug_list()
|
2021-02-17 22:39:46 +00:00
|
|
|
.entries(self.0.iter().map(|(_, expr)| expr))
|
2021-02-17 22:15:08 +00:00
|
|
|
.finish()
|
2021-02-17 17:46:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-11 23:18:41 +00:00
|
|
|
impl<F: Field> Default for ConstraintSystem<F> {
|
|
|
|
|
fn default() -> ConstraintSystem<F> {
|
|
|
|
|
ConstraintSystem {
|
2020-11-06 03:13:54 +00:00
|
|
|
num_fixed_columns: 0,
|
|
|
|
|
num_advice_columns: 0,
|
2021-02-14 17:30:36 +00:00
|
|
|
num_instance_columns: 0,
|
2020-08-24 14:28:42 +00:00
|
|
|
gates: vec![],
|
2020-08-27 16:10:55 +00:00
|
|
|
fixed_queries: Vec::new(),
|
|
|
|
|
advice_queries: Vec::new(),
|
2021-02-14 17:30:36 +00:00
|
|
|
instance_queries: Vec::new(),
|
2020-08-31 16:01:09 +00:00
|
|
|
permutations: Vec::new(),
|
2020-12-01 19:00:59 +00:00
|
|
|
lookups: Vec::new(),
|
2020-08-22 22:10:27 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-11 23:18:41 +00:00
|
|
|
impl<F: Field> ConstraintSystem<F> {
|
2021-02-17 22:15:08 +00: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,
|
|
|
|
|
gates: PinnedGates(&self.gates),
|
|
|
|
|
fixed_queries: &self.fixed_queries,
|
|
|
|
|
advice_queries: &self.advice_queries,
|
|
|
|
|
instance_queries: &self.instance_queries,
|
|
|
|
|
permutations: &self.permutations,
|
|
|
|
|
lookups: &self.lookups,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Add a permutation argument for some advice columns
|
2021-02-17 13:13:25 +00:00
|
|
|
pub fn permutation(&mut self, columns: &[Column<Any>]) -> usize {
|
2020-08-31 16:01:09 +00:00
|
|
|
let index = self.permutations.len();
|
2020-09-29 14:51:00 +00:00
|
|
|
|
2020-11-06 03:13:54 +00:00
|
|
|
for column in columns {
|
2021-02-17 13:13:25 +00:00
|
|
|
self.query_any_index(*column, Rotation::cur());
|
2020-09-29 14:51:00 +00:00
|
|
|
}
|
2020-12-01 02:09:03 +00:00
|
|
|
self.permutations
|
|
|
|
|
.push(permutation::Argument::new(columns.to_vec()));
|
2020-09-02 16:45:03 +00:00
|
|
|
|
2020-08-31 16:01:09 +00:00
|
|
|
index
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-01 19:48:19 +00:00
|
|
|
/// Add a lookup argument for some input columns and table columns.
|
2020-12-05 04:51:28 +00:00
|
|
|
/// The function will panic if the number of input columns and table
|
|
|
|
|
/// columns are not the same.
|
2020-12-01 19:48:19 +00:00
|
|
|
pub fn lookup(
|
|
|
|
|
&mut self,
|
|
|
|
|
input_columns: &[Column<Any>],
|
|
|
|
|
table_columns: &[Column<Any>],
|
|
|
|
|
) -> usize {
|
2020-12-03 04:39:44 +00:00
|
|
|
assert_eq!(input_columns.len(), table_columns.len());
|
|
|
|
|
|
2020-12-01 19:48:19 +00:00
|
|
|
let index = self.lookups.len();
|
|
|
|
|
|
|
|
|
|
for input in input_columns {
|
2020-12-23 16:45:16 +00:00
|
|
|
self.query_any_index(*input, Rotation::cur());
|
2020-12-01 19:48:19 +00:00
|
|
|
}
|
|
|
|
|
for table in table_columns {
|
2020-12-23 16:45:16 +00:00
|
|
|
self.query_any_index(*table, Rotation::cur());
|
2020-12-01 19:48:19 +00:00
|
|
|
}
|
|
|
|
|
self.lookups
|
|
|
|
|
.push(lookup::Argument::new(input_columns, table_columns));
|
|
|
|
|
|
|
|
|
|
index
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-23 16:45:16 +00:00
|
|
|
fn query_fixed_index(&mut self, column: Column<Fixed>, at: Rotation) -> usize {
|
2020-09-03 20:26:00 +00:00
|
|
|
// Return existing query, if it exists
|
|
|
|
|
for (index, fixed_query) in self.fixed_queries.iter().enumerate() {
|
2020-11-06 03:13:54 +00:00
|
|
|
if fixed_query == &(column, at) {
|
2020-09-03 20:26:00 +00:00
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make a new query
|
2020-08-27 16:10:55 +00:00
|
|
|
let index = self.fixed_queries.len();
|
2020-11-06 03:13:54 +00:00
|
|
|
self.fixed_queries.push((column, at));
|
2020-08-27 16:10:55 +00:00
|
|
|
|
2020-09-03 20:26:00 +00:00
|
|
|
index
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-06 03:13:54 +00:00
|
|
|
/// Query a fixed column at a relative position
|
2020-12-23 16:45:16 +00:00
|
|
|
pub fn query_fixed(&mut self, column: Column<Fixed>, at: Rotation) -> Expression<F> {
|
2020-11-06 03:13:54 +00:00
|
|
|
Expression::Fixed(self.query_fixed_index(column, at))
|
2020-08-24 14:28:42 +00:00
|
|
|
}
|
|
|
|
|
|
2020-12-23 16:45:16 +00:00
|
|
|
pub(crate) fn query_advice_index(&mut self, column: Column<Advice>, at: Rotation) -> usize {
|
2020-09-03 20:26:00 +00:00
|
|
|
// Return existing query, if it exists
|
|
|
|
|
for (index, advice_query) in self.advice_queries.iter().enumerate() {
|
2020-11-06 03:13:54 +00:00
|
|
|
if advice_query == &(column, at) {
|
2020-09-03 20:26:00 +00:00
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make a new query
|
2020-08-27 16:10:55 +00:00
|
|
|
let index = self.advice_queries.len();
|
2020-11-06 03:13:54 +00:00
|
|
|
self.advice_queries.push((column, at));
|
2020-08-27 16:10:55 +00:00
|
|
|
|
2020-09-02 19:15:40 +00:00
|
|
|
index
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-06 03:13:54 +00:00
|
|
|
/// Query an advice column at a relative position
|
2020-12-23 16:45:16 +00:00
|
|
|
pub fn query_advice(&mut self, column: Column<Advice>, at: Rotation) -> Expression<F> {
|
2020-11-06 03:13:54 +00:00
|
|
|
Expression::Advice(self.query_advice_index(column, at))
|
2020-08-24 14:28:42 +00:00
|
|
|
}
|
|
|
|
|
|
2021-02-14 17:30:36 +00:00
|
|
|
fn query_instance_index(&mut self, column: Column<Instance>, at: Rotation) -> usize {
|
2020-09-17 17:07:19 +00:00
|
|
|
// Return existing query, if it exists
|
2021-02-14 17:30:36 +00:00
|
|
|
for (index, instance_query) in self.instance_queries.iter().enumerate() {
|
|
|
|
|
if instance_query == &(column, at) {
|
2020-09-17 17:07:19 +00:00
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make a new query
|
2021-02-14 17:30:36 +00:00
|
|
|
let index = self.instance_queries.len();
|
|
|
|
|
self.instance_queries.push((column, at));
|
2020-09-17 17:07:19 +00:00
|
|
|
|
|
|
|
|
index
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-14 17:30:36 +00:00
|
|
|
/// 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))
|
2020-11-07 05:22:33 +00:00
|
|
|
}
|
|
|
|
|
|
2020-12-23 16:45:16 +00:00
|
|
|
fn query_any_index(&mut self, column: Column<Any>, at: Rotation) -> usize {
|
2020-12-01 06:35:56 +00:00
|
|
|
match column.column_type() {
|
2020-11-09 16:39:08 +00:00
|
|
|
Any::Advice => self.query_advice_index(Column::<Advice>::try_from(column).unwrap(), at),
|
|
|
|
|
Any::Fixed => self.query_fixed_index(Column::<Fixed>::try_from(column).unwrap(), at),
|
2021-02-14 17:30:36 +00:00
|
|
|
Any::Instance => {
|
|
|
|
|
self.query_instance_index(Column::<Instance>::try_from(column).unwrap(), at)
|
|
|
|
|
}
|
2020-12-01 06:35:56 +00:00
|
|
|
}
|
2020-11-06 03:36:54 +00:00
|
|
|
}
|
|
|
|
|
|
2020-11-07 05:22:33 +00:00
|
|
|
/// Query an Any column at a relative position
|
2020-12-23 16:45:16 +00:00
|
|
|
pub fn query_any(&mut self, column: Column<Any>, at: Rotation) -> Expression<F> {
|
2020-11-09 16:45:52 +00:00
|
|
|
match column.column_type() {
|
2020-11-09 16:39:08 +00:00
|
|
|
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),
|
|
|
|
|
),
|
2021-02-14 17:30:36 +00:00
|
|
|
Any::Instance => Expression::Instance(
|
|
|
|
|
self.query_instance_index(Column::<Instance>::try_from(column).unwrap(), at),
|
|
|
|
|
),
|
2020-11-07 05:22:33 +00:00
|
|
|
}
|
2020-09-17 17:07:19 +00:00
|
|
|
}
|
|
|
|
|
|
2020-12-23 16:45:16 +00:00
|
|
|
pub(crate) fn get_advice_query_index(&self, column: Column<Advice>, at: Rotation) -> usize {
|
2020-11-06 03:25:50 +00:00
|
|
|
for (index, advice_query) in self.advice_queries.iter().enumerate() {
|
|
|
|
|
if advice_query == &(column, at) {
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-06 03:36:54 +00:00
|
|
|
panic!("get_advice_query_index called for non-existent query");
|
2020-11-06 03:25:50 +00:00
|
|
|
}
|
|
|
|
|
|
2020-12-23 16:45:16 +00:00
|
|
|
pub(crate) fn get_fixed_query_index(&self, column: Column<Fixed>, at: Rotation) -> usize {
|
2020-11-06 03:25:50 +00: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 17:30:36 +00: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-06 03:36:54 +00:00
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-14 17:30:36 +00:00
|
|
|
panic!("get_instance_query_index called for non-existent query");
|
2020-11-06 03:36:54 +00:00
|
|
|
}
|
|
|
|
|
|
2020-12-23 16:45:16 +00:00
|
|
|
pub(crate) fn get_any_query_index(&self, column: Column<Any>, at: Rotation) -> usize {
|
2020-11-11 05:46:18 +00:00
|
|
|
match column.column_type() {
|
2020-11-09 16:39:08 +00:00
|
|
|
Any::Advice => {
|
|
|
|
|
self.get_advice_query_index(Column::<Advice>::try_from(column).unwrap(), at)
|
|
|
|
|
}
|
|
|
|
|
Any::Fixed => {
|
|
|
|
|
self.get_fixed_query_index(Column::<Fixed>::try_from(column).unwrap(), at)
|
|
|
|
|
}
|
2021-02-14 17:30:36 +00:00
|
|
|
Any::Instance => {
|
|
|
|
|
self.get_instance_query_index(Column::<Instance>::try_from(column).unwrap(), at)
|
|
|
|
|
}
|
2020-11-11 05:46:18 +00:00
|
|
|
}
|
2020-11-06 03:36:54 +00:00
|
|
|
}
|
|
|
|
|
|
2020-08-24 14:28:42 +00:00
|
|
|
/// Create a new gate
|
2021-01-22 19:46:06 +00:00
|
|
|
pub fn create_gate(&mut self, name: &'static str, f: impl FnOnce(&mut Self) -> Expression<F>) {
|
2020-08-24 14:28:42 +00:00
|
|
|
let poly = f(self);
|
2021-01-22 19:46:06 +00:00
|
|
|
self.gates.push((name, poly));
|
2020-08-24 14:28:42 +00:00
|
|
|
}
|
|
|
|
|
|
2020-11-06 03:13:54 +00:00
|
|
|
/// Allocate a new fixed column
|
2020-11-06 03:25:50 +00:00
|
|
|
pub fn fixed_column(&mut self) -> Column<Fixed> {
|
|
|
|
|
let tmp = Column {
|
|
|
|
|
index: self.num_fixed_columns,
|
|
|
|
|
column_type: Fixed,
|
|
|
|
|
};
|
2020-11-06 03:13:54 +00:00
|
|
|
self.num_fixed_columns += 1;
|
2020-08-22 22:10:27 +00:00
|
|
|
tmp
|
|
|
|
|
}
|
2020-08-27 16:10:55 +00:00
|
|
|
|
2020-11-06 03:13:54 +00:00
|
|
|
/// Allocate a new advice column
|
2020-11-06 03:25:50 +00:00
|
|
|
pub fn advice_column(&mut self) -> Column<Advice> {
|
|
|
|
|
let tmp = Column {
|
|
|
|
|
index: self.num_advice_columns,
|
|
|
|
|
column_type: Advice,
|
|
|
|
|
};
|
2020-11-06 03:13:54 +00:00
|
|
|
self.num_advice_columns += 1;
|
2020-08-22 22:10:27 +00:00
|
|
|
tmp
|
2020-08-22 21:09:47 +00:00
|
|
|
}
|
2020-09-17 17:07:19 +00:00
|
|
|
|
2021-02-14 17:30:36 +00:00
|
|
|
/// Allocate a new instance column
|
|
|
|
|
pub fn instance_column(&mut self) -> Column<Instance> {
|
2020-11-06 03:25:50 +00:00
|
|
|
let tmp = Column {
|
2021-02-14 17:30:36 +00:00
|
|
|
index: self.num_instance_columns,
|
|
|
|
|
column_type: Instance,
|
2020-11-06 03:25:50 +00:00
|
|
|
};
|
2021-02-14 17:30:36 +00:00
|
|
|
self.num_instance_columns += 1;
|
2020-09-17 17:07:19 +00:00
|
|
|
tmp
|
|
|
|
|
}
|
2020-08-22 20:15:39 +00:00
|
|
|
}
|