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;
|
|
|
|
|
2021-06-07 05:11:14 -07:00
|
|
|
use super::{Cell, RegionIndex};
|
2021-06-11 09:41:27 -07:00
|
|
|
use crate::plonk::Assigned;
|
2021-07-02 15:20:36 -07:00
|
|
|
use crate::plonk::{Advice, Any, Column, Error, Fixed, 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
|
2021-04-19 06:25:32 -07:00
|
|
|
/// impl<'a, F: FieldExt, 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>;
|
|
|
|
|
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,
|
2021-06-11 09:41:27 -07:00
|
|
|
to: &'v mut (dyn FnMut() -> Result<Assigned<F>, Error> + 'v),
|
2020-12-14 16:36:58 -08:00
|
|
|
) -> Result<Cell, Error>;
|
|
|
|
|
|
|
|
/// Assign a fixed value
|
|
|
|
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,
|
2021-06-11 09:41:27 -07:00
|
|
|
to: &'v mut (dyn FnMut() -> Result<Assigned<F>, Error> + 'v),
|
2020-12-14 16:36:58 -08:00
|
|
|
) -> Result<Cell, Error>;
|
|
|
|
|
|
|
|
/// 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,
|
|
|
|
pub(super) columns: HashSet<Column<Any>>,
|
|
|
|
pub(super) row_count: usize,
|
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`.
|
|
|
|
pub fn columns(&self) -> &HashSet<Column<Any>> {
|
|
|
|
&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.
|
|
|
|
// TODO: Avoid exposing selector internals?
|
|
|
|
self.columns.insert(selector.0.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,
|
2021-06-11 09:41:27 -07:00
|
|
|
_to: &'v mut (dyn FnMut() -> Result<Assigned<F>, Error> + 'v),
|
2021-01-13 06:58:12 -08:00
|
|
|
) -> Result<Cell, Error> {
|
|
|
|
self.columns.insert(column.into());
|
|
|
|
self.row_count = cmp::max(self.row_count, offset + 1);
|
|
|
|
|
|
|
|
Ok(Cell {
|
|
|
|
region_index: self.region_index,
|
|
|
|
row_offset: offset,
|
|
|
|
column: column.into(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2021-06-11 09:41:27 -07:00
|
|
|
_to: &'v mut (dyn FnMut() -> Result<Assigned<F>, Error> + 'v),
|
2021-01-13 06:58:12 -08:00
|
|
|
) -> Result<Cell, Error> {
|
|
|
|
self.columns.insert(column.into());
|
|
|
|
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-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(())
|
|
|
|
}
|
|
|
|
}
|