2020-12-14 16:36:58 -08:00
|
|
|
//! Implementations of common circuit layouters.
|
|
|
|
|
2021-01-07 17:54:28 -08:00
|
|
|
use std::cmp;
|
2021-06-07 05:11:14 -07:00
|
|
|
use std::collections::HashSet;
|
2020-12-14 16:36:58 -08:00
|
|
|
use std::fmt;
|
|
|
|
|
2021-06-20 16:10:16 -07:00
|
|
|
use ff::Field;
|
|
|
|
|
2023-04-03 19:27:32 -07:00
|
|
|
pub use super::table_layouter::TableLayouter;
|
2022-06-07 16:15:35 -07:00
|
|
|
use super::{Cell, RegionIndex, Value};
|
2023-02-21 09:00:52 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
use crate::plonk::TableTag;
|
2023-03-20 22:23:37 -07:00
|
|
|
use crate::plonk::{Advice, Any, Assigned, Column, Error, Fixed, Instance, Selector};
|
2021-06-07 05:11:14 -07:00
|
|
|
|
2020-12-14 16:36:58 -08:00
|
|
|
/// Helper trait for implementing a custom [`Layouter`].
|
|
|
|
///
|
|
|
|
/// This trait is used for implementing region assignments:
|
|
|
|
///
|
|
|
|
/// ```ignore
|
2023-02-21 09:00:52 -08:00
|
|
|
/// impl<'a, F: Field, C: Chip<F>, CS: Assignment<F> + 'a> Layouter<C> for MyLayouter<'a, C, CS> {
|
2020-12-14 16:36:58 -08:00
|
|
|
/// fn assign_region(
|
|
|
|
/// &mut self,
|
2021-04-19 06:25:32 -07:00
|
|
|
/// assignment: impl FnOnce(Region<'_, F, C>) -> Result<(), Error>,
|
2020-12-14 16:36:58 -08:00
|
|
|
/// ) -> Result<(), Error> {
|
|
|
|
/// let region_index = self.regions.len();
|
|
|
|
/// self.regions.push(self.current_gate);
|
|
|
|
///
|
|
|
|
/// let mut region = MyRegion::new(self, region_index);
|
|
|
|
/// {
|
2021-04-19 06:25:32 -07:00
|
|
|
/// let region: &mut dyn RegionLayouter<F> = &mut region;
|
2020-12-14 16:36:58 -08:00
|
|
|
/// assignment(region.into())?;
|
|
|
|
/// }
|
|
|
|
/// self.current_gate += region.row_count;
|
|
|
|
///
|
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// TODO: It would be great if we could constrain the columns in these types to be
|
|
|
|
/// "logical" columns that are guaranteed to correspond to the chip (and have come from
|
|
|
|
/// `Chip::Config`).
|
2021-06-07 05:11:14 -07:00
|
|
|
///
|
|
|
|
/// [`Layouter`]: super::Layouter
|
2021-06-20 16:10:16 -07:00
|
|
|
pub trait RegionLayouter<F: Field>: fmt::Debug {
|
2021-05-27 04:43:32 -07:00
|
|
|
/// Enables a selector at the given offset.
|
|
|
|
fn enable_selector<'v>(
|
|
|
|
&'v mut self,
|
|
|
|
annotation: &'v (dyn Fn() -> String + 'v),
|
|
|
|
selector: &Selector,
|
|
|
|
offset: usize,
|
|
|
|
) -> Result<(), Error>;
|
|
|
|
|
2023-02-21 10:16:23 -08:00
|
|
|
/// Enables a dynamic table lookup at the given offset.
|
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
fn add_to_lookup(&mut self, table: TableTag, offset: usize) -> Result<(), Error>;
|
|
|
|
|
2020-12-14 16:36:58 -08:00
|
|
|
/// Assign an advice column value (witness)
|
|
|
|
fn assign_advice<'v>(
|
|
|
|
&'v mut self,
|
2021-01-22 08:57:38 -08:00
|
|
|
annotation: &'v (dyn Fn() -> String + 'v),
|
2020-12-14 16:36:58 -08:00
|
|
|
column: Column<Advice>,
|
|
|
|
offset: usize,
|
2022-06-07 16:15:35 -07:00
|
|
|
to: &'v mut (dyn FnMut() -> Value<Assigned<F>> + 'v),
|
2020-12-14 16:36:58 -08:00
|
|
|
) -> Result<Cell, Error>;
|
|
|
|
|
2021-07-20 08:01:38 -07:00
|
|
|
/// Assigns a constant value to the column `advice` at `offset` within this region.
|
|
|
|
///
|
|
|
|
/// The constant value will be assigned to a cell within one of the fixed columns
|
|
|
|
/// configured via `ConstraintSystem::enable_constant`.
|
|
|
|
///
|
|
|
|
/// Returns the advice cell that has been equality-constrained to the constant.
|
|
|
|
fn assign_advice_from_constant<'v>(
|
|
|
|
&'v mut self,
|
|
|
|
annotation: &'v (dyn Fn() -> String + 'v),
|
|
|
|
column: Column<Advice>,
|
|
|
|
offset: usize,
|
|
|
|
constant: Assigned<F>,
|
|
|
|
) -> Result<Cell, Error>;
|
|
|
|
|
2021-07-08 13:44:01 -07:00
|
|
|
/// Assign the value of the instance column's cell at absolute location
|
2021-07-10 07:20:34 -07:00
|
|
|
/// `row` to the column `advice` at `offset` within this region.
|
|
|
|
///
|
2022-07-07 14:14:59 -07:00
|
|
|
/// Returns the advice cell that has been equality-constrained to the
|
|
|
|
/// instance cell, and its value if known.
|
2021-07-08 13:44:01 -07:00
|
|
|
fn assign_advice_from_instance<'v>(
|
|
|
|
&mut self,
|
|
|
|
annotation: &'v (dyn Fn() -> String + 'v),
|
|
|
|
instance: Column<Instance>,
|
|
|
|
row: usize,
|
|
|
|
advice: Column<Advice>,
|
|
|
|
offset: usize,
|
2022-06-07 16:15:35 -07:00
|
|
|
) -> Result<(Cell, Value<F>), Error>;
|
2021-07-08 13:44:01 -07:00
|
|
|
|
2022-07-07 14:14:59 -07:00
|
|
|
/// Returns the value of the instance column's cell at absolute location `row`.
|
|
|
|
fn instance_value(&mut self, instance: Column<Instance>, row: usize)
|
|
|
|
-> Result<Value<F>, Error>;
|
|
|
|
|
|
|
|
/// Assigns a fixed value
|
2020-12-14 16:36:58 -08:00
|
|
|
fn assign_fixed<'v>(
|
|
|
|
&'v mut self,
|
2021-01-22 08:57:38 -08:00
|
|
|
annotation: &'v (dyn Fn() -> String + 'v),
|
2020-12-14 16:36:58 -08:00
|
|
|
column: Column<Fixed>,
|
|
|
|
offset: usize,
|
2022-06-07 16:15:35 -07:00
|
|
|
to: &'v mut (dyn FnMut() -> Value<Assigned<F>> + 'v),
|
2020-12-14 16:36:58 -08:00
|
|
|
) -> Result<Cell, Error>;
|
|
|
|
|
2021-07-20 09:19:47 -07:00
|
|
|
/// Constrains a cell to have a constant value.
|
|
|
|
///
|
|
|
|
/// Returns an error if the cell is in a column where equality has not been enabled.
|
|
|
|
fn constrain_constant(&mut self, cell: Cell, constant: Assigned<F>) -> Result<(), Error>;
|
|
|
|
|
2020-12-14 16:36:58 -08:00
|
|
|
/// Constraint two cells to have the same value.
|
|
|
|
///
|
|
|
|
/// Returns an error if either of the cells is not within the given permutation.
|
2021-07-02 15:20:36 -07:00
|
|
|
fn constrain_equal(&mut self, left: Cell, right: Cell) -> Result<(), Error>;
|
2020-12-14 16:36:58 -08:00
|
|
|
}
|
2021-01-07 17:54:28 -08:00
|
|
|
|
2021-01-14 20:07:39 -08:00
|
|
|
/// The shape of a region. For a region at a certain index, we track
|
|
|
|
/// the set of columns it uses as well as the number of rows it uses.
|
2021-06-08 03:03:29 -07:00
|
|
|
#[derive(Clone, Debug)]
|
2021-01-14 20:07:39 -08:00
|
|
|
pub struct RegionShape {
|
2021-06-21 11:10:59 -07:00
|
|
|
pub(super) region_index: RegionIndex,
|
2021-07-21 09:19:35 -07:00
|
|
|
pub(super) columns: HashSet<RegionColumn>,
|
2021-06-21 11:10:59 -07:00
|
|
|
pub(super) row_count: usize,
|
2021-01-13 06:58:12 -08:00
|
|
|
}
|
|
|
|
|
2021-07-24 09:27:50 -07:00
|
|
|
/// The virtual column involved in a region. This includes concrete columns,
|
|
|
|
/// as well as selectors that are not concrete columns at this stage.
|
2021-07-21 09:19:35 -07:00
|
|
|
#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash)]
|
|
|
|
pub enum RegionColumn {
|
2021-07-24 09:27:50 -07:00
|
|
|
/// Concrete column
|
2021-07-21 09:19:35 -07:00
|
|
|
Column(Column<Any>),
|
|
|
|
/// Virtual column representing a (boolean) selector
|
|
|
|
Selector(Selector),
|
2023-02-21 09:00:52 -08:00
|
|
|
/// Virtual column used for storing dynamic table tags
|
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
TableTag(TableTag),
|
2021-07-21 09:19:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Column<Any>> for RegionColumn {
|
|
|
|
fn from(column: Column<Any>) -> RegionColumn {
|
|
|
|
RegionColumn::Column(column)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<Selector> for RegionColumn {
|
|
|
|
fn from(selector: Selector) -> RegionColumn {
|
|
|
|
RegionColumn::Selector(selector)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-21 09:00:52 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
impl From<TableTag> for RegionColumn {
|
|
|
|
fn from(table_tag: TableTag) -> RegionColumn {
|
|
|
|
RegionColumn::TableTag(table_tag)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-21 09:19:35 -07:00
|
|
|
impl Ord for RegionColumn {
|
|
|
|
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
|
|
|
match (self, other) {
|
|
|
|
(Self::Column(ref a), Self::Column(ref b)) => a.cmp(b),
|
|
|
|
(Self::Selector(ref a), Self::Selector(ref b)) => a.0.cmp(&b.0),
|
2023-02-21 09:00:52 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
(Self::TableTag(ref a), Self::TableTag(ref b)) => a.0.cmp(&b.0),
|
|
|
|
(Self::Column(_), _) => cmp::Ordering::Less,
|
2021-07-24 09:27:50 -07:00
|
|
|
(Self::Selector(_), Self::Column(_)) => cmp::Ordering::Greater,
|
2023-02-21 09:00:52 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
(Self::TableTag(_), _) => cmp::Ordering::Greater,
|
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
(_, Self::TableTag(_)) => cmp::Ordering::Less,
|
2021-07-21 09:19:35 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialOrd for RegionColumn {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-13 06:58:12 -08:00
|
|
|
impl RegionShape {
|
2021-01-14 20:07:39 -08:00
|
|
|
/// Create a new `RegionShape` for a region at `region_index`.
|
2021-02-20 05:19:06 -08:00
|
|
|
pub fn new(region_index: RegionIndex) -> Self {
|
2021-01-13 06:58:12 -08:00
|
|
|
RegionShape {
|
|
|
|
region_index,
|
|
|
|
columns: HashSet::default(),
|
|
|
|
row_count: 0,
|
|
|
|
}
|
|
|
|
}
|
2021-01-14 20:07:39 -08:00
|
|
|
|
|
|
|
/// Get the `region_index` of a `RegionShape`.
|
2021-02-20 05:19:06 -08:00
|
|
|
pub fn region_index(&self) -> RegionIndex {
|
2021-01-14 20:07:39 -08:00
|
|
|
self.region_index
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get a reference to the set of `columns` used in a `RegionShape`.
|
2021-07-21 09:19:35 -07:00
|
|
|
pub fn columns(&self) -> &HashSet<RegionColumn> {
|
2021-01-14 20:07:39 -08:00
|
|
|
&self.columns
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the `row_count` of a `RegionShape`.
|
|
|
|
pub fn row_count(&self) -> usize {
|
|
|
|
self.row_count
|
|
|
|
}
|
2021-01-13 06:58:12 -08:00
|
|
|
}
|
|
|
|
|
2021-06-20 16:10:16 -07:00
|
|
|
impl<F: Field> RegionLayouter<F> for RegionShape {
|
2021-05-27 04:43:32 -07:00
|
|
|
fn enable_selector<'v>(
|
|
|
|
&'v mut self,
|
|
|
|
_: &'v (dyn Fn() -> String + 'v),
|
|
|
|
selector: &Selector,
|
|
|
|
offset: usize,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
// Track the selector's fixed column as part of the region's shape.
|
2021-07-21 09:19:35 -07:00
|
|
|
self.columns.insert((*selector).into());
|
2021-05-27 04:43:32 -07:00
|
|
|
self.row_count = cmp::max(self.row_count, offset + 1);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-02-21 10:16:23 -08:00
|
|
|
#[cfg(feature = "unstable-dynamic-lookups")]
|
|
|
|
fn add_to_lookup(&mut self, table: TableTag, offset: usize) -> Result<(), Error> {
|
|
|
|
// Track the tag's fixed column as part of the region's shape.
|
|
|
|
self.columns.insert(table.into());
|
|
|
|
self.row_count = cmp::max(self.row_count, offset + 1);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-01-13 06:58:12 -08:00
|
|
|
fn assign_advice<'v>(
|
|
|
|
&'v mut self,
|
2021-01-22 08:57:38 -08:00
|
|
|
_: &'v (dyn Fn() -> String + 'v),
|
2021-01-13 06:58:12 -08:00
|
|
|
column: Column<Advice>,
|
|
|
|
offset: usize,
|
2022-06-07 16:15:35 -07:00
|
|
|
_to: &'v mut (dyn FnMut() -> Value<Assigned<F>> + 'v),
|
2021-01-13 06:58:12 -08:00
|
|
|
) -> Result<Cell, Error> {
|
2021-07-21 09:19:35 -07:00
|
|
|
self.columns.insert(Column::<Any>::from(column).into());
|
2021-01-13 06:58:12 -08:00
|
|
|
self.row_count = cmp::max(self.row_count, offset + 1);
|
|
|
|
|
|
|
|
Ok(Cell {
|
|
|
|
region_index: self.region_index,
|
|
|
|
row_offset: offset,
|
|
|
|
column: column.into(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-07-20 08:07:47 -07:00
|
|
|
fn assign_advice_from_constant<'v>(
|
|
|
|
&'v mut self,
|
|
|
|
annotation: &'v (dyn Fn() -> String + 'v),
|
|
|
|
column: Column<Advice>,
|
|
|
|
offset: usize,
|
|
|
|
constant: Assigned<F>,
|
|
|
|
) -> Result<Cell, Error> {
|
|
|
|
// The rest is identical to witnessing an advice cell.
|
2022-06-07 16:15:35 -07:00
|
|
|
self.assign_advice(annotation, column, offset, &mut || Value::known(constant))
|
2021-07-20 08:07:47 -07:00
|
|
|
}
|
|
|
|
|
2021-07-08 13:44:01 -07:00
|
|
|
fn assign_advice_from_instance<'v>(
|
|
|
|
&mut self,
|
|
|
|
_: &'v (dyn Fn() -> String + 'v),
|
|
|
|
_: Column<Instance>,
|
|
|
|
_: usize,
|
|
|
|
advice: Column<Advice>,
|
|
|
|
offset: usize,
|
2022-06-07 16:15:35 -07:00
|
|
|
) -> Result<(Cell, Value<F>), Error> {
|
2021-07-21 09:19:35 -07:00
|
|
|
self.columns.insert(Column::<Any>::from(advice).into());
|
2021-07-08 13:44:01 -07:00
|
|
|
self.row_count = cmp::max(self.row_count, offset + 1);
|
|
|
|
|
|
|
|
Ok((
|
|
|
|
Cell {
|
|
|
|
region_index: self.region_index,
|
|
|
|
row_offset: offset,
|
|
|
|
column: advice.into(),
|
|
|
|
},
|
2022-06-07 16:15:35 -07:00
|
|
|
Value::unknown(),
|
2021-07-08 13:44:01 -07:00
|
|
|
))
|
|
|
|
}
|
|
|
|
|
2022-07-07 14:14:59 -07:00
|
|
|
fn instance_value(
|
|
|
|
&mut self,
|
|
|
|
_instance: Column<Instance>,
|
|
|
|
_row: usize,
|
|
|
|
) -> Result<Value<F>, Error> {
|
|
|
|
Ok(Value::unknown())
|
|
|
|
}
|
|
|
|
|
2021-01-13 06:58:12 -08:00
|
|
|
fn assign_fixed<'v>(
|
|
|
|
&'v mut self,
|
2021-01-22 08:57:38 -08:00
|
|
|
_: &'v (dyn Fn() -> String + 'v),
|
2021-01-13 06:58:12 -08:00
|
|
|
column: Column<Fixed>,
|
|
|
|
offset: usize,
|
2022-06-07 16:15:35 -07:00
|
|
|
_to: &'v mut (dyn FnMut() -> Value<Assigned<F>> + 'v),
|
2021-01-13 06:58:12 -08:00
|
|
|
) -> Result<Cell, Error> {
|
2021-07-21 09:19:35 -07:00
|
|
|
self.columns.insert(Column::<Any>::from(column).into());
|
2021-01-13 06:58:12 -08:00
|
|
|
self.row_count = cmp::max(self.row_count, offset + 1);
|
|
|
|
|
|
|
|
Ok(Cell {
|
|
|
|
region_index: self.region_index,
|
|
|
|
row_offset: offset,
|
|
|
|
column: column.into(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-07-20 09:19:47 -07:00
|
|
|
fn constrain_constant(&mut self, _cell: Cell, _constant: Assigned<F>) -> Result<(), Error> {
|
|
|
|
// Global constants don't affect the region shape.
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-07-02 15:20:36 -07:00
|
|
|
fn constrain_equal(&mut self, _left: Cell, _right: Cell) -> Result<(), Error> {
|
2021-01-13 06:58:12 -08:00
|
|
|
// Equality constraints don't affect the region shape.
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|