use std::{fmt, marker::PhantomData};
use ff::Field;
use crate::plonk::{Advice, Any, Challenge, Column, Error, Fixed, Instance, Selector, TableColumn};
mod value;
pub use value::Value;
pub mod floor_planner;
pub use floor_planner::single_pass::SimpleFloorPlanner;
pub mod layouter;
mod table_layouter;
pub use table_layouter::{SimpleTableLayouter, TableLayouter};
use crate::utils::rational::Rational;
pub trait Chip<F: Field>: Sized {
type Config: fmt::Debug + Clone;
type Loaded: fmt::Debug + Clone;
fn config(&self) -> &Self::Config;
fn loaded(&self) -> &Self::Loaded;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct RegionIndex(usize);
impl From<usize> for RegionIndex {
fn from(idx: usize) -> RegionIndex {
RegionIndex(idx)
}
}
impl std::ops::Deref for RegionIndex {
type Target = usize;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RegionStart(usize);
impl From<usize> for RegionStart {
fn from(idx: usize) -> RegionStart {
RegionStart(idx)
}
}
impl std::ops::Deref for RegionStart {
type Target = usize;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Cell {
pub region_index: RegionIndex,
pub row_offset: usize,
pub column: Column<Any>,
}
#[derive(Clone, Debug)]
pub struct AssignedCell<V, F: Field> {
value: Value<V>,
cell: Cell,
_marker: PhantomData<F>,
}
impl<V: Eq, F: Field> AssignedCell<V, F> {
pub fn update_value(&mut self, v: V) -> Result<(), Error> {
self.value.error_if_known_and(|other| v != *other)?;
self.value = Value::known(v);
Ok(())
}
}
impl<V, F: Field> PartialEq for AssignedCell<V, F> {
fn eq(&self, other: &Self) -> bool {
self.cell == other.cell
}
}
impl<V, F: Field> Eq for AssignedCell<V, F> {}
use std::hash::{Hash, Hasher};
impl<V, F: Field> Hash for AssignedCell<V, F> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.cell.hash(state)
}
}
impl<V, F: Field> AssignedCell<V, F> {
pub fn value(&self) -> Value<&V> {
self.value.as_ref()
}
pub fn cell(&self) -> Cell {
self.cell
}
}
impl<V, F: Field> AssignedCell<V, F>
where
for<'v> Rational<F>: From<&'v V>,
{
pub fn value_field(&self) -> Value<Rational<F>> {
self.value.to_field()
}
}
impl<F: Field> AssignedCell<Rational<F>, F> {
pub fn evaluate(self) -> AssignedCell<F, F> {
AssignedCell {
value: self.value.evaluate(),
cell: self.cell,
_marker: Default::default(),
}
}
}
impl<V: Clone, F: Field> AssignedCell<V, F>
where
for<'v> Rational<F>: From<&'v V>,
{
pub fn convert_to_native(&self) -> AssignedCell<F, F> {
AssignedCell {
value: self.value_field(),
cell: self.cell,
_marker: self._marker,
}
.evaluate()
}
}
impl<V: Clone, F: Field> AssignedCell<V, F>
where
for<'v> Rational<F>: From<&'v V>,
{
pub fn copy_advice<A, AR>(
&self,
annotation: A,
region: &mut Region<'_, F>,
column: Column<Advice>,
offset: usize,
) -> Result<Self, Error>
where
A: Fn() -> AR,
AR: Into<String>,
{
let assigned_cell =
region.assign_advice(annotation, column, offset, || self.value.clone())?;
region.constrain_equal(assigned_cell.cell(), self.cell())?;
Ok(assigned_cell)
}
}
#[derive(Debug)]
pub struct Region<'r, F: Field> {
region: &'r mut dyn layouter::RegionLayouter<F>,
}
impl<'r, F: Field> From<&'r mut dyn layouter::RegionLayouter<F>> for Region<'r, F> {
fn from(region: &'r mut dyn layouter::RegionLayouter<F>) -> Self {
Region { region }
}
}
impl<F: Field> Region<'_, F> {
pub(crate) fn enable_selector<A, AR>(
&mut self,
annotation: A,
selector: &Selector,
offset: usize,
) -> Result<(), Error>
where
A: Fn() -> AR,
AR: Into<String>,
{
self.region.enable_selector(&|| annotation().into(), selector, offset)
}
pub fn name_column<A, AR, T>(&mut self, annotation: A, column: T)
where
A: Fn() -> AR,
AR: Into<String>,
T: Into<Column<Any>>,
{
self.region.name_column(&|| annotation().into(), column.into());
}
pub fn assign_advice<'v, V, VR, A, AR>(
&'v mut self,
annotation: A,
column: Column<Advice>,
offset: usize,
mut to: V,
) -> Result<AssignedCell<VR, F>, Error>
where
V: FnMut() -> Value<VR> + 'v,
for<'vr> Rational<F>: From<&'vr VR>,
A: Fn() -> AR,
AR: Into<String>,
{
let mut value = Value::unknown();
let cell =
self.region.assign_advice(&|| annotation().into(), column, offset, &mut || {
let v = to();
let value_f = v.to_field();
value = v;
value_f
})?;
Ok(AssignedCell {
value,
cell,
_marker: PhantomData,
})
}
pub fn assign_advice_from_constant<VR, A, AR>(
&mut self,
annotation: A,
column: Column<Advice>,
offset: usize,
constant: VR,
) -> Result<AssignedCell<VR, F>, Error>
where
for<'vr> Rational<F>: From<&'vr VR>,
A: Fn() -> AR,
AR: Into<String>,
{
let cell = self.region.assign_advice_from_constant(
&|| annotation().into(),
column,
offset,
(&constant).into(),
)?;
Ok(AssignedCell {
value: Value::known(constant),
cell,
_marker: PhantomData,
})
}
pub fn assign_advice_from_instance<A, AR>(
&mut self,
annotation: A,
instance: Column<Instance>,
row: usize,
advice: Column<Advice>,
offset: usize,
) -> Result<AssignedCell<F, F>, Error>
where
A: Fn() -> AR,
AR: Into<String>,
{
let (cell, value) = self.region.assign_advice_from_instance(
&|| annotation().into(),
instance,
row,
advice,
offset,
)?;
Ok(AssignedCell {
value,
cell,
_marker: PhantomData,
})
}
pub fn instance_value(
&mut self,
instance: Column<Instance>,
row: usize,
) -> Result<Value<F>, Error> {
self.region.instance_value(instance, row)
}
pub fn assign_fixed<'v, V, VR, A, AR>(
&'v mut self,
annotation: A,
column: Column<Fixed>,
offset: usize,
mut to: V,
) -> Result<AssignedCell<VR, F>, Error>
where
V: FnMut() -> Value<VR> + 'v,
for<'vr> Rational<F>: From<&'vr VR>,
A: Fn() -> AR,
AR: Into<String>,
{
let mut value = Value::unknown();
let cell =
self.region.assign_fixed(&|| annotation().into(), column, offset, &mut || {
let v = to();
let value_f = v.to_field();
value = v;
value_f
})?;
Ok(AssignedCell {
value,
cell,
_marker: PhantomData,
})
}
pub fn constrain_constant<VR>(&mut self, cell: Cell, constant: VR) -> Result<(), Error>
where
VR: Into<Rational<F>>,
{
self.region.constrain_constant(cell, constant.into())
}
pub fn constrain_equal(&mut self, left: Cell, right: Cell) -> Result<(), Error> {
self.region.constrain_equal(left, right)
}
}
#[derive(Debug)]
pub struct Table<'r, F: Field> {
table: &'r mut dyn TableLayouter<F>,
}
impl<'r, F: Field> From<&'r mut dyn TableLayouter<F>> for Table<'r, F> {
fn from(table: &'r mut dyn TableLayouter<F>) -> Self {
Table { table }
}
}
impl<F: Field> Table<'_, F> {
pub fn assign_cell<'v, V, VR, A, AR>(
&'v mut self,
annotation: A,
column: TableColumn,
offset: usize,
mut to: V,
) -> Result<(), Error>
where
V: FnMut() -> Value<VR> + 'v,
VR: Into<Rational<F>>,
A: Fn() -> AR,
AR: Into<String>,
{
self.table.assign_cell(&|| annotation().into(), column, offset, &mut || {
to().into_field()
})
}
}
pub trait Layouter<F: Field> {
type Root: Layouter<F>;
fn assign_region<A, AR, N, NR>(&mut self, name: N, assignment: A) -> Result<AR, Error>
where
A: FnMut(Region<'_, F>) -> Result<AR, Error>,
N: Fn() -> NR,
NR: Into<String>;
fn assign_table<A, N, NR>(&mut self, name: N, assignment: A) -> Result<(), Error>
where
A: FnMut(Table<'_, F>) -> Result<(), Error>,
N: Fn() -> NR,
NR: Into<String>;
fn constrain_instance(
&mut self,
cell: Cell,
column: Column<Instance>,
row: usize,
) -> Result<(), Error>;
fn get_challenge(&self, challenge: Challenge) -> Value<F>;
fn get_root(&mut self) -> &mut Self::Root;
fn push_namespace<NR, N>(&mut self, name_fn: N)
where
NR: Into<String>,
N: FnOnce() -> NR;
fn pop_namespace(&mut self, gadget_name: Option<String>);
fn namespace<NR, N>(&mut self, name_fn: N) -> NamespacedLayouter<'_, F, Self::Root>
where
NR: Into<String>,
N: FnOnce() -> NR,
{
self.get_root().push_namespace(name_fn);
NamespacedLayouter(self.get_root(), PhantomData)
}
}
#[derive(Debug)]
pub struct NamespacedLayouter<'a, F: Field, L: Layouter<F> + 'a>(&'a mut L, PhantomData<F>);
impl<'a, F: Field, L: Layouter<F> + 'a> Layouter<F> for NamespacedLayouter<'a, F, L> {
type Root = L::Root;
fn assign_region<A, AR, N, NR>(&mut self, name: N, assignment: A) -> Result<AR, Error>
where
A: FnMut(Region<'_, F>) -> Result<AR, Error>,
N: Fn() -> NR,
NR: Into<String>,
{
self.0.assign_region(name, assignment)
}
fn assign_table<A, N, NR>(&mut self, name: N, assignment: A) -> Result<(), Error>
where
A: FnMut(Table<'_, F>) -> Result<(), Error>,
N: Fn() -> NR,
NR: Into<String>,
{
self.0.assign_table(name, assignment)
}
fn constrain_instance(
&mut self,
cell: Cell,
column: Column<Instance>,
row: usize,
) -> Result<(), Error> {
self.0.constrain_instance(cell, column, row)
}
fn get_challenge(&self, challenge: Challenge) -> Value<F> {
self.0.get_challenge(challenge)
}
fn get_root(&mut self) -> &mut Self::Root {
self.0.get_root()
}
fn push_namespace<NR, N>(&mut self, _name_fn: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
{
panic!("Only the root's push_namespace should be called");
}
fn pop_namespace(&mut self, _gadget_name: Option<String>) {
panic!("Only the root's pop_namespace should be called");
}
}