pasta_curves-source/src/plonk/circuit.rs

539 lines
16 KiB
Rust
Raw Normal View History

2020-08-22 21:09:47 +00:00
use core::cmp::max;
use core::ops::{Add, Mul};
use ff::Field;
use std::collections::BTreeMap;
use std::convert::TryFrom;
2020-08-22 20:15:39 +00:00
2020-08-22 21:09:47 +00:00
use super::Error;
2020-09-07 16:22:25 +00:00
use crate::poly::Rotation;
/// A column type
pub trait ColumnType: 'static + Sized {}
/// A column with an index and type
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Column<C: ColumnType> {
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
}
}
/// An advice column
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Advice;
/// A fixed column
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Fixed;
/// An auxiliary column
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Aux;
/// An enum over the Advice, Fixed, Aux structs
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Any {
/// An Advice variant
Advice,
/// A Fixed variant
Fixed,
/// An Auxiliary variant
Aux,
}
impl ColumnType for Advice {}
impl ColumnType for Fixed {}
impl ColumnType for Aux {}
impl ColumnType for Any {}
impl From<Column<Advice>> for Column<Any> {
fn from(advice: Column<Advice>) -> Column<Any> {
Column {
index: advice.index(),
column_type: Any::Advice,
}
}
}
impl From<Column<Fixed>> for Column<Any> {
fn from(advice: Column<Fixed>) -> Column<Any> {
Column {
index: advice.index(),
column_type: Any::Fixed,
}
}
}
impl From<Column<Aux>> for Column<Any> {
fn from(advice: Column<Aux>) -> Column<Any> {
Column {
index: advice.index(),
column_type: Any::Aux,
}
}
}
impl TryFrom<Column<Any>> for Column<Advice> {
type Error = &'static str;
fn try_from(any: Column<Any>) -> Result<Self, Self::Error> {
match any.column_type() {
Any::Advice => Ok(Column {
index: any.index(),
column_type: Advice,
}),
_ => Err("Cannot convert into Column<Advice>"),
}
}
}
impl TryFrom<Column<Any>> for Column<Fixed> {
type Error = &'static str;
fn try_from(any: Column<Any>) -> Result<Self, Self::Error> {
match any.column_type() {
Any::Fixed => Ok(Column {
index: any.index(),
column_type: Fixed,
}),
_ => Err("Cannot convert into Column<Fixed>"),
}
}
}
impl TryFrom<Column<Any>> for Column<Aux> {
type Error = &'static str;
fn try_from(any: Column<Any>) -> Result<Self, Self::Error> {
match any.column_type() {
Any::Aux => Ok(Column {
index: any.index(),
column_type: Aux,
}),
_ => Err("Cannot convert into Column<Aux>"),
}
}
}
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.
pub trait Assignment<F: Field> {
2020-11-06 03:13:54 +00:00
/// Assign an advice column value (witness)
fn assign_advice(
&mut self,
column: Column<Advice>,
row: usize,
to: impl FnOnce() -> Result<F, Error>,
) -> Result<(), Error>;
/// Assign a fixed value
fn assign_fixed(
&mut self,
column: Column<Fixed>,
row: usize,
to: impl FnOnce() -> Result<F, Error>,
) -> Result<(), Error>;
2020-11-06 03:13:54 +00:00
/// Assign two advice columns to have the same value
fn copy(
&mut self,
permutation: usize,
2020-11-06 03:13:54 +00:00
left_column: usize,
left_row: usize,
2020-11-06 03:13:54 +00:00
right_column: usize,
right_row: usize,
) -> Result<(), Error>;
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.
2020-08-22 21:09:47 +00:00
type Config;
/// The circuit is given an opportunity to describe the exact gate
2020-11-06 03:13:54 +00:00
/// arrangement, column arrangement, etc.
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.
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
Fixed(usize),
2020-11-06 03:13:54 +00:00
/// This is an advice (witness) column queried at a certain relative location
Advice(usize),
2020-11-06 03:13:54 +00:00
/// This is an auxiliary (external) column queried at a certain relative location
Aux(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> {
/// 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,
aux_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),
Expression::Aux(index) => aux_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,
aux_column,
sum,
product,
scaled,
);
let b = b.evaluate(
fixed_column,
advice_column,
aux_column,
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,
aux_column,
sum,
product,
scaled,
);
let b = b.evaluate(
fixed_column,
advice_column,
aux_column,
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,
aux_column,
sum,
product,
scaled,
);
2020-08-24 14:28:42 +00:00
scaled(a, *f)
}
}
}
/// 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,
Expression::Aux(_) => 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
}
}
}
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
}
}
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
}
}
/// 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-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)]
pub struct ConstraintSystem<F> {
2020-11-06 03:13:54 +00:00
pub(crate) num_fixed_columns: usize,
pub(crate) num_advice_columns: usize,
pub(crate) num_aux_columns: usize,
2020-09-07 16:22:25 +00:00
pub(crate) gates: Vec<Expression<F>>,
pub(crate) advice_queries: Vec<(Column<Advice>, Rotation)>,
pub(crate) aux_queries: Vec<(Column<Aux>, Rotation)>,
pub(crate) fixed_queries: Vec<(Column<Fixed>, Rotation)>,
// Mapping from a witness vector rotation to the index in the point vector.
pub(crate) rotations: BTreeMap<Rotation, PointIndex>,
2020-11-07 05:22:33 +00:00
// Vector of permutation arguments, where each corresponds to a sequence of columns
// that are involved in a permutation argument.
pub(crate) permutations: Vec<Vec<Column<Advice>>>,
2020-08-22 21:09:47 +00:00
}
impl<F: Field> Default for ConstraintSystem<F> {
fn default() -> ConstraintSystem<F> {
let mut rotations = BTreeMap::new();
rotations.insert(Rotation::default(), PointIndex(0));
ConstraintSystem {
2020-11-06 03:13:54 +00:00
num_fixed_columns: 0,
num_advice_columns: 0,
num_aux_columns: 0,
2020-08-24 14:28:42 +00:00
gates: vec![],
fixed_queries: Vec::new(),
advice_queries: Vec::new(),
aux_queries: Vec::new(),
rotations,
permutations: Vec::new(),
}
}
}
impl<F: Field> ConstraintSystem<F> {
2020-11-06 03:13:54 +00:00
/// Add a permutation argument for some advice columns
pub fn permutation(&mut self, columns: &[Column<Advice>]) -> usize {
let index = self.permutations.len();
if self.permutations.is_empty() {
let at = Rotation(-1);
let len = self.rotations.len();
self.rotations.entry(at).or_insert(PointIndex(len));
2020-09-02 16:45:03 +00:00
}
2020-11-06 03:13:54 +00:00
for column in columns {
self.query_advice_index(*column, 0);
}
2020-11-06 03:13:54 +00:00
self.permutations.push(columns.to_vec());
2020-09-02 16:45:03 +00:00
index
}
fn query_fixed_index(&mut self, column: Column<Fixed>, at: i32) -> usize {
let at = Rotation(at);
{
let len = self.rotations.len();
self.rotations.entry(at).or_insert(PointIndex(len));
}
2020-08-24 14:28:42 +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) {
return index;
}
}
// Make a new query
let index = self.fixed_queries.len();
2020-11-06 03:13:54 +00:00
self.fixed_queries.push((column, at));
index
}
2020-11-06 03:13:54 +00:00
/// Query a fixed column at a relative position
pub fn query_fixed(&mut self, column: Column<Fixed>, at: i32) -> 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
}
pub(crate) fn query_advice_index(&mut self, column: Column<Advice>, at: i32) -> usize {
let at = Rotation(at);
{
let len = self.rotations.len();
self.rotations.entry(at).or_insert(PointIndex(len));
}
2020-08-24 14:28:42 +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) {
return index;
}
}
// Make a new query
let index = self.advice_queries.len();
2020-11-06 03:13:54 +00:00
self.advice_queries.push((column, at));
index
}
2020-11-06 03:13:54 +00:00
/// Query an advice column at a relative position
pub fn query_advice(&mut self, column: Column<Advice>, at: i32) -> 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
}
fn query_aux_index(&mut self, column: Column<Aux>, at: i32) -> usize {
2020-09-17 17:07:19 +00:00
let at = Rotation(at);
{
let len = self.rotations.len();
self.rotations.entry(at).or_insert(PointIndex(len));
}
// Return existing query, if it exists
for (index, aux_query) in self.aux_queries.iter().enumerate() {
2020-11-06 03:13:54 +00:00
if aux_query == &(column, at) {
2020-09-17 17:07:19 +00:00
return index;
}
}
// Make a new query
let index = self.aux_queries.len();
2020-11-06 03:13:54 +00:00
self.aux_queries.push((column, at));
2020-09-17 17:07:19 +00:00
index
}
2020-11-07 05:22:33 +00:00
/// Query an auxiliary column at a relative position
pub fn query_aux(&mut self, column: Column<Aux>, at: i32) -> Expression<F> {
Expression::Aux(self.query_aux_index(column, at))
}
fn query_any_index(&mut self, column: Column<Any>, at: i32) -> usize {
let index = match column.column_type() {
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),
Any::Aux => self.query_aux_index(Column::<Aux>::try_from(column).unwrap(), at),
};
index
}
2020-11-07 05:22:33 +00:00
/// Query an Any column at a relative position
pub fn query_any(&mut self, column: Column<Any>, at: i32) -> Expression<F> {
match column.column_type() {
Any::Advice => Expression::Advice(
self.query_advice_index(Column::<Advice>::try_from(column).unwrap(), at),
),
Any::Fixed => Expression::Fixed(
self.query_fixed_index(Column::<Fixed>::try_from(column).unwrap(), at),
),
Any::Aux => {
Expression::Aux(self.query_aux_index(Column::<Aux>::try_from(column).unwrap(), at))
2020-11-07 05:22:33 +00:00
}
}
2020-09-17 17:07:19 +00:00
}
pub(crate) fn get_advice_query_index(&self, column: Column<Advice>, at: i32) -> usize {
let at = Rotation(at);
for (index, advice_query) in self.advice_queries.iter().enumerate() {
if advice_query == &(column, at) {
return index;
}
}
panic!("get_advice_query_index called for non-existent query");
}
pub(crate) fn get_fixed_query_index(&self, column: Column<Fixed>, at: i32) -> usize {
let at = Rotation(at);
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");
}
pub(crate) fn get_aux_query_index(&self, column: Column<Aux>, at: i32) -> usize {
let at = Rotation(at);
for (index, aux_query) in self.aux_queries.iter().enumerate() {
if aux_query == &(column, at) {
return index;
}
}
panic!("get_aux_query_index called for non-existent query");
}
pub(crate) fn get_any_query_index(&self, column: Column<Any>, at: i32) -> usize {
match column.column_type() {
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)
}
Any::Aux => self.get_aux_query_index(Column::<Aux>::try_from(column).unwrap(), at),
}
}
2020-08-24 14:28:42 +00:00
/// Create a new gate
2020-09-07 16:22:25 +00:00
pub fn create_gate(&mut self, f: impl FnOnce(&mut Self) -> Expression<F>) {
2020-08-24 14:28:42 +00:00
let poly = f(self);
self.gates.push(poly);
}
2020-11-06 03:13:54 +00:00
/// Allocate a new fixed column
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;
tmp
}
2020-11-06 03:13:54 +00:00
/// Allocate a new advice column
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;
tmp
2020-08-22 21:09:47 +00:00
}
2020-09-17 17:07:19 +00:00
2020-11-06 03:13:54 +00:00
/// Allocate a new auxiliary column
pub fn aux_column(&mut self) -> Column<Aux> {
let tmp = Column {
index: self.num_aux_columns,
column_type: Aux,
};
2020-11-06 03:13:54 +00:00
self.num_aux_columns += 1;
2020-09-17 17:07:19 +00:00
tmp
}
2020-08-22 20:15:39 +00:00
}