pasta_curves-source/src/plonk/circuit.rs

365 lines
11 KiB
Rust
Raw Normal View History

2020-08-22 21:09:47 +00:00
use core::cmp::max;
use core::ops::{Add, Mul};
use std::collections::BTreeMap;
2020-08-22 20:15:39 +00:00
2020-08-22 21:09:47 +00:00
use super::Error;
2020-08-22 20:15:39 +00:00
use crate::arithmetic::Field;
2020-09-07 16:22:25 +00:00
use crate::poly::Rotation;
2020-11-06 03:13:54 +00:00
/// This represents a column which has a fixed (permanent) value
2020-08-24 14:28:42 +00:00
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
2020-11-06 03:13:54 +00:00
pub struct FixedColumn(pub usize);
2020-11-06 03:13:54 +00:00
/// This represents a column which has a witness-specific value
2020-08-24 14:28:42 +00:00
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
2020-11-06 03:13:54 +00:00
pub struct AdviceColumn(pub usize);
2020-11-06 03:13:54 +00:00
/// This represents a column which has an externally assigned value
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
2020-11-06 03:13:54 +00:00
pub struct AuxColumn(pub usize);
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,
2020-11-06 03:13:54 +00:00
column: AdviceColumn,
row: usize,
to: impl FnOnce() -> Result<F, Error>,
) -> Result<(), Error>;
/// Assign a fixed value
fn assign_fixed(
&mut self,
2020-11-06 03:13:54 +00:00
column: FixedColumn,
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>>,
2020-11-06 03:13:54 +00:00
pub(crate) advice_queries: Vec<(AdviceColumn, Rotation)>,
pub(crate) aux_queries: Vec<(AuxColumn, Rotation)>,
pub(crate) fixed_queries: Vec<(FixedColumn, Rotation)>,
// Mapping from a witness vector rotation to the index in the point vector.
pub(crate) rotations: BTreeMap<Rotation, PointIndex>,
2020-11-06 03:13:54 +00:00
// Vector of permutation arguments, where each corresponds to a set of columns
// that are involved in a permutation argument.
2020-11-06 03:13:54 +00:00
pub(crate) permutations: Vec<Vec<AdviceColumn>>,
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: &[AdviceColumn]) -> 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
}
2020-11-06 03:13:54 +00:00
fn query_fixed_index(&mut self, column: FixedColumn, 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: FixedColumn, at: i32) -> Expression<F> {
Expression::Fixed(self.query_fixed_index(column, at))
2020-08-24 14:28:42 +00:00
}
2020-11-06 03:13:54 +00:00
pub(crate) fn get_advice_query_index(&self, column: AdviceColumn, at: i32) -> usize {
let at = Rotation(at);
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;
}
}
panic!("get_advice_query_index called for non-existant query");
}
2020-11-06 03:13:54 +00:00
pub(crate) fn query_advice_index(&mut self, column: AdviceColumn, 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: AdviceColumn, at: i32) -> Expression<F> {
Expression::Advice(self.query_advice_index(column, at))
2020-08-24 14:28:42 +00:00
}
2020-11-06 03:13:54 +00:00
fn query_aux_index(&mut self, column: AuxColumn, 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-06 03:13:54 +00:00
/// Query an auxiliary column at a relative position
pub fn query_aux(&mut self, column: AuxColumn, at: i32) -> Expression<F> {
Expression::Aux(self.query_aux_index(column, at))
2020-09-17 17:07:19 +00:00
}
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) -> FixedColumn {
let tmp = FixedColumn(self.num_fixed_columns);
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) -> AdviceColumn {
let tmp = AdviceColumn(self.num_advice_columns);
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) -> AuxColumn {
let tmp = AuxColumn(self.num_aux_columns);
self.num_aux_columns += 1;
2020-09-17 17:07:19 +00:00
tmp
}
2020-08-22 20:15:39 +00:00
}