From fed2c5c653a0e4135417d0cf63d68ab171a128c5 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Tue, 21 Feb 2023 18:59:27 +0800 Subject: [PATCH 01/25] return expression from cell --- halo2_proofs/src/dev.rs | 6 +- halo2_proofs/src/dev/failure.rs | 6 +- halo2_proofs/src/dev/failure/emitter.rs | 2 +- halo2_proofs/src/dev/metadata.rs | 2 +- halo2_proofs/src/dev/util.rs | 6 +- halo2_proofs/src/plonk/circuit.rs | 312 +++++++++++++++++----- halo2_proofs/src/plonk/lookup/verifier.rs | 6 +- halo2_proofs/src/plonk/verifier.rs | 6 +- 8 files changed, 257 insertions(+), 89 deletions(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index b5b92d390f..dc46e78aaa 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -742,7 +742,7 @@ impl MockProver { &|scalar| Value::Real(scalar), &|_| panic!("virtual selectors are removed during optimization"), &|query| { - let query = self.cs.fixed_queries[query.index]; + let query = self.cs.fixed_queries[query.index.unwrap()]; let column_index = query.0.index(); let rotation = query.1 .0; self.fixed[column_index] @@ -750,7 +750,7 @@ impl MockProver { .into() }, &|query| { - let query = self.cs.advice_queries[query.index]; + let query = self.cs.advice_queries[query.index.unwrap()]; let column_index = query.0.index(); let rotation = query.1 .0; self.advice[column_index] @@ -758,7 +758,7 @@ impl MockProver { .into() }, &|query| { - let query = self.cs.instance_queries[query.index]; + let query = self.cs.instance_queries[query.index.unwrap()]; let column_index = query.0.index(); let rotation = query.1 .0; Value::Real( diff --git a/halo2_proofs/src/dev/failure.rs b/halo2_proofs/src/dev/failure.rs index c3c7ab93a9..79425d5cb0 100644 --- a/halo2_proofs/src/dev/failure.rs +++ b/halo2_proofs/src/dev/failure.rs @@ -59,9 +59,9 @@ impl FailureLocation { expression.evaluate( &|_| vec![], &|_| panic!("virtual selectors are removed during optimization"), - &|query| vec![cs.fixed_queries[query.index].0.into()], - &|query| vec![cs.advice_queries[query.index].0.into()], - &|query| vec![cs.instance_queries[query.index].0.into()], + &|query| vec![cs.fixed_queries[query.index.unwrap()].0.into()], + &|query| vec![cs.advice_queries[query.index.unwrap()].0.into()], + &|query| vec![cs.instance_queries[query.index.unwrap()].0.into()], &|_| vec![], &|a| a, &|mut a, mut b| { diff --git a/halo2_proofs/src/dev/failure/emitter.rs b/halo2_proofs/src/dev/failure/emitter.rs index 0e792367c7..d8df36ec16 100644 --- a/halo2_proofs/src/dev/failure/emitter.rs +++ b/halo2_proofs/src/dev/failure/emitter.rs @@ -111,7 +111,7 @@ pub(super) fn expression_to_string( label.clone() } else if query.rotation.0 == 0 { // This is most likely a merged selector - format!("S{}", query.index) + format!("S{}", query.index.unwrap()) } else { // No idea how we'd get here... format!("F{}@{}", query.column_index, query.rotation.0) diff --git a/halo2_proofs/src/dev/metadata.rs b/halo2_proofs/src/dev/metadata.rs index d7d2443e7d..d4e0c151eb 100644 --- a/halo2_proofs/src/dev/metadata.rs +++ b/halo2_proofs/src/dev/metadata.rs @@ -4,7 +4,7 @@ use crate::plonk::{self, Any}; use std::fmt; /// Metadata about a column within a circuit. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Column { /// The type of the column. pub(super) column_type: Any, diff --git a/halo2_proofs/src/dev/util.rs b/halo2_proofs/src/dev/util.rs index a4dbfe5a40..dffd9743ee 100644 --- a/halo2_proofs/src/dev/util.rs +++ b/halo2_proofs/src/dev/util.rs @@ -14,7 +14,7 @@ use crate::{ pub(crate) struct AnyQuery { /// Query index - pub index: usize, + pub index: Option, /// Column type pub column_type: Any, /// Column index @@ -80,7 +80,7 @@ pub(super) fn load<'a, F: FieldExt, T: ColumnType, Q: Into + Copy>( cells: &'a [Vec>], ) -> impl Fn(Q) -> Value + 'a { move |query| { - let (column, at) = &queries[query.into().index]; + let (column, at) = &queries[query.into().index.unwrap()]; let resolved_row = (row + at.0) % n; cells[column.index()][resolved_row as usize].into() } @@ -93,7 +93,7 @@ pub(super) fn load_instance<'a, F: FieldExt, T: ColumnType, Q: Into + cells: &'a [Vec], ) -> impl Fn(Q) -> Value + 'a { move |query| { - let (column, at) = &queries[query.into().index]; + let (column, at) = &queries[query.into().index.unwrap()]; let resolved_row = (row + at.0) % n; Value::Real(cells[column.index()][resolved_row as usize]) } diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 7ad8d8b8e1..4c38d5801a 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -1,12 +1,18 @@ use core::cmp::max; use core::ops::{Add, Mul}; use ff::Field; +use std::collections::HashMap; use std::{ convert::TryFrom, ops::{Neg, Sub}, }; +use std::cmp::Ordering; +use std::hash::{Hash, Hasher}; +use std::marker::PhantomData; +use halo2curves::FieldExt; use super::{lookup, permutation, Assigned, Error}; +use crate::dev::metadata; use crate::{ circuit::{Layouter, Region, Value}, poly::Rotation, @@ -17,21 +23,25 @@ mod compress_selectors; /// A column type pub trait ColumnType: - 'static + Sized + Copy + std::fmt::Debug + PartialEq + Eq + Into +'static + Sized + Copy + std::fmt::Debug + PartialEq + Eq + Into { + /// Return expression from cell + fn query_cell(&self, index: usize, at: Rotation) -> Expression; } + /// A column with an index and type -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct Column { index: usize, column_type: C, } impl Column { + #[cfg(test)] pub(crate) fn new(index: usize, column_type: C) -> Self { - Column { index, column_type } + Column {index, column_type, } } /// Index of this column. @@ -43,9 +53,36 @@ impl Column { pub fn column_type(&self) -> &C { &self.column_type } + + /// Return expression from cell + pub fn query_cell(&self, at: Rotation) -> Expression { + self.column_type.query_cell(self.index, at) + } + + /// Return expression from cell + pub fn cur(&self) -> Expression { + self.query_cell(Rotation::cur()) + } + + /// Return expression from cell + pub fn next(&self) -> Expression { + self.query_cell(Rotation::next()) + } + + /// Return expression from cell + pub fn prev(&self) -> Expression { + self.query_cell(Rotation::prev()) + } } -impl Ord for Column { + +impl PartialOrd for Column { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Column { fn cmp(&self, other: &Self) -> std::cmp::Ordering { // This ordering is consensus-critical! The layouters rely on deterministic column // orderings. @@ -57,12 +94,13 @@ impl Ord for Column { } } -impl PartialOrd for Column { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) +impl Hash for Column { + fn hash(&self, state: &mut H) { + self.index.hash(state); } } + pub(crate) mod sealed { /// Phase of advice column #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] @@ -74,6 +112,12 @@ pub(crate) mod sealed { } } + impl SealedPhase for Phase { + fn to_sealed(self) -> Phase { + self + } + } + /// Sealed trait to help keep `Phase` private. pub trait SealedPhase { fn to_sealed(self) -> Phase; @@ -141,6 +185,7 @@ impl Advice { pub fn phase(&self) -> u8 { self.phase.0 } + } impl std::fmt::Debug for Advice { @@ -158,6 +203,10 @@ impl std::fmt::Debug for Advice { #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub struct Fixed; +impl Fixed { + +} + /// An instance column #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub struct Instance; @@ -226,10 +275,57 @@ impl PartialOrd for Any { } } -impl ColumnType for Advice {} -impl ColumnType for Fixed {} -impl ColumnType for Instance {} -impl ColumnType for Any {} +impl ColumnType for Advice { + fn query_cell(&self, index: usize, at: Rotation) -> Expression { + Expression::Advice(AdviceQuery { + index: None, + column_index: index, + rotation: at, + phase: self.phase + }) + } +} +impl ColumnType for Fixed { + fn query_cell(&self, index: usize, at: Rotation) -> Expression { + Expression::Fixed(FixedQuery { + index: None, + column_index: index, + rotation: at, + }) + } +} +impl ColumnType for Instance { + fn query_cell(&self, index: usize, at: Rotation) -> Expression { + Expression::Instance(InstanceQuery { + index: None, + column_index: index, + rotation: at, + }) + } +} +impl ColumnType for Any { + fn query_cell(&self, index: usize, at: Rotation) -> Expression { + match self { + Any::Advice(Advice{phase}) => Expression::Advice(AdviceQuery { + index: None, + column_index: index, + rotation: at, + phase: phase.clone(), + }), + Any::Fixed => Expression::Fixed(FixedQuery { + index: None, + column_index: index, + rotation: at, + }), + Any::Instance => Expression::Instance(InstanceQuery { + index: None, + column_index: index, + rotation: at, + }), + } + } +} + impl From for Any { fn from(advice: Advice) -> Any { @@ -346,7 +442,7 @@ impl TryFrom> for Column { /// row when required: /// ``` /// use halo2_proofs::{ -/// arithmetic::FieldExt, +/// arithmetic::Field, /// circuit::{Chip, Layouter, Value}, /// plonk::{Advice, Column, Error, Selector}, /// }; @@ -359,7 +455,7 @@ impl TryFrom> for Column { /// s: Selector, /// } /// -/// fn circuit_logic>(chip: C, mut layouter: impl Layouter) -> Result<(), Error> { +/// fn circuit_logic>(chip: C, mut layouter: impl Layouter) -> Result<(), Error> { /// let config = chip.config(); /// # let config: Config = todo!(); /// layouter.assign_region(|| "bar", |mut region| { @@ -390,7 +486,7 @@ impl Selector { #[derive(Copy, Clone, Debug)] pub struct FixedQuery { /// Query index - pub(crate) index: usize, + pub(crate) index: Option, /// Column index pub(crate) column_index: usize, /// Rotation of this query @@ -413,7 +509,7 @@ impl FixedQuery { #[derive(Copy, Clone, Debug)] pub struct AdviceQuery { /// Query index - pub(crate) index: usize, + pub(crate) index: Option, /// Column index pub(crate) column_index: usize, /// Rotation of this query @@ -443,7 +539,7 @@ impl AdviceQuery { #[derive(Copy, Clone, Debug)] pub struct InstanceQuery { /// Query index - pub(crate) index: usize, + pub(crate) index: Option, /// Column index pub(crate) column_index: usize, /// Rotation of this query @@ -494,7 +590,7 @@ impl TableColumn { #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub struct Challenge { index: usize, - phase: sealed::Phase, + pub(crate) phase: sealed::Phase, } impl Challenge { @@ -520,9 +616,17 @@ pub trait Assignment { /// /// [`Layouter::assign_region`]: crate::circuit::Layouter#method.assign_region fn enter_region(&mut self, name_fn: N) - where - NR: Into, - N: FnOnce() -> NR; + where + NR: Into, + N: FnOnce() -> NR; + + // /// Allows the developer to include an annotation for an specific column within a `Region`. + // /// + // /// This is usually useful for debugging circuit failures. + // fn annotate_column(&mut self, annotation: A, column: Column) + // where + // A: FnOnce() -> AR, + // AR: Into; /// Exits the current region. /// @@ -540,9 +644,9 @@ pub trait Assignment { selector: &Selector, row: usize, ) -> Result<(), Error> - where - A: FnOnce() -> AR, - AR: Into; + where + A: FnOnce() -> AR, + AR: Into; /// Queries the cell of an instance column at a particular absolute row. /// @@ -557,11 +661,11 @@ pub trait Assignment { row: usize, to: V, ) -> Result<(), Error> - where - V: FnOnce() -> Value, - VR: Into>, - A: FnOnce() -> AR, - AR: Into; + where + V: FnOnce() -> Value, + VR: Into>, + A: FnOnce() -> AR, + AR: Into; /// Assign a fixed value fn assign_fixed( @@ -571,11 +675,11 @@ pub trait Assignment { row: usize, to: V, ) -> Result<(), Error> - where - V: FnOnce() -> Value, - VR: Into>, - A: FnOnce() -> AR, - AR: Into; + where + V: FnOnce() -> Value, + VR: Into>, + A: FnOnce() -> AR, + AR: Into; /// Assign two cells to have the same value fn copy( @@ -605,9 +709,9 @@ pub trait Assignment { /// /// [`Layouter::namespace`]: crate::circuit::Layouter#method.namespace fn push_namespace(&mut self, name_fn: N) - where - NR: Into, - N: FnOnce() -> NR; + where + NR: Into, + N: FnOnce() -> NR; /// Exits out of the existing namespace. /// @@ -689,7 +793,10 @@ pub enum Expression { Scaled(Box>, F), } + + impl Expression { + /// Evaluate the polynomial using the provided closures to perform the /// operations. pub fn evaluate( @@ -925,40 +1032,69 @@ impl Expression { } } - /// Identifier for this expression. Expressions with identical identifiers - /// do the same calculation (but the expressions don't need to be exactly equal - /// in how they are composed e.g. `1 + 2` and `2 + 1` can have the same identifier). - pub fn identifier(&self) -> String { + fn write_identifier(&self, writer: &mut W) -> std::io::Result<()> { match self { - Expression::Constant(scalar) => format!("{:?}", scalar), - Expression::Selector(selector) => format!("selector[{}]", selector.0), + Expression::Constant(scalar) => write!(writer, "{:?}", scalar), + Expression::Selector(selector) => write!(writer, "selector[{}]", selector.0), Expression::Fixed(query) => { - format!("fixed[{}][{}]", query.column_index, query.rotation.0) + write!( + writer, + "fixed[{}][{}]", + query.column_index, query.rotation.0 + ) } Expression::Advice(query) => { - format!("advice[{}][{}]", query.column_index, query.rotation.0) + write!( + writer, + "advice[{}][{}]", + query.column_index, query.rotation.0 + ) } Expression::Instance(query) => { - format!("instance[{}][{}]", query.column_index, query.rotation.0) + write!( + writer, + "instance[{}][{}]", + query.column_index, query.rotation.0 + ) } Expression::Challenge(challenge) => { - format!("challenge[{}]", challenge.index()) + write!(writer, "challenge[{}]", challenge.index()) } Expression::Negated(a) => { - format!("(-{})", a.identifier()) + writer.write_all(b"(-")?; + a.write_identifier(writer)?; + writer.write_all(b")") } Expression::Sum(a, b) => { - format!("({}+{})", a.identifier(), b.identifier()) + writer.write_all(b"(")?; + a.write_identifier(writer)?; + writer.write_all(b"+")?; + b.write_identifier(writer)?; + writer.write_all(b")") } Expression::Product(a, b) => { - format!("({}*{})", a.identifier(), b.identifier()) + writer.write_all(b"(")?; + a.write_identifier(writer)?; + writer.write_all(b"*")?; + b.write_identifier(writer)?; + writer.write_all(b")") } Expression::Scaled(a, f) => { - format!("{}*{:?}", a.identifier(), f) + a.write_identifier(writer)?; + write!(writer, "*{:?}", f) } } } + /// Identifier for this expression. Expressions with identical identifiers + /// do the same calculation (but the expressions don't need to be exactly equal + /// in how they are composed e.g. `1 + 2` and `2 + 1` can have the same identifier). + pub fn identifier(&self) -> String { + let mut cursor = std::io::Cursor::new(Vec::new()); + self.write_identifier(&mut cursor).unwrap(); + String::from_utf8(cursor.into_inner()).unwrap() + } + /// Compute the degree of this polynomial pub fn degree(&self) -> usize { match self { @@ -1048,21 +1184,21 @@ impl std::fmt::Debug for Expression { Expression::Selector(selector) => f.debug_tuple("Selector").field(selector).finish(), // Skip enum variant and print query struct directly to maintain backwards compatibility. Expression::Fixed(FixedQuery { - index, - column_index, - rotation, - }) => f + index, + column_index, + rotation, + }) => f .debug_struct("Fixed") .field("query_index", index) .field("column_index", column_index) .field("rotation", rotation) .finish(), Expression::Advice(AdviceQuery { - index, - column_index, - rotation, - phase, - }) => { + index, + column_index, + rotation, + phase, + }) => { let mut debug_struct = f.debug_struct("Advice"); debug_struct .field("query_index", index) @@ -1075,10 +1211,10 @@ impl std::fmt::Debug for Expression { debug_struct.finish() } Expression::Instance(InstanceQuery { - index, - column_index, - rotation, - }) => f + index, + column_index, + rotation, + }) => f .debug_struct("Instance") .field("query_index", index) .field("column_index", column_index) @@ -1261,7 +1397,7 @@ type ConstraintsIterator = std::iter::Map< >; impl>, Iter: IntoIterator> IntoIterator - for Constraints +for Constraints { type Item = Constraint; type IntoIter = ConstraintsIterator; @@ -1344,6 +1480,9 @@ pub struct ConstraintSystem { // input expressions and a sequence of table expressions involved in the lookup. pub(crate) lookups: Vec>, + // List of indexes of Fixed columns which are associated to a circuit-general Column tied to their annotation. + pub(crate) general_column_annotations: HashMap, + // Vector of fixed columns, which can be used to store constant values // that are copied into advice columns. pub(crate) constants: Vec>, @@ -1427,6 +1566,7 @@ impl Default for ConstraintSystem { instance_queries: Vec::new(), permutation: permutation::Argument::new(), lookups: Vec::new(), + general_column_annotations: HashMap::new(), constants: vec![], minimum_degree: None, } @@ -1716,7 +1856,7 @@ impl ConstraintSystem { let column = self.fixed_column(); new_columns.push(column); Expression::Fixed(FixedQuery { - index: self.query_fixed_index(column, Rotation::cur()), + index: Some(self.query_fixed_index(column, Rotation::cur())), column_index: column.index, rotation: Rotation::cur(), }) @@ -1811,6 +1951,34 @@ impl ConstraintSystem { } } + /// Annotate a Lookup column. + pub fn annotate_lookup_column(&mut self, column: TableColumn, annotation: A) + where + A: Fn() -> AR, + AR: Into, + { + // We don't care if the table has already an annotation. If it's the case we keep the new one. + self.general_column_annotations.insert( + metadata::Column::from((Any::Fixed, column.inner().index)), + annotation().into(), + ); + } + + /// Annotate an Instance column. + pub fn annotate_lookup_any_column(&mut self, column: T, annotation: A) + where + A: Fn() -> AR, + AR: Into, + T: Into>, + { + let col_any = column.into(); + // We don't care if the table has already an annotation. If it's the case we keep the new one. + self.general_column_annotations.insert( + metadata::Column::from((col_any.column_type, col_any.index)), + annotation().into(), + ); + } + /// Allocate a new fixed column pub fn fixed_column(&mut self) -> Column { let tmp = Column { @@ -1965,9 +2133,9 @@ impl ConstraintSystem { self.blinding_factors() // m blinding factors + 1 // for l_{-(m + 1)} (l_last) + 1 // for l_0 (just for extra breathing room for the permutation - // argument, to essentially force a separation in the - // permutation polynomial between the roles of l_last, l_0 - // and the interstitial values.) + // argument, to essentially force a separation in the + // permutation polynomial between the roles of l_last, l_0 + // and the interstitial values.) + 1 // for at least one row } @@ -2068,17 +2236,17 @@ impl<'a, F: Field> VirtualCells<'a, F> { pub fn query_fixed(&mut self, column: Column, at: Rotation) -> Expression { self.queried_cells.push((column, at).into()); Expression::Fixed(FixedQuery { - index: self.meta.query_fixed_index(column, at), + index: Some(self.meta.query_fixed_index(column, at)), column_index: column.index, rotation: at, }) } /// Query an advice column at a relative position - pub fn query_advice(&mut self, column: Column, at: Rotation) -> Expression { + pub fn query_advice(&mut self, column: Column, at: Rotation) -> Expression { self.queried_cells.push((column, at).into()); Expression::Advice(AdviceQuery { - index: self.meta.query_advice_index(column, at), + index: Some(self.meta.query_advice_index(column, at)), column_index: column.index, rotation: at, phase: column.column_type().phase, @@ -2089,7 +2257,7 @@ impl<'a, F: Field> VirtualCells<'a, F> { pub fn query_instance(&mut self, column: Column, at: Rotation) -> Expression { self.queried_cells.push((column, at).into()); Expression::Instance(InstanceQuery { - index: self.meta.query_instance_index(column, at), + index: Some(self.meta.query_instance_index(column, at)), column_index: column.index, rotation: at, }) diff --git a/halo2_proofs/src/plonk/lookup/verifier.rs b/halo2_proofs/src/plonk/lookup/verifier.rs index 88041c29b3..bb916d0c0f 100644 --- a/halo2_proofs/src/plonk/lookup/verifier.rs +++ b/halo2_proofs/src/plonk/lookup/verifier.rs @@ -120,9 +120,9 @@ impl Evaluated { expression.evaluate( &|scalar| scalar, &|_| panic!("virtual selectors are removed during optimization"), - &|query| fixed_evals[query.index], - &|query| advice_evals[query.index], - &|query| instance_evals[query.index], + &|query| fixed_evals[query.index.unwrap()], + &|query| advice_evals[query.index.unwrap()], + &|query| instance_evals[query.index.unwrap()], &|challenge| challenges[challenge.index()], &|a| -a, &|a, b| a + &b, diff --git a/halo2_proofs/src/plonk/verifier.rs b/halo2_proofs/src/plonk/verifier.rs index 0163b9fef3..ae1637799b 100644 --- a/halo2_proofs/src/plonk/verifier.rs +++ b/halo2_proofs/src/plonk/verifier.rs @@ -215,9 +215,9 @@ pub fn verify_proof< poly.evaluate( &|scalar| scalar, &|_| panic!("virtual selectors are removed during optimization"), - &|query| fixed_evals[query.index], - &|query| advice_evals[query.index], - &|query| instance_evals[query.index], + &|query| fixed_evals[query.index.unwrap()], + &|query| advice_evals[query.index.unwrap()], + &|query| instance_evals[query.index.unwrap()], &|challenge| challenges[challenge.index()], &|a| -a, &|a, b| a + &b, From d0450f649aa2ddd31f0bf25b0f464e8cfe79b536 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Tue, 21 Feb 2023 19:34:11 +0800 Subject: [PATCH 02/25] add example --- halo2_proofs/examples/simple-example-2.rs | 323 ++++++++++++++++++++++ halo2_proofs/src/plonk/circuit.rs | 1 + 2 files changed, 324 insertions(+) create mode 100644 halo2_proofs/examples/simple-example-2.rs diff --git a/halo2_proofs/examples/simple-example-2.rs b/halo2_proofs/examples/simple-example-2.rs new file mode 100644 index 0000000000..a5d96afc03 --- /dev/null +++ b/halo2_proofs/examples/simple-example-2.rs @@ -0,0 +1,323 @@ +use std::marker::PhantomData; + +use halo2_proofs::{ + arithmetic::FieldExt, + circuit::{AssignedCell, Chip, Layouter, Region, SimpleFloorPlanner, Value}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance, Selector}, + poly::Rotation, +}; + +// ANCHOR: instructions +trait NumericInstructions: Chip { + /// Variable representing a number. + type Num; + + /// Loads a number into the circuit as a private input. + fn load_private(&self, layouter: impl Layouter, a: Value) -> Result; + + /// Loads a number into the circuit as a fixed constant. + fn load_constant(&self, layouter: impl Layouter, constant: F) -> Result; + + /// Returns `c = a * b`. + fn mul( + &self, + layouter: impl Layouter, + a: Self::Num, + b: Self::Num, + ) -> Result; + + /// Exposes a number as a public input to the circuit. + fn expose_public( + &self, + layouter: impl Layouter, + num: Self::Num, + row: usize, + ) -> Result<(), Error>; +} +// ANCHOR_END: instructions + +// ANCHOR: chip +/// The chip that will implement our instructions! Chips store their own +/// config, as well as type markers if necessary. +struct FieldChip { + config: FieldConfig, + _marker: PhantomData, +} +// ANCHOR_END: chip + +// ANCHOR: chip-config +/// Chip state is stored in a config struct. This is generated by the chip +/// during configuration, and then stored inside the chip. +#[derive(Clone, Debug)] +struct FieldConfig { + /// For this chip, we will use two advice columns to implement our instructions. + /// These are also the columns through which we communicate with other parts of + /// the circuit. + advice: [Column; 2], + + /// This is the public input (instance) column. + instance: Column, + + // We need a selector to enable the multiplication gate, so that we aren't placing + // any constraints on cells where `NumericInstructions::mul` is not being used. + // This is important when building larger circuits, where columns are used by + // multiple sets of instructions. + s_mul: Selector, +} + +impl FieldChip { + fn construct(config: >::Config) -> Self { + Self { + config, + _marker: PhantomData, + } + } + + fn configure( + meta: &mut ConstraintSystem, + advice: [Column; 2], + instance: Column, + constant: Column, + ) -> >::Config { + meta.enable_equality(instance); + meta.enable_constant(constant); + for column in &advice { + meta.enable_equality(*column); + } + let s_mul = meta.selector(); + + // Define our multiplication gate! + meta.create_gate("mul", |meta| { + + // let lhs = meta.query_advice(advice[0], Rotation::cur()); + // let rhs = meta.query_advice(advice[1], Rotation::cur()); + // let out = meta.query_advice(advice[0], Rotation::next()); + let s_mul = meta.query_selector(s_mul); + // vec![s_mul * (lhs * rhs - out)] + + vec![s_mul * (advice[0].cur() * advice[1].cur() - advice[0].next())] + + }); + + FieldConfig { + advice, + instance, + s_mul, + } + } +} +// ANCHOR_END: chip-config + +// ANCHOR: chip-impl +impl Chip for FieldChip { + type Config = FieldConfig; + type Loaded = (); + + fn config(&self) -> &Self::Config { + &self.config + } + + fn loaded(&self) -> &Self::Loaded { + &() + } +} +// ANCHOR_END: chip-impl + +// ANCHOR: instructions-impl +/// A variable representing a number. +#[derive(Clone)] +struct Number(AssignedCell); + +impl NumericInstructions for FieldChip { + type Num = Number; + + fn load_private( + &self, + mut layouter: impl Layouter, + value: Value, + ) -> Result { + let config = self.config(); + + layouter.assign_region( + || "load private", + |mut region| { + region + .assign_advice(|| "private input", config.advice[0], 0, || value) + .map(Number) + }, + ) + } + + fn load_constant( + &self, + mut layouter: impl Layouter, + constant: F, + ) -> Result { + let config = self.config(); + + layouter.assign_region( + || "load constant", + |mut region| { + region + .assign_advice_from_constant(|| "constant value", config.advice[0], 0, constant) + .map(Number) + }, + ) + } + + fn mul( + &self, + mut layouter: impl Layouter, + a: Self::Num, + b: Self::Num, + ) -> Result { + let config = self.config(); + + layouter.assign_region( + || "mul", + |mut region: Region<'_, F>| { + // We only want to use a single multiplication gate in this region, + // so we enable it at region offset 0; this means it will constrain + // cells at offsets 0 and 1. + config.s_mul.enable(&mut region, 0)?; + + // The inputs we've been given could be located anywhere in the circuit, + // but we can only rely on relative offsets inside this region. So we + // assign new cells inside the region and constrain them to have the + // same values as the inputs. + a.0.copy_advice(|| "lhs", &mut region, config.advice[0], 0)?; + b.0.copy_advice(|| "rhs", &mut region, config.advice[1], 0)?; + + // Now we can assign the multiplication result, which is to be assigned + // into the output position. + let value = a.0.value().copied() * b.0.value(); + + // Finally, we do the assignment to the output, returning a + // variable to be used in another part of the circuit. + region + .assign_advice(|| "lhs * rhs", config.advice[0], 1, || value) + .map(Number) + }, + ) + } + + fn expose_public( + &self, + mut layouter: impl Layouter, + num: Self::Num, + row: usize, + ) -> Result<(), Error> { + let config = self.config(); + + layouter.constrain_instance(num.0.cell(), config.instance, row) + } +} +// ANCHOR_END: instructions-impl + +// ANCHOR: circuit +/// The full circuit implementation. +/// +/// In this struct we store the private input variables. We use `Option` because +/// they won't have any value during key generation. During proving, if any of these +/// were `None` we would get an error. +#[derive(Default)] +struct MyCircuit { + constant: F, + a: Value, + b: Value, +} + +impl Circuit for MyCircuit { + // Since we are using a single chip for everything, we can just reuse its config. + type Config = FieldConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + // We create the two advice columns that FieldChip uses for I/O. + let advice = [meta.advice_column(), meta.advice_column()]; + + // We also need an instance column to store public inputs. + let instance = meta.instance_column(); + + // Create a fixed column to load constants. + let constant = meta.fixed_column(); + + FieldChip::configure(meta, advice, instance, constant) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let field_chip = FieldChip::::construct(config); + + // Load our private values into the circuit. + let a = field_chip.load_private(layouter.namespace(|| "load a"), self.a)?; + let b = field_chip.load_private(layouter.namespace(|| "load b"), self.b)?; + + // Load the constant factor into the circuit. + let constant = + field_chip.load_constant(layouter.namespace(|| "load constant"), self.constant)?; + + // We only have access to plain multiplication. + // We could implement our circuit as: + // asq = a*a + // bsq = b*b + // absq = asq*bsq + // c = constant*asq*bsq + // + // but it's more efficient to implement it as: + // ab = a*b + // absq = ab^2 + // c = constant*absq + let ab = field_chip.mul(layouter.namespace(|| "a * b"), a, b)?; + let absq = field_chip.mul(layouter.namespace(|| "ab * ab"), ab.clone(), ab)?; + let c = field_chip.mul(layouter.namespace(|| "constant * absq"), constant, absq)?; + + // Expose the result as a public input to the circuit. + field_chip.expose_public(layouter.namespace(|| "expose c"), c, 0) + } +} +// ANCHOR_END: circuit + +fn main() { + use halo2_proofs::dev::MockProver; + use halo2curves::pasta::Fp; + + // ANCHOR: test-circuit + // The number of rows in our circuit cannot exceed 2^k. Since our example + // circuit is very small, we can pick a very small value here. + let k = 4; + + // Prepare the private and public inputs to the circuit! + let constant = Fp::from(7); + let a = Fp::from(2); + let b = Fp::from(3); + let c = constant * a.square() * b.square(); + + // Instantiate the circuit with the private inputs. + let circuit = MyCircuit { + constant, + a: Value::known(a), + b: Value::known(b), + }; + + // Arrange the public input. We expose the multiplication result in row 0 + // of the instance column, so we position it there in our public inputs. + let mut public_inputs = vec![c]; + + // Given the correct public input, our circuit will verify. + let prover = MockProver::run(k, &circuit, vec![public_inputs.clone()]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + + // If we try some other public input, the proof will fail! + public_inputs[0] += Fp::one(); + let prover = MockProver::run(k, &circuit, vec![public_inputs]).unwrap(); + assert!(prover.verify().is_err()); + // ANCHOR_END: test-circuit +} diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 4c38d5801a..14a317735b 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -480,6 +480,7 @@ impl Selector { pub fn is_simple(&self) -> bool { self.1 } + } /// Query of fixed column at a certain relative location From 680a5830966ab1bbf3771be6bfddeb50ee322dff Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Tue, 21 Feb 2023 20:21:55 +0800 Subject: [PATCH 03/25] selector --- halo2_proofs/examples/simple-example-2.rs | 4 ++-- halo2_proofs/src/plonk/circuit.rs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/halo2_proofs/examples/simple-example-2.rs b/halo2_proofs/examples/simple-example-2.rs index a5d96afc03..01b5586316 100644 --- a/halo2_proofs/examples/simple-example-2.rs +++ b/halo2_proofs/examples/simple-example-2.rs @@ -92,10 +92,10 @@ impl FieldChip { // let lhs = meta.query_advice(advice[0], Rotation::cur()); // let rhs = meta.query_advice(advice[1], Rotation::cur()); // let out = meta.query_advice(advice[0], Rotation::next()); - let s_mul = meta.query_selector(s_mul); + // let s_mul = meta.query_selector(s_mul); // vec![s_mul * (lhs * rhs - out)] - vec![s_mul * (advice[0].cur() * advice[1].cur() - advice[0].next())] + vec![s_mul.expr() * (advice[0].cur() * advice[1].cur() - advice[0].next())] }); diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 14a317735b..3beceb92d2 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -481,6 +481,12 @@ impl Selector { self.1 } + /// Return expression from selector + pub fn expr(&self) -> Expression { + Expression::Selector(*self) + } + + } /// Query of fixed column at a certain relative location From 4ac383d73aa3b7c8e203880c09379208456972f6 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Wed, 22 Feb 2023 13:49:45 +0800 Subject: [PATCH 04/25] recurse Expression to fill in index --- halo2_proofs/src/plonk/circuit.rs | 73 +++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 4 deletions(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 3beceb92d2..ff1fee09bf 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -804,6 +804,40 @@ pub enum Expression { impl Expression { + /// Make side effects + pub fn load_to_virtual_cells(&mut self, cells: &mut VirtualCells<'_, F>) { + match self { + Expression::Constant(_) => (), + Expression::Selector(_) => (), + Expression::Fixed(query) => { + let col = Column{ index: query.column_index, column_type: Fixed}; + cells.queried_cells.push((col, query.rotation).into()); + query.index = Some(cells.meta.query_fixed_index(col, query.rotation)); + }, + Expression::Advice(query) => { + let col = Column{ index: query.column_index, column_type: Advice{phase: query.phase}}; + cells.queried_cells.push((col, query.rotation).into()); + query.index = Some(cells.meta.query_advice_index(col, query.rotation)); + } + Expression::Instance(query) => { + let col = Column{ index: query.column_index, column_type: Instance}; + cells.queried_cells.push((col, query.rotation).into()); + query.index = Some(cells.meta.query_instance_index(col, query.rotation)); + }, + Expression::Challenge(_) => (), + Expression::Negated(a) => a.load_to_virtual_cells(cells), + Expression::Sum(a, b) => { + a.load_to_virtual_cells(cells); + b.load_to_virtual_cells(cells); + }, + Expression::Product(a, b) => { + a.load_to_virtual_cells(cells); + b.load_to_virtual_cells(cells); + }, + Expression::Scaled(a, _) => a.load_to_virtual_cells(cells), + }; + } + /// Evaluate the polynomial using the provided closures to perform the /// operations. pub fn evaluate( @@ -1306,6 +1340,34 @@ impl>> From<(Col, Rotation)> for VirtualCell { } } +// impl From for VirtualCell { +// fn from(query: FixedQuery) -> VirtualCell{ +// VirtualCell{ +// column: Column {index: query.column_index, column_type: Any::from(Fixed) }, +// rotation: query.rotation +// } +// } +// } +// +// impl From for VirtualCell { +// fn from(query: AdviceQuery) -> VirtualCell{ +// VirtualCell{ +// column: Column {index: query.column_index, column_type: Advice(Advice{phase: query.phase})}, +// rotation: query.rotation +// } +// } +// } +// +// impl From for VirtualCell { +// fn from(query: InstanceQuery) -> VirtualCell{ +// VirtualCell{ +// column: Column {index: query.column_index, column_type: Any::from(Instance) }, +// rotation: query.rotation +// } +// } +// } + + /// An individual polynomial constraint. /// /// These are returned by the closures passed to `ConstraintSystem::create_gate`. @@ -1794,15 +1856,18 @@ impl ConstraintSystem { ) { let mut cells = VirtualCells::new(self); let constraints = constraints(&mut cells); - let queried_selectors = cells.queried_selectors; - let queried_cells = cells.queried_cells; - let (constraint_names, polys): (_, Vec<_>) = constraints .into_iter() .map(|c| c.into()) - .map(|c| (c.name, c.poly)) + .map(|mut c: Constraint| { + c.poly.load_to_virtual_cells(&mut cells); + (c.name, c.poly) + }) .unzip(); + let queried_selectors = cells.queried_selectors; + let queried_cells = cells.queried_cells; + assert!( !polys.is_empty(), "Gates must contain at least one constraint." From e8c79c9b910e591570b8f692e70728a323bf6d36 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Thu, 23 Feb 2023 19:06:10 +0800 Subject: [PATCH 05/25] minimized changes from the original --- halo2_proofs/examples/simple-example-2.rs | 2 - halo2_proofs/src/plonk/circuit.rs | 212 +++++++++------------- 2 files changed, 84 insertions(+), 130 deletions(-) diff --git a/halo2_proofs/examples/simple-example-2.rs b/halo2_proofs/examples/simple-example-2.rs index 01b5586316..36f38e8377 100644 --- a/halo2_proofs/examples/simple-example-2.rs +++ b/halo2_proofs/examples/simple-example-2.rs @@ -88,7 +88,6 @@ impl FieldChip { // Define our multiplication gate! meta.create_gate("mul", |meta| { - // let lhs = meta.query_advice(advice[0], Rotation::cur()); // let rhs = meta.query_advice(advice[1], Rotation::cur()); // let out = meta.query_advice(advice[0], Rotation::next()); @@ -96,7 +95,6 @@ impl FieldChip { // vec![s_mul * (lhs * rhs - out)] vec![s_mul.expr() * (advice[0].cur() * advice[1].cur() - advice[0].next())] - }); FieldConfig { diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index cee5e3fdbe..9639e87d0f 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -1,47 +1,41 @@ +use super::{lookup, permutation, Assigned, Error}; +use crate::dev::metadata; +use crate::{ + circuit::{Layouter, Region, Value}, + poly::Rotation, +}; use core::cmp::max; use core::ops::{Add, Mul}; use ff::Field; +use sealed::SealedPhase; +use std::cmp::Ordering; use std::collections::HashMap; use std::{ convert::TryFrom, ops::{Neg, Sub}, }; -use std::cmp::Ordering; -use std::hash::{Hash, Hasher}; -use std::marker::PhantomData; -use halo2curves::FieldExt; - -use super::{lookup, permutation, Assigned, Error}; -use crate::dev::metadata; -use crate::{ - circuit::{Layouter, Region, Value}, - poly::Rotation, -}; -use sealed::SealedPhase; mod compress_selectors; /// A column type pub trait ColumnType: -'static + Sized + Copy + std::fmt::Debug + PartialEq + Eq + Into + 'static + Sized + Copy + std::fmt::Debug + PartialEq + Eq + Into { /// Return expression from cell fn query_cell(&self, index: usize, at: Rotation) -> Expression; } - /// A column with an index and type -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub struct Column { index: usize, column_type: C, } impl Column { - #[cfg(test)] pub(crate) fn new(index: usize, column_type: C) -> Self { - Column {index, column_type, } + Column { index, column_type } } /// Index of this column. @@ -75,14 +69,7 @@ impl Column { } } - -impl PartialOrd for Column { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Column { +impl Ord for Column { fn cmp(&self, other: &Self) -> std::cmp::Ordering { // This ordering is consensus-critical! The layouters rely on deterministic column // orderings. @@ -94,13 +81,12 @@ impl Ord for Column { } } -impl Hash for Column { - fn hash(&self, state: &mut H) { - self.index.hash(state); +impl PartialOrd for Column { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) } } - pub(crate) mod sealed { /// Phase of advice column #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] @@ -185,7 +171,6 @@ impl Advice { pub fn phase(&self) -> u8 { self.phase.0 } - } impl std::fmt::Debug for Advice { @@ -203,10 +188,6 @@ impl std::fmt::Debug for Advice { #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub struct Fixed; -impl Fixed { - -} - /// An instance column #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub struct Instance; @@ -281,7 +262,7 @@ impl ColumnType for Advice { index: None, column_index: index, rotation: at, - phase: self.phase + phase: self.phase, }) } } @@ -306,7 +287,7 @@ impl ColumnType for Instance { impl ColumnType for Any { fn query_cell(&self, index: usize, at: Rotation) -> Expression { match self { - Any::Advice(Advice{phase}) => Expression::Advice(AdviceQuery { + Any::Advice(Advice { phase }) => Expression::Advice(AdviceQuery { index: None, column_index: index, rotation: at, @@ -326,7 +307,6 @@ impl ColumnType for Any { } } - impl From for Any { fn from(advice: Advice) -> Any { Any::Advice(advice) @@ -442,7 +422,7 @@ impl TryFrom> for Column { /// row when required: /// ``` /// use halo2_proofs::{ -/// arithmetic::Field, +/// arithmetic::FieldExt, /// circuit::{Chip, Layouter, Value}, /// plonk::{Advice, Column, Error, Selector}, /// }; @@ -455,7 +435,7 @@ impl TryFrom> for Column { /// s: Selector, /// } /// -/// fn circuit_logic>(chip: C, mut layouter: impl Layouter) -> Result<(), Error> { +/// fn circuit_logic>(chip: C, mut layouter: impl Layouter) -> Result<(), Error> { /// let config = chip.config(); /// # let config: Config = todo!(); /// layouter.assign_region(|| "bar", |mut region| { @@ -485,8 +465,6 @@ impl Selector { pub fn expr(&self) -> Expression { Expression::Selector(*self) } - - } /// Query of fixed column at a certain relative location @@ -623,9 +601,9 @@ pub trait Assignment { /// /// [`Layouter::assign_region`]: crate::circuit::Layouter#method.assign_region fn enter_region(&mut self, name_fn: N) - where - NR: Into, - N: FnOnce() -> NR; + where + NR: Into, + N: FnOnce() -> NR; // /// Allows the developer to include an annotation for an specific column within a `Region`. // /// @@ -659,9 +637,9 @@ pub trait Assignment { selector: &Selector, row: usize, ) -> Result<(), Error> - where - A: FnOnce() -> AR, - AR: Into; + where + A: FnOnce() -> AR, + AR: Into; /// Queries the cell of an instance column at a particular absolute row. /// @@ -676,11 +654,11 @@ pub trait Assignment { row: usize, to: V, ) -> Result<(), Error> - where - V: FnOnce() -> Value, - VR: Into>, - A: FnOnce() -> AR, - AR: Into; + where + V: FnOnce() -> Value, + VR: Into>, + A: FnOnce() -> AR, + AR: Into; /// Assign a fixed value fn assign_fixed( @@ -690,11 +668,11 @@ pub trait Assignment { row: usize, to: V, ) -> Result<(), Error> - where - V: FnOnce() -> Value, - VR: Into>, - A: FnOnce() -> AR, - AR: Into; + where + V: FnOnce() -> Value, + VR: Into>, + A: FnOnce() -> AR, + AR: Into; /// Assign two cells to have the same value fn copy( @@ -724,9 +702,9 @@ pub trait Assignment { /// /// [`Layouter::namespace`]: crate::circuit::Layouter#method.namespace fn push_namespace(&mut self, name_fn: N) - where - NR: Into, - N: FnOnce() -> NR; + where + NR: Into, + N: FnOnce() -> NR; /// Exits out of the existing namespace. /// @@ -808,41 +786,47 @@ pub enum Expression { Scaled(Box>, F), } - - impl Expression { - /// Make side effects - pub fn load_to_virtual_cells(&mut self, cells: &mut VirtualCells<'_, F>) { + pub fn query_cells(&mut self, cells: &mut VirtualCells<'_, F>) { match self { Expression::Constant(_) => (), Expression::Selector(_) => (), Expression::Fixed(query) => { - let col = Column{ index: query.column_index, column_type: Fixed}; + let col = Column { + index: query.column_index, + column_type: Fixed, + }; cells.queried_cells.push((col, query.rotation).into()); query.index = Some(cells.meta.query_fixed_index(col, query.rotation)); - }, + } Expression::Advice(query) => { - let col = Column{ index: query.column_index, column_type: Advice{phase: query.phase}}; + let col = Column { + index: query.column_index, + column_type: Advice { phase: query.phase }, + }; cells.queried_cells.push((col, query.rotation).into()); query.index = Some(cells.meta.query_advice_index(col, query.rotation)); } Expression::Instance(query) => { - let col = Column{ index: query.column_index, column_type: Instance}; + let col = Column { + index: query.column_index, + column_type: Instance, + }; cells.queried_cells.push((col, query.rotation).into()); query.index = Some(cells.meta.query_instance_index(col, query.rotation)); - }, + } Expression::Challenge(_) => (), - Expression::Negated(a) => a.load_to_virtual_cells(cells), + Expression::Negated(a) => a.query_cells(cells), Expression::Sum(a, b) => { - a.load_to_virtual_cells(cells); - b.load_to_virtual_cells(cells); - }, + a.query_cells(cells); + b.query_cells(cells); + } Expression::Product(a, b) => { - a.load_to_virtual_cells(cells); - b.load_to_virtual_cells(cells); - }, - Expression::Scaled(a, _) => a.load_to_virtual_cells(cells), + a.query_cells(cells); + b.query_cells(cells); + } + Expression::Scaled(a, _) => a.query_cells(cells), }; } @@ -1233,21 +1217,21 @@ impl std::fmt::Debug for Expression { Expression::Selector(selector) => f.debug_tuple("Selector").field(selector).finish(), // Skip enum variant and print query struct directly to maintain backwards compatibility. Expression::Fixed(FixedQuery { - index, - column_index, - rotation, - }) => f + index, + column_index, + rotation, + }) => f .debug_struct("Fixed") .field("query_index", index) .field("column_index", column_index) .field("rotation", rotation) .finish(), Expression::Advice(AdviceQuery { - index, - column_index, - rotation, - phase, - }) => { + index, + column_index, + rotation, + phase, + }) => { let mut debug_struct = f.debug_struct("Advice"); debug_struct .field("query_index", index) @@ -1260,10 +1244,10 @@ impl std::fmt::Debug for Expression { debug_struct.finish() } Expression::Instance(InstanceQuery { - index, - column_index, - rotation, - }) => f + index, + column_index, + rotation, + }) => f .debug_struct("Instance") .field("query_index", index) .field("column_index", column_index) @@ -1348,34 +1332,6 @@ impl>> From<(Col, Rotation)> for VirtualCell { } } -// impl From for VirtualCell { -// fn from(query: FixedQuery) -> VirtualCell{ -// VirtualCell{ -// column: Column {index: query.column_index, column_type: Any::from(Fixed) }, -// rotation: query.rotation -// } -// } -// } -// -// impl From for VirtualCell { -// fn from(query: AdviceQuery) -> VirtualCell{ -// VirtualCell{ -// column: Column {index: query.column_index, column_type: Advice(Advice{phase: query.phase})}, -// rotation: query.rotation -// } -// } -// } -// -// impl From for VirtualCell { -// fn from(query: InstanceQuery) -> VirtualCell{ -// VirtualCell{ -// column: Column {index: query.column_index, column_type: Any::from(Instance) }, -// rotation: query.rotation -// } -// } -// } - - /// An individual polynomial constraint. /// /// These are returned by the closures passed to `ConstraintSystem::create_gate`. @@ -1474,7 +1430,7 @@ type ConstraintsIterator = std::iter::Map< >; impl>, Iter: IntoIterator> IntoIterator -for Constraints + for Constraints { type Item = Constraint; type IntoIter = ConstraintsIterator; @@ -1868,7 +1824,7 @@ impl ConstraintSystem { .into_iter() .map(|c| c.into()) .map(|mut c: Constraint| { - c.poly.load_to_virtual_cells(&mut cells); + c.poly.query_cells(&mut cells); (c.name, c.poly) }) .unzip(); @@ -2033,9 +1989,9 @@ impl ConstraintSystem { /// Annotate a Lookup column. pub fn annotate_lookup_column(&mut self, column: TableColumn, annotation: A) - where - A: Fn() -> AR, - AR: Into, + where + A: Fn() -> AR, + AR: Into, { // We don't care if the table has already an annotation. If it's the case we keep the new one. self.general_column_annotations.insert( @@ -2046,10 +2002,10 @@ impl ConstraintSystem { /// Annotate an Instance column. pub fn annotate_lookup_any_column(&mut self, column: T, annotation: A) - where - A: Fn() -> AR, - AR: Into, - T: Into>, + where + A: Fn() -> AR, + AR: Into, + T: Into>, { let col_any = column.into(); // We don't care if the table has already an annotation. If it's the case we keep the new one. @@ -2323,7 +2279,7 @@ impl<'a, F: Field> VirtualCells<'a, F> { } /// Query an advice column at a relative position - pub fn query_advice(&mut self, column: Column, at: Rotation) -> Expression { + pub fn query_advice(&mut self, column: Column, at: Rotation) -> Expression { self.queried_cells.push((column, at).into()); Expression::Advice(AdviceQuery { index: Some(self.meta.query_advice_index(column, at)), From 9d3296a4cf20c4118854e100db7900d8c2f342c0 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Fri, 24 Feb 2023 00:29:15 +0800 Subject: [PATCH 06/25] backword compatible meta.query_X & challange.expr() --- halo2_proofs/examples/shuffle.rs | 24 ++++++++-------- halo2_proofs/examples/simple-example-2.rs | 3 +- halo2_proofs/src/plonk/circuit.rs | 34 ++++++++--------------- 3 files changed, 25 insertions(+), 36 deletions(-) diff --git a/halo2_proofs/examples/shuffle.rs b/halo2_proofs/examples/shuffle.rs index 1926074371..640d17ea8f 100644 --- a/halo2_proofs/examples/shuffle.rs +++ b/halo2_proofs/examples/shuffle.rs @@ -66,28 +66,26 @@ impl MyConfig { let z = meta.advice_column_in(SecondPhase); meta.create_gate("z should start with 1", |meta| { - let q_first = meta.query_selector(q_first); - let z = meta.query_advice(z, Rotation::cur()); + // let q_first = meta.query_selector(q_first); + // let z = meta.query_advice(z, Rotation::cur()); let one = Expression::Constant(F::one()); - vec![q_first * (one - z)] + vec![q_first.expr() * (one - z.cur())] }); meta.create_gate("z should end with 1", |meta| { - let q_last = meta.query_selector(q_last); - let z = meta.query_advice(z, Rotation::cur()); + // let q_last = meta.query_selector(q_last); + // let z = meta.query_advice(z, Rotation::cur()); let one = Expression::Constant(F::one()); - vec![q_last * (one - z)] + vec![q_last.expr() * (one - z.cur())] }); meta.create_gate("z should have valid transition", |meta| { - let q_shuffle = meta.query_selector(q_shuffle); - let original = original.map(|advice| meta.query_advice(advice, Rotation::cur())); - let shuffled = shuffled.map(|advice| meta.query_advice(advice, Rotation::cur())); - let [theta, gamma] = [theta, gamma].map(|challenge| meta.query_challenge(challenge)); - let [z, z_w] = - [Rotation::cur(), Rotation::next()].map(|rotation| meta.query_advice(z, rotation)); + let q_shuffle = q_shuffle.expr(); + let original = original.map(|advice| advice.cur()); + let shuffled = shuffled.map(|advice| advice.cur()); + let [theta, gamma] = [theta, gamma].map(|challenge| challenge.expr()); // Compress let original = original @@ -101,7 +99,7 @@ impl MyConfig { .reduce(|acc, a| acc * theta.clone() + a) .unwrap(); - vec![q_shuffle * (z * (original + gamma.clone()) - z_w * (shuffled + gamma))] + vec![q_shuffle * (z.cur() * (original + gamma.clone()) - z.next() * (shuffled + gamma))] }); Self { diff --git a/halo2_proofs/examples/simple-example-2.rs b/halo2_proofs/examples/simple-example-2.rs index 36f38e8377..b202640711 100644 --- a/halo2_proofs/examples/simple-example-2.rs +++ b/halo2_proofs/examples/simple-example-2.rs @@ -251,7 +251,8 @@ impl Circuit for MyCircuit { &self, config: Self::Config, mut layouter: impl Layouter, - ) -> Result<(), Error> { + ) -> Result<(), Error> + { let field_chip = FieldChip::::construct(config); // Load our private values into the circuit. diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 9639e87d0f..2a8247126a 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -588,6 +588,11 @@ impl Challenge { pub fn phase(&self) -> u8 { self.phase.0 } + + /// Return Expression + pub fn expr(&self) -> Expression { + Expression::Challenge(*self) + } } /// This trait allows a [`Circuit`] to direct some backend to assign a witness @@ -791,7 +796,9 @@ impl Expression { pub fn query_cells(&mut self, cells: &mut VirtualCells<'_, F>) { match self { Expression::Constant(_) => (), - Expression::Selector(_) => (), + Expression::Selector(selector) => { + cells.queried_selectors.push(*selector); + }, Expression::Fixed(query) => { let col = Column { index: query.column_index, @@ -2264,39 +2271,22 @@ impl<'a, F: Field> VirtualCells<'a, F> { /// Query a selector at the current position. pub fn query_selector(&mut self, selector: Selector) -> Expression { - self.queried_selectors.push(selector); - Expression::Selector(selector) + selector.expr() } /// Query a fixed column at a relative position pub fn query_fixed(&mut self, column: Column, at: Rotation) -> Expression { - self.queried_cells.push((column, at).into()); - Expression::Fixed(FixedQuery { - index: Some(self.meta.query_fixed_index(column, at)), - column_index: column.index, - rotation: at, - }) + column.query_cell(at) } /// Query an advice column at a relative position pub fn query_advice(&mut self, column: Column, at: Rotation) -> Expression { - self.queried_cells.push((column, at).into()); - Expression::Advice(AdviceQuery { - index: Some(self.meta.query_advice_index(column, at)), - column_index: column.index, - rotation: at, - phase: column.column_type().phase, - }) + column.query_cell(at) } /// Query an instance column at a relative position pub fn query_instance(&mut self, column: Column, at: Rotation) -> Expression { - self.queried_cells.push((column, at).into()); - Expression::Instance(InstanceQuery { - index: Some(self.meta.query_instance_index(column, at)), - column_index: column.index, - rotation: at, - }) + column.query_cell(at) } /// Query an Any column at a relative position From 1f4d27073ed73d17d6626764d09076aa2fecc3b4 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Fri, 24 Feb 2023 00:32:30 +0800 Subject: [PATCH 07/25] cargo fmt --- halo2_proofs/examples/shuffle.rs | 4 ---- halo2_proofs/examples/simple-example-2.rs | 3 +-- halo2_proofs/src/plonk/circuit.rs | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/halo2_proofs/examples/shuffle.rs b/halo2_proofs/examples/shuffle.rs index 640d17ea8f..63e7e8ce06 100644 --- a/halo2_proofs/examples/shuffle.rs +++ b/halo2_proofs/examples/shuffle.rs @@ -66,16 +66,12 @@ impl MyConfig { let z = meta.advice_column_in(SecondPhase); meta.create_gate("z should start with 1", |meta| { - // let q_first = meta.query_selector(q_first); - // let z = meta.query_advice(z, Rotation::cur()); let one = Expression::Constant(F::one()); vec![q_first.expr() * (one - z.cur())] }); meta.create_gate("z should end with 1", |meta| { - // let q_last = meta.query_selector(q_last); - // let z = meta.query_advice(z, Rotation::cur()); let one = Expression::Constant(F::one()); vec![q_last.expr() * (one - z.cur())] diff --git a/halo2_proofs/examples/simple-example-2.rs b/halo2_proofs/examples/simple-example-2.rs index b202640711..36f38e8377 100644 --- a/halo2_proofs/examples/simple-example-2.rs +++ b/halo2_proofs/examples/simple-example-2.rs @@ -251,8 +251,7 @@ impl Circuit for MyCircuit { &self, config: Self::Config, mut layouter: impl Layouter, - ) -> Result<(), Error> - { + ) -> Result<(), Error> { let field_chip = FieldChip::::construct(config); // Load our private values into the circuit. diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 2a8247126a..9a0119cd9e 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -798,7 +798,7 @@ impl Expression { Expression::Constant(_) => (), Expression::Selector(selector) => { cells.queried_selectors.push(*selector); - }, + } Expression::Fixed(query) => { let col = Column { index: query.column_index, From c2c89ad610a3d177d964084708f0ed4aaf6be228 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Fri, 24 Feb 2023 02:17:59 +0800 Subject: [PATCH 08/25] fixed lookup to pass all tests --- halo2_gadgets/Cargo.toml | 4 +- halo2_gadgets/benches/primitives.rs | 136 +++++++++--------- halo2_proofs/src/plonk/circuit.rs | 19 ++- .../src/plonk/circuit/compress_selectors.rs | 4 +- halo2_proofs/tests/plonk_api.rs | 76 +++++++--- 5 files changed, 139 insertions(+), 100 deletions(-) diff --git a/halo2_gadgets/Cargo.toml b/halo2_gadgets/Cargo.toml index 6025ef7297..787dc85834 100644 --- a/halo2_gadgets/Cargo.toml +++ b/halo2_gadgets/Cargo.toml @@ -41,8 +41,8 @@ plotters = { version = "0.3.0", optional = true } criterion = "0.3" proptest = "1.0.0" -[target.'cfg(unix)'.dev-dependencies] -pprof = { version = "0.8", features = ["criterion", "flamegraph"] } # MSRV 1.56 +#[target.'cfg(unix)'.dev-dependencies] +#pprof = { version = "0.8", features = ["criterion", "flamegraph"] } # MSRV 1.56 [lib] bench = false diff --git a/halo2_gadgets/benches/primitives.rs b/halo2_gadgets/benches/primitives.rs index 5397efce05..3b1d50aef5 100644 --- a/halo2_gadgets/benches/primitives.rs +++ b/halo2_gadgets/benches/primitives.rs @@ -1,68 +1,68 @@ -use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; -use ff::Field; -use halo2_gadgets::{ - poseidon::primitives::{self as poseidon, ConstantLength, P128Pow5T3}, - sinsemilla::primitives as sinsemilla, -}; - -use halo2curves::pasta::pallas; -#[cfg(unix)] -use pprof::criterion::{Output, PProfProfiler}; -use rand::{rngs::OsRng, Rng}; - -fn bench_primitives(c: &mut Criterion) { - let mut rng = OsRng; - - { - let mut group = c.benchmark_group("Poseidon"); - - let message = [pallas::Base::random(rng), pallas::Base::random(rng)]; - - group.bench_function("2-to-1", |b| { - b.iter(|| { - poseidon::Hash::<_, P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(message) - }) - }); - } - - { - let mut group = c.benchmark_group("Sinsemilla"); - - let hasher = sinsemilla::HashDomain::new("hasher"); - let committer = sinsemilla::CommitDomain::new("committer"); - let bits: Vec = (0..1086).map(|_| rng.gen()).collect(); - let r = pallas::Scalar::random(rng); - - // Benchmark the input sizes we use in Orchard: - // - 510 bits for Commit^ivk - // - 520 bits for MerkleCRH - // - 1086 bits for NoteCommit - for size in [510, 520, 1086] { - group.bench_function(BenchmarkId::new("hash-to-point", size), |b| { - b.iter(|| hasher.hash_to_point(bits[..size].iter().cloned())) - }); - - group.bench_function(BenchmarkId::new("hash", size), |b| { - b.iter(|| hasher.hash(bits[..size].iter().cloned())) - }); - - group.bench_function(BenchmarkId::new("commit", size), |b| { - b.iter(|| committer.commit(bits[..size].iter().cloned(), &r)) - }); - - group.bench_function(BenchmarkId::new("short-commit", size), |b| { - b.iter(|| committer.commit(bits[..size].iter().cloned(), &r)) - }); - } - } -} - -#[cfg(unix)] -criterion_group! { - name = benches; - config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); - targets = bench_primitives -} -#[cfg(not(unix))] -criterion_group!(benches, bench_primitives); -criterion_main!(benches); +// use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; +// use ff::Field; +// use halo2_gadgets::{ +// poseidon::primitives::{self as poseidon, ConstantLength, P128Pow5T3}, +// sinsemilla::primitives as sinsemilla, +// }; +// +// use halo2curves::pasta::pallas; +// #[cfg(unix)] +// use pprof::criterion::{Output, PProfProfiler}; +// use rand::{rngs::OsRng, Rng}; +// +// fn bench_primitives(c: &mut Criterion) { +// let mut rng = OsRng; +// +// { +// let mut group = c.benchmark_group("Poseidon"); +// +// let message = [pallas::Base::random(rng), pallas::Base::random(rng)]; +// +// group.bench_function("2-to-1", |b| { +// b.iter(|| { +// poseidon::Hash::<_, P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(message) +// }) +// }); +// } +// +// { +// let mut group = c.benchmark_group("Sinsemilla"); +// +// let hasher = sinsemilla::HashDomain::new("hasher"); +// let committer = sinsemilla::CommitDomain::new("committer"); +// let bits: Vec = (0..1086).map(|_| rng.gen()).collect(); +// let r = pallas::Scalar::random(rng); +// +// // Benchmark the input sizes we use in Orchard: +// // - 510 bits for Commit^ivk +// // - 520 bits for MerkleCRH +// // - 1086 bits for NoteCommit +// for size in [510, 520, 1086] { +// group.bench_function(BenchmarkId::new("hash-to-point", size), |b| { +// b.iter(|| hasher.hash_to_point(bits[..size].iter().cloned())) +// }); +// +// group.bench_function(BenchmarkId::new("hash", size), |b| { +// b.iter(|| hasher.hash(bits[..size].iter().cloned())) +// }); +// +// group.bench_function(BenchmarkId::new("commit", size), |b| { +// b.iter(|| committer.commit(bits[..size].iter().cloned(), &r)) +// }); +// +// group.bench_function(BenchmarkId::new("short-commit", size), |b| { +// b.iter(|| committer.commit(bits[..size].iter().cloned(), &r)) +// }); +// } +// } +// } +// +// #[cfg(unix)] +// criterion_group! { +// name = benches; +// config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); +// targets = bench_primitives +// } +// #[cfg(not(unix))] +// criterion_group!(benches, bench_primitives); +// criterion_main!(benches); diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 9a0119cd9e..6b54117152 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -1668,17 +1668,16 @@ impl ConstraintSystem { let mut cells = VirtualCells::new(self); let table_map = table_map(&mut cells) .into_iter() - .map(|(input, table)| { + .map(|(mut input, mut table)| { if input.contains_simple_selector() { panic!("expression containing simple selector supplied to lookup argument"); } - - let table = cells.query_fixed(table.inner(), Rotation::cur()); - + let mut table = cells.query_fixed(table.inner(), Rotation::cur()); + input.query_cells(&mut cells); + table.query_cells(&mut cells); (input, table) }) .collect(); - let index = self.lookups.len(); self.lookups.push(lookup::Argument::new(name, table_map)); @@ -1696,8 +1695,14 @@ impl ConstraintSystem { table_map: impl FnOnce(&mut VirtualCells<'_, F>) -> Vec<(Expression, Expression)>, ) -> usize { let mut cells = VirtualCells::new(self); - let table_map = table_map(&mut cells); - + let table_map = table_map(&mut cells) + .into_iter() + .map(|(mut input, mut table)| { + input.query_cells(&mut cells); + table.query_cells(&mut cells); + (input, table) + }) + .collect(); let index = self.lookups.len(); self.lookups.push(lookup::Argument::new(name, table_map)); diff --git a/halo2_proofs/src/plonk/circuit/compress_selectors.rs b/halo2_proofs/src/plonk/circuit/compress_selectors.rs index b6807e1163..4179b9876e 100644 --- a/halo2_proofs/src/plonk/circuit/compress_selectors.rs +++ b/halo2_proofs/src/plonk/circuit/compress_selectors.rs @@ -281,7 +281,7 @@ mod tests { let (combination_assignments, selector_assignments) = process::(selectors.clone(), max_degree, || { let tmp = Expression::Fixed(FixedQuery { - index: query, + index: Some(query), column_index: query, rotation: Rotation::cur(), }); @@ -320,7 +320,7 @@ mod tests { &|_| panic!("should not occur in returned expressions"), &|query| { // Should be the correct combination in the expression - assert_eq!(selector.combination_index, query.index); + assert_eq!(selector.combination_index, query.index.unwrap()); assignment }, &|_| panic!("should not occur in returned expressions"), diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index af63b5fb30..bdf17e04fb 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -643,14 +643,18 @@ fn plonk_api() { Sum( Product( Advice { - query_index: 0, + query_index: Some( + 0, + ), column_index: 1, rotation: Rotation( 0, ), }, Fixed { - query_index: 2, + query_index: Some( + 1, + ), column_index: 2, rotation: Rotation( 0, @@ -659,14 +663,18 @@ fn plonk_api() { ), Product( Advice { - query_index: 1, + query_index: Some( + 1, + ), column_index: 2, rotation: Rotation( 0, ), }, Fixed { - query_index: 3, + query_index: Some( + 2, + ), column_index: 3, rotation: Rotation( 0, @@ -677,14 +685,18 @@ fn plonk_api() { Product( Product( Advice { - query_index: 0, + query_index: Some( + 0, + ), column_index: 1, rotation: Rotation( 0, ), }, Advice { - query_index: 1, + query_index: Some( + 1, + ), column_index: 2, rotation: Rotation( 0, @@ -692,7 +704,9 @@ fn plonk_api() { }, ), Fixed { - query_index: 5, + query_index: Some( + 3, + ), column_index: 1, rotation: Rotation( 0, @@ -703,14 +717,18 @@ fn plonk_api() { Negated( Product( Advice { - query_index: 2, + query_index: Some( + 2, + ), column_index: 3, rotation: Rotation( 0, ), }, Fixed { - query_index: 4, + query_index: Some( + 4, + ), column_index: 4, rotation: Rotation( 0, @@ -721,7 +739,9 @@ fn plonk_api() { ), Product( Fixed { - query_index: 1, + query_index: Some( + 5, + ), column_index: 0, rotation: Rotation( 0, @@ -729,14 +749,18 @@ fn plonk_api() { }, Product( Advice { - query_index: 3, + query_index: Some( + 3, + ), column_index: 4, rotation: Rotation( 1, ), }, Advice { - query_index: 4, + query_index: Some( + 4, + ), column_index: 0, rotation: Rotation( -1, @@ -747,7 +771,9 @@ fn plonk_api() { ), Product( Fixed { - query_index: 6, + query_index: Some( + 6, + ), column_index: 5, rotation: Rotation( 0, @@ -755,7 +781,9 @@ fn plonk_api() { }, Sum( Advice { - query_index: 0, + query_index: Some( + 0, + ), column_index: 1, rotation: Rotation( 0, @@ -763,7 +791,9 @@ fn plonk_api() { }, Negated( Instance { - query_index: 0, + query_index: Some( + 0, + ), column_index: 0, rotation: Rotation( 0, @@ -861,7 +891,7 @@ fn plonk_api() { ), ( Column { - index: 0, + index: 2, column_type: Fixed, }, Rotation( @@ -870,7 +900,7 @@ fn plonk_api() { ), ( Column { - index: 2, + index: 3, column_type: Fixed, }, Rotation( @@ -879,7 +909,7 @@ fn plonk_api() { ), ( Column { - index: 3, + index: 1, column_type: Fixed, }, Rotation( @@ -897,7 +927,7 @@ fn plonk_api() { ), ( Column { - index: 1, + index: 0, column_type: Fixed, }, Rotation( @@ -970,7 +1000,9 @@ fn plonk_api() { Argument { input_expressions: [ Advice { - query_index: 0, + query_index: Some( + 0, + ), column_index: 1, rotation: Rotation( 0, @@ -979,7 +1011,9 @@ fn plonk_api() { ], table_expressions: [ Fixed { - query_index: 0, + query_index: Some( + 0, + ), column_index: 6, rotation: Rotation( 0, From a40341526383c69e49c3c8e073357c9462ec5eef Mon Sep 17 00:00:00 2001 From: CeciliaZ030 <45245961+CeciliaZ030@users.noreply.github.com> Date: Fri, 24 Feb 2023 14:22:14 +0800 Subject: [PATCH 09/25] Update comments Co-authored-by: Brecht Devos --- halo2_proofs/src/plonk/circuit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 6b54117152..362f20d8c5 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -48,7 +48,7 @@ impl Column { &self.column_type } - /// Return expression from cell + /// Return expression from column at a relative position pub fn query_cell(&self, at: Rotation) -> Expression { self.column_type.query_cell(self.index, at) } From 3a0922e8c8cb6137469cf3f2f29b94e1089f0404 Mon Sep 17 00:00:00 2001 From: CeciliaZ030 <45245961+CeciliaZ030@users.noreply.github.com> Date: Fri, 24 Feb 2023 14:22:30 +0800 Subject: [PATCH 10/25] Update comments Co-authored-by: Brecht Devos --- halo2_proofs/src/plonk/circuit.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 362f20d8c5..5489aab1c9 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -53,8 +53,8 @@ impl Column { self.column_type.query_cell(self.index, at) } - /// Return expression from cell - pub fn cur(&self) -> Expression { + /// Return expression from column at the current row + pub fn expr(&self) -> Expression { self.query_cell(Rotation::cur()) } From f7b73c788dd923ffdeb65a732515d1ff5eb86d2c Mon Sep 17 00:00:00 2001 From: CeciliaZ030 <45245961+CeciliaZ030@users.noreply.github.com> Date: Fri, 24 Feb 2023 14:22:40 +0800 Subject: [PATCH 11/25] Update comments Co-authored-by: Brecht Devos --- halo2_proofs/src/plonk/circuit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 5489aab1c9..0531ea04ae 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -58,7 +58,7 @@ impl Column { self.query_cell(Rotation::cur()) } - /// Return expression from cell + /// Return expression from column at the next row pub fn next(&self) -> Expression { self.query_cell(Rotation::next()) } From 85445df5a76e47adb7d5a316e50cb88983cf29b2 Mon Sep 17 00:00:00 2001 From: CeciliaZ030 <45245961+CeciliaZ030@users.noreply.github.com> Date: Fri, 24 Feb 2023 14:22:51 +0800 Subject: [PATCH 12/25] Update comments Co-authored-by: Brecht Devos --- halo2_proofs/src/plonk/circuit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 0531ea04ae..3708883886 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -63,7 +63,7 @@ impl Column { self.query_cell(Rotation::next()) } - /// Return expression from cell + /// Return expression from column at the previous row pub fn prev(&self) -> Expression { self.query_cell(Rotation::prev()) } From ee56f9c5a3424287db75c40485a8a87e27550aec Mon Sep 17 00:00:00 2001 From: CeciliaZ030 <45245961+CeciliaZ030@users.noreply.github.com> Date: Fri, 24 Feb 2023 14:23:08 +0800 Subject: [PATCH 13/25] Update comments Co-authored-by: Brecht Devos --- halo2_proofs/src/plonk/circuit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 3708883886..63a5786b75 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -81,7 +81,7 @@ impl Ord for Column { } } -impl PartialOrd for Column { +impl PartialOrd for Column { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } From 411595c36e86caa0fced16677ad4b56af05cb18a Mon Sep 17 00:00:00 2001 From: CeciliaZ030 <45245961+CeciliaZ030@users.noreply.github.com> Date: Fri, 24 Feb 2023 14:23:39 +0800 Subject: [PATCH 14/25] Update comments Co-authored-by: Brecht Devos --- halo2_proofs/src/plonk/circuit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 63a5786b75..e8cf66b30c 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -291,7 +291,7 @@ impl ColumnType for Any { index: None, column_index: index, rotation: at, - phase: phase.clone(), + phase: *phase, }), Any::Fixed => Expression::Fixed(FixedQuery { index: None, From 97712385aa12a15a35c84714ecbf9115e691ef1c Mon Sep 17 00:00:00 2001 From: CeciliaZ030 <45245961+CeciliaZ030@users.noreply.github.com> Date: Fri, 24 Feb 2023 16:08:29 +0800 Subject: [PATCH 15/25] update Co-authored-by: Brecht Devos --- halo2_proofs/src/plonk/circuit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index e8cf66b30c..fae7dc4302 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -1668,7 +1668,7 @@ impl ConstraintSystem { let mut cells = VirtualCells::new(self); let table_map = table_map(&mut cells) .into_iter() - .map(|(mut input, mut table)| { + .map(|(mut input, table)| { if input.contains_simple_selector() { panic!("expression containing simple selector supplied to lookup argument"); } From 615296643bcbcf6955d27020f390650008eebd69 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Fri, 24 Feb 2023 16:34:07 +0800 Subject: [PATCH 16/25] add primitives.rs back --- halo2_gadgets/Cargo.toml | 4 +- halo2_gadgets/benches/primitives.rs | 136 +++++++++++----------- halo2_proofs/examples/shuffle.rs | 12 +- halo2_proofs/examples/simple-example-2.rs | 2 +- 4 files changed, 78 insertions(+), 76 deletions(-) diff --git a/halo2_gadgets/Cargo.toml b/halo2_gadgets/Cargo.toml index 787dc85834..6025ef7297 100644 --- a/halo2_gadgets/Cargo.toml +++ b/halo2_gadgets/Cargo.toml @@ -41,8 +41,8 @@ plotters = { version = "0.3.0", optional = true } criterion = "0.3" proptest = "1.0.0" -#[target.'cfg(unix)'.dev-dependencies] -#pprof = { version = "0.8", features = ["criterion", "flamegraph"] } # MSRV 1.56 +[target.'cfg(unix)'.dev-dependencies] +pprof = { version = "0.8", features = ["criterion", "flamegraph"] } # MSRV 1.56 [lib] bench = false diff --git a/halo2_gadgets/benches/primitives.rs b/halo2_gadgets/benches/primitives.rs index 3b1d50aef5..5397efce05 100644 --- a/halo2_gadgets/benches/primitives.rs +++ b/halo2_gadgets/benches/primitives.rs @@ -1,68 +1,68 @@ -// use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; -// use ff::Field; -// use halo2_gadgets::{ -// poseidon::primitives::{self as poseidon, ConstantLength, P128Pow5T3}, -// sinsemilla::primitives as sinsemilla, -// }; -// -// use halo2curves::pasta::pallas; -// #[cfg(unix)] -// use pprof::criterion::{Output, PProfProfiler}; -// use rand::{rngs::OsRng, Rng}; -// -// fn bench_primitives(c: &mut Criterion) { -// let mut rng = OsRng; -// -// { -// let mut group = c.benchmark_group("Poseidon"); -// -// let message = [pallas::Base::random(rng), pallas::Base::random(rng)]; -// -// group.bench_function("2-to-1", |b| { -// b.iter(|| { -// poseidon::Hash::<_, P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(message) -// }) -// }); -// } -// -// { -// let mut group = c.benchmark_group("Sinsemilla"); -// -// let hasher = sinsemilla::HashDomain::new("hasher"); -// let committer = sinsemilla::CommitDomain::new("committer"); -// let bits: Vec = (0..1086).map(|_| rng.gen()).collect(); -// let r = pallas::Scalar::random(rng); -// -// // Benchmark the input sizes we use in Orchard: -// // - 510 bits for Commit^ivk -// // - 520 bits for MerkleCRH -// // - 1086 bits for NoteCommit -// for size in [510, 520, 1086] { -// group.bench_function(BenchmarkId::new("hash-to-point", size), |b| { -// b.iter(|| hasher.hash_to_point(bits[..size].iter().cloned())) -// }); -// -// group.bench_function(BenchmarkId::new("hash", size), |b| { -// b.iter(|| hasher.hash(bits[..size].iter().cloned())) -// }); -// -// group.bench_function(BenchmarkId::new("commit", size), |b| { -// b.iter(|| committer.commit(bits[..size].iter().cloned(), &r)) -// }); -// -// group.bench_function(BenchmarkId::new("short-commit", size), |b| { -// b.iter(|| committer.commit(bits[..size].iter().cloned(), &r)) -// }); -// } -// } -// } -// -// #[cfg(unix)] -// criterion_group! { -// name = benches; -// config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); -// targets = bench_primitives -// } -// #[cfg(not(unix))] -// criterion_group!(benches, bench_primitives); -// criterion_main!(benches); +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; +use ff::Field; +use halo2_gadgets::{ + poseidon::primitives::{self as poseidon, ConstantLength, P128Pow5T3}, + sinsemilla::primitives as sinsemilla, +}; + +use halo2curves::pasta::pallas; +#[cfg(unix)] +use pprof::criterion::{Output, PProfProfiler}; +use rand::{rngs::OsRng, Rng}; + +fn bench_primitives(c: &mut Criterion) { + let mut rng = OsRng; + + { + let mut group = c.benchmark_group("Poseidon"); + + let message = [pallas::Base::random(rng), pallas::Base::random(rng)]; + + group.bench_function("2-to-1", |b| { + b.iter(|| { + poseidon::Hash::<_, P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(message) + }) + }); + } + + { + let mut group = c.benchmark_group("Sinsemilla"); + + let hasher = sinsemilla::HashDomain::new("hasher"); + let committer = sinsemilla::CommitDomain::new("committer"); + let bits: Vec = (0..1086).map(|_| rng.gen()).collect(); + let r = pallas::Scalar::random(rng); + + // Benchmark the input sizes we use in Orchard: + // - 510 bits for Commit^ivk + // - 520 bits for MerkleCRH + // - 1086 bits for NoteCommit + for size in [510, 520, 1086] { + group.bench_function(BenchmarkId::new("hash-to-point", size), |b| { + b.iter(|| hasher.hash_to_point(bits[..size].iter().cloned())) + }); + + group.bench_function(BenchmarkId::new("hash", size), |b| { + b.iter(|| hasher.hash(bits[..size].iter().cloned())) + }); + + group.bench_function(BenchmarkId::new("commit", size), |b| { + b.iter(|| committer.commit(bits[..size].iter().cloned(), &r)) + }); + + group.bench_function(BenchmarkId::new("short-commit", size), |b| { + b.iter(|| committer.commit(bits[..size].iter().cloned(), &r)) + }); + } + } +} + +#[cfg(unix)] +criterion_group! { + name = benches; + config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); + targets = bench_primitives +} +#[cfg(not(unix))] +criterion_group!(benches, bench_primitives); +criterion_main!(benches); diff --git a/halo2_proofs/examples/shuffle.rs b/halo2_proofs/examples/shuffle.rs index 63e7e8ce06..bf0b95e28b 100644 --- a/halo2_proofs/examples/shuffle.rs +++ b/halo2_proofs/examples/shuffle.rs @@ -68,19 +68,19 @@ impl MyConfig { meta.create_gate("z should start with 1", |meta| { let one = Expression::Constant(F::one()); - vec![q_first.expr() * (one - z.cur())] + vec![q_first.expr() * (one - z.expr())] }); meta.create_gate("z should end with 1", |meta| { let one = Expression::Constant(F::one()); - vec![q_last.expr() * (one - z.cur())] + vec![q_last.expr() * (one - z.expr())] }); meta.create_gate("z should have valid transition", |meta| { let q_shuffle = q_shuffle.expr(); - let original = original.map(|advice| advice.cur()); - let shuffled = shuffled.map(|advice| advice.cur()); + let original = original.map(|advice| advice.expr()); + let shuffled = shuffled.map(|advice| advice.expr()); let [theta, gamma] = [theta, gamma].map(|challenge| challenge.expr()); // Compress @@ -95,7 +95,9 @@ impl MyConfig { .reduce(|acc, a| acc * theta.clone() + a) .unwrap(); - vec![q_shuffle * (z.cur() * (original + gamma.clone()) - z.next() * (shuffled + gamma))] + vec![ + q_shuffle * (z.expr() * (original + gamma.clone()) - z.next() * (shuffled + gamma)), + ] }); Self { diff --git a/halo2_proofs/examples/simple-example-2.rs b/halo2_proofs/examples/simple-example-2.rs index 36f38e8377..09dea201db 100644 --- a/halo2_proofs/examples/simple-example-2.rs +++ b/halo2_proofs/examples/simple-example-2.rs @@ -94,7 +94,7 @@ impl FieldChip { // let s_mul = meta.query_selector(s_mul); // vec![s_mul * (lhs * rhs - out)] - vec![s_mul.expr() * (advice[0].cur() * advice[1].cur() - advice[0].next())] + vec![s_mul.expr() * (advice[0].expr() * advice[1].expr() - advice[0].expr())] }); FieldConfig { From 4303039e1f98bfdaa784e2abf614d24b66a5a087 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Fri, 24 Feb 2023 16:47:56 +0800 Subject: [PATCH 17/25] remove example2 --- halo2_proofs/examples/simple-example-2.rs | 321 ---------------------- 1 file changed, 321 deletions(-) delete mode 100644 halo2_proofs/examples/simple-example-2.rs diff --git a/halo2_proofs/examples/simple-example-2.rs b/halo2_proofs/examples/simple-example-2.rs deleted file mode 100644 index 09dea201db..0000000000 --- a/halo2_proofs/examples/simple-example-2.rs +++ /dev/null @@ -1,321 +0,0 @@ -use std::marker::PhantomData; - -use halo2_proofs::{ - arithmetic::FieldExt, - circuit::{AssignedCell, Chip, Layouter, Region, SimpleFloorPlanner, Value}, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance, Selector}, - poly::Rotation, -}; - -// ANCHOR: instructions -trait NumericInstructions: Chip { - /// Variable representing a number. - type Num; - - /// Loads a number into the circuit as a private input. - fn load_private(&self, layouter: impl Layouter, a: Value) -> Result; - - /// Loads a number into the circuit as a fixed constant. - fn load_constant(&self, layouter: impl Layouter, constant: F) -> Result; - - /// Returns `c = a * b`. - fn mul( - &self, - layouter: impl Layouter, - a: Self::Num, - b: Self::Num, - ) -> Result; - - /// Exposes a number as a public input to the circuit. - fn expose_public( - &self, - layouter: impl Layouter, - num: Self::Num, - row: usize, - ) -> Result<(), Error>; -} -// ANCHOR_END: instructions - -// ANCHOR: chip -/// The chip that will implement our instructions! Chips store their own -/// config, as well as type markers if necessary. -struct FieldChip { - config: FieldConfig, - _marker: PhantomData, -} -// ANCHOR_END: chip - -// ANCHOR: chip-config -/// Chip state is stored in a config struct. This is generated by the chip -/// during configuration, and then stored inside the chip. -#[derive(Clone, Debug)] -struct FieldConfig { - /// For this chip, we will use two advice columns to implement our instructions. - /// These are also the columns through which we communicate with other parts of - /// the circuit. - advice: [Column; 2], - - /// This is the public input (instance) column. - instance: Column, - - // We need a selector to enable the multiplication gate, so that we aren't placing - // any constraints on cells where `NumericInstructions::mul` is not being used. - // This is important when building larger circuits, where columns are used by - // multiple sets of instructions. - s_mul: Selector, -} - -impl FieldChip { - fn construct(config: >::Config) -> Self { - Self { - config, - _marker: PhantomData, - } - } - - fn configure( - meta: &mut ConstraintSystem, - advice: [Column; 2], - instance: Column, - constant: Column, - ) -> >::Config { - meta.enable_equality(instance); - meta.enable_constant(constant); - for column in &advice { - meta.enable_equality(*column); - } - let s_mul = meta.selector(); - - // Define our multiplication gate! - meta.create_gate("mul", |meta| { - // let lhs = meta.query_advice(advice[0], Rotation::cur()); - // let rhs = meta.query_advice(advice[1], Rotation::cur()); - // let out = meta.query_advice(advice[0], Rotation::next()); - // let s_mul = meta.query_selector(s_mul); - // vec![s_mul * (lhs * rhs - out)] - - vec![s_mul.expr() * (advice[0].expr() * advice[1].expr() - advice[0].expr())] - }); - - FieldConfig { - advice, - instance, - s_mul, - } - } -} -// ANCHOR_END: chip-config - -// ANCHOR: chip-impl -impl Chip for FieldChip { - type Config = FieldConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} -// ANCHOR_END: chip-impl - -// ANCHOR: instructions-impl -/// A variable representing a number. -#[derive(Clone)] -struct Number(AssignedCell); - -impl NumericInstructions for FieldChip { - type Num = Number; - - fn load_private( - &self, - mut layouter: impl Layouter, - value: Value, - ) -> Result { - let config = self.config(); - - layouter.assign_region( - || "load private", - |mut region| { - region - .assign_advice(|| "private input", config.advice[0], 0, || value) - .map(Number) - }, - ) - } - - fn load_constant( - &self, - mut layouter: impl Layouter, - constant: F, - ) -> Result { - let config = self.config(); - - layouter.assign_region( - || "load constant", - |mut region| { - region - .assign_advice_from_constant(|| "constant value", config.advice[0], 0, constant) - .map(Number) - }, - ) - } - - fn mul( - &self, - mut layouter: impl Layouter, - a: Self::Num, - b: Self::Num, - ) -> Result { - let config = self.config(); - - layouter.assign_region( - || "mul", - |mut region: Region<'_, F>| { - // We only want to use a single multiplication gate in this region, - // so we enable it at region offset 0; this means it will constrain - // cells at offsets 0 and 1. - config.s_mul.enable(&mut region, 0)?; - - // The inputs we've been given could be located anywhere in the circuit, - // but we can only rely on relative offsets inside this region. So we - // assign new cells inside the region and constrain them to have the - // same values as the inputs. - a.0.copy_advice(|| "lhs", &mut region, config.advice[0], 0)?; - b.0.copy_advice(|| "rhs", &mut region, config.advice[1], 0)?; - - // Now we can assign the multiplication result, which is to be assigned - // into the output position. - let value = a.0.value().copied() * b.0.value(); - - // Finally, we do the assignment to the output, returning a - // variable to be used in another part of the circuit. - region - .assign_advice(|| "lhs * rhs", config.advice[0], 1, || value) - .map(Number) - }, - ) - } - - fn expose_public( - &self, - mut layouter: impl Layouter, - num: Self::Num, - row: usize, - ) -> Result<(), Error> { - let config = self.config(); - - layouter.constrain_instance(num.0.cell(), config.instance, row) - } -} -// ANCHOR_END: instructions-impl - -// ANCHOR: circuit -/// The full circuit implementation. -/// -/// In this struct we store the private input variables. We use `Option` because -/// they won't have any value during key generation. During proving, if any of these -/// were `None` we would get an error. -#[derive(Default)] -struct MyCircuit { - constant: F, - a: Value, - b: Value, -} - -impl Circuit for MyCircuit { - // Since we are using a single chip for everything, we can just reuse its config. - type Config = FieldConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - // We create the two advice columns that FieldChip uses for I/O. - let advice = [meta.advice_column(), meta.advice_column()]; - - // We also need an instance column to store public inputs. - let instance = meta.instance_column(); - - // Create a fixed column to load constants. - let constant = meta.fixed_column(); - - FieldChip::configure(meta, advice, instance, constant) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let field_chip = FieldChip::::construct(config); - - // Load our private values into the circuit. - let a = field_chip.load_private(layouter.namespace(|| "load a"), self.a)?; - let b = field_chip.load_private(layouter.namespace(|| "load b"), self.b)?; - - // Load the constant factor into the circuit. - let constant = - field_chip.load_constant(layouter.namespace(|| "load constant"), self.constant)?; - - // We only have access to plain multiplication. - // We could implement our circuit as: - // asq = a*a - // bsq = b*b - // absq = asq*bsq - // c = constant*asq*bsq - // - // but it's more efficient to implement it as: - // ab = a*b - // absq = ab^2 - // c = constant*absq - let ab = field_chip.mul(layouter.namespace(|| "a * b"), a, b)?; - let absq = field_chip.mul(layouter.namespace(|| "ab * ab"), ab.clone(), ab)?; - let c = field_chip.mul(layouter.namespace(|| "constant * absq"), constant, absq)?; - - // Expose the result as a public input to the circuit. - field_chip.expose_public(layouter.namespace(|| "expose c"), c, 0) - } -} -// ANCHOR_END: circuit - -fn main() { - use halo2_proofs::dev::MockProver; - use halo2curves::pasta::Fp; - - // ANCHOR: test-circuit - // The number of rows in our circuit cannot exceed 2^k. Since our example - // circuit is very small, we can pick a very small value here. - let k = 4; - - // Prepare the private and public inputs to the circuit! - let constant = Fp::from(7); - let a = Fp::from(2); - let b = Fp::from(3); - let c = constant * a.square() * b.square(); - - // Instantiate the circuit with the private inputs. - let circuit = MyCircuit { - constant, - a: Value::known(a), - b: Value::known(b), - }; - - // Arrange the public input. We expose the multiplication result in row 0 - // of the instance column, so we position it there in our public inputs. - let mut public_inputs = vec![c]; - - // Given the correct public input, our circuit will verify. - let prover = MockProver::run(k, &circuit, vec![public_inputs.clone()]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - - // If we try some other public input, the proof will fail! - public_inputs[0] += Fp::one(); - let prover = MockProver::run(k, &circuit, vec![public_inputs]).unwrap(); - assert!(prover.verify().is_err()); - // ANCHOR_END: test-circuit -} From 7b7fb1a15718dfafc92d0bacf05f04c423b15a5b Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Wed, 8 Mar 2023 12:47:18 +0800 Subject: [PATCH 18/25] backward compatible meta.query_X & Column.cur(), next(), prev(), at(usize) --- halo2_proofs/examples/shuffle.rs | 10 +++++----- halo2_proofs/src/plonk/circuit.rs | 32 ++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/halo2_proofs/examples/shuffle.rs b/halo2_proofs/examples/shuffle.rs index bf0b95e28b..96fc72dc45 100644 --- a/halo2_proofs/examples/shuffle.rs +++ b/halo2_proofs/examples/shuffle.rs @@ -68,19 +68,19 @@ impl MyConfig { meta.create_gate("z should start with 1", |meta| { let one = Expression::Constant(F::one()); - vec![q_first.expr() * (one - z.expr())] + vec![q_first.expr() * (one - z.cur())] }); meta.create_gate("z should end with 1", |meta| { let one = Expression::Constant(F::one()); - vec![q_last.expr() * (one - z.expr())] + vec![q_last.expr() * (one - z.cur())] }); meta.create_gate("z should have valid transition", |meta| { let q_shuffle = q_shuffle.expr(); - let original = original.map(|advice| advice.expr()); - let shuffled = shuffled.map(|advice| advice.expr()); + let original = original.map(|advice| advice.cur()); + let shuffled = shuffled.map(|advice| advice.cur()); let [theta, gamma] = [theta, gamma].map(|challenge| challenge.expr()); // Compress @@ -96,7 +96,7 @@ impl MyConfig { .unwrap(); vec![ - q_shuffle * (z.expr() * (original + gamma.clone()) - z.next() * (shuffled + gamma)), + q_shuffle * (z.cur() * (original + gamma.clone()) - z.next() * (shuffled + gamma)), ] }); diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index fae7dc4302..1759a07a93 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -54,7 +54,7 @@ impl Column { } /// Return expression from column at the current row - pub fn expr(&self) -> Expression { + pub fn cur(&self) -> Expression { self.query_cell(Rotation::cur()) } @@ -67,6 +67,11 @@ impl Column { pub fn prev(&self) -> Expression { self.query_cell(Rotation::prev()) } + + /// Return expression from column at the specified row + pub fn at(&self, at: usize) -> Expression { + self.query_cell(Rotation(at as i32)) + } } impl Ord for Column { @@ -2276,22 +2281,39 @@ impl<'a, F: Field> VirtualCells<'a, F> { /// Query a selector at the current position. pub fn query_selector(&mut self, selector: Selector) -> Expression { - selector.expr() + self.queried_selectors.push(selector); + Expression::Selector(selector) } /// Query a fixed column at a relative position pub fn query_fixed(&mut self, column: Column, at: Rotation) -> Expression { - column.query_cell(at) + self.queried_cells.push((column, at).into()); + Expression::Fixed(FixedQuery { + index: Some(self.meta.query_fixed_index(column, at)), + column_index: column.index, + rotation: at, + }) } /// Query an advice column at a relative position pub fn query_advice(&mut self, column: Column, at: Rotation) -> Expression { - column.query_cell(at) + self.queried_cells.push((column, at).into()); + Expression::Advice(AdviceQuery { + index: Some(self.meta.query_advice_index(column, at)), + column_index: column.index, + rotation: at, + phase: column.column_type().phase, + }) } /// Query an instance column at a relative position pub fn query_instance(&mut self, column: Column, at: Rotation) -> Expression { - column.query_cell(at) + self.queried_cells.push((column, at).into()); + Expression::Instance(InstanceQuery { + index: Some(self.meta.query_instance_index(column, at)), + column_index: column.index, + rotation: at, + }) } /// Query an Any column at a relative position From 0200e30559239d35dd811c30c7057140704f9850 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Wed, 8 Mar 2023 16:06:59 +0800 Subject: [PATCH 19/25] impl Debug & make side effects only when query.index.is_none() --- halo2_proofs/examples/shuffle.rs | 4 +- halo2_proofs/src/plonk/circuit.rs | 113 ++++++++++++++++++++++++------ 2 files changed, 92 insertions(+), 25 deletions(-) diff --git a/halo2_proofs/examples/shuffle.rs b/halo2_proofs/examples/shuffle.rs index 96fc72dc45..63e7e8ce06 100644 --- a/halo2_proofs/examples/shuffle.rs +++ b/halo2_proofs/examples/shuffle.rs @@ -95,9 +95,7 @@ impl MyConfig { .reduce(|acc, a| acc * theta.clone() + a) .unwrap(); - vec![ - q_shuffle * (z.cur() * (original + gamma.clone()) - z.next() * (shuffled + gamma)), - ] + vec![q_shuffle * (z.cur() * (original + gamma.clone()) - z.next() * (shuffled + gamma))] }); Self { diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 1759a07a93..84feb405c7 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -10,8 +10,10 @@ use ff::Field; use sealed::SealedPhase; use std::cmp::Ordering; use std::collections::HashMap; +use std::fmt::{Debug, Formatter}; use std::{ convert::TryFrom, + fmt, ops::{Neg, Sub}, }; @@ -473,7 +475,7 @@ impl Selector { } /// Query of fixed column at a certain relative location -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone)] pub struct FixedQuery { /// Query index pub(crate) index: Option, @@ -495,8 +497,27 @@ impl FixedQuery { } } +impl Debug for FixedQuery { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self.index { + None => f + .debug_struct("FixedQuery") + .field("index", &self.index) + .field("column_index", &self.column_index) + .field("rotation", &self.rotation) + .finish(), + Some(idx) => f + .debug_struct("FixedQuery") + .field("index", &idx) + .field("column_index", &self.column_index) + .field("rotation", &self.rotation) + .finish(), + } + } +} + /// Query of advice column at a certain relative location -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone)] pub struct AdviceQuery { /// Query index pub(crate) index: Option, @@ -525,8 +546,29 @@ impl AdviceQuery { } } +impl Debug for AdviceQuery { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self.index { + None => f + .debug_struct("AdviceQuery") + .field("index", &self.index) + .field("column_index", &self.column_index) + .field("rotation", &self.rotation) + .field("phase", &self.phase) + .finish(), + Some(idx) => f + .debug_struct("InstanceQuery") + .field("index", &idx) + .field("column_index", &self.column_index) + .field("rotation", &self.rotation) + .field("phase", &self.phase) + .finish(), + } + } +} + /// Query of instance column at a certain relative location -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone)] pub struct InstanceQuery { /// Query index pub(crate) index: Option, @@ -548,6 +590,25 @@ impl InstanceQuery { } } +impl Debug for InstanceQuery { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self.index { + None => f + .debug_struct("InstanceQuery") + .field("index", &self.index) + .field("column_index", &self.column_index) + .field("rotation", &self.rotation) + .finish(), + Some(idx) => f + .debug_struct("InstanceQuery") + .field("index", &idx) + .field("column_index", &self.column_index) + .field("rotation", &self.rotation) + .finish(), + } + } +} + /// A fixed column of a lookup table. /// /// A lookup table can be loaded into this column via [`Layouter::assign_table`]. Columns @@ -802,31 +863,39 @@ impl Expression { match self { Expression::Constant(_) => (), Expression::Selector(selector) => { - cells.queried_selectors.push(*selector); + if !cells.queried_selectors.contains(selector) { + cells.queried_selectors.push(*selector); + } } Expression::Fixed(query) => { - let col = Column { - index: query.column_index, - column_type: Fixed, - }; - cells.queried_cells.push((col, query.rotation).into()); - query.index = Some(cells.meta.query_fixed_index(col, query.rotation)); + if query.index.is_none() { + let col = Column { + index: query.column_index, + column_type: Fixed, + }; + cells.queried_cells.push((col, query.rotation).into()); + query.index = Some(cells.meta.query_fixed_index(col, query.rotation)); + } } Expression::Advice(query) => { - let col = Column { - index: query.column_index, - column_type: Advice { phase: query.phase }, - }; - cells.queried_cells.push((col, query.rotation).into()); - query.index = Some(cells.meta.query_advice_index(col, query.rotation)); + if query.index.is_none() { + let col = Column { + index: query.column_index, + column_type: Advice { phase: query.phase }, + }; + cells.queried_cells.push((col, query.rotation).into()); + query.index = Some(cells.meta.query_advice_index(col, query.rotation)); + } } Expression::Instance(query) => { - let col = Column { - index: query.column_index, - column_type: Instance, - }; - cells.queried_cells.push((col, query.rotation).into()); - query.index = Some(cells.meta.query_instance_index(col, query.rotation)); + if query.index.is_none() { + let col = Column { + index: query.column_index, + column_type: Instance, + }; + cells.queried_cells.push((col, query.rotation).into()); + query.index = Some(cells.meta.query_instance_index(col, query.rotation)); + } } Expression::Challenge(_) => (), Expression::Negated(a) => a.query_cells(cells), From 66282363fe5e58710cde6df52a0fb27fc39f1780 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Wed, 8 Mar 2023 16:43:09 +0800 Subject: [PATCH 20/25] change impl Debug for Expression instead & revert test in plonk_api --- halo2_proofs/src/plonk/circuit.rs | 128 ++++++++---------------------- halo2_proofs/tests/plonk_api.rs | 76 +++++------------- 2 files changed, 55 insertions(+), 149 deletions(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 84feb405c7..dcd66ce673 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -13,7 +13,6 @@ use std::collections::HashMap; use std::fmt::{Debug, Formatter}; use std::{ convert::TryFrom, - fmt, ops::{Neg, Sub}, }; @@ -475,7 +474,7 @@ impl Selector { } /// Query of fixed column at a certain relative location -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct FixedQuery { /// Query index pub(crate) index: Option, @@ -497,27 +496,8 @@ impl FixedQuery { } } -impl Debug for FixedQuery { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self.index { - None => f - .debug_struct("FixedQuery") - .field("index", &self.index) - .field("column_index", &self.column_index) - .field("rotation", &self.rotation) - .finish(), - Some(idx) => f - .debug_struct("FixedQuery") - .field("index", &idx) - .field("column_index", &self.column_index) - .field("rotation", &self.rotation) - .finish(), - } - } -} - /// Query of advice column at a certain relative location -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct AdviceQuery { /// Query index pub(crate) index: Option, @@ -546,29 +526,8 @@ impl AdviceQuery { } } -impl Debug for AdviceQuery { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self.index { - None => f - .debug_struct("AdviceQuery") - .field("index", &self.index) - .field("column_index", &self.column_index) - .field("rotation", &self.rotation) - .field("phase", &self.phase) - .finish(), - Some(idx) => f - .debug_struct("InstanceQuery") - .field("index", &idx) - .field("column_index", &self.column_index) - .field("rotation", &self.rotation) - .field("phase", &self.phase) - .finish(), - } - } -} - /// Query of instance column at a certain relative location -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct InstanceQuery { /// Query index pub(crate) index: Option, @@ -590,25 +549,6 @@ impl InstanceQuery { } } -impl Debug for InstanceQuery { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self.index { - None => f - .debug_struct("InstanceQuery") - .field("index", &self.index) - .field("column_index", &self.column_index) - .field("rotation", &self.rotation) - .finish(), - Some(idx) => f - .debug_struct("InstanceQuery") - .field("index", &idx) - .field("column_index", &self.column_index) - .field("rotation", &self.rotation) - .finish(), - } - } -} - /// A fixed column of a lookup table. /// /// A lookup table can be loaded into this column via [`Layouter::assign_table`]. Columns @@ -1297,43 +1237,43 @@ impl std::fmt::Debug for Expression { Expression::Constant(scalar) => f.debug_tuple("Constant").field(scalar).finish(), Expression::Selector(selector) => f.debug_tuple("Selector").field(selector).finish(), // Skip enum variant and print query struct directly to maintain backwards compatibility. - Expression::Fixed(FixedQuery { - index, - column_index, - rotation, - }) => f - .debug_struct("Fixed") - .field("query_index", index) - .field("column_index", column_index) - .field("rotation", rotation) - .finish(), - Expression::Advice(AdviceQuery { - index, - column_index, - rotation, - phase, - }) => { + Expression::Fixed(query) => { + let mut debug_struct = f.debug_struct("Fixed"); + match query.index { + None => debug_struct.field("query_index", &query.index), + Some(idx) => debug_struct.field("query_index", &idx), + }; + debug_struct + .field("column_index", &query.column_index) + .field("rotation", &query.rotation) + .finish() + } + Expression::Advice(query) => { let mut debug_struct = f.debug_struct("Advice"); + match query.index { + None => debug_struct.field("query_index", &query.index), + Some(idx) => debug_struct.field("query_index", &idx), + }; debug_struct - .field("query_index", index) - .field("column_index", column_index) - .field("rotation", rotation); + .field("column_index", &query.column_index) + .field("rotation", &query.rotation); // Only show advice's phase if it's not in first phase. - if *phase != FirstPhase.to_sealed() { - debug_struct.field("phase", phase); + if query.phase != FirstPhase.to_sealed() { + debug_struct.field("phase", &query.phase); } debug_struct.finish() } - Expression::Instance(InstanceQuery { - index, - column_index, - rotation, - }) => f - .debug_struct("Instance") - .field("query_index", index) - .field("column_index", column_index) - .field("rotation", rotation) - .finish(), + Expression::Instance(query) => { + let mut debug_struct = f.debug_struct("Instance"); + match query.index { + None => debug_struct.field("query_index", &query.index), + Some(idx) => debug_struct.field("query_index", &idx), + }; + debug_struct + .field("column_index", &query.column_index) + .field("rotation", &query.rotation) + .finish() + } Expression::Challenge(challenge) => { f.debug_tuple("Challenge").field(challenge).finish() } diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index bdf17e04fb..af63b5fb30 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -643,18 +643,14 @@ fn plonk_api() { Sum( Product( Advice { - query_index: Some( - 0, - ), + query_index: 0, column_index: 1, rotation: Rotation( 0, ), }, Fixed { - query_index: Some( - 1, - ), + query_index: 2, column_index: 2, rotation: Rotation( 0, @@ -663,18 +659,14 @@ fn plonk_api() { ), Product( Advice { - query_index: Some( - 1, - ), + query_index: 1, column_index: 2, rotation: Rotation( 0, ), }, Fixed { - query_index: Some( - 2, - ), + query_index: 3, column_index: 3, rotation: Rotation( 0, @@ -685,18 +677,14 @@ fn plonk_api() { Product( Product( Advice { - query_index: Some( - 0, - ), + query_index: 0, column_index: 1, rotation: Rotation( 0, ), }, Advice { - query_index: Some( - 1, - ), + query_index: 1, column_index: 2, rotation: Rotation( 0, @@ -704,9 +692,7 @@ fn plonk_api() { }, ), Fixed { - query_index: Some( - 3, - ), + query_index: 5, column_index: 1, rotation: Rotation( 0, @@ -717,18 +703,14 @@ fn plonk_api() { Negated( Product( Advice { - query_index: Some( - 2, - ), + query_index: 2, column_index: 3, rotation: Rotation( 0, ), }, Fixed { - query_index: Some( - 4, - ), + query_index: 4, column_index: 4, rotation: Rotation( 0, @@ -739,9 +721,7 @@ fn plonk_api() { ), Product( Fixed { - query_index: Some( - 5, - ), + query_index: 1, column_index: 0, rotation: Rotation( 0, @@ -749,18 +729,14 @@ fn plonk_api() { }, Product( Advice { - query_index: Some( - 3, - ), + query_index: 3, column_index: 4, rotation: Rotation( 1, ), }, Advice { - query_index: Some( - 4, - ), + query_index: 4, column_index: 0, rotation: Rotation( -1, @@ -771,9 +747,7 @@ fn plonk_api() { ), Product( Fixed { - query_index: Some( - 6, - ), + query_index: 6, column_index: 5, rotation: Rotation( 0, @@ -781,9 +755,7 @@ fn plonk_api() { }, Sum( Advice { - query_index: Some( - 0, - ), + query_index: 0, column_index: 1, rotation: Rotation( 0, @@ -791,9 +763,7 @@ fn plonk_api() { }, Negated( Instance { - query_index: Some( - 0, - ), + query_index: 0, column_index: 0, rotation: Rotation( 0, @@ -891,7 +861,7 @@ fn plonk_api() { ), ( Column { - index: 2, + index: 0, column_type: Fixed, }, Rotation( @@ -900,7 +870,7 @@ fn plonk_api() { ), ( Column { - index: 3, + index: 2, column_type: Fixed, }, Rotation( @@ -909,7 +879,7 @@ fn plonk_api() { ), ( Column { - index: 1, + index: 3, column_type: Fixed, }, Rotation( @@ -927,7 +897,7 @@ fn plonk_api() { ), ( Column { - index: 0, + index: 1, column_type: Fixed, }, Rotation( @@ -1000,9 +970,7 @@ fn plonk_api() { Argument { input_expressions: [ Advice { - query_index: Some( - 0, - ), + query_index: 0, column_index: 1, rotation: Rotation( 0, @@ -1011,9 +979,7 @@ fn plonk_api() { ], table_expressions: [ Fixed { - query_index: Some( - 0, - ), + query_index: 0, column_index: 6, rotation: Rotation( 0, From 502db56e8b5941ec479f60b777952e267b43cae6 Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Fri, 10 Mar 2023 00:44:50 +0800 Subject: [PATCH 21/25] upgrade rust-toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index af92bdd9f5..9405730420 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.63.0 +1.64.0 From fe4a554e71a93d79e27da530cab1065fe6e29401 Mon Sep 17 00:00:00 2001 From: CeciliaZ030 <45245961+CeciliaZ030@users.noreply.github.com> Date: Fri, 10 Mar 2023 01:25:44 +0800 Subject: [PATCH 22/25] Update halo2_proofs/src/plonk/circuit.rs Co-authored-by: Han --- halo2_proofs/src/plonk/circuit.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index dcd66ce673..9bc9e0469b 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -2195,9 +2195,9 @@ impl ConstraintSystem { self.blinding_factors() // m blinding factors + 1 // for l_{-(m + 1)} (l_last) + 1 // for l_0 (just for extra breathing room for the permutation - // argument, to essentially force a separation in the - // permutation polynomial between the roles of l_last, l_0 - // and the interstitial values.) + // argument, to essentially force a separation in the + // permutation polynomial between the roles of l_last, l_0 + // and the interstitial values.) + 1 // for at least one row } From 046ac793cd6b7efc673a008b6d94f8a6eb867b07 Mon Sep 17 00:00:00 2001 From: CeciliaZ030 <45245961+CeciliaZ030@users.noreply.github.com> Date: Fri, 10 Mar 2023 01:25:58 +0800 Subject: [PATCH 23/25] Update halo2_proofs/src/plonk/circuit.rs Co-authored-by: Han --- halo2_proofs/src/plonk/circuit.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 9bc9e0469b..1fbe6da7bb 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -616,14 +616,6 @@ pub trait Assignment { NR: Into, N: FnOnce() -> NR; - // /// Allows the developer to include an annotation for an specific column within a `Region`. - // /// - // /// This is usually useful for debugging circuit failures. - // fn annotate_column(&mut self, annotation: A, column: Column) - // where - // A: FnOnce() -> AR, - // AR: Into; - /// Allows the developer to include an annotation for an specific column within a `Region`. /// /// This is usually useful for debugging circuit failures. From d2b57981afad6874f8cbb68304cdbabd09a06eca Mon Sep 17 00:00:00 2001 From: Cecilia Zhang Date: Sun, 12 Mar 2023 16:41:24 +0800 Subject: [PATCH 24/25] ran clippy --- halo2_proofs/examples/shuffle.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/halo2_proofs/examples/shuffle.rs b/halo2_proofs/examples/shuffle.rs index c482b7b06c..9e2a36d3b7 100644 --- a/halo2_proofs/examples/shuffle.rs +++ b/halo2_proofs/examples/shuffle.rs @@ -12,7 +12,7 @@ use halo2_proofs::{ multiopen::{ProverIPA, VerifierIPA}, strategy::AccumulatorStrategy, }, - Rotation, VerificationStrategy, + VerificationStrategy, }, transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, @@ -63,19 +63,19 @@ impl MyConfig { // Second phase let z = meta.advice_column_in(SecondPhase); - meta.create_gate("z should start with 1", |meta| { + meta.create_gate("z should start with 1", |_| { let one = Expression::Constant(F::ONE); vec![q_first.expr() * (one - z.cur())] }); - meta.create_gate("z should end with 1", |meta| { + meta.create_gate("z should end with 1", |_| { let one = Expression::Constant(F::ONE); vec![q_last.expr() * (one - z.cur())] }); - meta.create_gate("z should have valid transition", |meta| { + meta.create_gate("z should have valid transition", |_| { let q_shuffle = q_shuffle.expr(); let original = original.map(|advice| advice.cur()); let shuffled = shuffled.map(|advice| advice.cur()); From e7be268cd7c7e6078eed26a6bd5ae184f960b841 Mon Sep 17 00:00:00 2001 From: CeciliaZ030 <45245961+CeciliaZ030@users.noreply.github.com> Date: Wed, 26 Apr 2023 22:31:04 +0800 Subject: [PATCH 25/25] Update halo2_proofs/src/plonk/circuit.rs Co-authored-by: Han --- halo2_proofs/src/plonk/circuit.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 9b9ca83fb7..bb37459c42 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -69,9 +69,9 @@ impl Column { self.query_cell(Rotation::prev()) } - /// Return expression from column at the specified row - pub fn at(&self, at: usize) -> Expression { - self.query_cell(Rotation(at as i32)) + /// Return expression from column at the specified rotation + pub fn rot(&self, rotation: i32) -> Expression { + self.query_cell(Rotation(rotation)) } }