Add annotations to Region::{assign_advice, assign_fixed}

This enables circuits to annotate individual cells with variable names
or similar protocol-specific metadata.
This commit is contained in:
Jack Grigg 2021-01-22 16:57:38 +00:00
parent fb82730d85
commit 4c3adf59d5
9 changed files with 292 additions and 141 deletions

View file

@ -76,25 +76,36 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) {
let index = self.current_gate;
self.current_gate += 1;
let mut value = None;
self.cs.assign_advice(self.config.a, index, || {
self.cs.assign_advice(
|| "lhs",
self.config.a,
index,
|| {
value = Some(f()?);
Ok(value.ok_or(Error::SynthesisError)?.0)
})?;
self.cs.assign_advice(self.config.b, index, || {
Ok(value.ok_or(Error::SynthesisError)?.1)
})?;
self.cs.assign_advice(self.config.c, index, || {
Ok(value.ok_or(Error::SynthesisError)?.2)
})?;
},
)?;
self.cs.assign_advice(
|| "rhs",
self.config.b,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.1),
)?;
self.cs.assign_advice(
|| "out",
self.config.c,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.2),
)?;
self.cs
.assign_fixed(self.config.sa, index, || Ok(FF::zero()))?;
.assign_fixed(|| "a", self.config.sa, index, || Ok(FF::zero()))?;
self.cs
.assign_fixed(self.config.sb, index, || Ok(FF::zero()))?;
.assign_fixed(|| "b", self.config.sb, index, || Ok(FF::zero()))?;
self.cs
.assign_fixed(self.config.sc, index, || Ok(FF::one()))?;
.assign_fixed(|| "c", self.config.sc, index, || Ok(FF::one()))?;
self.cs
.assign_fixed(self.config.sm, index, || Ok(FF::one()))?;
.assign_fixed(|| "a * b", self.config.sm, index, || Ok(FF::one()))?;
Ok((
Variable(self.config.a, index),
Variable(self.config.b, index),
@ -108,25 +119,36 @@ fn bench_with_k(name: &str, k: u32, c: &mut Criterion) {
let index = self.current_gate;
self.current_gate += 1;
let mut value = None;
self.cs.assign_advice(self.config.a, index, || {
self.cs.assign_advice(
|| "lhs",
self.config.a,
index,
|| {
value = Some(f()?);
Ok(value.ok_or(Error::SynthesisError)?.0)
})?;
self.cs.assign_advice(self.config.b, index, || {
Ok(value.ok_or(Error::SynthesisError)?.1)
})?;
self.cs.assign_advice(self.config.c, index, || {
Ok(value.ok_or(Error::SynthesisError)?.2)
})?;
},
)?;
self.cs.assign_advice(
|| "rhs",
self.config.b,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.1),
)?;
self.cs.assign_advice(
|| "out",
self.config.c,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.2),
)?;
self.cs
.assign_fixed(self.config.sa, index, || Ok(FF::one()))?;
.assign_fixed(|| "a", self.config.sa, index, || Ok(FF::one()))?;
self.cs
.assign_fixed(self.config.sb, index, || Ok(FF::one()))?;
.assign_fixed(|| "b", self.config.sb, index, || Ok(FF::one()))?;
self.cs
.assign_fixed(self.config.sc, index, || Ok(FF::one()))?;
.assign_fixed(|| "c", self.config.sc, index, || Ok(FF::one()))?;
self.cs
.assign_fixed(self.config.sm, index, || Ok(FF::zero()))?;
.assign_fixed(|| "a * b", self.config.sm, index, || Ok(FF::zero()))?;
Ok((
Variable(self.config.a, index),
Variable(self.config.b, index),

View file

@ -76,25 +76,36 @@ impl<'a, FF: FieldExt, CS: Assignment<FF>> StandardCS<FF> for StandardPLONK<'a,
let index = self.current_gate;
self.current_gate += 1;
let mut value = None;
self.cs.assign_advice(self.config.a, index, || {
self.cs.assign_advice(
|| "lhs",
self.config.a,
index,
|| {
value = Some(f()?);
Ok(value.ok_or(Error::SynthesisError)?.0)
})?;
self.cs.assign_advice(self.config.b, index, || {
Ok(value.ok_or(Error::SynthesisError)?.1)
})?;
self.cs.assign_advice(self.config.c, index, || {
Ok(value.ok_or(Error::SynthesisError)?.2)
})?;
},
)?;
self.cs.assign_advice(
|| "rhs",
self.config.b,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.1),
)?;
self.cs.assign_advice(
|| "out",
self.config.c,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.2),
)?;
self.cs
.assign_fixed(self.config.sa, index, || Ok(FF::zero()))?;
.assign_fixed(|| "a", self.config.sa, index, || Ok(FF::zero()))?;
self.cs
.assign_fixed(self.config.sb, index, || Ok(FF::zero()))?;
.assign_fixed(|| "b", self.config.sb, index, || Ok(FF::zero()))?;
self.cs
.assign_fixed(self.config.sc, index, || Ok(FF::one()))?;
.assign_fixed(|| "c", self.config.sc, index, || Ok(FF::one()))?;
self.cs
.assign_fixed(self.config.sm, index, || Ok(FF::one()))?;
.assign_fixed(|| "a * b", self.config.sm, index, || Ok(FF::one()))?;
Ok((
Variable(self.config.a, index),
Variable(self.config.b, index),
@ -108,25 +119,36 @@ impl<'a, FF: FieldExt, CS: Assignment<FF>> StandardCS<FF> for StandardPLONK<'a,
let index = self.current_gate;
self.current_gate += 1;
let mut value = None;
self.cs.assign_advice(self.config.a, index, || {
self.cs.assign_advice(
|| "lhs",
self.config.a,
index,
|| {
value = Some(f()?);
Ok(value.ok_or(Error::SynthesisError)?.0)
})?;
self.cs.assign_advice(self.config.b, index, || {
Ok(value.ok_or(Error::SynthesisError)?.1)
})?;
self.cs.assign_advice(self.config.c, index, || {
Ok(value.ok_or(Error::SynthesisError)?.2)
})?;
},
)?;
self.cs.assign_advice(
|| "rhs",
self.config.b,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.1),
)?;
self.cs.assign_advice(
|| "out",
self.config.c,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.2),
)?;
self.cs
.assign_fixed(self.config.sa, index, || Ok(FF::one()))?;
.assign_fixed(|| "a", self.config.sa, index, || Ok(FF::one()))?;
self.cs
.assign_fixed(self.config.sb, index, || Ok(FF::one()))?;
.assign_fixed(|| "b", self.config.sb, index, || Ok(FF::one()))?;
self.cs
.assign_fixed(self.config.sc, index, || Ok(FF::one()))?;
.assign_fixed(|| "c", self.config.sc, index, || Ok(FF::one()))?;
self.cs
.assign_fixed(self.config.sm, index, || Ok(FF::zero()))?;
.assign_fixed(|| "a * b", self.config.sm, index, || Ok(FF::zero()))?;
Ok((
Variable(self.config.a, index),
Variable(self.config.b, index),
@ -156,9 +178,10 @@ impl<'a, FF: FieldExt, CS: Assignment<FF>> StandardCS<FF> for StandardPLONK<'a,
{
let index = self.current_gate;
self.current_gate += 1;
self.cs.assign_advice(self.config.a, index, || f())?;
self.cs
.assign_fixed(self.config.sp, index, || Ok(FF::one()))?;
.assign_advice(|| "value", self.config.a, index, || f())?;
self.cs
.assign_fixed(|| "public", self.config.sp, index, || Ok(FF::one()))?;
Ok(Variable(self.config.a, index))
}

View file

@ -81,25 +81,39 @@ impl<'r, C: Chip> Region<'r, C> {
/// Assign an advice column value (witness).
///
/// Even though `to` has `FnMut` bounds, it is guaranteed to be called at most once.
pub fn assign_advice<'v>(
pub fn assign_advice<'v, V, A, AR>(
&'v mut self,
annotation: A,
column: Column<Advice>,
offset: usize,
mut to: impl FnMut() -> Result<C::Field, Error> + 'v,
) -> Result<Cell, Error> {
self.region.assign_advice(column, offset, &mut to)
mut to: V,
) -> Result<Cell, Error>
where
V: FnMut() -> Result<C::Field, Error> + 'v,
A: Fn() -> AR,
AR: Into<String>,
{
self.region
.assign_advice(&|| annotation().into(), column, offset, &mut to)
}
/// Assign a fixed value.
///
/// Even though `to` has `FnMut` bounds, it is guaranteed to be called at most once.
pub fn assign_fixed<'v>(
pub fn assign_fixed<'v, V, A, AR>(
&'v mut self,
annotation: A,
column: Column<Fixed>,
offset: usize,
mut to: impl FnMut() -> Result<C::Field, Error> + 'v,
) -> Result<Cell, Error> {
self.region.assign_fixed(column, offset, &mut to)
mut to: V,
) -> Result<Cell, Error>
where
V: FnMut() -> Result<C::Field, Error> + 'v,
A: Fn() -> AR,
AR: Into<String>,
{
self.region
.assign_fixed(&|| annotation().into(), column, offset, &mut to)
}
/// Constraint two cells to have the same value.

View file

@ -40,6 +40,7 @@ pub trait RegionLayouter<C: Chip>: fmt::Debug {
/// Assign an advice column value (witness)
fn assign_advice<'v>(
&'v mut self,
annotation: &'v (dyn Fn() -> String + 'v),
column: Column<Advice>,
offset: usize,
to: &'v mut (dyn FnMut() -> Result<C::Field, Error> + 'v),
@ -48,6 +49,7 @@ pub trait RegionLayouter<C: Chip>: fmt::Debug {
/// Assign a fixed value
fn assign_fixed<'v>(
&'v mut self,
annotation: &'v (dyn Fn() -> String + 'v),
column: Column<Fixed>,
offset: usize,
to: &'v mut (dyn FnMut() -> Result<C::Field, Error> + 'v),
@ -176,6 +178,7 @@ impl RegionShape {
impl<C: Chip> RegionLayouter<C> for RegionShape {
fn assign_advice<'v>(
&'v mut self,
_: &'v (dyn Fn() -> String + 'v),
column: Column<Advice>,
offset: usize,
_to: &'v mut (dyn FnMut() -> Result<C::Field, Error> + 'v),
@ -192,6 +195,7 @@ impl<C: Chip> RegionLayouter<C> for RegionShape {
fn assign_fixed<'v>(
&'v mut self,
_: &'v (dyn Fn() -> String + 'v),
column: Column<Fixed>,
offset: usize,
_to: &'v mut (dyn FnMut() -> Result<C::Field, Error> + 'v),
@ -247,11 +251,13 @@ impl<'r, 'a, C: Chip, CS: Assignment<C::Field> + 'a> RegionLayouter<C>
{
fn assign_advice<'v>(
&'v mut self,
annotation: &'v (dyn Fn() -> String + 'v),
column: Column<Advice>,
offset: usize,
to: &'v mut (dyn FnMut() -> Result<C::Field, Error> + 'v),
) -> Result<Cell, Error> {
self.layouter.cs.assign_advice(
annotation,
column,
self.layouter.regions[self.region_index] + offset,
to,
@ -266,11 +272,13 @@ impl<'r, 'a, C: Chip, CS: Assignment<C::Field> + 'a> RegionLayouter<C>
fn assign_fixed<'v>(
&'v mut self,
annotation: &'v (dyn Fn() -> String + 'v),
column: Column<Fixed>,
offset: usize,
to: &'v mut (dyn FnMut() -> Result<C::Field, Error> + 'v),
) -> Result<Cell, Error> {
self.layouter.cs.assign_fixed(
annotation,
column,
self.layouter.regions[self.region_index] + offset,
to,

View file

@ -4,7 +4,10 @@ use ff::Field;
use crate::{
arithmetic::{FieldExt, Group},
plonk::{permutation, Any, Assignment, Circuit, Column, ColumnType, ConstraintSystem, Error},
plonk::{
permutation, Advice, Any, Assignment, Circuit, Column, ColumnType, ConstraintSystem, Error,
Fixed,
},
poly::Rotation,
};
@ -96,13 +99,13 @@ pub enum VerifyFailure {
/// }
///
/// fn synthesize(&self, cs: &mut impl Assignment<F>, config: MyConfig) -> Result<(), Error> {
/// cs.assign_advice(config.a, 0, || {
/// cs.assign_advice(|| "a", config.a, 0, || {
/// self.a.map(|v| F::from_u64(v)).ok_or(Error::SynthesisError)
/// })?;
/// cs.assign_advice(config.b, 0, || {
/// cs.assign_advice(|| "b", config.b, 0, || {
/// self.b.map(|v| F::from_u64(v)).ok_or(Error::SynthesisError)
/// })?;
/// cs.assign_advice(config.c, 0, || {
/// cs.assign_advice(|| "c", config.c, 0, || {
/// self.a
/// .and_then(|a| self.b.map(|b| F::from_u64(a * b)))
/// .ok_or(Error::SynthesisError)
@ -144,12 +147,18 @@ pub struct MockProver<F: Group> {
}
impl<F: Field + Group> Assignment<F> for MockProver<F> {
fn assign_advice(
fn assign_advice<V, A, AR>(
&mut self,
column: crate::plonk::Column<crate::plonk::Advice>,
_: A,
column: Column<Advice>,
row: usize,
to: impl FnOnce() -> Result<F, crate::plonk::Error>,
) -> Result<(), crate::plonk::Error> {
to: V,
) -> Result<(), Error>
where
V: FnOnce() -> Result<F, Error>,
A: FnOnce() -> AR,
AR: Into<String>,
{
*self
.advice
.get_mut(column.index())
@ -159,12 +168,18 @@ impl<F: Field + Group> Assignment<F> for MockProver<F> {
Ok(())
}
fn assign_fixed(
fn assign_fixed<V, A, AR>(
&mut self,
column: crate::plonk::Column<crate::plonk::Fixed>,
_: A,
column: Column<Fixed>,
row: usize,
to: impl FnOnce() -> Result<F, crate::plonk::Error>,
) -> Result<(), crate::plonk::Error> {
to: V,
) -> Result<(), Error>
where
V: FnOnce() -> Result<F, Error>,
A: FnOnce() -> AR,
AR: Into<String>,
{
*self
.fixed
.get_mut(column.index())

View file

@ -230,31 +230,48 @@ fn test_proving() {
let index = self.current_gate;
self.current_gate += 1;
let mut value = None;
self.cs.assign_advice(self.config.a, index, || {
self.cs.assign_advice(
|| "lhs",
self.config.a,
index,
|| {
value = Some(f()?);
Ok(value.ok_or(Error::SynthesisError)?.0)
})?;
self.cs.assign_advice(self.config.d, index, || {
Ok(value.ok_or(Error::SynthesisError)?.0.square().square())
})?;
self.cs.assign_advice(self.config.b, index, || {
Ok(value.ok_or(Error::SynthesisError)?.1)
})?;
self.cs.assign_advice(self.config.e, index, || {
Ok(value.ok_or(Error::SynthesisError)?.1.square().square())
})?;
self.cs.assign_advice(self.config.c, index, || {
Ok(value.ok_or(Error::SynthesisError)?.2)
})?;
},
)?;
self.cs.assign_advice(
|| "lhs^4",
self.config.d,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.0.square().square()),
)?;
self.cs.assign_advice(
|| "rhs",
self.config.b,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.1),
)?;
self.cs.assign_advice(
|| "rhs^4",
self.config.e,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.1.square().square()),
)?;
self.cs.assign_advice(
|| "out",
self.config.c,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.2),
)?;
self.cs
.assign_fixed(self.config.sa, index, || Ok(FF::zero()))?;
.assign_fixed(|| "a", self.config.sa, index, || Ok(FF::zero()))?;
self.cs
.assign_fixed(self.config.sb, index, || Ok(FF::zero()))?;
.assign_fixed(|| "b", self.config.sb, index, || Ok(FF::zero()))?;
self.cs
.assign_fixed(self.config.sc, index, || Ok(FF::one()))?;
.assign_fixed(|| "c", self.config.sc, index, || Ok(FF::one()))?;
self.cs
.assign_fixed(self.config.sm, index, || Ok(FF::one()))?;
.assign_fixed(|| "a * b", self.config.sm, index, || Ok(FF::one()))?;
Ok((
Variable(self.config.a, index),
Variable(self.config.b, index),
@ -268,31 +285,48 @@ fn test_proving() {
let index = self.current_gate;
self.current_gate += 1;
let mut value = None;
self.cs.assign_advice(self.config.a, index, || {
self.cs.assign_advice(
|| "lhs",
self.config.a,
index,
|| {
value = Some(f()?);
Ok(value.ok_or(Error::SynthesisError)?.0)
})?;
self.cs.assign_advice(self.config.d, index, || {
Ok(value.ok_or(Error::SynthesisError)?.0.square().square())
})?;
self.cs.assign_advice(self.config.b, index, || {
Ok(value.ok_or(Error::SynthesisError)?.1)
})?;
self.cs.assign_advice(self.config.e, index, || {
Ok(value.ok_or(Error::SynthesisError)?.1.square().square())
})?;
self.cs.assign_advice(self.config.c, index, || {
Ok(value.ok_or(Error::SynthesisError)?.2)
})?;
},
)?;
self.cs.assign_advice(
|| "lhs^4",
self.config.d,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.0.square().square()),
)?;
self.cs.assign_advice(
|| "rhs",
self.config.b,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.1),
)?;
self.cs.assign_advice(
|| "rhs^4",
self.config.e,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.1.square().square()),
)?;
self.cs.assign_advice(
|| "out",
self.config.c,
index,
|| Ok(value.ok_or(Error::SynthesisError)?.2),
)?;
self.cs
.assign_fixed(self.config.sa, index, || Ok(FF::one()))?;
.assign_fixed(|| "a", self.config.sa, index, || Ok(FF::one()))?;
self.cs
.assign_fixed(self.config.sb, index, || Ok(FF::one()))?;
.assign_fixed(|| "b", self.config.sb, index, || Ok(FF::one()))?;
self.cs
.assign_fixed(self.config.sc, index, || Ok(FF::one()))?;
.assign_fixed(|| "c", self.config.sc, index, || Ok(FF::one()))?;
self.cs
.assign_fixed(self.config.sm, index, || Ok(FF::zero()))?;
.assign_fixed(|| "a * b", self.config.sm, index, || Ok(FF::zero()))?;
Ok((
Variable(self.config.a, index),
Variable(self.config.b, index),
@ -329,9 +363,10 @@ fn test_proving() {
{
let index = self.current_gate;
self.current_gate += 1;
self.cs.assign_advice(self.config.a, index, || f())?;
self.cs
.assign_fixed(self.config.sp, index, || Ok(FF::one()))?;
.assign_advice(|| "value", self.config.a, index, || f())?;
self.cs
.assign_fixed(|| "public", self.config.sp, index, || Ok(FF::one()))?;
Ok(Variable(self.config.a, index))
}
@ -341,9 +376,9 @@ fn test_proving() {
self.current_gate += 1;
self.cs
.assign_fixed(self.config.sl, index, || Ok(value_0))?;
.assign_fixed(|| "table col 1", self.config.sl, index, || Ok(value_0))?;
self.cs
.assign_fixed(self.config.sl2, index, || Ok(value_1))?;
.assign_fixed(|| "table col 2", self.config.sl2, index, || Ok(value_1))?;
}
Ok(())
}

View file

@ -127,20 +127,30 @@ impl TryFrom<Column<Any>> for Column<Aux> {
/// for a constraint system.
pub trait Assignment<F: Field> {
/// Assign an advice column value (witness)
fn assign_advice(
fn assign_advice<V, A, AR>(
&mut self,
annotation: A,
column: Column<Advice>,
row: usize,
to: impl FnOnce() -> Result<F, Error>,
) -> Result<(), Error>;
to: V,
) -> Result<(), Error>
where
V: FnOnce() -> Result<F, Error>,
A: FnOnce() -> AR,
AR: Into<String>;
/// Assign a fixed value
fn assign_fixed(
fn assign_fixed<V, A, AR>(
&mut self,
annotation: A,
column: Column<Fixed>,
row: usize,
to: impl FnOnce() -> Result<F, Error>,
) -> Result<(), Error>;
to: V,
) -> Result<(), Error>
where
V: FnOnce() -> Result<F, Error>,
A: FnOnce() -> AR,
AR: Into<String>;
/// Assign two advice columns to have the same value
fn copy(

View file

@ -57,29 +57,41 @@ where
/// Assembly to be used in circuit synthesis.
#[derive(Debug)]
pub struct Assembly<F: Field> {
struct Assembly<F: Field> {
fixed: Vec<Polynomial<F, LagrangeCoeff>>,
permutations: Vec<permutation::keygen::Assembly>,
_marker: std::marker::PhantomData<F>,
}
impl<F: Field> Assignment<F> for Assembly<F> {
fn assign_advice(
fn assign_advice<V, A, AR>(
&mut self,
_: A,
_: Column<Advice>,
_: usize,
_: impl FnOnce() -> Result<F, Error>,
) -> Result<(), Error> {
_: V,
) -> Result<(), Error>
where
V: FnOnce() -> Result<F, Error>,
A: FnOnce() -> AR,
AR: Into<String>,
{
// We only care about fixed columns here
Ok(())
}
fn assign_fixed(
fn assign_fixed<V, A, AR>(
&mut self,
_: A,
column: Column<Fixed>,
row: usize,
to: impl FnOnce() -> Result<F, Error>,
) -> Result<(), Error> {
to: V,
) -> Result<(), Error>
where
V: FnOnce() -> Result<F, Error>,
A: FnOnce() -> AR,
AR: Into<String>,
{
*self
.fixed
.get_mut(column.index())

View file

@ -100,12 +100,18 @@ pub fn create_proof<C: CurveAffine, T: TranscriptWrite<C>, ConcreteCircuit: Circ
}
impl<F: Field> Assignment<F> for WitnessCollection<F> {
fn assign_advice(
fn assign_advice<V, A, AR>(
&mut self,
_: A,
column: Column<Advice>,
row: usize,
to: impl FnOnce() -> Result<F, Error>,
) -> Result<(), Error> {
to: V,
) -> Result<(), Error>
where
V: FnOnce() -> Result<F, Error>,
A: FnOnce() -> AR,
AR: Into<String>,
{
*self
.advice
.get_mut(column.index())
@ -115,12 +121,18 @@ pub fn create_proof<C: CurveAffine, T: TranscriptWrite<C>, ConcreteCircuit: Circ
Ok(())
}
fn assign_fixed(
fn assign_fixed<V, A, AR>(
&mut self,
_: A,
_: Column<Fixed>,
_: usize,
_: impl FnOnce() -> Result<F, Error>,
) -> Result<(), Error> {
_: V,
) -> Result<(), Error>
where
V: FnOnce() -> Result<F, Error>,
A: FnOnce() -> AR,
AR: Into<String>,
{
// We only care about advice columns here
Ok(())