From 4c3adf59d57bc1492d1fd48df41cc9fe8fb6271d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 22 Jan 2021 16:57:38 +0000 Subject: [PATCH] Add annotations to Region::{assign_advice, assign_fixed} This enables circuits to annotate individual cells with variable names or similar protocol-specific metadata. --- benches/plonk.rs | 78 +++++++++++++-------- examples/performance_model.rs | 83 ++++++++++++++--------- src/circuit.rs | 30 ++++++--- src/circuit/layouter.rs | 8 +++ src/dev.rs | 39 +++++++---- src/plonk.rs | 123 ++++++++++++++++++++++------------ src/plonk/circuit.rs | 22 ++++-- src/plonk/keygen.rs | 26 +++++-- src/plonk/prover.rs | 24 +++++-- 9 files changed, 292 insertions(+), 141 deletions(-) diff --git a/benches/plonk.rs b/benches/plonk.rs index 7b7bbb4..6a6a1d4 100644 --- a/benches/plonk.rs +++ b/benches/plonk.rs @@ -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, || { - 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( + || "lhs", + self.config.a, + index, + || { + value = Some(f()?); + Ok(value.ok_or(Error::SynthesisError)?.0) + }, + )?; + 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, || { - 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( + || "lhs", + self.config.a, + index, + || { + value = Some(f()?); + Ok(value.ok_or(Error::SynthesisError)?.0) + }, + )?; + 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), diff --git a/examples/performance_model.rs b/examples/performance_model.rs index 23785eb..ed068c8 100644 --- a/examples/performance_model.rs +++ b/examples/performance_model.rs @@ -76,25 +76,36 @@ impl<'a, FF: FieldExt, CS: Assignment> StandardCS for StandardPLONK<'a, let index = self.current_gate; self.current_gate += 1; let mut value = None; - self.cs.assign_advice(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( + || "lhs", + self.config.a, + index, + || { + value = Some(f()?); + Ok(value.ok_or(Error::SynthesisError)?.0) + }, + )?; + 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> StandardCS for StandardPLONK<'a, let index = self.current_gate; self.current_gate += 1; let mut value = None; - self.cs.assign_advice(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( + || "lhs", + self.config.a, + index, + || { + value = Some(f()?); + Ok(value.ok_or(Error::SynthesisError)?.0) + }, + )?; + 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> StandardCS 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)) } diff --git a/src/circuit.rs b/src/circuit.rs index 29d53cd..903cd86 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -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, offset: usize, - mut to: impl FnMut() -> Result + 'v, - ) -> Result { - self.region.assign_advice(column, offset, &mut to) + mut to: V, + ) -> Result + where + V: FnMut() -> Result + 'v, + A: Fn() -> AR, + AR: Into, + { + 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, offset: usize, - mut to: impl FnMut() -> Result + 'v, - ) -> Result { - self.region.assign_fixed(column, offset, &mut to) + mut to: V, + ) -> Result + where + V: FnMut() -> Result + 'v, + A: Fn() -> AR, + AR: Into, + { + self.region + .assign_fixed(&|| annotation().into(), column, offset, &mut to) } /// Constraint two cells to have the same value. diff --git a/src/circuit/layouter.rs b/src/circuit/layouter.rs index a6c282b..fcd8155 100644 --- a/src/circuit/layouter.rs +++ b/src/circuit/layouter.rs @@ -40,6 +40,7 @@ pub trait RegionLayouter: fmt::Debug { /// Assign an advice column value (witness) fn assign_advice<'v>( &'v mut self, + annotation: &'v (dyn Fn() -> String + 'v), column: Column, offset: usize, to: &'v mut (dyn FnMut() -> Result + 'v), @@ -48,6 +49,7 @@ pub trait RegionLayouter: fmt::Debug { /// Assign a fixed value fn assign_fixed<'v>( &'v mut self, + annotation: &'v (dyn Fn() -> String + 'v), column: Column, offset: usize, to: &'v mut (dyn FnMut() -> Result + 'v), @@ -176,6 +178,7 @@ impl RegionShape { impl RegionLayouter for RegionShape { fn assign_advice<'v>( &'v mut self, + _: &'v (dyn Fn() -> String + 'v), column: Column, offset: usize, _to: &'v mut (dyn FnMut() -> Result + 'v), @@ -192,6 +195,7 @@ impl RegionLayouter for RegionShape { fn assign_fixed<'v>( &'v mut self, + _: &'v (dyn Fn() -> String + 'v), column: Column, offset: usize, _to: &'v mut (dyn FnMut() -> Result + 'v), @@ -247,11 +251,13 @@ impl<'r, 'a, C: Chip, CS: Assignment + 'a> RegionLayouter { fn assign_advice<'v>( &'v mut self, + annotation: &'v (dyn Fn() -> String + 'v), column: Column, offset: usize, to: &'v mut (dyn FnMut() -> Result + 'v), ) -> Result { 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 + 'a> RegionLayouter fn assign_fixed<'v>( &'v mut self, + annotation: &'v (dyn Fn() -> String + 'v), column: Column, offset: usize, to: &'v mut (dyn FnMut() -> Result + 'v), ) -> Result { self.layouter.cs.assign_fixed( + annotation, column, self.layouter.regions[self.region_index] + offset, to, diff --git a/src/dev.rs b/src/dev.rs index 17b5b10..7cd2208 100644 --- a/src/dev.rs +++ b/src/dev.rs @@ -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, 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 { } impl Assignment for MockProver { - fn assign_advice( + fn assign_advice( &mut self, - column: crate::plonk::Column, + _: A, + column: Column, row: usize, - to: impl FnOnce() -> Result, - ) -> Result<(), crate::plonk::Error> { + to: V, + ) -> Result<(), Error> + where + V: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, + { *self .advice .get_mut(column.index()) @@ -159,12 +168,18 @@ impl Assignment for MockProver { Ok(()) } - fn assign_fixed( + fn assign_fixed( &mut self, - column: crate::plonk::Column, + _: A, + column: Column, row: usize, - to: impl FnOnce() -> Result, - ) -> Result<(), crate::plonk::Error> { + to: V, + ) -> Result<(), Error> + where + V: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, + { *self .fixed .get_mut(column.index()) diff --git a/src/plonk.rs b/src/plonk.rs index d612df5..dfedc64 100644 --- a/src/plonk.rs +++ b/src/plonk.rs @@ -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, || { - 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", + self.config.a, + index, + || { + value = Some(f()?); + Ok(value.ok_or(Error::SynthesisError)?.0) + }, + )?; + 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, || { - 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", + self.config.a, + index, + || { + value = Some(f()?); + Ok(value.ok_or(Error::SynthesisError)?.0) + }, + )?; + 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(()) } diff --git a/src/plonk/circuit.rs b/src/plonk/circuit.rs index 25d97c1..d0ae0a2 100644 --- a/src/plonk/circuit.rs +++ b/src/plonk/circuit.rs @@ -127,20 +127,30 @@ impl TryFrom> for Column { /// for a constraint system. pub trait Assignment { /// Assign an advice column value (witness) - fn assign_advice( + fn assign_advice( &mut self, + annotation: A, column: Column, row: usize, - to: impl FnOnce() -> Result, - ) -> Result<(), Error>; + to: V, + ) -> Result<(), Error> + where + V: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into; /// Assign a fixed value - fn assign_fixed( + fn assign_fixed( &mut self, + annotation: A, column: Column, row: usize, - to: impl FnOnce() -> Result, - ) -> Result<(), Error>; + to: V, + ) -> Result<(), Error> + where + V: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into; /// Assign two advice columns to have the same value fn copy( diff --git a/src/plonk/keygen.rs b/src/plonk/keygen.rs index 8c99b7a..bb1e388 100644 --- a/src/plonk/keygen.rs +++ b/src/plonk/keygen.rs @@ -57,29 +57,41 @@ where /// Assembly to be used in circuit synthesis. #[derive(Debug)] -pub struct Assembly { +struct Assembly { fixed: Vec>, permutations: Vec, _marker: std::marker::PhantomData, } impl Assignment for Assembly { - fn assign_advice( + fn assign_advice( &mut self, + _: A, _: Column, _: usize, - _: impl FnOnce() -> Result, - ) -> Result<(), Error> { + _: V, + ) -> Result<(), Error> + where + V: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, + { // We only care about fixed columns here Ok(()) } - fn assign_fixed( + fn assign_fixed( &mut self, + _: A, column: Column, row: usize, - to: impl FnOnce() -> Result, - ) -> Result<(), Error> { + to: V, + ) -> Result<(), Error> + where + V: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, + { *self .fixed .get_mut(column.index()) diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 4bc6ce2..5f7d830 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -100,12 +100,18 @@ pub fn create_proof, ConcreteCircuit: Circ } impl Assignment for WitnessCollection { - fn assign_advice( + fn assign_advice( &mut self, + _: A, column: Column, row: usize, - to: impl FnOnce() -> Result, - ) -> Result<(), Error> { + to: V, + ) -> Result<(), Error> + where + V: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, + { *self .advice .get_mut(column.index()) @@ -115,12 +121,18 @@ pub fn create_proof, ConcreteCircuit: Circ Ok(()) } - fn assign_fixed( + fn assign_fixed( &mut self, + _: A, _: Column, _: usize, - _: impl FnOnce() -> Result, - ) -> Result<(), Error> { + _: V, + ) -> Result<(), Error> + where + V: FnOnce() -> Result, + A: FnOnce() -> AR, + AR: Into, + { // We only care about advice columns here Ok(())