From 3a7197456147fd13be4a87ab3172a9d601823153 Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Tue, 7 Feb 2023 22:07:50 +0800 Subject: [PATCH 01/54] feat: add assign_regions api --- halo2_proofs/Cargo.toml | 1 + halo2_proofs/src/circuit.rs | 25 ++++ .../src/circuit/floor_planner/single_pass.rs | 141 +++++++++++++++++- halo2_proofs/src/circuit/floor_planner/v1.rs | 13 ++ halo2_proofs/src/dev.rs | 4 + halo2_proofs/src/dev/cost.rs | 5 + halo2_proofs/src/plonk/circuit.rs | 6 +- halo2_proofs/src/plonk/keygen.rs | 4 + halo2_proofs/src/plonk/prover.rs | 6 +- 9 files changed, 202 insertions(+), 3 deletions(-) diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index a941f0437f..cbd28e528d 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -59,6 +59,7 @@ poseidon = { git = 'https://github.com/appliedzkp/poseidon.git' } #, branch = 'c num-integer = "0.1" num-bigint = { version = "0.4", features = ["rand"] } +crossbeam = "0.8.0" # Developer tooling dependencies plotters = { version = "0.3.0", optional = true } tabbycat = { version = "0.1", features = ["attributes"], optional = true } diff --git a/halo2_proofs/src/circuit.rs b/halo2_proofs/src/circuit.rs index c48bb77459..c156ad7452 100644 --- a/halo2_proofs/src/circuit.rs +++ b/halo2_proofs/src/circuit.rs @@ -420,6 +420,17 @@ pub trait Layouter { N: Fn() -> NR, NR: Into; + fn assign_regions( + &mut self, + name: N, + assignments: Vec, + ) -> Result, Error> + where + A: FnMut(Region<'_, F>) -> Result + Send, + AR: Send, + N: Fn() -> NR, + NR: Into; + /// Assign a table region to an absolute row number. /// /// ```ignore @@ -495,6 +506,20 @@ impl<'a, F: Field, L: Layouter + 'a> Layouter for NamespacedLayouter<'a, F self.0.assign_region(name, assignment) } + fn assign_regions( + &mut self, + name: N, + assignments: Vec, + ) -> Result, Error> + where + A: FnMut(Region<'_, F>) -> Result + Send, + AR: Send, + N: Fn() -> NR, + NR: Into, + { + self.0.assign_regions(name, assignments) + } + fn assign_table(&mut self, name: N, assignment: A) -> Result<(), Error> where A: FnMut(Table<'_, F>) -> Result<(), Error>, diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index f0e9098d12..31b9cb5c30 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -2,6 +2,8 @@ use std::cmp; use std::collections::HashMap; use std::fmt; use std::marker::PhantomData; +use std::ops::Range; +use std::sync::{Arc, Mutex}; use ff::Field; @@ -12,6 +14,7 @@ use crate::{ layouter::{RegionColumn, RegionLayouter, RegionShape, TableLayouter}, Cell, Layouter, Region, RegionIndex, RegionStart, Table, Value, }, + multicore, plonk::{ Advice, Any, Assigned, Assignment, Challenge, Circuit, Column, Error, Fixed, FloorPlanner, Instance, Selector, TableColumn, @@ -42,7 +45,7 @@ impl FloorPlanner for SimpleFloorPlanner { } /// A [`Layouter`] for a single-chip circuit. -pub struct SingleChipLayouter<'a, F: Field, CS: Assignment + 'a> { +pub struct SingleChipLayouter<'a, F: Field, CS: Assignment> { cs: &'a mut CS, constants: Vec>, /// Stores the starting row for each region. @@ -76,6 +79,24 @@ impl<'a, F: Field, CS: Assignment> SingleChipLayouter<'a, F, CS> { }; Ok(ret) } + + fn fork( + &mut self, + sub_cs: Vec<&'a mut CS>, + ranges: &Vec>, + ) -> Result, Error> { + Ok(sub_cs + .into_iter() + .map(|mut sub_cs| Self { + cs: sub_cs, + constants: self.constants.clone(), + regions: self.regions.clone(), + columns: self.columns.clone(), + table_columns: self.table_columns.clone(), + _marker: Default::default(), + }) + .collect::>()) + } } impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a, F, CS> { @@ -170,6 +191,124 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a Ok(result) } + fn assign_regions( + &mut self, + name: N, + mut assignments: Vec, + ) -> Result, Error> + where + A: FnMut(Region<'_, F>) -> Result + Send, + AR: Send, + N: Fn() -> NR, + NR: Into, + { + let region_index = self.regions.len(); + let region_name: String = name().into(); + // Get region shapes sequentially + let mut ranges = vec![]; + for (i, assignment) in assignments.iter_mut().enumerate() { + // Get shape of the ith sub-region. + let mut shape = RegionShape::new((region_index + i).into()); + let region: &mut dyn RegionLayouter = &mut shape; + assignment(region.into())?; + + let mut region_start = 0; + for column in &shape.columns { + let column_start = self.columns.get(column).cloned().unwrap_or(0); + region_start = cmp::max(region_start, column_start); + } + log::debug!( + "{}_{} start: {}, end: {}", + region_name, + i, + region_start, + region_start + shape.row_count() + ); + self.regions.push(region_start.into()); + ranges.push(region_start..(region_start + shape.row_count())); + + // Update column usage information. + for column in shape.columns.iter() { + self.columns + .insert(*column, region_start + shape.row_count()); + } + } + + // Do actual synthesis of sub-regions in parallel + let mut sub_cs = self.cs.fork(&ranges)?; + let mut sub_layouters = self.fork(sub_cs.iter_mut().collect(), &ranges)?; + let ret = crossbeam::scope(|scope| { + let mut handles = vec![]; + for (i, (mut assignment, sub_layouter)) in assignments + .into_iter() + .zip(sub_layouters.iter_mut()) + .enumerate() + { + let sub_layouter = Arc::new(Mutex::new(sub_layouter)); + handles.push(scope.spawn(move |_| { + let mut sub_layouter = sub_layouter.lock().unwrap(); // it's the only thread that's accessing sub_layouter + let mut region = + SingleChipLayouterRegion::new(*sub_layouter, (region_index + i).into()); + let region_ref: &mut dyn RegionLayouter = &mut region; + let result = assignment(region_ref.into()); + let constant = region.constants.clone(); + + (result, constant) + })); + } + + handles + .into_iter() + .map(|handle| handle.join().expect("handle.join should never fail")) + .collect::>() + }) + .expect("scope should not fail"); + let (results, constants): (Vec<_>, Vec<_>) = ret.into_iter().unzip(); + + // Check if there are errors in sub-region synthesis + let results = results + .into_iter() + .map(|result| result) + .collect::, Error>>()?; + + // Merge all constants from sub-regions together + let constants_to_assign = constants + .into_iter() + .flat_map(|constant_to_assign| constant_to_assign.into_iter()) + .collect::>(); + + // Assign constants. For the simple floor planner, we assign constants in order in + // the first `constants` column. + if self.constants.is_empty() { + if !constants_to_assign.is_empty() { + return Err(Error::NotEnoughColumnsForConstants); + } + } else { + let constants_column = self.constants[0]; + let next_constant_row = self + .columns + .entry(Column::::from(constants_column).into()) + .or_default(); + for (constant, advice) in constants_to_assign { + self.cs.assign_fixed( + || format!("Constant({:?})", constant.evaluate()), + constants_column, + *next_constant_row, + || Value::known(constant), + )?; + self.cs.copy( + constants_column.into(), + *next_constant_row, + advice.column, + *self.regions[*advice.region_index] + advice.row_offset, + )?; + *next_constant_row += 1; + } + } + + Ok(results) + } + fn assign_table(&mut self, name: N, mut assignment: A) -> Result<(), Error> where A: FnMut(Table<'_, F>) -> Result<(), Error>, diff --git a/halo2_proofs/src/circuit/floor_planner/v1.rs b/halo2_proofs/src/circuit/floor_planner/v1.rs index 1a3b5b676b..bdb396d907 100644 --- a/halo2_proofs/src/circuit/floor_planner/v1.rs +++ b/halo2_proofs/src/circuit/floor_planner/v1.rs @@ -184,6 +184,19 @@ impl<'p, 'a, F: Field, CS: Assignment + 'a> Layouter for V1Pass<'p, 'a, F, } } + fn assign_regions( + &mut self, + name: N, + assignments: Vec, + ) -> Result, Error> + where + A: FnMut(Region<'_, F>) -> Result, + N: Fn() -> NR, + NR: Into, + { + todo!() + } + fn assign_table(&mut self, name: N, assignment: A) -> Result<(), Error> where A: FnMut(Table<'_, F>) -> Result<(), Error>, diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index f2155165b8..3fbde0e3e1 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -355,6 +355,10 @@ impl Assignment for MockProver { Ok(()) } + fn fork(&mut self, ranges: &Vec>) -> Result, Error> { + todo!() + } + fn query_instance( &self, column: Column, diff --git a/halo2_proofs/src/dev/cost.rs b/halo2_proofs/src/dev/cost.rs index ad6f8b1eec..e44ecfc8ae 100644 --- a/halo2_proofs/src/dev/cost.rs +++ b/halo2_proofs/src/dev/cost.rs @@ -1,5 +1,6 @@ //! Developer tools for investigating the cost of a circuit. +use std::ops::Range; use std::{ collections::{HashMap, HashSet}, iter, @@ -69,6 +70,10 @@ impl Assignment for Assembly { Ok(()) } + fn fork(&mut self, ranges: &Vec>) -> Result, Error> { + todo!() + } + fn query_instance(&self, _: Column, _: usize) -> Result, Error> { Ok(Value::unknown()) } diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index e94787b619..6c458e28b1 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -1,6 +1,7 @@ use core::cmp::max; use core::ops::{Add, Mul}; use ff::Field; +use std::ops::Range; use std::{ convert::TryFrom, ops::{Neg, Sub}, @@ -523,7 +524,7 @@ impl Challenge { /// This trait allows a [`Circuit`] to direct some backend to assign a witness /// for a constraint system. -pub trait Assignment { +pub trait Assignment: Sized + Send { /// Creates a new region and enters into it. /// /// Panics if we are currently in a region (if `exit_region` was not called). @@ -556,6 +557,9 @@ pub trait Assignment { A: FnOnce() -> AR, AR: Into; + /// fork + fn fork(&mut self, ranges: &Vec>) -> Result, Error>; + /// Queries the cell of an instance column at a particular absolute row. /// /// Returns the cell's value, if known. diff --git a/halo2_proofs/src/plonk/keygen.rs b/halo2_proofs/src/plonk/keygen.rs index e18d9c62d2..49eb91ec16 100644 --- a/halo2_proofs/src/plonk/keygen.rs +++ b/halo2_proofs/src/plonk/keygen.rs @@ -84,6 +84,10 @@ impl Assignment for Assembly { Ok(()) } + fn fork(&mut self, ranges: &Vec>) -> Result, Error> { + todo!() + } + fn query_instance(&self, _: Column, row: usize) -> Result, Error> { if !self.usable_rows.contains(&row) { return Err(Error::not_enough_rows_available(self.k)); diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index bd9257c6b3..242471619d 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -4,7 +4,7 @@ use halo2curves::CurveExt; use rand_core::RngCore; use std::collections::BTreeSet; use std::env::var; -use std::ops::RangeTo; +use std::ops::{Range, RangeTo}; use std::sync::atomic::AtomicUsize; use std::time::Instant; use std::{collections::HashMap, iter, mem, sync::atomic::Ordering}; @@ -164,6 +164,10 @@ pub fn create_proof< Ok(()) } + fn fork(&mut self, ranges: &Vec>) -> Result, Error> { + todo!() + } + fn query_instance(&self, column: Column, row: usize) -> Result, Error> { if !self.usable_rows.contains(&row) { return Err(Error::not_enough_rows_available(self.k)); From d2b83b3f678f32137f3ed1889a5accdd4983a1c4 Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Wed, 8 Feb 2023 11:55:35 +0800 Subject: [PATCH 02/54] fix lifetime compilation error --- .../src/circuit/floor_planner/single_pass.rs | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index 31b9cb5c30..17cd3f4588 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -45,7 +45,7 @@ impl FloorPlanner for SimpleFloorPlanner { } /// A [`Layouter`] for a single-chip circuit. -pub struct SingleChipLayouter<'a, F: Field, CS: Assignment> { +pub struct SingleChipLayouter<'a, F: Field, CS: Assignment + 'a> { cs: &'a mut CS, constants: Vec>, /// Stores the starting row for each region. @@ -66,7 +66,7 @@ impl<'a, F: Field, CS: Assignment + 'a> fmt::Debug for SingleChipLayouter<'a, } } -impl<'a, F: Field, CS: Assignment> SingleChipLayouter<'a, F, CS> { +impl<'a, F: Field, CS: Assignment + 'a> SingleChipLayouter<'a, F, CS> { /// Creates a new single-chip layouter. pub fn new(cs: &'a mut CS, constants: Vec>) -> Result { let ret = SingleChipLayouter { @@ -81,13 +81,12 @@ impl<'a, F: Field, CS: Assignment> SingleChipLayouter<'a, F, CS> { } fn fork( - &mut self, + &self, sub_cs: Vec<&'a mut CS>, - ranges: &Vec>, ) -> Result, Error> { Ok(sub_cs .into_iter() - .map(|mut sub_cs| Self { + .map(|sub_cs| Self { cs: sub_cs, constants: self.constants.clone(), regions: self.regions.clone(), @@ -236,19 +235,22 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a // Do actual synthesis of sub-regions in parallel let mut sub_cs = self.cs.fork(&ranges)?; - let mut sub_layouters = self.fork(sub_cs.iter_mut().collect(), &ranges)?; + let sub_cs = sub_cs.iter_mut().collect(); + let sub_layouters = self.fork(sub_cs)?; let ret = crossbeam::scope(|scope| { let mut handles = vec![]; for (i, (mut assignment, sub_layouter)) in assignments .into_iter() - .zip(sub_layouters.iter_mut()) + .zip(sub_layouters.into_iter()) .enumerate() { let sub_layouter = Arc::new(Mutex::new(sub_layouter)); handles.push(scope.spawn(move |_| { let mut sub_layouter = sub_layouter.lock().unwrap(); // it's the only thread that's accessing sub_layouter - let mut region = - SingleChipLayouterRegion::new(*sub_layouter, (region_index + i).into()); + let mut region = SingleChipLayouterRegion::new( + &mut *sub_layouter, + (region_index + i).into(), + ); let region_ref: &mut dyn RegionLayouter = &mut region; let result = assignment(region_ref.into()); let constant = region.constants.clone(); From ce99b2d749bf235ef51dbbbc233c03d5f0d7da4e Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Wed, 8 Feb 2023 12:03:01 +0800 Subject: [PATCH 03/54] include assign_regions in plonk_api test --- halo2_proofs/tests/plonk_api.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index 913762c0da..c79619423b 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -3,7 +3,7 @@ use assert_matches::assert_matches; use halo2_proofs::arithmetic::{Field, FieldExt}; -use halo2_proofs::circuit::{Cell, Layouter, SimpleFloorPlanner, Value}; +use halo2_proofs::circuit::{Cell, Layouter, Region, SimpleFloorPlanner, Value}; use halo2_proofs::dev::MockProver; use halo2_proofs::plonk::{ create_proof as create_plonk_proof, keygen_pk, keygen_vk, verify_proof as verify_plonk_proof, @@ -22,7 +22,7 @@ use std::marker::PhantomData; #[test] fn plonk_api() { - const K: u32 = 5; + const K: u32 = 16; /// This represents an advice column at a certain row in the ConstraintSystem #[derive(Copy, Clone, Debug)] @@ -376,6 +376,25 @@ fn plonk_api() { let _ = cs.public_input(&mut layouter, || Value::known(F::one() + F::one()))?; + let a: Value> = self.a.into(); + let assignments = |mut region: Region<'_, F>| -> Result<(), Error> { + for i in 0..(1<<12) { + region.assign_advice(|| "config.a", cs.config.a, i, || a)?; + region.assign_advice(|| "config.b", cs.config.b, i, || a)?; + region.assign_advice(|| "config.c", cs.config.c, i, || a.double())?; + + region.assign_fixed(|| "a", cs.config.sa, i, || Value::known(F::one()))?; + region.assign_fixed(|| "b", cs.config.sb, i, || Value::known(F::one()))?; + region.assign_fixed(|| "c", cs.config.sc, i, || Value::known(F::one()))?; + region.assign_fixed(|| "a * b", cs.config.sm, i, || Value::known(F::zero()))?; + } + Ok(()) + }; + layouter.assign_regions( + || "regions", + (0..8).into_iter().map(|_| assignments).collect(), + )?; + for _ in 0..10 { let a: Value> = self.a.into(); let mut a_squared = Value::unknown(); @@ -393,6 +412,7 @@ fn plonk_api() { cs.copy(&mut layouter, b1, c0)?; } + cs.lookup_table(&mut layouter, &self.lookup_table)?; Ok(()) From 7af66a88d373a612ff704daf828009312bcfb899 Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Wed, 8 Feb 2023 14:22:10 +0800 Subject: [PATCH 04/54] fmt --- halo2_proofs/src/circuit/floor_planner/single_pass.rs | 5 +---- halo2_proofs/tests/plonk_api.rs | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index 17cd3f4588..e5799a2322 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -80,10 +80,7 @@ impl<'a, F: Field, CS: Assignment + 'a> SingleChipLayouter<'a, F, CS> { Ok(ret) } - fn fork( - &self, - sub_cs: Vec<&'a mut CS>, - ) -> Result, Error> { + fn fork(&self, sub_cs: Vec<&'a mut CS>) -> Result, Error> { Ok(sub_cs .into_iter() .map(|sub_cs| Self { diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index c79619423b..d8b50f5aa1 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -378,7 +378,7 @@ fn plonk_api() { let a: Value> = self.a.into(); let assignments = |mut region: Region<'_, F>| -> Result<(), Error> { - for i in 0..(1<<12) { + for i in 0..(1 << 12) { region.assign_advice(|| "config.a", cs.config.a, i, || a)?; region.assign_advice(|| "config.b", cs.config.b, i, || a)?; region.assign_advice(|| "config.c", cs.config.c, i, || a.double())?; @@ -412,7 +412,6 @@ fn plonk_api() { cs.copy(&mut layouter, b1, c0)?; } - cs.lookup_table(&mut layouter, &self.lookup_table)?; Ok(()) From 032cd5d93362d5a857bfb4453c8763b43b9e477e Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Thu, 9 Feb 2023 00:32:02 +0800 Subject: [PATCH 05/54] feat: implement fork for MockProver (WIP) --- .../src/circuit/floor_planner/single_pass.rs | 12 +- halo2_proofs/src/dev.rs | 161 +++++++++++++++--- halo2_proofs/src/dev/failure.rs | 7 +- halo2_proofs/src/dev/util.rs | 12 ++ halo2_proofs/src/lib.rs | 2 +- halo2_proofs/tests/plonk_api.rs | 28 +-- 6 files changed, 177 insertions(+), 45 deletions(-) diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index e5799a2322..75f3a00295 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -236,18 +236,16 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a let sub_layouters = self.fork(sub_cs)?; let ret = crossbeam::scope(|scope| { let mut handles = vec![]; - for (i, (mut assignment, sub_layouter)) in assignments + for (i, (mut assignment, mut sub_layouter)) in assignments .into_iter() .zip(sub_layouters.into_iter()) .enumerate() { - let sub_layouter = Arc::new(Mutex::new(sub_layouter)); + // let sub_layouter = sub_layouter; handles.push(scope.spawn(move |_| { - let mut sub_layouter = sub_layouter.lock().unwrap(); // it's the only thread that's accessing sub_layouter - let mut region = SingleChipLayouterRegion::new( - &mut *sub_layouter, - (region_index + i).into(), - ); + // let mut sub_layouter = sub_layouter.lock().unwrap(); // it's the only thread that's accessing sub_layouter + let mut region = + SingleChipLayouterRegion::new(&mut sub_layouter, (region_index + i).into()); let region_ref: &mut dyn RegionLayouter = &mut region; let result = assignment(region_ref.into()); let constant = region.constants.clone(); diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 3fbde0e3e1..43c7a1c888 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -4,7 +4,8 @@ use std::collections::HashMap; use std::collections::HashSet; use std::fmt; use std::iter; -use std::ops::{Add, Mul, Neg, Range}; +use std::ops::{Add, DerefMut, Mul, Neg, Range}; +use std::sync::Arc; use std::time::{Duration, Instant}; use blake2b_simd::blake2b; @@ -49,7 +50,7 @@ mod graph; #[cfg_attr(docsrs, doc(cfg(feature = "dev-graph")))] pub use graph::{circuit_dot_graph, layout::CircuitLayout}; -#[derive(Debug)] +#[derive(Clone, Debug)] struct Region { /// The name of the region. Not required to be unique. name: String, @@ -280,7 +281,7 @@ impl Mul for Value { /// )); /// ``` #[derive(Debug)] -pub struct MockProver { +pub struct MockProver<'a, F: Group + Field> { k: u32, n: u32, cs: ConstraintSystem, @@ -292,14 +293,16 @@ pub struct MockProver { current_region: Option, // The fixed cells in the circuit, arranged as [column][row]. - fixed: Vec>>, + fixed_vec: Arc>>>, + fixed: Vec<&'a mut [CellValue]>, // The advice cells in the circuit, arranged as [column][row]. pub(crate) advice: Vec>>, advice_prev: Vec>>, // The instance cells in the circuit, arranged as [column][row]. instance: Vec>, - selectors: Vec>, + selectors_vec: Arc>>, + selectors: Vec<&'a mut [bool]>, challenges: Vec, @@ -311,7 +314,7 @@ pub struct MockProver { current_phase: crate::plonk::sealed::Phase, } -impl Assignment for MockProver { +impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { fn enter_region(&mut self, name: N) where NR: Into, @@ -356,7 +359,69 @@ impl Assignment for MockProver { } fn fork(&mut self, ranges: &Vec>) -> Result, Error> { - todo!() + // check ranges are non-overlapping and monotonically increasing + let mut range_start = self.usable_rows.start; + for (i, sub_range) in ranges.iter().enumerate() { + if sub_range.start < range_start { + return Err(Error::Synthesis); + } + range_start = sub_range.end; + } + + // split self.fixed into several pieces + let fixed_ptrs = self + .fixed + .iter_mut() + .map(|vec| vec.as_mut_ptr()) + .collect::>(); + let selectors_ptrs = self + .selectors + .iter_mut() + .map(|vec| vec.as_mut_ptr()) + .collect::>(); + + let mut sub_cs = vec![]; + for (i, sub_range) in ranges.iter().enumerate() { + let fixed = fixed_ptrs + .iter() + .map(|ptr| unsafe { + std::slice::from_raw_parts_mut( + ptr.add(sub_range.start), + sub_range.end - sub_range.start, + ) + }) + .collect::]>>(); + let selectors = selectors_ptrs + .iter() + .map(|ptr| unsafe { + std::slice::from_raw_parts_mut( + ptr.add(sub_range.start), + sub_range.end - sub_range.start, + ) + }) + .collect::>(); + + sub_cs.push(Self { + k: self.k, + n: self.n, + cs: self.cs.clone(), + regions: self.regions.clone(), + current_region: None, + fixed_vec: self.fixed_vec.clone(), + fixed, + advice: self.advice.clone(), + advice_prev: self.advice_prev.clone(), + instance: self.instance.clone(), + selectors_vec: self.selectors_vec.clone(), + selectors, + challenges: self.challenges.clone(), + permutation: self.permutation.clone(), + usable_rows: sub_range.clone(), + current_phase: self.current_phase, + }); + } + + Ok(sub_cs) } fn query_instance( @@ -459,12 +524,15 @@ impl Assignment for MockProver { .or_default(); } - *self + let fix_cell = self .fixed .get_mut(column.index()) - .and_then(|v| v.get_mut(row)) - .ok_or(Error::BoundsFailure)? = - CellValue::Assigned(to().into_field().evaluate().assign()?); + .and_then(|v| v.get_mut(row - self.usable_rows.start)) + .ok_or(Error::BoundsFailure); + if fix_cell.is_err() { + println!("fix cell is none: {}, row: {}", column.index(), row); + } + *fix_cell? = CellValue::Assigned(to().into_field().evaluate().assign()?); Ok(()) } @@ -521,7 +589,7 @@ impl Assignment for MockProver { } } -impl MockProver { +impl<'a, F: FieldExt> MockProver<'a, F> { /// Runs a synthetic keygen-and-prove operation on the given circuit, collecting data /// about the constraints and their assignments. pub fn run>( @@ -556,8 +624,29 @@ impl MockProver { .collect::, _>>()?; // Fixed columns contain no blinding factors. - let fixed = vec![vec![CellValue::Unassigned; n]; cs.num_fixed_columns]; - let selectors = vec![vec![false; n]; cs.num_selectors]; + let fixed_vec = Arc::new(vec![vec![CellValue::Unassigned; n]; cs.num_fixed_columns]); + + let fixed = unsafe { + // extract an mutable reference to the 2-dimensional vector + // we are forced to use unsafe method because vec is + // protected by the Arc struct + let fixed_vec_clone = fixed_vec.clone(); + let ptr = Arc::as_ptr(&fixed_vec_clone) as *mut Vec>>; + let mut_ref = &mut (*ptr); + mut_ref + .iter_mut() + .map(|fixed| fixed.as_mut_slice()) + .collect::>() + }; + + let selectors_vec = Arc::new(vec![vec![false; n]; cs.num_selectors]); + let selectors = unsafe { + let selectors_vec_clone = selectors_vec.clone(); + let ptr = Arc::as_ptr(&selectors_vec_clone) as *mut Vec>; + let mut_ref = &mut (*ptr); + + mut_ref.iter_mut().map(|item| item.as_mut_slice()).collect() + }; // Advice columns contain blinding factors. let blinding_factors = cs.blinding_factors(); let usable_rows = n - (blinding_factors + 1); @@ -649,10 +738,12 @@ impl MockProver { cs, regions: vec![], current_region: None, + fixed_vec, fixed, advice, advice_prev: vec![], instance, + selectors_vec, selectors, challenges: challenges.clone(), permutation, @@ -661,15 +752,23 @@ impl MockProver { }; ConcreteCircuit::FloorPlanner::synthesize(&mut prover, circuit, config, constants)?; - let (cs, selector_polys) = prover.cs.compress_selectors(prover.selectors.clone()); + let (cs, selector_polys) = prover + .cs + .compress_selectors(prover.selectors_vec.as_ref().clone()); prover.cs = cs; - prover.fixed.extend(selector_polys.into_iter().map(|poly| { - let mut v = vec![CellValue::Unassigned; n]; - for (v, p) in v.iter_mut().zip(&poly[..]) { - *v = CellValue::Assigned(*p); - } - v - })); + println!( + "prover.fixed_vec.strong_count: {}", + Arc::strong_count(&prover.fixed_vec) + ); + Arc::get_mut(&mut prover.fixed_vec) + .expect("get_mut prover.fixed_vec") + .extend(selector_polys.into_iter().map(|poly| { + let mut v = vec![CellValue::Unassigned; n]; + for (v, p) in v.iter_mut().zip(&poly[..]) { + *v = CellValue::Assigned(*p); + } + v + })); Ok(prover) } @@ -766,7 +865,7 @@ impl MockProver { move |(poly_index, poly)| match poly.evaluate_lazy( &|scalar| Value::Real(scalar), &|_| panic!("virtual selectors are removed during optimization"), - &util::load(n, row, &self.cs.fixed_queries, &self.fixed), + &util::load_slice(n, row, &self.cs.fixed_queries, &self.fixed), &util::load(n, row, &self.cs.advice_queries, &self.advice), &util::load_instance( n, @@ -798,7 +897,12 @@ impl MockProver { cell_values: util::cell_values( gate, poly, - &util::load(n, row, &self.cs.fixed_queries, &self.fixed), + &util::load_slice( + n, + row, + &self.cs.fixed_queries, + &self.fixed, + ), &util::load(n, row, &self.cs.advice_queries, &self.advice), &util::load_instance( n, @@ -1135,7 +1239,7 @@ impl MockProver { match poly.evaluate_lazy( &|scalar| Value::Real(scalar), &|_| panic!("virtual selectors are removed during optimization"), - &util::load(n, row, &self.cs.fixed_queries, &self.fixed), + &util::load_slice(n, row, &self.cs.fixed_queries, &self.fixed), &util::load(n, row, &self.cs.advice_queries, &self.advice), &util::load_instance( n, @@ -1167,7 +1271,12 @@ impl MockProver { cell_values: util::cell_values( gate, poly, - &util::load(n, row, &self.cs.fixed_queries, &self.fixed), + &util::load_slice( + n, + row, + &self.cs.fixed_queries, + &self.fixed, + ), &util::load(n, row, &self.cs.advice_queries, &self.advice), &util::load_instance( n, diff --git a/halo2_proofs/src/dev/failure.rs b/halo2_proofs/src/dev/failure.rs index e20eb7058b..632e6d056b 100644 --- a/halo2_proofs/src/dev/failure.rs +++ b/halo2_proofs/src/dev/failure.rs @@ -456,7 +456,12 @@ fn render_lookup( let cell_values = input.evaluate( &|_| BTreeMap::default(), &|_| panic!("virtual selectors are removed during optimization"), - &cell_value(&util::load(n, row, &cs.fixed_queries, &prover.fixed)), + &cell_value(&util::load_slice( + n, + row, + &cs.fixed_queries, + &prover.fixed.as_slice(), + )), &cell_value(&util::load(n, row, &cs.advice_queries, &prover.advice)), &cell_value(&util::load_instance( n, diff --git a/halo2_proofs/src/dev/util.rs b/halo2_proofs/src/dev/util.rs index a4dbfe5a40..00693fd2d2 100644 --- a/halo2_proofs/src/dev/util.rs +++ b/halo2_proofs/src/dev/util.rs @@ -86,6 +86,18 @@ pub(super) fn load<'a, F: FieldExt, T: ColumnType, Q: Into + Copy>( } } +pub(super) fn load_slice<'a, F: FieldExt, T: ColumnType, Q: Into + Copy>( + n: i32, + row: i32, + queries: &'a [(Column, Rotation)], + cells: &'a [&mut [CellValue]], +) -> impl Fn(Q) -> Value + 'a { + move |query| { + let (column, at) = &queries[query.into().index]; + let resolved_row = (row + at.0) % n; + cells[column.index()][resolved_row as usize].into() + } +} pub(super) fn load_instance<'a, F: FieldExt, T: ColumnType, Q: Into + Copy>( n: i32, row: i32, diff --git a/halo2_proofs/src/lib.rs b/halo2_proofs/src/lib.rs index b4bdcd5baf..8f1b70b309 100644 --- a/halo2_proofs/src/lib.rs +++ b/halo2_proofs/src/lib.rs @@ -19,7 +19,7 @@ )] #![deny(broken_intra_doc_links)] #![deny(missing_debug_implementations)] -#![deny(unsafe_code)] +// #![deny(unsafe_code)] // Remove this once we update pasta_curves #![allow(unused_imports)] #![allow(clippy::derive_partial_eq_without_eq)] diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index d8b50f5aa1..435edf8070 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -510,13 +510,6 @@ fn plonk_api() { ) .expect("proof generation should not fail"); - // Check this circuit is satisfied. - let prover = match MockProver::run(K, &circuit, vec![vec![instance]]) { - Ok(prover) => prover, - Err(e) => panic!("{:?}", e), - }; - assert_eq!(prover.verify(), Ok(())); - transcript.finalize() } @@ -558,11 +551,26 @@ fn plonk_api() { use halo2curves::bn256::Bn256; type Scheme = KZGCommitmentScheme; - bad_keys!(Scheme); + // bad_keys!(Scheme); let params = ParamsKZG::::new(K); let rng = OsRng; + let (a, instance, lookup_table) = common!(Scheme); + + let circuit: MyCircuit<::Scalar> = MyCircuit { + a: Value::known(a), + lookup_table, + }; + + // Check this circuit is satisfied. + let prover = match MockProver::run(K, &circuit, vec![vec![instance]]) { + Ok(prover) => prover, + Err(e) => panic!("{:?}", e), + }; + assert_eq!(prover.verify_par(), Ok(())); + log::info!("mock proving succeed!"); + let pk = keygen::>(¶ms); let proof = create_proof::<_, ProverGWC<_>, _, _, Blake2bWrite<_, _, Challenge255<_>>>( @@ -1039,7 +1047,7 @@ fn plonk_api() { ); } } - test_plonk_api_ipa(); + // test_plonk_api_ipa(); test_plonk_api_gwc(); - test_plonk_api_shplonk(); + // test_plonk_api_shplonk(); } From 04b350905680b5fd8fd6c3f5f88170fbfba671cf Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Thu, 9 Feb 2023 11:49:47 +0800 Subject: [PATCH 06/54] add MockProver fork (continue) --- .../src/circuit/floor_planner/single_pass.rs | 12 +- halo2_proofs/src/dev.rs | 109 +++++++++++++++--- halo2_proofs/src/dev/failure.rs | 7 +- halo2_proofs/src/plonk/error.rs | 9 ++ 4 files changed, 116 insertions(+), 21 deletions(-) diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index 75f3a00295..33f75490d3 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -4,6 +4,7 @@ use std::fmt; use std::marker::PhantomData; use std::ops::Range; use std::sync::{Arc, Mutex}; +use std::time::Instant; use ff::Field; @@ -231,9 +232,12 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a } // Do actual synthesis of sub-regions in parallel + let cs_fork_time = Instant::now(); let mut sub_cs = self.cs.fork(&ranges)?; + println!("CS forked into {} subCS took {:?}", sub_cs.len(), cs_fork_time.elapsed()); let sub_cs = sub_cs.iter_mut().collect(); let sub_layouters = self.fork(sub_cs)?; + let regions_2nd_pass = Instant::now(); let ret = crossbeam::scope(|scope| { let mut handles = vec![]; for (i, (mut assignment, mut sub_layouter)) in assignments @@ -241,14 +245,17 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a .zip(sub_layouters.into_iter()) .enumerate() { - // let sub_layouter = sub_layouter; + let region_name = format!("{}_{}", region_name, i); handles.push(scope.spawn(move |_| { - // let mut sub_layouter = sub_layouter.lock().unwrap(); // it's the only thread that's accessing sub_layouter + let sub_region_2nd_pass = Instant::now(); + sub_layouter.cs.enter_region(|| region_name.clone()); let mut region = SingleChipLayouterRegion::new(&mut sub_layouter, (region_index + i).into()); let region_ref: &mut dyn RegionLayouter = &mut region; let result = assignment(region_ref.into()); let constant = region.constants.clone(); + sub_layouter.cs.exit_region(); + println!("region {} 2nd pass synthesis took {:?}", region_name, sub_region_2nd_pass.elapsed()); (result, constant) })); @@ -260,6 +267,7 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a .collect::>() }) .expect("scope should not fail"); + println!("{} sub_regions of {} 2nd pass synthesis took {:?}", ranges.len(), region_name, regions_2nd_pass.elapsed()); let (results, constants): (Vec<_>, Vec<_>) = ret.into_iter().unzip(); // Check if there are errors in sub-region synthesis diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 43c7a1c888..08a2a9f8f4 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -46,6 +46,7 @@ pub use gates::CircuitGates; #[cfg(feature = "dev-graph")] mod graph; +use crate::circuit::Cell; #[cfg(feature = "dev-graph")] #[cfg_attr(docsrs, doc(cfg(feature = "dev-graph")))] pub use graph::{circuit_dot_graph, layout::CircuitLayout}; @@ -296,7 +297,8 @@ pub struct MockProver<'a, F: Group + Field> { fixed_vec: Arc>>>, fixed: Vec<&'a mut [CellValue]>, // The advice cells in the circuit, arranged as [column][row]. - pub(crate) advice: Vec>>, + pub(crate) advice_vec: Arc>>>, + pub(crate) advice: Vec<&'a mut [CellValue]>, advice_prev: Vec>>, // The instance cells in the circuit, arranged as [column][row]. instance: Vec>, @@ -308,6 +310,8 @@ pub struct MockProver<'a, F: Group + Field> { permutation: permutation::keygen::Assembly, + rw_rows: Range, + // A range of available rows for assignment and copies. usable_rows: Range, @@ -343,6 +347,16 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { return Err(Error::not_enough_rows_available(self.k)); } + if !self.rw_rows.contains(&row) { + return Err(Error::InvalidRange( + row, + self.current_region + .as_ref() + .map(|region| region.name.clone()) + .unwrap(), + )); + } + // Track that this selector was enabled. We require that all selectors are enabled // inside some region (i.e. no floating selectors). self.current_region @@ -353,19 +367,24 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { .or_default() .push(row); - self.selectors[selector.0][row] = true; + self.selectors[selector.0][row - self.rw_rows.start] = true; Ok(()) } fn fork(&mut self, ranges: &Vec>) -> Result, Error> { // check ranges are non-overlapping and monotonically increasing - let mut range_start = self.usable_rows.start; + let mut range_start = self.rw_rows.start; for (i, sub_range) in ranges.iter().enumerate() { if sub_range.start < range_start { + // TODO: use more precise error type + return Err(Error::Synthesis); + } + if i == ranges.len() - 1 && sub_range.end >= self.rw_rows.end { return Err(Error::Synthesis); } range_start = sub_range.end; + println!("subCS_{} rw_rows: {}..{}", i, sub_range.start, sub_range.end); } // split self.fixed into several pieces @@ -379,6 +398,11 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { .iter_mut() .map(|vec| vec.as_mut_ptr()) .collect::>(); + let advice_ptrs = self + .advice + .iter_mut() + .map(|vec| vec.as_mut_ptr()) + .collect::>(); let mut sub_cs = vec![]; for (i, sub_range) in ranges.iter().enumerate() { @@ -400,23 +424,36 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { ) }) .collect::>(); + let advice = advice_ptrs + .iter() + .map(|ptr| unsafe { + std::slice::from_raw_parts_mut( + ptr.add(sub_range.start), + sub_range.end - sub_range.start, + ) + }) + .collect::]>>(); sub_cs.push(Self { k: self.k, n: self.n, cs: self.cs.clone(), + // TODO: use a cheaper way to clone regions: self.regions.clone(), current_region: None, fixed_vec: self.fixed_vec.clone(), fixed, - advice: self.advice.clone(), + advice_vec: self.advice_vec.clone(), + advice, advice_prev: self.advice_prev.clone(), instance: self.instance.clone(), selectors_vec: self.selectors_vec.clone(), selectors, challenges: self.challenges.clone(), + // TODO: use a cheaper way to clone permutation: self.permutation.clone(), - usable_rows: sub_range.clone(), + rw_rows: sub_range.clone(), + usable_rows: self.usable_rows.clone(), current_phase: self.current_phase, }); } @@ -461,6 +498,16 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { return Err(Error::not_enough_rows_available(self.k)); } + if !self.rw_rows.contains(&row) { + return Err(Error::InvalidRange( + row, + self.current_region + .as_ref() + .map(|region| region.name.clone()) + .unwrap(), + )); + } + if let Some(region) = self.current_region.as_mut() { region.update_extent(column.into(), row); region @@ -474,7 +521,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { *self .advice .get_mut(column.index()) - .and_then(|v| v.get_mut(row)) + .and_then(|v| v.get_mut(row - self.rw_rows.start)) .ok_or(Error::BoundsFailure)? = assigned; #[cfg(feature = "phase-check")] @@ -515,6 +562,16 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { return Err(Error::not_enough_rows_available(self.k)); } + if !self.rw_rows.contains(&row) { + return Err(Error::InvalidRange( + row, + self.current_region + .as_ref() + .map(|region| region.name.clone()) + .unwrap(), + )); + } + if let Some(region) = self.current_region.as_mut() { region.update_extent(column.into(), row); region @@ -527,7 +584,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { let fix_cell = self .fixed .get_mut(column.index()) - .and_then(|v| v.get_mut(row - self.usable_rows.start)) + .and_then(|v| v.get_mut(row - self.rw_rows.start)) .ok_or(Error::BoundsFailure); if fix_cell.is_err() { println!("fix cell is none: {}, row: {}", column.index(), row); @@ -625,7 +682,6 @@ impl<'a, F: FieldExt> MockProver<'a, F> { // Fixed columns contain no blinding factors. let fixed_vec = Arc::new(vec![vec![CellValue::Unassigned; n]; cs.num_fixed_columns]); - let fixed = unsafe { // extract an mutable reference to the 2-dimensional vector // we are forced to use unsafe method because vec is @@ -647,10 +703,11 @@ impl<'a, F: FieldExt> MockProver<'a, F> { mut_ref.iter_mut().map(|item| item.as_mut_slice()).collect() }; + // Advice columns contain blinding factors. let blinding_factors = cs.blinding_factors(); let usable_rows = n - (blinding_factors + 1); - let advice = vec![ + let advice_vec = Arc::new(vec![ { let mut column = vec![CellValue::Unassigned; n]; // Poison unusable rows. @@ -660,7 +717,15 @@ impl<'a, F: FieldExt> MockProver<'a, F> { column }; cs.num_advice_columns - ]; + ]); + let advice = unsafe { + let advice_vec_clone = advice_vec.clone(); + let ptr = Arc::as_ptr(&advice_vec_clone) as *mut Vec>>; + let mut_ref = &mut (*ptr); + + mut_ref.iter_mut().map(|item| item.as_mut_slice()).collect() + }; + let permutation = permutation::keygen::Assembly::new(n, &cs.permutation); let constants = cs.constants.clone(); @@ -740,6 +805,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { current_region: None, fixed_vec, fixed, + advice_vec, advice, advice_prev: vec![], instance, @@ -747,6 +813,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { selectors, challenges: challenges.clone(), permutation, + rw_rows: 0..usable_rows, usable_rows: 0..usable_rows, current_phase: ThirdPhase.to_sealed(), }; @@ -756,10 +823,6 @@ impl<'a, F: FieldExt> MockProver<'a, F> { .cs .compress_selectors(prover.selectors_vec.as_ref().clone()); prover.cs = cs; - println!( - "prover.fixed_vec.strong_count: {}", - Arc::strong_count(&prover.fixed_vec) - ); Arc::get_mut(&mut prover.fixed_vec) .expect("get_mut prover.fixed_vec") .extend(selector_polys.into_iter().map(|poly| { @@ -866,7 +929,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { &|scalar| Value::Real(scalar), &|_| panic!("virtual selectors are removed during optimization"), &util::load_slice(n, row, &self.cs.fixed_queries, &self.fixed), - &util::load(n, row, &self.cs.advice_queries, &self.advice), + &util::load_slice(n, row, &self.cs.advice_queries, &self.advice), &util::load_instance( n, row, @@ -903,7 +966,12 @@ impl<'a, F: FieldExt> MockProver<'a, F> { &self.cs.fixed_queries, &self.fixed, ), - &util::load(n, row, &self.cs.advice_queries, &self.advice), + &util::load_slice( + n, + row, + &self.cs.advice_queries, + &self.advice, + ), &util::load_instance( n, row, @@ -1240,7 +1308,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { &|scalar| Value::Real(scalar), &|_| panic!("virtual selectors are removed during optimization"), &util::load_slice(n, row, &self.cs.fixed_queries, &self.fixed), - &util::load(n, row, &self.cs.advice_queries, &self.advice), + &util::load_slice(n, row, &self.cs.advice_queries, &self.advice), &util::load_instance( n, row, @@ -1277,7 +1345,12 @@ impl<'a, F: FieldExt> MockProver<'a, F> { &self.cs.fixed_queries, &self.fixed, ), - &util::load(n, row, &self.cs.advice_queries, &self.advice), + &util::load_slice( + n, + row, + &self.cs.advice_queries, + &self.advice, + ), &util::load_instance( n, row, diff --git a/halo2_proofs/src/dev/failure.rs b/halo2_proofs/src/dev/failure.rs index 632e6d056b..72d53731af 100644 --- a/halo2_proofs/src/dev/failure.rs +++ b/halo2_proofs/src/dev/failure.rs @@ -462,7 +462,12 @@ fn render_lookup( &cs.fixed_queries, &prover.fixed.as_slice(), )), - &cell_value(&util::load(n, row, &cs.advice_queries, &prover.advice)), + &cell_value(&util::load_slice( + n, + row, + &cs.advice_queries, + &prover.advice, + )), &cell_value(&util::load_instance( n, row, diff --git a/halo2_proofs/src/plonk/error.rs b/halo2_proofs/src/plonk/error.rs index 33fdae9083..84b14cbd2d 100644 --- a/halo2_proofs/src/plonk/error.rs +++ b/halo2_proofs/src/plonk/error.rs @@ -1,3 +1,4 @@ +use crate::circuit::RegionIndex; use std::cmp; use std::error; use std::fmt; @@ -18,6 +19,8 @@ pub enum Error { ConstraintSystemFailure, /// Out of bounds index passed to a backend BoundsFailure, + /// Out of bounds an subCS is allowed to access(r/w). + InvalidRange(usize, String), /// Opening error Opening, /// Transcript error @@ -60,6 +63,12 @@ impl fmt::Display for Error { Error::InvalidInstances => write!(f, "Provided instances do not match the circuit"), Error::ConstraintSystemFailure => write!(f, "The constraint system is not satisfied"), Error::BoundsFailure => write!(f, "An out-of-bounds index was passed to the backend"), + Error::InvalidRange(row, region_name) => write!( + f, + "the row={} is not in the range that this subCS owns (region name = {})", + row, + region_name, + ), Error::Opening => write!(f, "Multi-opening proof was invalid"), Error::Transcript(e) => write!(f, "Transcript error: {}", e), Error::NotEnoughRowsAvailable { current_k } => write!( From 7e8cfe49e40e922f10fee06f0772b273f7f62690 Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Thu, 9 Feb 2023 11:50:17 +0800 Subject: [PATCH 07/54] fmt --- .../src/circuit/floor_planner/single_pass.rs | 19 ++++++++++++++++--- halo2_proofs/src/dev.rs | 5 ++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index 33f75490d3..a9e040d633 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -234,7 +234,11 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a // Do actual synthesis of sub-regions in parallel let cs_fork_time = Instant::now(); let mut sub_cs = self.cs.fork(&ranges)?; - println!("CS forked into {} subCS took {:?}", sub_cs.len(), cs_fork_time.elapsed()); + println!( + "CS forked into {} subCS took {:?}", + sub_cs.len(), + cs_fork_time.elapsed() + ); let sub_cs = sub_cs.iter_mut().collect(); let sub_layouters = self.fork(sub_cs)?; let regions_2nd_pass = Instant::now(); @@ -255,7 +259,11 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a let result = assignment(region_ref.into()); let constant = region.constants.clone(); sub_layouter.cs.exit_region(); - println!("region {} 2nd pass synthesis took {:?}", region_name, sub_region_2nd_pass.elapsed()); + println!( + "region {} 2nd pass synthesis took {:?}", + region_name, + sub_region_2nd_pass.elapsed() + ); (result, constant) })); @@ -267,7 +275,12 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a .collect::>() }) .expect("scope should not fail"); - println!("{} sub_regions of {} 2nd pass synthesis took {:?}", ranges.len(), region_name, regions_2nd_pass.elapsed()); + println!( + "{} sub_regions of {} 2nd pass synthesis took {:?}", + ranges.len(), + region_name, + regions_2nd_pass.elapsed() + ); let (results, constants): (Vec<_>, Vec<_>) = ret.into_iter().unzip(); // Check if there are errors in sub-region synthesis diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 08a2a9f8f4..cb986fc5c2 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -384,7 +384,10 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { return Err(Error::Synthesis); } range_start = sub_range.end; - println!("subCS_{} rw_rows: {}..{}", i, sub_range.start, sub_range.end); + println!( + "subCS_{} rw_rows: {}..{}", + i, sub_range.start, sub_range.end + ); } // split self.fixed into several pieces From 87aaef3586dbaff38f98bacdaac7844e9ccdecdb Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Thu, 9 Feb 2023 18:52:20 +0800 Subject: [PATCH 08/54] finished adding fork for MockProver --- .../src/circuit/floor_planner/single_pass.rs | 5 +- halo2_proofs/src/dev.rs | 61 ++++++++++++++++--- halo2_proofs/src/dev/cost.rs | 4 ++ halo2_proofs/src/plonk/circuit.rs | 5 +- halo2_proofs/src/plonk/keygen.rs | 24 ++++++++ halo2_proofs/src/plonk/prover.rs | 4 ++ halo2_proofs/tests/plonk_api.rs | 6 +- 7 files changed, 96 insertions(+), 13 deletions(-) diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index a9e040d633..821ca86fe0 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -239,8 +239,8 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a sub_cs.len(), cs_fork_time.elapsed() ); - let sub_cs = sub_cs.iter_mut().collect(); - let sub_layouters = self.fork(sub_cs)?; + let ref_sub_cs = sub_cs.iter_mut().collect(); + let sub_layouters = self.fork(ref_sub_cs)?; let regions_2nd_pass = Instant::now(); let ret = crossbeam::scope(|scope| { let mut handles = vec![]; @@ -275,6 +275,7 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a .collect::>() }) .expect("scope should not fail"); + self.cs.merge(sub_cs)?; println!( "{} sub_regions of {} 2nd pass synthesis took {:?}", ranges.len(), diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index cb986fc5c2..a9bc87c879 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -51,6 +51,12 @@ use crate::circuit::Cell; #[cfg_attr(docsrs, doc(cfg(feature = "dev-graph")))] pub use graph::{circuit_dot_graph, layout::CircuitLayout}; +#[derive(Clone, Debug)] +struct CopyCell { + pub column: Column, + pub row: usize, +} + #[derive(Clone, Debug)] struct Region { /// The name of the region. Not required to be unique. @@ -65,6 +71,8 @@ struct Region { /// The cells assigned in this region. We store this as a `HashMap` with count so that if any cells /// are double-assigned, they will be visibly darker. cells: HashMap<(Column, usize), usize>, + /// The copies that need to be enforced in this region. + copies: Vec<(CopyCell, CopyCell)>, } impl Region { @@ -308,7 +316,8 @@ pub struct MockProver<'a, F: Group + Field> { challenges: Vec, - permutation: permutation::keygen::Assembly, + /// For mock prover which is generated from `fork()`, this field is None. + permutation: Option, rw_rows: Range, @@ -331,6 +340,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { rows: None, enabled_selectors: HashMap::default(), cells: HashMap::default(), + copies: Vec::new(), }); } @@ -441,8 +451,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { k: self.k, n: self.n, cs: self.cs.clone(), - // TODO: use a cheaper way to clone - regions: self.regions.clone(), + regions: vec![], current_region: None, fixed_vec: self.fixed_vec.clone(), fixed, @@ -453,8 +462,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { selectors_vec: self.selectors_vec.clone(), selectors, challenges: self.challenges.clone(), - // TODO: use a cheaper way to clone - permutation: self.permutation.clone(), + permutation: None, rw_rows: sub_range.clone(), usable_rows: self.usable_rows.clone(), current_phase: self.current_phase, @@ -464,6 +472,22 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { Ok(sub_cs) } + fn merge(&mut self, sub_cs: Vec) -> Result<(), Error> { + for (left, right) in self + .regions + .iter() + .skip(self.regions.len() - sub_cs.len()) + .flat_map(|region| region.copies.iter()) + { + self.permutation + .as_mut() + .expect("root cs permutation should be Some") + .copy(left.column, left.row, right.column, right.row)?; + } + + Ok(()) + } + fn query_instance( &self, column: Column, @@ -608,8 +632,25 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { return Err(Error::not_enough_rows_available(self.k)); } - self.permutation - .copy(left_column, left_row, right_column, right_row) + match self.permutation.as_mut() { + Some(permutation) => permutation.copy(left_column, left_row, right_column, right_row), + None => { + let left_cell = CopyCell { + column: left_column, + row: left_row, + }; + let right_cell = CopyCell { + column: right_column, + row: right_row, + }; + self.current_region + .as_mut() + .unwrap() + .copies + .push((left_cell, right_cell)); + Ok(()) + } + } } fn fill_from_row( @@ -815,7 +856,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { selectors_vec, selectors, challenges: challenges.clone(), - permutation, + permutation: Some(permutation), rw_rows: 0..usable_rows, usable_rows: 0..usable_rows, current_phase: ThirdPhase.to_sealed(), @@ -1154,6 +1195,8 @@ impl<'a, F: FieldExt> MockProver<'a, F> { // Iterate over each column of the permutation self.permutation + .as_ref() + .expect("root cs permutation must be Some") .mapping .iter() .enumerate() @@ -1521,6 +1564,8 @@ impl<'a, F: FieldExt> MockProver<'a, F> { // Iterate over each column of the permutation self.permutation + .as_ref() + .expect("root cs permutation must be Some") .mapping .iter() .enumerate() diff --git a/halo2_proofs/src/dev/cost.rs b/halo2_proofs/src/dev/cost.rs index e44ecfc8ae..a97a9e07f6 100644 --- a/halo2_proofs/src/dev/cost.rs +++ b/halo2_proofs/src/dev/cost.rs @@ -74,6 +74,10 @@ impl Assignment for Assembly { todo!() } + fn merge(&mut self, sub_cs: Vec) -> Result<(), Error> { + todo!() + } + fn query_instance(&self, _: Column, _: usize) -> Result, Error> { Ok(Value::unknown()) } diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 6c458e28b1..aed811b614 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -557,9 +557,12 @@ pub trait Assignment: Sized + Send { A: FnOnce() -> AR, AR: Into; - /// fork + /// Fork fn fork(&mut self, ranges: &Vec>) -> Result, Error>; + /// Merge + fn merge(&mut self, sub_cs: Vec) -> Result<(), Error>; + /// Queries the cell of an instance column at a particular absolute row. /// /// Returns the cell's value, if known. diff --git a/halo2_proofs/src/plonk/keygen.rs b/halo2_proofs/src/plonk/keygen.rs index 49eb91ec16..d965d2945d 100644 --- a/halo2_proofs/src/plonk/keygen.rs +++ b/halo2_proofs/src/plonk/keygen.rs @@ -53,6 +53,7 @@ struct Assembly { permutation: permutation::keygen::Assembly, selectors: Vec>, // A range of available rows for assignment and copies. + rw_rows: Range, usable_rows: Range, _marker: std::marker::PhantomData, } @@ -85,6 +86,27 @@ impl Assignment for Assembly { } fn fork(&mut self, ranges: &Vec>) -> Result, Error> { + let mut range_start = self.rw_rows.start; + for (i, sub_range) in ranges.iter().enumerate() { + if sub_range.start < range_start { + // TODO: use more precise error type + return Err(Error::Synthesis); + } + if i == ranges.len() - 1 && sub_range.end >= self.rw_rows.end { + return Err(Error::Synthesis); + } + range_start = sub_range.end; + println!( + "subCS_{} rw_rows: {}..{}", + i, sub_range.start, sub_range.end + ); + } + + for (i, sub_range) in ranges.iter().enumerate() {} + todo!() + } + + fn merge(&mut self, sub_cs: Vec) -> Result<(), Error> { todo!() } @@ -216,6 +238,7 @@ where fixed: vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns], permutation: permutation::keygen::Assembly::new(params.n() as usize, &cs.permutation), selectors: vec![vec![false; params.n() as usize]; cs.num_selectors], + rw_rows: 0..params.n() as usize - (cs.blinding_factors() + 1), usable_rows: 0..params.n() as usize - (cs.blinding_factors() + 1), _marker: std::marker::PhantomData, }; @@ -302,6 +325,7 @@ where fixed: vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns], permutation: permutation::keygen::Assembly::new(params.n() as usize, &cs.permutation), selectors: vec![vec![false; params.n() as usize]; cs.num_selectors], + rw_rows: 0..params.n() as usize - (cs.blinding_factors() + 1), usable_rows: 0..params.n() as usize - (cs.blinding_factors() + 1), _marker: std::marker::PhantomData, }; diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index 242471619d..6c339ea9e0 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -168,6 +168,10 @@ pub fn create_proof< todo!() } + fn merge(&mut self, sub_cs: Vec) -> Result<(), Error> { + todo!() + } + fn query_instance(&self, column: Column, row: usize) -> Result, Error> { if !self.usable_rows.contains(&row) { return Err(Error::not_enough_rows_available(self.k)); diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index 435edf8070..5937bb8054 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -379,14 +379,16 @@ fn plonk_api() { let a: Value> = self.a.into(); let assignments = |mut region: Region<'_, F>| -> Result<(), Error> { for i in 0..(1 << 12) { - region.assign_advice(|| "config.a", cs.config.a, i, || a)?; - region.assign_advice(|| "config.b", cs.config.b, i, || a)?; + let a0 = region.assign_advice(|| "config.a", cs.config.a, i, || a)?; + let a1 = region.assign_advice(|| "config.b", cs.config.b, i, || a)?; region.assign_advice(|| "config.c", cs.config.c, i, || a.double())?; region.assign_fixed(|| "a", cs.config.sa, i, || Value::known(F::one()))?; region.assign_fixed(|| "b", cs.config.sb, i, || Value::known(F::one()))?; region.assign_fixed(|| "c", cs.config.sc, i, || Value::known(F::one()))?; region.assign_fixed(|| "a * b", cs.config.sm, i, || Value::known(F::zero()))?; + + region.constrain_equal(a0.cell(), a1.cell())?; } Ok(()) }; From 49a136ff621976b5e1e5d750422451689b046925 Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Fri, 10 Feb 2023 18:40:53 +0800 Subject: [PATCH 09/54] log --- halo2_proofs/Cargo.toml | 1 + .../src/circuit/floor_planner/single_pass.rs | 6 +-- halo2_proofs/src/circuit/floor_planner/v1.rs | 4 +- halo2_proofs/src/dev.rs | 2 +- halo2_proofs/src/plonk/keygen.rs | 2 +- halo2_proofs/tests/plonk_api.rs | 46 ++++++++++++------- 6 files changed, 38 insertions(+), 23 deletions(-) diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index cbd28e528d..72368237ae 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -67,6 +67,7 @@ log = "0.4.17" # timer ark-std = { version = "0.3.0" } +env_logger = "0.8.0" [dev-dependencies] assert_matches = "1.5" diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index 821ca86fe0..8b03de2c50 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -234,7 +234,7 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a // Do actual synthesis of sub-regions in parallel let cs_fork_time = Instant::now(); let mut sub_cs = self.cs.fork(&ranges)?; - println!( + log::info!( "CS forked into {} subCS took {:?}", sub_cs.len(), cs_fork_time.elapsed() @@ -259,7 +259,7 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a let result = assignment(region_ref.into()); let constant = region.constants.clone(); sub_layouter.cs.exit_region(); - println!( + log::info!( "region {} 2nd pass synthesis took {:?}", region_name, sub_region_2nd_pass.elapsed() @@ -276,7 +276,7 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a }) .expect("scope should not fail"); self.cs.merge(sub_cs)?; - println!( + log::info!( "{} sub_regions of {} 2nd pass synthesis took {:?}", ranges.len(), region_name, diff --git a/halo2_proofs/src/circuit/floor_planner/v1.rs b/halo2_proofs/src/circuit/floor_planner/v1.rs index bdb396d907..6f1fd09a0b 100644 --- a/halo2_proofs/src/circuit/floor_planner/v1.rs +++ b/halo2_proofs/src/circuit/floor_planner/v1.rs @@ -186,8 +186,8 @@ impl<'p, 'a, F: Field, CS: Assignment + 'a> Layouter for V1Pass<'p, 'a, F, fn assign_regions( &mut self, - name: N, - assignments: Vec, + _name: N, + _assignments: Vec, ) -> Result, Error> where A: FnMut(Region<'_, F>) -> Result, diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index a9bc87c879..74f94784ee 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -394,7 +394,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { return Err(Error::Synthesis); } range_start = sub_range.end; - println!( + log::debug!( "subCS_{} rw_rows: {}..{}", i, sub_range.start, sub_range.end ); diff --git a/halo2_proofs/src/plonk/keygen.rs b/halo2_proofs/src/plonk/keygen.rs index d965d2945d..88f0a4e023 100644 --- a/halo2_proofs/src/plonk/keygen.rs +++ b/halo2_proofs/src/plonk/keygen.rs @@ -96,7 +96,7 @@ impl Assignment for Assembly { return Err(Error::Synthesis); } range_start = sub_range.end; - println!( + log::debug!( "subCS_{} rw_rows: {}..{}", i, sub_range.start, sub_range.end ); diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index 5937bb8054..31837be2ba 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -19,6 +19,7 @@ use halo2_proofs::transcript::{ }; use rand_core::{OsRng, RngCore}; use std::marker::PhantomData; +use std::time::Instant; #[test] fn plonk_api() { @@ -373,29 +374,41 @@ fn plonk_api() { mut layouter: impl Layouter, ) -> Result<(), Error> { let cs = StandardPlonk::new(config); + let mut is_first_pass_vec = vec![true; 8]; let _ = cs.public_input(&mut layouter, || Value::known(F::one() + F::one()))?; let a: Value> = self.a.into(); - let assignments = |mut region: Region<'_, F>| -> Result<(), Error> { - for i in 0..(1 << 12) { - let a0 = region.assign_advice(|| "config.a", cs.config.a, i, || a)?; - let a1 = region.assign_advice(|| "config.b", cs.config.b, i, || a)?; - region.assign_advice(|| "config.c", cs.config.c, i, || a.double())?; - - region.assign_fixed(|| "a", cs.config.sa, i, || Value::known(F::one()))?; - region.assign_fixed(|| "b", cs.config.sb, i, || Value::known(F::one()))?; - region.assign_fixed(|| "c", cs.config.sc, i, || Value::known(F::one()))?; - region.assign_fixed(|| "a * b", cs.config.sm, i, || Value::known(F::zero()))?; - - region.constrain_equal(a0.cell(), a1.cell())?; - } - Ok(()) - }; + let parallel_regions_time = Instant::now(); layouter.assign_regions( || "regions", - (0..8).into_iter().map(|_| assignments).collect(), + (0..8).into_iter() + .zip(is_first_pass_vec.chunks_mut(1).into_iter()) + .map(|(_, is_first_pass)| { + |mut region: Region<'_, F>| -> Result<(), Error> { + let n = 1 << 12; + for i in 0..n { + // skip the assign of rows except the last row in the first pass + if is_first_pass[0] && i < n-1 { + continue + } + let a0 = region.assign_advice(|| "config.a", cs.config.a, i, || a)?; + let a1 = region.assign_advice(|| "config.b", cs.config.b, i, || a)?; + region.assign_advice(|| "config.c", cs.config.c, i, || a.double())?; + + region.assign_fixed(|| "a", cs.config.sa, i, || Value::known(F::one()))?; + region.assign_fixed(|| "b", cs.config.sb, i, || Value::known(F::one()))?; + region.assign_fixed(|| "c", cs.config.sc, i, || Value::known(F::one()))?; + region.assign_fixed(|| "a * b", cs.config.sm, i, || Value::known(F::zero()))?; + + region.constrain_equal(a0.cell(), a1.cell())?; + } + is_first_pass[0] = false; + Ok(()) + } + }).collect(), )?; + log::info!("parallel_regions assign took {:?}", parallel_regions_time.elapsed()); for _ in 0..10 { let a: Value> = self.a.into(); @@ -1049,6 +1062,7 @@ fn plonk_api() { ); } } + env_logger::init(); // test_plonk_api_ipa(); test_plonk_api_gwc(); // test_plonk_api_shplonk(); From 73c70ed043ca012119531c03d976444990a81f3a Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Fri, 10 Feb 2023 22:55:31 +0800 Subject: [PATCH 10/54] add impl for keygen --- .../src/circuit/floor_planner/single_pass.rs | 3 + halo2_proofs/src/dev.rs | 11 +- halo2_proofs/src/dev/cost.rs | 4 +- halo2_proofs/src/helpers.rs | 7 + halo2_proofs/src/plonk/keygen.rs | 207 +++++++++++++++--- 5 files changed, 194 insertions(+), 38 deletions(-) diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index 8b03de2c50..653c8ac81f 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -275,7 +275,10 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a .collect::>() }) .expect("scope should not fail"); + let cs_merge_time = Instant::now(); + let num_sub_cs = sub_cs.len(); self.cs.merge(sub_cs)?; + log::info!("Merge {} subCS back took {:?}", num_sub_cs, cs_merge_time.elapsed()); log::info!( "{} sub_regions of {} 2nd pass synthesis took {:?}", ranges.len(), diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 74f94784ee..50fc4f244b 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -47,16 +47,11 @@ pub use gates::CircuitGates; mod graph; use crate::circuit::Cell; +use crate::helpers::CopyCell; #[cfg(feature = "dev-graph")] #[cfg_attr(docsrs, doc(cfg(feature = "dev-graph")))] pub use graph::{circuit_dot_graph, layout::CircuitLayout}; -#[derive(Clone, Debug)] -struct CopyCell { - pub column: Column, - pub row: usize, -} - #[derive(Clone, Debug)] struct Region { /// The name of the region. Not required to be unique. @@ -396,7 +391,9 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { range_start = sub_range.end; log::debug!( "subCS_{} rw_rows: {}..{}", - i, sub_range.start, sub_range.end + i, + sub_range.start, + sub_range.end ); } diff --git a/halo2_proofs/src/dev/cost.rs b/halo2_proofs/src/dev/cost.rs index a97a9e07f6..95d8c5f619 100644 --- a/halo2_proofs/src/dev/cost.rs +++ b/halo2_proofs/src/dev/cost.rs @@ -70,11 +70,11 @@ impl Assignment for Assembly { Ok(()) } - fn fork(&mut self, ranges: &Vec>) -> Result, Error> { + fn fork(&mut self, _ranges: &Vec>) -> Result, Error> { todo!() } - fn merge(&mut self, sub_cs: Vec) -> Result<(), Error> { + fn merge(&mut self, _sub_cs: Vec) -> Result<(), Error> { todo!() } diff --git a/halo2_proofs/src/helpers.rs b/halo2_proofs/src/helpers.rs index aef72b8338..3c389f2fc1 100644 --- a/halo2_proofs/src/helpers.rs +++ b/halo2_proofs/src/helpers.rs @@ -1,8 +1,15 @@ +use crate::plonk::{Any, Column}; use ff::Field; use halo2curves::{CurveAffine, FieldExt}; use num_bigint::BigUint; use std::io; +#[derive(Clone, Debug)] +pub(crate) struct CopyCell { + pub column: Column, + pub row: usize, +} + pub(crate) trait CurveRead: CurveAffine { /// Reads a compressed element from the buffer and attempts to parse it /// using `from_bytes`. diff --git a/halo2_proofs/src/plonk/keygen.rs b/halo2_proofs/src/plonk/keygen.rs index 88f0a4e023..e9958e8050 100644 --- a/halo2_proofs/src/plonk/keygen.rs +++ b/halo2_proofs/src/plonk/keygen.rs @@ -1,6 +1,7 @@ #![allow(clippy::int_plus_one)] use std::ops::Range; +use std::sync::Arc; use ff::Field; use group::Curve; @@ -14,6 +15,7 @@ use super::{ permutation, Assigned, Challenge, Error, Expression, LagrangeCoeff, Polynomial, ProvingKey, VerifyingKey, }; +use crate::helpers::CopyCell; use crate::{ arithmetic::{parallelize, CurveAffine}, circuit::Value, @@ -47,18 +49,21 @@ where /// Assembly to be used in circuit synthesis. #[derive(Debug)] -struct Assembly { +struct Assembly<'a, F: Field> { k: u32, - fixed: Vec, LagrangeCoeff>>, - permutation: permutation::keygen::Assembly, - selectors: Vec>, - // A range of available rows for assignment and copies. + fixed_vec: Arc, LagrangeCoeff>>>, + fixed: Vec<&'a mut [Assigned]>, + permutation: Option, + selectors_vec: Arc>>, + selectors: Vec<&'a mut [bool]>, rw_rows: Range, + copies: Vec<(CopyCell, CopyCell)>, + // A range of available rows for assignment and copies. usable_rows: Range, _marker: std::marker::PhantomData, } -impl Assignment for Assembly { +impl<'a, F: Field> Assignment for Assembly<'a, F> { fn enter_region(&mut self, _: N) where NR: Into, @@ -80,7 +85,11 @@ impl Assignment for Assembly { return Err(Error::not_enough_rows_available(self.k)); } - self.selectors[selector.0][row] = true; + if !self.rw_rows.contains(&row) { + return Err(Error::Synthesis); + } + + self.selectors[selector.0][row - self.rw_rows.start] = true; Ok(()) } @@ -98,16 +107,69 @@ impl Assignment for Assembly { range_start = sub_range.end; log::debug!( "subCS_{} rw_rows: {}..{}", - i, sub_range.start, sub_range.end + i, + sub_range.start, + sub_range.end ); } - for (i, sub_range) in ranges.iter().enumerate() {} - todo!() + let fixed_ptrs = self + .fixed + .iter_mut() + .map(|vec| vec.as_mut_ptr()) + .collect::>(); + let selectors_ptrs = self + .selectors + .iter_mut() + .map(|vec| vec.as_mut_ptr()) + .collect::>(); + + let mut sub_cs = vec![]; + for sub_range in ranges { + let fixed = fixed_ptrs + .iter() + .map(|ptr| unsafe { + std::slice::from_raw_parts_mut( + ptr.add(sub_range.start), + sub_range.end - sub_range.start, + ) + }) + .collect::]>>(); + let selectors = selectors_ptrs + .iter() + .map(|ptr| unsafe { + std::slice::from_raw_parts_mut( + ptr.add(sub_range.start), + sub_range.end - sub_range.start, + ) + }) + .collect::>(); + + sub_cs.push(Self { + k: 0, + fixed_vec: self.fixed_vec.clone(), + fixed, + permutation: None, + selectors_vec: self.selectors_vec.clone(), + selectors, + rw_rows: sub_range.clone(), + copies: vec![], + usable_rows: self.usable_rows.clone(), + _marker: Default::default(), + }); + } + + Ok(sub_cs) } fn merge(&mut self, sub_cs: Vec) -> Result<(), Error> { - todo!() + for (left, right) in sub_cs.into_iter().flat_map(|cs| cs.copies.into_iter()) { + self.permutation + .as_mut() + .expect("permutation must be Some") + .copy(left.column, left.row, right.column, right.row)?; + } + Ok(()) } fn query_instance(&self, _: Column, row: usize) -> Result, Error> { @@ -153,10 +215,14 @@ impl Assignment for Assembly { return Err(Error::not_enough_rows_available(self.k)); } + if !self.rw_rows.contains(&row) { + return Err(Error::Synthesis); + } + *self .fixed .get_mut(column.index()) - .and_then(|v| v.get_mut(row)) + .and_then(|v| v.get_mut(row - self.rw_rows.start)) .ok_or(Error::BoundsFailure)? = to().into_field().assign()?; Ok(()) @@ -173,8 +239,22 @@ impl Assignment for Assembly { return Err(Error::not_enough_rows_available(self.k)); } - self.permutation - .copy(left_column, left_row, right_column, right_row) + match self.permutation.as_mut() { + None => { + self.copies.push(( + CopyCell { + column: left_column, + row: left_row, + }, + CopyCell { + column: right_column, + row: right_row, + }, + )); + Ok(()) + } + Some(permutation) => permutation.copy(left_column, left_row, right_column, right_row), + } } fn fill_from_row( @@ -233,11 +313,38 @@ where return Err(Error::not_enough_rows_available(params.k())); } + let fixed_vec = Arc::new(vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns]); + let fixed = unsafe { + let fixed_vec_clone = fixed_vec.clone(); + let ptr = Arc::as_ptr(&fixed_vec_clone) as *mut Vec, LagrangeCoeff>>; + let mut_ref = &mut (*ptr); + mut_ref + .iter_mut() + .map(|poly| poly.values.as_mut_slice()) + .collect::>() + }; + + let selectors_vec = Arc::new(vec![vec![false; params.n() as usize]; cs.num_selectors]); + let selectors = unsafe { + let selectors_vec_clone = selectors_vec.clone(); + let ptr = Arc::as_ptr(&selectors_vec_clone) as *mut Vec>; + let mut_ref = &mut (*ptr); + mut_ref + .iter_mut() + .map(|vec| vec.as_mut_slice()) + .collect::>() + }; let mut assembly: Assembly = Assembly { k: params.k(), - fixed: vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns], - permutation: permutation::keygen::Assembly::new(params.n() as usize, &cs.permutation), - selectors: vec![vec![false; params.n() as usize]; cs.num_selectors], + fixed_vec, + fixed, + permutation: Some(permutation::keygen::Assembly::new( + params.n() as usize, + &cs.permutation, + )), + selectors_vec, + selectors, + copies: vec![], rw_rows: 0..params.n() as usize - (cs.blinding_factors() + 1), usable_rows: 0..params.n() as usize - (cs.blinding_factors() + 1), _marker: std::marker::PhantomData, @@ -251,8 +358,13 @@ where cs.constants.clone(), )?; - let mut fixed = batch_invert_assigned(assembly.fixed); - let (cs, selector_polys) = cs.compress_selectors(assembly.selectors); + debug_assert_eq!(Arc::strong_count(&assembly.fixed_vec), 1); + debug_assert_eq!(Arc::strong_count(&assembly.selectors_vec), 1); + let mut fixed = + batch_invert_assigned(Arc::try_unwrap(assembly.fixed_vec).expect("only one Arc for fixed")); + let (cs, selector_polys) = cs.compress_selectors( + Arc::try_unwrap(assembly.selectors_vec).expect("only one Arc for selectors"), + ); fixed.extend( selector_polys .into_iter() @@ -261,6 +373,8 @@ where let permutation_vk = assembly .permutation + .take() + .expect("permutation must be Some") .build_vk(params, &domain, &cs.permutation); let fixed_commitments = fixed @@ -320,11 +434,38 @@ where return Err(Error::not_enough_rows_available(params.k())); } + let fixed_vec = Arc::new(vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns]); + let fixed = unsafe { + let fixed_vec_clone = fixed_vec.clone(); + let ptr = Arc::as_ptr(&fixed_vec_clone) as *mut Vec, LagrangeCoeff>>; + let mut_ref = &mut (*ptr); + mut_ref + .iter_mut() + .map(|poly| poly.values.as_mut_slice()) + .collect::>() + }; + + let selectors_vec = Arc::new(vec![vec![false; params.n() as usize]; cs.num_selectors]); + let selectors = unsafe { + let selectors_vec_clone = selectors_vec.clone(); + let ptr = Arc::as_ptr(&selectors_vec_clone) as *mut Vec>; + let mut_ref = &mut (*ptr); + mut_ref + .iter_mut() + .map(|vec| vec.as_mut_slice()) + .collect::>() + }; let mut assembly: Assembly = Assembly { k: params.k(), - fixed: vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns], - permutation: permutation::keygen::Assembly::new(params.n() as usize, &cs.permutation), - selectors: vec![vec![false; params.n() as usize]; cs.num_selectors], + fixed_vec, + fixed, + permutation: Some(permutation::keygen::Assembly::new( + params.n() as usize, + &cs.permutation, + )), + selectors_vec, + selectors, + copies: vec![], rw_rows: 0..params.n() as usize - (cs.blinding_factors() + 1), usable_rows: 0..params.n() as usize - (cs.blinding_factors() + 1), _marker: std::marker::PhantomData, @@ -338,8 +479,13 @@ where cs.constants.clone(), )?; - let mut fixed = batch_invert_assigned(assembly.fixed); - let (cs, selector_polys) = cs.compress_selectors(assembly.selectors); + debug_assert_eq!(Arc::strong_count(&assembly.fixed_vec), 1); + debug_assert_eq!(Arc::strong_count(&assembly.selectors_vec), 1); + let mut fixed = + batch_invert_assigned(Arc::try_unwrap(assembly.fixed_vec).expect("only one Arc for fixed")); + let (cs, selector_polys) = cs.compress_selectors( + Arc::try_unwrap(assembly.selectors_vec).expect("only one Arc for selectors"), + ); fixed.extend( selector_polys .into_iter() @@ -347,11 +493,12 @@ where ); let vk = vk.unwrap_or_else(|| { - let permutation_vk = - assembly - .permutation - .clone() - .build_vk(params, &domain, &cs.permutation); + let permutation_vk = assembly + .permutation + .as_ref() + .expect("permutation must be Some") + .clone() + .build_vk(params, &domain, &cs.permutation); let fixed_commitments = fixed .iter() @@ -373,6 +520,8 @@ where let permutation_pk = assembly .permutation + .take() + .expect("permutation must be Some") .build_pk(params, &vk.domain, &cs.permutation); // Compute l_0(X) From 28116e1e329e6a63569114e5b6025bc6a080e2fa Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Fri, 10 Feb 2023 23:17:24 +0800 Subject: [PATCH 11/54] add impl for prover --- .../src/circuit/floor_planner/single_pass.rs | 6 +- halo2_proofs/src/plonk/prover.rs | 85 +++++++++++++++++-- 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index 653c8ac81f..f79cddb86a 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -278,7 +278,11 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a let cs_merge_time = Instant::now(); let num_sub_cs = sub_cs.len(); self.cs.merge(sub_cs)?; - log::info!("Merge {} subCS back took {:?}", num_sub_cs, cs_merge_time.elapsed()); + log::info!( + "Merge {} subCS back took {:?}", + num_sub_cs, + cs_merge_time.elapsed() + ); log::info!( "{} sub_regions of {} 2nd pass synthesis took {:?}", ranges.len(), diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index 6c339ea9e0..ef33d9d900 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -6,6 +6,7 @@ use std::collections::BTreeSet; use std::env::var; use std::ops::{Range, RangeTo}; use std::sync::atomic::AtomicUsize; +use std::sync::Arc; use std::time::Instant; use std::{collections::HashMap, iter, mem, sync::atomic::Ordering}; @@ -134,9 +135,11 @@ pub fn create_proof< struct WitnessCollection<'a, F: Field> { k: u32, current_phase: sealed::Phase, - advice: Vec, LagrangeCoeff>>, + advice_vec: Arc, LagrangeCoeff>>>, + advice: Vec<&'a mut [Assigned]>, challenges: &'a HashMap, instances: &'a [&'a [F]], + rw_rows: Range, usable_rows: RangeTo, _marker: std::marker::PhantomData, } @@ -165,11 +168,59 @@ pub fn create_proof< } fn fork(&mut self, ranges: &Vec>) -> Result, Error> { - todo!() + let mut range_start = self.rw_rows.start; + for (i, sub_range) in ranges.iter().enumerate() { + if sub_range.start < range_start { + return Err(Error::Synthesis); + } + if i == ranges.len() - 1 && sub_range.end >= self.rw_rows.end { + return Err(Error::Synthesis); + } + range_start = sub_range.end; + log::debug!( + "subCS_{} rw_rows: {}..{}", + i, + sub_range.start, + sub_range.end + ); + } + + let advice_ptrs = self + .advice + .iter_mut() + .map(|vec| vec.as_mut_ptr()) + .collect::>(); + + let mut sub_cs = vec![]; + for sub_range in ranges { + let advice = advice_ptrs + .iter() + .map(|ptr| unsafe { + std::slice::from_raw_parts_mut( + ptr.add(sub_range.start), + sub_range.end - sub_range.start, + ) + }) + .collect::]>>(); + + sub_cs.push(Self { + k: 0, + current_phase: self.current_phase, + advice_vec: self.advice_vec.clone(), + advice, + challenges: self.challenges, + instances: self.instances.clone(), + rw_rows: sub_range.clone(), + usable_rows: self.usable_rows.clone(), + _marker: Default::default(), + }); + } + + Ok(sub_cs) } fn merge(&mut self, sub_cs: Vec) -> Result<(), Error> { - todo!() + Ok(()) } fn query_instance(&self, column: Column, row: usize) -> Result, Error> { @@ -206,10 +257,14 @@ pub fn create_proof< return Err(Error::not_enough_rows_available(self.k)); } + if !self.rw_rows.contains(&row) { + return Err(Error::Synthesis); + } + *self .advice .get_mut(column.index()) - .and_then(|v| v.get_mut(row)) + .and_then(|v| v.get_mut(row - self.rw_rows.start)) .ok_or(Error::BoundsFailure)? = to().into_field().assign()?; Ok(()) @@ -309,10 +364,25 @@ pub fn create_proof< .zip(instances) .enumerate() { + let advice_vec = Arc::new(vec![ + domain.empty_lagrange_assigned(); + meta.num_advice_columns + ]); + let advice_slice = unsafe { + let advice_vec_clone = advice_vec.clone(); + let ptr = + Arc::as_ptr(&advice_vec_clone) as *mut Vec>; + let mut_ref = &mut (*ptr); + mut_ref + .iter_mut() + .map(|poly| poly.values.as_mut_slice()) + .collect() + }; let mut witness = WitnessCollection { k: params.k(), current_phase, - advice: vec![domain.empty_lagrange_assigned(); meta.num_advice_columns], + advice_vec, + advice: advice_slice, instances, challenges: &challenges, // The prover will not be allowed to assign values to advice @@ -320,6 +390,7 @@ pub fn create_proof< // number of blinding factors and an extra row for use in the // permutation argument. usable_rows: ..unusable_rows_start, + rw_rows: 0..unusable_rows_start, _marker: std::marker::PhantomData, }; @@ -348,8 +419,8 @@ pub fn create_proof< } let mut advice_values = batch_invert_assigned::( - witness - .advice + Arc::try_unwrap(witness.advice_vec) + .expect("there must only one Arc for advice_vec") .into_iter() .enumerate() .filter_map(|(column_index, advice)| { From eeed4826651b1a6c700e15d9c6981d0c6aa1ab37 Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Mon, 13 Feb 2023 12:08:33 +0800 Subject: [PATCH 12/54] bug_fix: update fixed in MockProver --- halo2_proofs/src/dev.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 50fc4f244b..8c6bedafa9 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -873,6 +873,17 @@ impl<'a, F: FieldExt> MockProver<'a, F> { } v })); + // update prover.fixed as prover.fixed_vec is updated + prover.fixed = unsafe { + let clone = prover.fixed_vec.clone(); + let ptr = Arc::as_ptr(&clone) as *mut Vec>>; + let mut_ref = &mut (*ptr); + mut_ref + .iter_mut() + .map(|vec| vec.as_mut_slice()) + .collect::>() + }; + debug_assert_eq!(Arc::strong_count(&prover.fixed_vec), 1); Ok(prover) } From fa5b1b0a8fc33b96d235ffdcc957729f8cbb6db4 Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Mon, 13 Feb 2023 16:25:58 +0800 Subject: [PATCH 13/54] bug-fix: merge --- halo2_proofs/src/dev.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 8c6bedafa9..24c786894c 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -470,10 +470,9 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { } fn merge(&mut self, sub_cs: Vec) -> Result<(), Error> { - for (left, right) in self - .regions + for (left, right) in sub_cs .iter() - .skip(self.regions.len() - sub_cs.len()) + .flat_map(|cs| cs.regions.iter()) .flat_map(|region| region.copies.iter()) { self.permutation @@ -482,6 +481,10 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { .copy(left.column, left.row, right.column, right.row)?; } + for region in sub_cs.into_iter().map(|cs| cs.regions) { + self.regions.extend_from_slice(®ion[..]) + } + Ok(()) } @@ -858,7 +861,9 @@ impl<'a, F: FieldExt> MockProver<'a, F> { usable_rows: 0..usable_rows, current_phase: ThirdPhase.to_sealed(), }; + let syn_time = Instant::now(); ConcreteCircuit::FloorPlanner::synthesize(&mut prover, circuit, config, constants)?; + log::info!("MockProver synthesize took {:?}", syn_time.elapsed()); let (cs, selector_polys) = prover .cs From 843feaad73cb518520d93d19e42c7635abb86568 Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Thu, 9 Mar 2023 23:31:59 +0800 Subject: [PATCH 14/54] add parallel_syn feature and refactor code using macro --- halo2_proofs/Cargo.toml | 1 + halo2_proofs/src/circuit.rs | 1 + halo2_proofs/src/dev.rs | 31 +++---------- halo2_proofs/src/helpers.rs | 13 ++++++ halo2_proofs/src/plonk/keygen.rs | 22 ++-------- halo2_proofs/src/plonk/prover.rs | 12 +---- halo2_proofs/tests/plonk_api.rs | 75 ++++++++++++++++++++++++-------- 7 files changed, 82 insertions(+), 73 deletions(-) diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index 72368237ae..2578ce0546 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -87,6 +87,7 @@ sanity-checks = [] batch = ["rand_core/getrandom"] shplonk = [] gwc = [] +parallel_syn = [] phase-check = [] profile = ["ark-std/print-trace"] diff --git a/halo2_proofs/src/circuit.rs b/halo2_proofs/src/circuit.rs index c156ad7452..43120f4e8a 100644 --- a/halo2_proofs/src/circuit.rs +++ b/halo2_proofs/src/circuit.rs @@ -420,6 +420,7 @@ pub trait Layouter { N: Fn() -> NR, NR: Into; + #[cfg(feature = "parallel_syn")] fn assign_regions( &mut self, name: N, diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 24c786894c..b2f4c0406d 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -43,6 +43,8 @@ pub use cost::CircuitCost; mod gates; pub use gates::CircuitGates; +use crate::two_dim_vec_to_vec_of_slice; + #[cfg(feature = "dev-graph")] mod graph; @@ -726,27 +728,10 @@ impl<'a, F: FieldExt> MockProver<'a, F> { // Fixed columns contain no blinding factors. let fixed_vec = Arc::new(vec![vec![CellValue::Unassigned; n]; cs.num_fixed_columns]); - let fixed = unsafe { - // extract an mutable reference to the 2-dimensional vector - // we are forced to use unsafe method because vec is - // protected by the Arc struct - let fixed_vec_clone = fixed_vec.clone(); - let ptr = Arc::as_ptr(&fixed_vec_clone) as *mut Vec>>; - let mut_ref = &mut (*ptr); - mut_ref - .iter_mut() - .map(|fixed| fixed.as_mut_slice()) - .collect::>() - }; + let fixed = two_dim_vec_to_vec_of_slice!(fixed_vec); let selectors_vec = Arc::new(vec![vec![false; n]; cs.num_selectors]); - let selectors = unsafe { - let selectors_vec_clone = selectors_vec.clone(); - let ptr = Arc::as_ptr(&selectors_vec_clone) as *mut Vec>; - let mut_ref = &mut (*ptr); - - mut_ref.iter_mut().map(|item| item.as_mut_slice()).collect() - }; + let selectors = two_dim_vec_to_vec_of_slice!(selectors_vec); // Advice columns contain blinding factors. let blinding_factors = cs.blinding_factors(); @@ -762,13 +747,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { }; cs.num_advice_columns ]); - let advice = unsafe { - let advice_vec_clone = advice_vec.clone(); - let ptr = Arc::as_ptr(&advice_vec_clone) as *mut Vec>>; - let mut_ref = &mut (*ptr); - - mut_ref.iter_mut().map(|item| item.as_mut_slice()).collect() - }; + let advice = two_dim_vec_to_vec_of_slice!(advice_vec); let permutation = permutation::keygen::Assembly::new(n, &cs.permutation); let constants = cs.constants.clone(); diff --git a/halo2_proofs/src/helpers.rs b/halo2_proofs/src/helpers.rs index 3c389f2fc1..2a4a3a6126 100644 --- a/halo2_proofs/src/helpers.rs +++ b/halo2_proofs/src/helpers.rs @@ -46,6 +46,19 @@ pub(crate) fn base_to_scalar(base: &C::Base) -> C::Scalar { bn_to_field(&bn) } +#[macro_export] +macro_rules! two_dim_vec_to_vec_of_slice { + ($arc_vec:ident) => { + unsafe { + let arc_vec_clone = $arc_vec.clone(); + let ptr = Arc::as_ptr(&arc_vec_clone) as *mut Vec>; + let mut_ref = &mut (*ptr); + + mut_ref.iter_mut().map(|item| item.as_mut_slice()).collect() + } + }; +} + #[cfg(test)] mod test { use super::*; diff --git a/halo2_proofs/src/plonk/keygen.rs b/halo2_proofs/src/plonk/keygen.rs index e9958e8050..59d84c7079 100644 --- a/halo2_proofs/src/plonk/keygen.rs +++ b/halo2_proofs/src/plonk/keygen.rs @@ -24,6 +24,7 @@ use crate::{ commitment::{Blind, Params, MSM}, EvaluationDomain, }, + two_dim_vec_to_vec_of_slice, }; pub(crate) fn create_domain( @@ -435,26 +436,11 @@ where } let fixed_vec = Arc::new(vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns]); - let fixed = unsafe { - let fixed_vec_clone = fixed_vec.clone(); - let ptr = Arc::as_ptr(&fixed_vec_clone) as *mut Vec, LagrangeCoeff>>; - let mut_ref = &mut (*ptr); - mut_ref - .iter_mut() - .map(|poly| poly.values.as_mut_slice()) - .collect::>() - }; + let fixed = two_dim_vec_to_vec_of_slice!(fixed_vec); let selectors_vec = Arc::new(vec![vec![false; params.n() as usize]; cs.num_selectors]); - let selectors = unsafe { - let selectors_vec_clone = selectors_vec.clone(); - let ptr = Arc::as_ptr(&selectors_vec_clone) as *mut Vec>; - let mut_ref = &mut (*ptr); - mut_ref - .iter_mut() - .map(|vec| vec.as_mut_slice()) - .collect::>() - }; + let selectors = two_dim_vec_to_vec_of_slice!(selectors_vec); + let mut assembly: Assembly = Assembly { k: params.k(), fixed_vec, diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index ef33d9d900..d5dc18550e 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -28,6 +28,7 @@ use crate::{ commitment::{Blind, CommitmentScheme, Params, Prover}, Basis, Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, ProverQuery, }, + two_dim_vec_to_vec_of_slice, }; use crate::{ poly::batch_invert_assigned, @@ -368,16 +369,7 @@ pub fn create_proof< domain.empty_lagrange_assigned(); meta.num_advice_columns ]); - let advice_slice = unsafe { - let advice_vec_clone = advice_vec.clone(); - let ptr = - Arc::as_ptr(&advice_vec_clone) as *mut Vec>; - let mut_ref = &mut (*ptr); - mut_ref - .iter_mut() - .map(|poly| poly.values.as_mut_slice()) - .collect() - }; + let advice_slice = two_dim_vec_to_vec_of_slice!(advice_vec); let mut witness = WitnessCollection { k: params.k(), current_phase, diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index 31837be2ba..53ac29ca3f 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -23,7 +23,7 @@ use std::time::Instant; #[test] fn plonk_api() { - const K: u32 = 16; + const K: u32 = 17; /// This represents an advice column at a certain row in the ConstraintSystem #[derive(Copy, Clone, Debug)] @@ -380,35 +380,68 @@ fn plonk_api() { let a: Value> = self.a.into(); let parallel_regions_time = Instant::now(); + #[cfg(feature = "parallel_syn")] layouter.assign_regions( || "regions", - (0..8).into_iter() + (0..8) + .into_iter() .zip(is_first_pass_vec.chunks_mut(1).into_iter()) .map(|(_, is_first_pass)| { |mut region: Region<'_, F>| -> Result<(), Error> { - let n = 1 << 12; + let n = 1 << 13; for i in 0..n { // skip the assign of rows except the last row in the first pass - if is_first_pass[0] && i < n-1 { - continue + if is_first_pass[0] && i < n - 1 { + continue; } - let a0 = region.assign_advice(|| "config.a", cs.config.a, i, || a)?; - let a1 = region.assign_advice(|| "config.b", cs.config.b, i, || a)?; - region.assign_advice(|| "config.c", cs.config.c, i, || a.double())?; - - region.assign_fixed(|| "a", cs.config.sa, i, || Value::known(F::one()))?; - region.assign_fixed(|| "b", cs.config.sb, i, || Value::known(F::one()))?; - region.assign_fixed(|| "c", cs.config.sc, i, || Value::known(F::one()))?; - region.assign_fixed(|| "a * b", cs.config.sm, i, || Value::known(F::zero()))?; + let a0 = + region.assign_advice(|| "config.a", cs.config.a, i, || a)?; + let a1 = + region.assign_advice(|| "config.b", cs.config.b, i, || a)?; + region.assign_advice( + || "config.c", + cs.config.c, + i, + || a.double(), + )?; + + region.assign_fixed( + || "a", + cs.config.sa, + i, + || Value::known(F::one()), + )?; + region.assign_fixed( + || "b", + cs.config.sb, + i, + || Value::known(F::one()), + )?; + region.assign_fixed( + || "c", + cs.config.sc, + i, + || Value::known(F::one()), + )?; + region.assign_fixed( + || "a * b", + cs.config.sm, + i, + || Value::known(F::zero()), + )?; region.constrain_equal(a0.cell(), a1.cell())?; } is_first_pass[0] = false; Ok(()) } - }).collect(), + }) + .collect(), )?; - log::info!("parallel_regions assign took {:?}", parallel_regions_time.elapsed()); + log::info!( + "parallel_regions assign took {:?}", + parallel_regions_time.elapsed() + ); for _ in 0..10 { let a: Value> = self.a.into(); @@ -490,8 +523,12 @@ fn plonk_api() { // Initialize the proving key let vk = keygen_vk(params, &empty_circuit).expect("keygen_vk should not fail"); + log::info!("keygen vk succeed"); + + let pk = keygen_pk(params, vk, &empty_circuit).expect("keygen_pk should not fail"); + log::info!("keygen pk succeed"); - keygen_pk(params, vk, &empty_circuit).expect("keygen_pk should not fail") + pk } fn create_proof< @@ -568,9 +605,6 @@ fn plonk_api() { type Scheme = KZGCommitmentScheme; // bad_keys!(Scheme); - let params = ParamsKZG::::new(K); - let rng = OsRng; - let (a, instance, lookup_table) = common!(Scheme); let circuit: MyCircuit<::Scalar> = MyCircuit { @@ -586,6 +620,9 @@ fn plonk_api() { assert_eq!(prover.verify_par(), Ok(())); log::info!("mock proving succeed!"); + let params = ParamsKZG::::new(K); + let rng = OsRng; + let pk = keygen::>(¶ms); let proof = create_proof::<_, ProverGWC<_>, _, _, Blake2bWrite<_, _, Challenge255<_>>>( From b09c358e8290d39ac97d11281e32789964a61662 Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Fri, 10 Mar 2023 15:03:29 +0800 Subject: [PATCH 15/54] fix --- halo2_proofs/src/dev.rs | 78 +++++++++++++--------------- halo2_proofs/src/dev/graph.rs | 9 ++++ halo2_proofs/src/dev/graph/layout.rs | 8 +++ halo2_proofs/src/dev/util.rs | 1 + halo2_proofs/src/helpers.rs | 2 +- halo2_proofs/src/plonk/prover.rs | 4 +- 6 files changed, 57 insertions(+), 45 deletions(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index b2f4c0406d..a86c1f5f51 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -304,6 +304,7 @@ pub struct MockProver<'a, F: Group + Field> { // The advice cells in the circuit, arranged as [column][row]. pub(crate) advice_vec: Arc>>>, pub(crate) advice: Vec<&'a mut [CellValue]>, + // This field is used only if the "phase_check" feature is turned on. advice_prev: Vec>>, // The instance cells in the circuit, arranged as [column][row]. instance: Vec>, @@ -763,46 +764,59 @@ impl<'a, F: FieldExt> MockProver<'a, F> { .collect() }; + #[cfg(feature = "phase-check")] + let current_phase = FirstPhase.to_sealed(); + #[cfg(not(feature = "phase-check"))] + let current_phase = ThirdPhase.to_sealed(); + + let mut prover = MockProver { + k, + n: n as u32, + cs, + regions: vec![], + current_region: None, + fixed_vec, + fixed, + advice_vec, + advice, + advice_prev: vec![], + instance, + selectors_vec, + selectors, + challenges: challenges.clone(), + permutation: Some(permutation), + rw_rows: 0..usable_rows, + usable_rows: 0..usable_rows, + current_phase, + }; + #[cfg(feature = "phase-check")] { // check1: phase1 should not assign expr including phase2 challenges // check2: phase2 assigns same phase1 columns with phase1 let mut cur_challenges: Vec = Vec::new(); let mut last_advice: Vec>> = Vec::new(); - for current_phase in cs.phases() { - let mut prover = MockProver { - k, - n: n as u32, - cs: cs.clone(), - regions: vec![], - current_region: None, - fixed: fixed.clone(), - advice: advice.clone(), - advice_prev: last_advice.clone(), - instance: instance.clone(), - selectors: selectors.clone(), - challenges: cur_challenges.clone(), - permutation: permutation.clone(), - usable_rows: 0..usable_rows, - current_phase, - }; + for current_phase in prover.cs.phases() { + prover.current_phase = current_phase; + prover.advice_prev = last_advice; ConcreteCircuit::FloorPlanner::synthesize( &mut prover, circuit, config.clone(), constants.clone(), )?; - for (index, phase) in cs.challenge_phase.iter().enumerate() { + + for (index, phase) in prover.cs.challenge_phase.iter().enumerate() { if current_phase == *phase { debug_assert_eq!(cur_challenges.len(), index); cur_challenges.push(challenges[index].clone()); } } - if !last_advice.is_empty() { + if !prover.advice_prev.is_empty() { let mut err = false; for (idx, advice_values) in prover.advice.iter().enumerate() { - if cs.advice_column_phase[idx].0 < current_phase.0 { - if advice_values != &last_advice[idx] { + if prover.cs.advice_column_phase[idx].0 < current_phase.0 { + if advice_values != &prover.advice_prev[idx] { log::error!( "PHASE ERR column{} not same after phase {:?}", idx, @@ -816,30 +830,10 @@ impl<'a, F: FieldExt> MockProver<'a, F> { panic!("wrong phase assignment"); } } - last_advice = prover.advice; + last_advice = prover.advice_vec.as_ref().clone(); } } - let mut prover = MockProver { - k, - n: n as u32, - cs, - regions: vec![], - current_region: None, - fixed_vec, - fixed, - advice_vec, - advice, - advice_prev: vec![], - instance, - selectors_vec, - selectors, - challenges: challenges.clone(), - permutation: Some(permutation), - rw_rows: 0..usable_rows, - usable_rows: 0..usable_rows, - current_phase: ThirdPhase.to_sealed(), - }; let syn_time = Instant::now(); ConcreteCircuit::FloorPlanner::synthesize(&mut prover, circuit, config, constants)?; log::info!("MockProver synthesize took {:?}", syn_time.elapsed()); diff --git a/halo2_proofs/src/dev/graph.rs b/halo2_proofs/src/dev/graph.rs index b8c6fd90d7..58f6f2e20f 100644 --- a/halo2_proofs/src/dev/graph.rs +++ b/halo2_proofs/src/dev/graph.rs @@ -1,4 +1,5 @@ use ff::Field; +use std::ops::Range; use tabbycat::{AttrList, Edge, GraphBuilder, GraphType, Identity, StmtList}; use crate::{ @@ -99,6 +100,14 @@ impl Assignment for Graph { Ok(()) } + fn fork(&mut self, _ranges: &Vec>) -> Result, Error> { + todo!() + } + + fn merge(&mut self, _sub_cs: Vec) -> Result<(), Error> { + todo!() + } + fn query_instance(&self, _: Column, _: usize) -> Result, Error> { Ok(Value::unknown()) } diff --git a/halo2_proofs/src/dev/graph/layout.rs b/halo2_proofs/src/dev/graph/layout.rs index 81f45a9010..28fd5700ad 100644 --- a/halo2_proofs/src/dev/graph/layout.rs +++ b/halo2_proofs/src/dev/graph/layout.rs @@ -432,6 +432,14 @@ impl Assignment for Layout { Ok(()) } + fn fork(&mut self, _ranges: &Vec>) -> Result, Error> { + todo!() + } + + fn merge(&mut self, _sub_cs: Vec) -> Result<(), Error> { + todo!() + } + fn query_instance(&self, _: Column, _: usize) -> Result, Error> { Ok(Value::unknown()) } diff --git a/halo2_proofs/src/dev/util.rs b/halo2_proofs/src/dev/util.rs index 00693fd2d2..2d739329dd 100644 --- a/halo2_proofs/src/dev/util.rs +++ b/halo2_proofs/src/dev/util.rs @@ -98,6 +98,7 @@ pub(super) fn load_slice<'a, F: FieldExt, T: ColumnType, Q: Into + Cop cells[column.index()][resolved_row as usize].into() } } + pub(super) fn load_instance<'a, F: FieldExt, T: ColumnType, Q: Into + Copy>( n: i32, row: i32, diff --git a/halo2_proofs/src/helpers.rs b/halo2_proofs/src/helpers.rs index 2a4a3a6126..1ec7393359 100644 --- a/halo2_proofs/src/helpers.rs +++ b/halo2_proofs/src/helpers.rs @@ -54,7 +54,7 @@ macro_rules! two_dim_vec_to_vec_of_slice { let ptr = Arc::as_ptr(&arc_vec_clone) as *mut Vec>; let mut_ref = &mut (*ptr); - mut_ref.iter_mut().map(|item| item.as_mut_slice()).collect() + mut_ref.iter_mut().map(|item| item.as_mut_slice()).collect::>() } }; } diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index d5dc18550e..d8a8ab7e49 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -220,7 +220,7 @@ pub fn create_proof< Ok(sub_cs) } - fn merge(&mut self, sub_cs: Vec) -> Result<(), Error> { + fn merge(&mut self, _sub_cs: Vec) -> Result<(), Error> { Ok(()) } @@ -396,7 +396,7 @@ pub fn create_proof< #[cfg(feature = "phase-check")] { - for (idx, advice_col) in witness.advice.iter().enumerate() { + for (idx, advice_col) in witness.advice_vec.iter().enumerate() { if pk.vk.cs.advice_column_phase[idx].0 < current_phase.0 { if advice_assignments[circuit_idx][idx].values != advice_col.values { log::error!( From 460e7085727c31bc7d0ff23ee94dc2edcab81935 Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Fri, 10 Mar 2023 15:04:34 +0800 Subject: [PATCH 16/54] fmt --- halo2_proofs/src/helpers.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/halo2_proofs/src/helpers.rs b/halo2_proofs/src/helpers.rs index 1ec7393359..b4adfefcee 100644 --- a/halo2_proofs/src/helpers.rs +++ b/halo2_proofs/src/helpers.rs @@ -54,7 +54,10 @@ macro_rules! two_dim_vec_to_vec_of_slice { let ptr = Arc::as_ptr(&arc_vec_clone) as *mut Vec>; let mut_ref = &mut (*ptr); - mut_ref.iter_mut().map(|item| item.as_mut_slice()).collect::>() + mut_ref + .iter_mut() + .map(|item| item.as_mut_slice()) + .collect::>() } }; } From f5f5e2903b12ed92d88b8cc3a66a4ddad8dc09f8 Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Fri, 10 Mar 2023 15:09:28 +0800 Subject: [PATCH 17/54] clippy --- halo2_proofs/src/circuit.rs | 1 + halo2_proofs/src/circuit/floor_planner/single_pass.rs | 1 + halo2_proofs/src/circuit/floor_planner/v1.rs | 1 + halo2_proofs/src/plonk/prover.rs | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/halo2_proofs/src/circuit.rs b/halo2_proofs/src/circuit.rs index 43120f4e8a..aaf8325502 100644 --- a/halo2_proofs/src/circuit.rs +++ b/halo2_proofs/src/circuit.rs @@ -507,6 +507,7 @@ impl<'a, F: Field, L: Layouter + 'a> Layouter for NamespacedLayouter<'a, F self.0.assign_region(name, assignment) } + #[cfg(feature = "parallel_syn")] fn assign_regions( &mut self, name: N, diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index f79cddb86a..259ee63845 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -188,6 +188,7 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a Ok(result) } + #[cfg(feature = "parallel_syn")] fn assign_regions( &mut self, name: N, diff --git a/halo2_proofs/src/circuit/floor_planner/v1.rs b/halo2_proofs/src/circuit/floor_planner/v1.rs index 6f1fd09a0b..d868010cb1 100644 --- a/halo2_proofs/src/circuit/floor_planner/v1.rs +++ b/halo2_proofs/src/circuit/floor_planner/v1.rs @@ -184,6 +184,7 @@ impl<'p, 'a, F: Field, CS: Assignment + 'a> Layouter for V1Pass<'p, 'a, F, } } + #[cfg(feature = "parallel_syn")] fn assign_regions( &mut self, _name: N, diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index d8a8ab7e49..580507aa4a 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -210,7 +210,7 @@ pub fn create_proof< advice_vec: self.advice_vec.clone(), advice, challenges: self.challenges, - instances: self.instances.clone(), + instances: self.instances, rw_rows: sub_range.clone(), usable_rows: self.usable_rows.clone(), _marker: Default::default(), From 4e36256dd523fe9dac62801d676a113ccec7d763 Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Fri, 10 Mar 2023 15:32:39 +0800 Subject: [PATCH 18/54] clippy --- halo2_proofs/src/arithmetic.rs | 2 +- halo2_proofs/src/dev.rs | 4 ++-- halo2_proofs/src/dev/cost.rs | 2 +- halo2_proofs/src/dev/failure.rs | 2 +- halo2_proofs/src/dev/graph.rs | 2 +- halo2_proofs/src/dev/graph/layout.rs | 2 +- halo2_proofs/src/plonk/circuit.rs | 2 +- halo2_proofs/src/plonk/keygen.rs | 2 +- halo2_proofs/src/plonk/prover.rs | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/halo2_proofs/src/arithmetic.rs b/halo2_proofs/src/arithmetic.rs index e919f5d0b0..0eb01ee1a6 100644 --- a/halo2_proofs/src/arithmetic.rs +++ b/halo2_proofs/src/arithmetic.rs @@ -372,7 +372,7 @@ pub fn parallel_fft(a: &mut [G], omega: G::Scalar, log_n: u32) { let twiddle_lut = &*twiddle_lut; for (chunk_idx, tmp) in tmp.chunks_mut(sub_n).enumerate() { scope.spawn(move |_| { - let split_fft_offset = chunk_idx * sub_n >> log_split; + let split_fft_offset = (chunk_idx * sub_n) >> log_split; for (i, tmp) in tmp.chunks_mut(split_m).enumerate() { let split_fft_offset = split_fft_offset + i; split_radix_fft(tmp, a, twiddle_lut, n, split_fft_offset, log_split); diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index a86c1f5f51..e898597496 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -380,7 +380,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { Ok(()) } - fn fork(&mut self, ranges: &Vec>) -> Result, Error> { + fn fork(&mut self, ranges: &[Range]) -> Result, Error> { // check ranges are non-overlapping and monotonically increasing let mut range_start = self.rw_rows.start; for (i, sub_range) in ranges.iter().enumerate() { @@ -809,7 +809,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { for (index, phase) in prover.cs.challenge_phase.iter().enumerate() { if current_phase == *phase { debug_assert_eq!(cur_challenges.len(), index); - cur_challenges.push(challenges[index].clone()); + cur_challenges.push(challenges[index]); } } if !prover.advice_prev.is_empty() { diff --git a/halo2_proofs/src/dev/cost.rs b/halo2_proofs/src/dev/cost.rs index 95d8c5f619..887ccc3907 100644 --- a/halo2_proofs/src/dev/cost.rs +++ b/halo2_proofs/src/dev/cost.rs @@ -70,7 +70,7 @@ impl Assignment for Assembly { Ok(()) } - fn fork(&mut self, _ranges: &Vec>) -> Result, Error> { + fn fork(&mut self, _ranges: &[Range]) -> Result, Error> { todo!() } diff --git a/halo2_proofs/src/dev/failure.rs b/halo2_proofs/src/dev/failure.rs index 72d53731af..5b7a2eb4ef 100644 --- a/halo2_proofs/src/dev/failure.rs +++ b/halo2_proofs/src/dev/failure.rs @@ -460,7 +460,7 @@ fn render_lookup( n, row, &cs.fixed_queries, - &prover.fixed.as_slice(), + prover.fixed.as_slice(), )), &cell_value(&util::load_slice( n, diff --git a/halo2_proofs/src/dev/graph.rs b/halo2_proofs/src/dev/graph.rs index 58f6f2e20f..d61cd1fbc5 100644 --- a/halo2_proofs/src/dev/graph.rs +++ b/halo2_proofs/src/dev/graph.rs @@ -100,7 +100,7 @@ impl Assignment for Graph { Ok(()) } - fn fork(&mut self, _ranges: &Vec>) -> Result, Error> { + fn fork(&mut self, _ranges: &[Range]) -> Result, Error> { todo!() } diff --git a/halo2_proofs/src/dev/graph/layout.rs b/halo2_proofs/src/dev/graph/layout.rs index 28fd5700ad..981266f958 100644 --- a/halo2_proofs/src/dev/graph/layout.rs +++ b/halo2_proofs/src/dev/graph/layout.rs @@ -432,7 +432,7 @@ impl Assignment for Layout { Ok(()) } - fn fork(&mut self, _ranges: &Vec>) -> Result, Error> { + fn fork(&mut self, _ranges: &[Range]) -> Result, Error> { todo!() } diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index aed811b614..569ea8f3fc 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -558,7 +558,7 @@ pub trait Assignment: Sized + Send { AR: Into; /// Fork - fn fork(&mut self, ranges: &Vec>) -> Result, Error>; + fn fork(&mut self, ranges: &[Range]) -> Result, Error>; /// Merge fn merge(&mut self, sub_cs: Vec) -> Result<(), Error>; diff --git a/halo2_proofs/src/plonk/keygen.rs b/halo2_proofs/src/plonk/keygen.rs index 59d84c7079..e7095e5f70 100644 --- a/halo2_proofs/src/plonk/keygen.rs +++ b/halo2_proofs/src/plonk/keygen.rs @@ -95,7 +95,7 @@ impl<'a, F: Field> Assignment for Assembly<'a, F> { Ok(()) } - fn fork(&mut self, ranges: &Vec>) -> Result, Error> { + fn fork(&mut self, ranges: &[Range]) -> Result, Error> { let mut range_start = self.rw_rows.start; for (i, sub_range) in ranges.iter().enumerate() { if sub_range.start < range_start { diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index 580507aa4a..c99d5e4646 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -168,7 +168,7 @@ pub fn create_proof< Ok(()) } - fn fork(&mut self, ranges: &Vec>) -> Result, Error> { + fn fork(&mut self, ranges: &[Range]) -> Result, Error> { let mut range_start = self.rw_rows.start; for (i, sub_range) in ranges.iter().enumerate() { if sub_range.start < range_start { From ed4985f6f91fa50219b8522902ca272a11724454 Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Fri, 10 Mar 2023 15:54:51 +0800 Subject: [PATCH 19/54] fix unit test error --- halo2_proofs/src/dev.rs | 13 ++++++++----- halo2_proofs/src/dev/util.rs | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index e898597496..e83ae7a02d 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -418,7 +418,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { .collect::>(); let mut sub_cs = vec![]; - for (i, sub_range) in ranges.iter().enumerate() { + for (_i, sub_range) in ranges.iter().enumerate() { let fixed = fixed_ptrs .iter() .map(|ptr| unsafe { @@ -767,7 +767,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { #[cfg(feature = "phase-check")] let current_phase = FirstPhase.to_sealed(); #[cfg(not(feature = "phase-check"))] - let current_phase = ThirdPhase.to_sealed(); + let current_phase = sealed::Phase(cs.max_phase()); let mut prover = MockProver { k, @@ -834,9 +834,12 @@ impl<'a, F: FieldExt> MockProver<'a, F> { } } - let syn_time = Instant::now(); - ConcreteCircuit::FloorPlanner::synthesize(&mut prover, circuit, config, constants)?; - log::info!("MockProver synthesize took {:?}", syn_time.elapsed()); + #[cfg(not(feature = "phase-check"))] + { + let syn_time = Instant::now(); + ConcreteCircuit::FloorPlanner::synthesize(&mut prover, circuit, config, constants)?; + log::info!("MockProver synthesize took {:?}", syn_time.elapsed()); + } let (cs, selector_polys) = prover .cs diff --git a/halo2_proofs/src/dev/util.rs b/halo2_proofs/src/dev/util.rs index 2d739329dd..aa1e3ccc42 100644 --- a/halo2_proofs/src/dev/util.rs +++ b/halo2_proofs/src/dev/util.rs @@ -73,6 +73,7 @@ pub(super) fn format_value(v: F) -> String { } } +/* pub(super) fn load<'a, F: FieldExt, T: ColumnType, Q: Into + Copy>( n: i32, row: i32, @@ -85,6 +86,7 @@ pub(super) fn load<'a, F: FieldExt, T: ColumnType, Q: Into + Copy>( cells[column.index()][resolved_row as usize].into() } } +*/ pub(super) fn load_slice<'a, F: FieldExt, T: ColumnType, Q: Into + Copy>( n: i32, From 13a438196ff4925f0c8f83baf5dd420f47260c2e Mon Sep 17 00:00:00 2001 From: kunxian xia Date: Fri, 10 Mar 2023 16:05:00 +0800 Subject: [PATCH 20/54] clippy --- halo2_proofs/src/arithmetic.rs | 16 ++++++------- .../src/circuit/floor_planner/single_pass.rs | 7 ++---- halo2_proofs/src/dev.rs | 24 +++++++++---------- halo2_proofs/src/plonk/evaluation.rs | 2 +- halo2_proofs/src/plonk/permutation/keygen.rs | 4 ++-- halo2_proofs/src/plonk/permutation/prover.rs | 2 +- .../src/plonk/permutation/verifier.rs | 2 +- halo2_proofs/src/plonk/prover.rs | 20 ++++++++-------- halo2_proofs/src/poly/domain.rs | 8 +++---- halo2_proofs/src/poly/kzg/commitment.rs | 6 ++--- 10 files changed, 43 insertions(+), 48 deletions(-) diff --git a/halo2_proofs/src/arithmetic.rs b/halo2_proofs/src/arithmetic.rs index 0eb01ee1a6..14d5df1933 100644 --- a/halo2_proofs/src/arithmetic.rs +++ b/halo2_proofs/src/arithmetic.rs @@ -206,7 +206,7 @@ fn serial_fft(a: &mut [G], omega: G::Scalar, log_n: u32) { let mut m = 1; for _ in 0..log_n { - let w_m = omega.pow_vartime(&[u64::from(n / (2 * m)), 0, 0, 0]); + let w_m = omega.pow_vartime([u64::from(n / (2 * m)), 0, 0, 0]); let mut k = 0; while k < n { @@ -316,7 +316,7 @@ pub fn generate_twiddle_lookup_table( if is_lut_len_large { let mut twiddle_lut = vec![F::zero(); (1 << log_n) as usize]; parallelize(&mut twiddle_lut, |twiddle_lut, start| { - let mut w_n = omega.pow_vartime(&[start as u64, 0, 0, 0]); + let mut w_n = omega.pow_vartime([start as u64, 0, 0, 0]); for twiddle_lut in twiddle_lut.iter_mut() { *twiddle_lut = w_n; w_n = w_n * omega; @@ -332,18 +332,18 @@ pub fn generate_twiddle_lookup_table( parallelize( &mut twiddle_lut[..low_degree_lut_len], |twiddle_lut, start| { - let mut w_n = omega.pow_vartime(&[start as u64, 0, 0, 0]); + let mut w_n = omega.pow_vartime([start as u64, 0, 0, 0]); for twiddle_lut in twiddle_lut.iter_mut() { *twiddle_lut = w_n; w_n = w_n * omega; } }, ); - let high_degree_omega = omega.pow_vartime(&[(1 << sparse_degree) as u64, 0, 0, 0]); + let high_degree_omega = omega.pow_vartime([(1 << sparse_degree) as u64, 0, 0, 0]); parallelize( &mut twiddle_lut[low_degree_lut_len..], |twiddle_lut, start| { - let mut w_n = high_degree_omega.pow_vartime(&[start as u64, 0, 0, 0]); + let mut w_n = high_degree_omega.pow_vartime([start as u64, 0, 0, 0]); for twiddle_lut in twiddle_lut.iter_mut() { *twiddle_lut = w_n; w_n = w_n * high_degree_omega; @@ -392,7 +392,7 @@ pub fn parallel_fft(a: &mut [G], omega: G::Scalar, log_n: u32) { }); // sub fft - let new_omega = omega.pow_vartime(&[split_m as u64, 0, 0, 0]); + let new_omega = omega.pow_vartime([split_m as u64, 0, 0, 0]); multicore::scope(|scope| { for a in a.chunks_mut(sub_n) { scope.spawn(move |_| { @@ -419,7 +419,7 @@ pub fn parallel_fft(a: &mut [G], omega: G::Scalar, log_n: u32) { /// Convert coefficient bases group elements to lagrange basis by inverse FFT. pub fn g_to_lagrange(g_projective: Vec, k: u32) -> Vec { - let n_inv = C::Scalar::TWO_INV.pow_vartime(&[k as u64, 0, 0, 0]); + let n_inv = C::Scalar::TWO_INV.pow_vartime([k as u64, 0, 0, 0]); let mut omega_inv = C::Scalar::ROOT_OF_UNITY_INV; for _ in k..C::Scalar::S { omega_inv = omega_inv.square(); @@ -464,7 +464,7 @@ pub fn eval_polynomial(poly: &[F], point: F) -> F { { scope.spawn(move |_| { let start = chunk_idx * chunk_size; - out[0] = evaluate(poly, point) * point.pow_vartime(&[start as u64, 0, 0, 0]); + out[0] = evaluate(poly, point) * point.pow_vartime([start as u64, 0, 0, 0]); }); } }); diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index 259ee63845..99d58bf0ae 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -37,7 +37,7 @@ impl FloorPlanner for SimpleFloorPlanner { config: C::Config, constants: Vec>, ) -> Result<(), Error> { - let timer = start_timer!(|| format!("SimpleFloorPlanner synthesize")); + let timer = start_timer!(|| ("SimpleFloorPlanner synthesize").to_string()); let layouter = SingleChipLayouter::new(cs, constants)?; let result = circuit.synthesize(config, layouter); end_timer!(timer); @@ -293,10 +293,7 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a let (results, constants): (Vec<_>, Vec<_>) = ret.into_iter().unzip(); // Check if there are errors in sub-region synthesis - let results = results - .into_iter() - .map(|result| result) - .collect::, Error>>()?; + let results = results.into_iter().collect::, Error>>()?; // Merge all constants from sub-regions together let constants_to_assign = constants diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index e83ae7a02d..a10421f7a9 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -558,9 +558,8 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { if false && self.current_phase.0 > column.column_type().phase.0 { // Some circuits assign cells more than one times with different values // So this check sometimes can be false alarm - if !self.advice_prev.is_empty() { - if self.advice_prev[column.index()][row] != assigned { - panic!("not same new {assigned:?} old {:?}, column idx {} row {} cur phase {:?} col phase {:?} region {:?}", + if !self.advice_prev.is_empty() && self.advice_prev[column.index()][row] != assigned { + panic!("not same new {assigned:?} old {:?}, column idx {} row {} cur phase {:?} col phase {:?} region {:?}", self.advice_prev[column.index()][row], column.index(), row, @@ -568,7 +567,6 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { column.column_type().phase, self.current_region ) - } } } @@ -815,15 +813,15 @@ impl<'a, F: FieldExt> MockProver<'a, F> { if !prover.advice_prev.is_empty() { let mut err = false; for (idx, advice_values) in prover.advice.iter().enumerate() { - if prover.cs.advice_column_phase[idx].0 < current_phase.0 { - if advice_values != &prover.advice_prev[idx] { - log::error!( - "PHASE ERR column{} not same after phase {:?}", - idx, - current_phase - ); - err = true; - } + if prover.cs.advice_column_phase[idx].0 < current_phase.0 + && advice_values != &prover.advice_prev[idx] + { + log::error!( + "PHASE ERR column{} not same after phase {:?}", + idx, + current_phase + ); + err = true; } } if err { diff --git a/halo2_proofs/src/plonk/evaluation.rs b/halo2_proofs/src/plonk/evaluation.rs index f324a4d438..bfb925882e 100644 --- a/halo2_proofs/src/plonk/evaluation.rs +++ b/halo2_proofs/src/plonk/evaluation.rs @@ -374,7 +374,7 @@ impl Evaluator { // Permutation constraints parallelize(&mut values, |values, start| { - let mut beta_term = extended_omega.pow_vartime(&[start as u64, 0, 0, 0]); + let mut beta_term = extended_omega.pow_vartime([start as u64, 0, 0, 0]); for (i, value) in values.iter_mut().enumerate() { let idx = start + i; let r_next = get_rotation_idx(idx, 1, rot_scale, isize); diff --git a/halo2_proofs/src/plonk/permutation/keygen.rs b/halo2_proofs/src/plonk/permutation/keygen.rs index 3b2552f64f..477e58c18c 100644 --- a/halo2_proofs/src/plonk/permutation/keygen.rs +++ b/halo2_proofs/src/plonk/permutation/keygen.rs @@ -108,7 +108,7 @@ impl Assembly { { let omega = domain.get_omega(); parallelize(&mut omega_powers, |o, start| { - let mut cur = omega.pow_vartime(&[start as u64]); + let mut cur = omega.pow_vartime([start as u64]); for v in o.iter_mut() { *v = cur; cur *= ω @@ -164,7 +164,7 @@ impl Assembly { { let omega = domain.get_omega(); parallelize(&mut omega_powers, |o, start| { - let mut cur = omega.pow_vartime(&[start as u64]); + let mut cur = omega.pow_vartime([start as u64]); for v in o.iter_mut() { *v = cur; cur *= ω diff --git a/halo2_proofs/src/plonk/permutation/prover.rs b/halo2_proofs/src/plonk/permutation/prover.rs index cddc02348a..b057688ac1 100644 --- a/halo2_proofs/src/plonk/permutation/prover.rs +++ b/halo2_proofs/src/plonk/permutation/prover.rs @@ -126,7 +126,7 @@ impl Argument { Any::Instance => instance, }; parallelize(&mut modified_values, |modified_values, start| { - let mut deltaomega = deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]); + let mut deltaomega = deltaomega * &omega.pow_vartime([start as u64, 0, 0, 0]); for (modified_values, value) in modified_values .iter_mut() .zip(values[column.index()][start..].iter()) diff --git a/halo2_proofs/src/plonk/permutation/verifier.rs b/halo2_proofs/src/plonk/permutation/verifier.rs index b892d1720d..a33b210e13 100644 --- a/halo2_proofs/src/plonk/permutation/verifier.rs +++ b/halo2_proofs/src/plonk/permutation/verifier.rs @@ -182,7 +182,7 @@ impl Evaluated { let mut right = set.permutation_product_eval; let mut current_delta = (*beta * &*x) - * &(C::Scalar::DELTA.pow_vartime(&[(chunk_index * chunk_len) as u64])); + * &(C::Scalar::DELTA.pow_vartime([(chunk_index * chunk_len) as u64])); for eval in columns.iter().map(|&column| match column.column_type() { Any::Advice(_) => { advice_evals[vk.cs.get_any_query_index(column, Rotation::cur())] diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index c99d5e4646..a38b1a75b9 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -212,7 +212,7 @@ pub fn create_proof< challenges: self.challenges, instances: self.instances, rw_rows: sub_range.clone(), - usable_rows: self.usable_rows.clone(), + usable_rows: self.usable_rows, _marker: Default::default(), }); } @@ -397,15 +397,15 @@ pub fn create_proof< #[cfg(feature = "phase-check")] { for (idx, advice_col) in witness.advice_vec.iter().enumerate() { - if pk.vk.cs.advice_column_phase[idx].0 < current_phase.0 { - if advice_assignments[circuit_idx][idx].values != advice_col.values { - log::error!( - "advice column {}(at {:?}) changed when {:?}", - idx, - pk.vk.cs.advice_column_phase[idx], - current_phase - ); - } + if pk.vk.cs.advice_column_phase[idx].0 < current_phase.0 + && advice_assignments[circuit_idx][idx].values != advice_col.values + { + log::error!( + "advice column {}(at {:?}) changed when {:?}", + idx, + pk.vk.cs.advice_column_phase[idx], + current_phase + ); } } } diff --git a/halo2_proofs/src/poly/domain.rs b/halo2_proofs/src/poly/domain.rs index a753cb859d..1d94a8d892 100644 --- a/halo2_proofs/src/poly/domain.rs +++ b/halo2_proofs/src/poly/domain.rs @@ -85,8 +85,8 @@ impl EvaluationDomain { { // Compute the evaluations of t(X) = X^n - 1 in the coset evaluation domain. // We don't have to compute all of them, because it will repeat. - let orig = G::Scalar::ZETA.pow_vartime(&[n as u64, 0, 0, 0]); - let step = extended_omega.pow_vartime(&[n as u64, 0, 0, 0]); + let orig = G::Scalar::ZETA.pow_vartime([n as u64, 0, 0, 0]); + let step = extended_omega.pow_vartime([n as u64, 0, 0, 0]); let mut cur = orig; loop { t_evaluations.push(cur); @@ -396,11 +396,11 @@ impl EvaluationDomain { pub fn rotate_omega(&self, value: G::Scalar, rotation: Rotation) -> G::Scalar { let mut point = value; if rotation.0 >= 0 { - point *= &self.get_omega().pow_vartime(&[rotation.0 as u64]); + point *= &self.get_omega().pow_vartime([rotation.0 as u64]); } else { point *= &self .get_omega_inv() - .pow_vartime(&[(rotation.0 as i64).unsigned_abs()]); + .pow_vartime([(rotation.0 as i64).unsigned_abs()]); } point } diff --git a/halo2_proofs/src/poly/kzg/commitment.rs b/halo2_proofs/src/poly/kzg/commitment.rs index d7ce1cc02d..910e8dacc6 100644 --- a/halo2_proofs/src/poly/kzg/commitment.rs +++ b/halo2_proofs/src/poly/kzg/commitment.rs @@ -78,7 +78,7 @@ impl ParamsKZG { let mut g_projective = vec![E::G1::group_zero(); n as usize]; parallelize(&mut g_projective, |g, start| { let mut current_g: E::G1 = g1.into(); - current_g *= s.pow_vartime(&[start as u64]); + current_g *= s.pow_vartime([start as u64]); for g in g.iter_mut() { *g = current_g; current_g *= s; @@ -100,11 +100,11 @@ impl ParamsKZG { } let n_inv = Option::::from(E::Scalar::from(n).invert()) .expect("inversion should be ok for n = 1< Date: Fri, 10 Mar 2023 16:10:13 +0800 Subject: [PATCH 21/54] clippy --- halo2_proofs/src/dev.rs | 3 ++- halo2_proofs/src/dev/graph/layout.rs | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index a10421f7a9..428a812a29 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -555,7 +555,8 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { .ok_or(Error::BoundsFailure)? = assigned; #[cfg(feature = "phase-check")] - if false && self.current_phase.0 > column.column_type().phase.0 { + // if false && self.current_phase.0 > column.column_type().phase.0 { + if false { // Some circuits assign cells more than one times with different values // So this check sometimes can be false alarm if !self.advice_prev.is_empty() && self.advice_prev[column.index()][row] != assigned { diff --git a/halo2_proofs/src/dev/graph/layout.rs b/halo2_proofs/src/dev/graph/layout.rs index 981266f958..af4b2a016b 100644 --- a/halo2_proofs/src/dev/graph/layout.rs +++ b/halo2_proofs/src/dev/graph/layout.rs @@ -181,7 +181,7 @@ impl CircuitLayout { root.draw(&Rectangle::new( [(0, 0), (total_columns, view_bottom)], - &BLACK, + BLACK, ))?; let draw_region = |root: &DrawingArea<_, _>, top_left, bottom_right| { @@ -197,7 +197,7 @@ impl CircuitLayout { [top_left, bottom_right], ShapeStyle::from(&GREEN.mix(0.2)).filled(), ))?; - root.draw(&Rectangle::new([top_left, bottom_right], &BLACK))?; + root.draw(&Rectangle::new([top_left, bottom_right], BLACK))?; Ok(()) }; From 2e9710ca3d5291a566a813866e268b994b543249 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Thu, 23 Mar 2023 16:50:46 -0400 Subject: [PATCH 22/54] [chore] update cargo.toml --- halo2_proofs/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index de5a92a3f6..9afcc0caec 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -48,14 +48,14 @@ backtrace = { version = "0.3", optional = true } rayon = "1.5.1" ff = "0.12" group = "0.12" -halo2curves = { git = 'https://github.com/privacy-scaling-explorations/halo2curves.git', tag = "0.3.1" } +halo2curves = { git = 'https://github.com/scroll-tech/halo2curves.git', branch = "0.3.1-derive-serde" } rand_core = { version = "0.6", default-features = false } tracing = "0.1" blake2b_simd = "1" sha3 = "0.9.1" subtle = "2.3" cfg-if = "0.1" -poseidon = { git = 'https://github.com/privacy-scaling-explorations/poseidon.git' } #, branch = 'circuit' } +poseidon = { git = "https://github.com/scroll-tech/poseidon.git", branch = "scroll-dev-0220" } num-integer = "0.1" num-bigint = { version = "0.4", features = ["rand"] } From 3d40ae4968759ac4516c5f9c45ad20140e2d35d5 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Sun, 9 Apr 2023 15:53:51 +0800 Subject: [PATCH 23/54] update cargo lock --- Cargo.lock | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 072c38d9db..ec56f19b08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -408,6 +408,20 @@ dependencies = [ "itertools", ] +[[package]] +name = "crossbeam" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + [[package]] name = "crossbeam-channel" version = "0.5.4" @@ -443,6 +457,16 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.8" @@ -608,6 +632,19 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "expat-sys" version = "2.1.6" @@ -843,11 +880,13 @@ dependencies = [ "blake2b_simd", "cfg-if 0.1.10", "criterion", + "crossbeam", + "env_logger", "ff", "getrandom", "group", "gumdrop", - "halo2curves 0.3.1", + "halo2curves 0.3.1 (git+https://github.com/scroll-tech/halo2curves.git?branch=0.3.1-derive-serde)", "log", "num-bigint", "num-integer", @@ -896,6 +935,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "halo2curves" +version = "0.3.1" +source = "git+https://github.com/scroll-tech/halo2curves.git?branch=0.3.1-derive-serde#c0ac1935e5da2a620204b5b011be2c924b1e0155" +dependencies = [ + "ff", + "group", + "lazy_static", + "num-bigint", + "num-traits", + "pasta_curves", + "paste", + "rand", + "rand_core", + "serde", + "static_assertions", + "subtle", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -917,6 +975,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "ident_case" version = "1.0.1" @@ -1252,6 +1316,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + [[package]] name = "pathfinder_geometry" version = "0.5.1" @@ -1353,10 +1423,10 @@ dependencies = [ [[package]] name = "poseidon" version = "0.2.0" -source = "git+https://github.com/privacy-scaling-explorations/poseidon.git?tag=v2022_10_22#5d29df01a95e3df6334080d28e983407f56b5da3" +source = "git+https://github.com/scroll-tech/poseidon.git?branch=scroll-dev-0220#2fb4a2385bada39b50dce12fe50cb80d2fd33476" dependencies = [ "group", - "halo2curves 0.2.1", + "halo2curves 0.3.1 (git+https://github.com/privacy-scaling-explorations/halo2curves.git?tag=0.3.1)", "subtle", ] @@ -1663,6 +1733,9 @@ name = "serde" version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +dependencies = [ + "serde_derive", +] [[package]] name = "serde_cbor" @@ -1830,6 +1903,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + [[package]] name = "textwrap" version = "0.11.0" From 1c78e1665e7827b04ebcc57bf435427507e05147 Mon Sep 17 00:00:00 2001 From: xkx Date: Mon, 3 Apr 2023 12:56:40 +0800 Subject: [PATCH 24/54] add default implementation for fork and merge functions (#39) --- halo2_proofs/src/plonk/circuit.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 966c7fb5a2..80ed439454 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -568,10 +568,14 @@ pub trait Assignment: Sized + Send { AR: Into; /// Fork - fn fork(&mut self, ranges: &[Range]) -> Result, Error>; + fn fork(&mut self, ranges: &[Range]) -> Result, Error> { + unimplemented!("fork is not implemented by default") + } /// Merge - fn merge(&mut self, sub_cs: Vec) -> Result<(), Error>; + fn merge(&mut self, sub_cs: Vec) -> Result<(), Error> { + unimplemented!("merge is not implemented by default") + } /// Queries the cell of an instance column at a particular absolute row. /// From 9bf3562083dd9bed8a19f651b52bc810f5e2235f Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Thu, 27 Apr 2023 08:27:40 +0800 Subject: [PATCH 25/54] export advices for MockProver --- halo2_proofs/src/dev.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index f2b95c2c0a..9e72d69795 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -1709,6 +1709,11 @@ impl<'a, F: FieldExt> MockProver<'a, F> { self.fixed_vec.as_ref() } + /// Returns the list of Advice Columns used within a MockProver instance and the associated values contained on each Cell. + pub fn advices(&self) -> &Vec>> { + self.advice_vec.as_ref() + } + /// Returns the permutation argument (`Assembly`) used within a MockProver instance. pub fn permutation(&self) -> &Assembly { self.permutation.as_ref().unwrap() From aab39d5c107fdeec62ce7d2aeec6b72de681ba23 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Tue, 4 Jul 2023 14:07:15 +0800 Subject: [PATCH 26/54] fix load_slice panic in mock prover err display --- halo2_proofs/src/circuit/floor_planner/single_pass.rs | 2 +- halo2_proofs/src/dev/util.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index b95529addb..a11b4155a9 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -121,7 +121,7 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a let log_region_info = row_count >= 40; if log_region_info { log::debug!( - "region row_count \"{}\": {}", + "region \"{}\" row_count: {}", region_name, shape.row_count() ); diff --git a/halo2_proofs/src/dev/util.rs b/halo2_proofs/src/dev/util.rs index aa1e3ccc42..83126e79c7 100644 --- a/halo2_proofs/src/dev/util.rs +++ b/halo2_proofs/src/dev/util.rs @@ -96,7 +96,7 @@ pub(super) fn load_slice<'a, F: FieldExt, T: ColumnType, Q: Into + Cop ) -> impl Fn(Q) -> Value + 'a { move |query| { let (column, at) = &queries[query.into().index]; - let resolved_row = (row + at.0) % n; + let resolved_row = (row + at.0 + n) % n; cells[column.index()][resolved_row as usize].into() } } @@ -109,7 +109,7 @@ pub(super) fn load_instance<'a, F: FieldExt, T: ColumnType, Q: Into + ) -> impl Fn(Q) -> Value + 'a { move |query| { let (column, at) = &queries[query.into().index]; - let resolved_row = (row + at.0) % n; + let resolved_row = (row + at.0 + n) % n; Value::Real(cells[column.index()][resolved_row as usize]) } } From 90e22c6d50290442fabfa8cb36a74e46a9b6b5e1 Mon Sep 17 00:00:00 2001 From: Velaciela Date: Wed, 5 Jul 2023 03:41:16 +0000 Subject: [PATCH 27/54] boundary handling of the fork() function in MockProver --- halo2_proofs/src/dev.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 9e72d69795..53b55309fb 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -405,9 +405,21 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { for (i, sub_range) in ranges.iter().enumerate() { if sub_range.start < range_start { // TODO: use more precise error type + log::debug!( + "subCS_{} sub_range.start: {} < range_start{}", + i, + sub_range.start, + range_start + ); return Err(Error::Synthesis); } - if i == ranges.len() - 1 && sub_range.end >= self.rw_rows.end { + if i == ranges.len() - 1 && sub_range.end > self.rw_rows.end { + log::debug!( + "subCS_{} sub_range.end: {} > self.rw_rows.end{}", + i, + sub_range.end, + self.rw_rows.end + ); return Err(Error::Synthesis); } range_start = sub_range.end; From ea071153061d5cad0c506155dedfbaf305620b10 Mon Sep 17 00:00:00 2001 From: Velaciela Date: Wed, 5 Jul 2023 14:36:12 +0000 Subject: [PATCH 28/54] keygen, prover, and error message --- halo2_proofs/src/dev.rs | 4 ++-- halo2_proofs/src/plonk/keygen.rs | 16 +++++++++++++++- halo2_proofs/src/plonk/prover.rs | 15 ++++++++++++++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 53b55309fb..a78ca2b277 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -405,7 +405,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { for (i, sub_range) in ranges.iter().enumerate() { if sub_range.start < range_start { // TODO: use more precise error type - log::debug!( + log::error!( "subCS_{} sub_range.start: {} < range_start{}", i, sub_range.start, @@ -414,7 +414,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { return Err(Error::Synthesis); } if i == ranges.len() - 1 && sub_range.end > self.rw_rows.end { - log::debug!( + log::error!( "subCS_{} sub_range.end: {} > self.rw_rows.end{}", i, sub_range.end, diff --git a/halo2_proofs/src/plonk/keygen.rs b/halo2_proofs/src/plonk/keygen.rs index c52c03d50e..abbfa2dc0b 100644 --- a/halo2_proofs/src/plonk/keygen.rs +++ b/halo2_proofs/src/plonk/keygen.rs @@ -87,6 +87,7 @@ impl<'a, F: Field> Assignment for Assembly<'a, F> { } if !self.rw_rows.contains(&row) { + log::error!("enable_selector: {:?}, row: {}", selector, row); return Err(Error::Synthesis); } @@ -100,9 +101,21 @@ impl<'a, F: Field> Assignment for Assembly<'a, F> { for (i, sub_range) in ranges.iter().enumerate() { if sub_range.start < range_start { // TODO: use more precise error type + log::error!( + "subCS_{} sub_range.start: {} < range_start{}", + i, + sub_range.start, + range_start + ); return Err(Error::Synthesis); } - if i == ranges.len() - 1 && sub_range.end >= self.rw_rows.end { + if i == ranges.len() - 1 && sub_range.end > self.rw_rows.end { + log::error!( + "subCS_{} sub_range.end: {} > self.rw_rows.end{}", + i, + sub_range.end, + self.rw_rows.end + ); return Err(Error::Synthesis); } range_start = sub_range.end; @@ -217,6 +230,7 @@ impl<'a, F: Field> Assignment for Assembly<'a, F> { } if !self.rw_rows.contains(&row) { + log::error!("assign_fixed: {:?}, row: {}", column, row); return Err(Error::Synthesis); } diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index 6924625c33..10c0e1660e 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -178,9 +178,21 @@ pub fn create_proof< let mut range_start = self.rw_rows.start; for (i, sub_range) in ranges.iter().enumerate() { if sub_range.start < range_start { + log::error!( + "subCS_{} sub_range.start: {} < range_start{}", + i, + sub_range.start, + range_start + ); return Err(Error::Synthesis); } - if i == ranges.len() - 1 && sub_range.end >= self.rw_rows.end { + if i == ranges.len() - 1 && sub_range.end > self.rw_rows.end { + log::error!( + "subCS_{} sub_range.end: {} > self.rw_rows.end{}", + i, + sub_range.end, + self.rw_rows.end + ); return Err(Error::Synthesis); } range_start = sub_range.end; @@ -273,6 +285,7 @@ pub fn create_proof< } if !self.rw_rows.contains(&row) { + log::error!("assign_advice: {:?}, row: {}", column, row); return Err(Error::Synthesis); } From b2f596ae99c23e85fa2b7b8fd35f887d714e5537 Mon Sep 17 00:00:00 2001 From: Velaciela Date: Wed, 5 Jul 2023 14:44:17 +0000 Subject: [PATCH 29/54] lints --- halo2_proofs/src/dev.rs | 4 ++-- halo2_proofs/src/plonk/circuit.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index a78ca2b277..72c4032fd9 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -900,11 +900,11 @@ impl<'a, F: FieldExt> MockProver<'a, F> { } pub fn advice_values(&self, column: Column) -> &[CellValue] { - &self.advice[column.index()] + self.advice[column.index()] } pub fn fixed_values(&self, column: Column) -> &[CellValue] { - &self.fixed[column.index()] + self.fixed[column.index()] } /// Returns `Ok(())` if this `MockProver` is satisfied, or a list of errors indicating diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 80ed439454..80eb37048a 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -568,12 +568,12 @@ pub trait Assignment: Sized + Send { AR: Into; /// Fork - fn fork(&mut self, ranges: &[Range]) -> Result, Error> { + fn fork(&mut self, _ranges: &[Range]) -> Result, Error> { unimplemented!("fork is not implemented by default") } /// Merge - fn merge(&mut self, sub_cs: Vec) -> Result<(), Error> { + fn merge(&mut self, _sub_cs: Vec) -> Result<(), Error> { unimplemented!("merge is not implemented by default") } From a00de9e0b5311647f0046ead97b96dede4e01945 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Tue, 11 Jul 2023 16:00:02 +0800 Subject: [PATCH 30/54] disable selector compression (#54) --- halo2_proofs/src/plonk.rs | 20 ++++++------------- .../src/plonk/circuit/compress_selectors.rs | 3 ++- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/halo2_proofs/src/plonk.rs b/halo2_proofs/src/plonk.rs index f3857aa42c..a4ab3ab207 100644 --- a/halo2_proofs/src/plonk.rs +++ b/halo2_proofs/src/plonk.rs @@ -74,6 +74,7 @@ where /// WITHOUT performing the expensive Montgomery reduction. pub fn write(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> { writer.write_all(&self.domain.k().to_be_bytes())?; + // the `fixed_commitments` here includes selectors writer.write_all(&(self.fixed_commitments.len() as u32).to_be_bytes())?; for commitment in &self.fixed_commitments { commitment.write(writer, format)?; @@ -119,21 +120,12 @@ where let permutation = permutation::VerifyingKey::read(reader, &cs.permutation, format)?; - /* - // read selectors - let selectors: Vec> = vec![vec![false; 1 << k]; cs.num_selectors] - .into_iter() - .map(|mut selector| { - let mut selector_bytes = vec![0u8; (selector.len() + 7) / 8]; - reader.read_exact(&mut selector_bytes)?; - for (bits, byte) in selector.chunks_mut(8).into_iter().zip(selector_bytes) { - crate::helpers::unpack(byte, bits); - } - Ok(selector) - }) - .collect::>()?; + // We already disable compressing selectors inside `compress_selectors::process`. + // So `selectors` values is not relevant here actually. + // The selector commitments are already in fixed_commitments. + let selectors: Vec> = vec![vec![false; 1 << k]; cs.num_selectors]; let (cs, _) = cs.compress_selectors(selectors.clone()); - */ + Ok(Self::from_parts( domain, fixed_commitments, diff --git a/halo2_proofs/src/plonk/circuit/compress_selectors.rs b/halo2_proofs/src/plonk/circuit/compress_selectors.rs index b6807e1163..16b569be1d 100644 --- a/halo2_proofs/src/plonk/circuit/compress_selectors.rs +++ b/halo2_proofs/src/plonk/circuit/compress_selectors.rs @@ -71,7 +71,8 @@ where // All provided selectors of degree 0 are assumed to be either concrete // selectors or do not appear in a gate. Let's address these first. selectors.retain(|selector| { - if selector.max_degree == 0 { + // here we disable any compression. Each selector will become a fixed column. + if true || selector.max_degree == 0 { // This is a complex selector, or a selector that does not appear in any // gate constraint. let expression = allocate_fixed_column(); From fcf53dcdd7607cedb95240f54a87ba602848ada5 Mon Sep 17 00:00:00 2001 From: xkx Date: Tue, 18 Jul 2023 22:54:23 +0800 Subject: [PATCH 31/54] Fix clippy warnings and comment out outdated integration test cases (#56) * fix clippy warnings * comment out inconsistency tests --- halo2_proofs/src/dev.rs | 4 +- halo2_proofs/src/helpers.rs | 2 + halo2_proofs/src/plonk.rs | 2 +- .../src/plonk/circuit/compress_selectors.rs | 3 +- halo2_proofs/src/plonk/keygen.rs | 4 +- halo2_proofs/src/plonk/prover.rs | 4 +- halo2_proofs/tests/plonk_api.rs | 735 +++++++++--------- 7 files changed, 380 insertions(+), 374 deletions(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 72c4032fd9..7f4201492b 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -406,7 +406,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { if sub_range.start < range_start { // TODO: use more precise error type log::error!( - "subCS_{} sub_range.start: {} < range_start{}", + "subCS_{} sub_range.start ({}) < range_start ({})", i, sub_range.start, range_start @@ -415,7 +415,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { } if i == ranges.len() - 1 && sub_range.end > self.rw_rows.end { log::error!( - "subCS_{} sub_range.end: {} > self.rw_rows.end{}", + "subCS_{} sub_range.end ({}) > self.rw_rows.end ({})", i, sub_range.end, self.rw_rows.end diff --git a/halo2_proofs/src/helpers.rs b/halo2_proofs/src/helpers.rs index ea7adb3382..f58ec9b100 100644 --- a/halo2_proofs/src/helpers.rs +++ b/halo2_proofs/src/helpers.rs @@ -167,6 +167,7 @@ impl SerdePrimeField for F {} /// Convert a slice of `bool` into a `u8`. /// /// Panics if the slice has length greater than 8. +#[allow(unused)] pub fn pack(bits: &[bool]) -> u8 { let mut value = 0u8; assert!(bits.len() <= 8); @@ -177,6 +178,7 @@ pub fn pack(bits: &[bool]) -> u8 { } /// Writes the first `bits.len()` bits of a `u8` into `bits`. +#[allow(unused)] pub fn unpack(byte: u8, bits: &mut [bool]) { for (bit_index, bit) in bits.iter_mut().enumerate() { *bit = (byte >> bit_index) & 1 == 1; diff --git a/halo2_proofs/src/plonk.rs b/halo2_proofs/src/plonk.rs index a4ab3ab207..d1aecca38e 100644 --- a/halo2_proofs/src/plonk.rs +++ b/halo2_proofs/src/plonk.rs @@ -124,7 +124,7 @@ where // So `selectors` values is not relevant here actually. // The selector commitments are already in fixed_commitments. let selectors: Vec> = vec![vec![false; 1 << k]; cs.num_selectors]; - let (cs, _) = cs.compress_selectors(selectors.clone()); + let (cs, _) = cs.compress_selectors(selectors); Ok(Self::from_parts( domain, diff --git a/halo2_proofs/src/plonk/circuit/compress_selectors.rs b/halo2_proofs/src/plonk/circuit/compress_selectors.rs index 16b569be1d..0e8db9ffc8 100644 --- a/halo2_proofs/src/plonk/circuit/compress_selectors.rs +++ b/halo2_proofs/src/plonk/circuit/compress_selectors.rs @@ -72,7 +72,8 @@ where // selectors or do not appear in a gate. Let's address these first. selectors.retain(|selector| { // here we disable any compression. Each selector will become a fixed column. - if true || selector.max_degree == 0 { + // if true || selector.max_degree == 0 { + if true { // This is a complex selector, or a selector that does not appear in any // gate constraint. let expression = allocate_fixed_column(); diff --git a/halo2_proofs/src/plonk/keygen.rs b/halo2_proofs/src/plonk/keygen.rs index abbfa2dc0b..2f461491f6 100644 --- a/halo2_proofs/src/plonk/keygen.rs +++ b/halo2_proofs/src/plonk/keygen.rs @@ -102,7 +102,7 @@ impl<'a, F: Field> Assignment for Assembly<'a, F> { if sub_range.start < range_start { // TODO: use more precise error type log::error!( - "subCS_{} sub_range.start: {} < range_start{}", + "subCS_{} sub_range.start ({}) < range_start ({})", i, sub_range.start, range_start @@ -111,7 +111,7 @@ impl<'a, F: Field> Assignment for Assembly<'a, F> { } if i == ranges.len() - 1 && sub_range.end > self.rw_rows.end { log::error!( - "subCS_{} sub_range.end: {} > self.rw_rows.end{}", + "subCS_{} sub_range.end ({}) > self.rw_rows.end ({})", i, sub_range.end, self.rw_rows.end diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index 10c0e1660e..7c176e576a 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -179,7 +179,7 @@ pub fn create_proof< for (i, sub_range) in ranges.iter().enumerate() { if sub_range.start < range_start { log::error!( - "subCS_{} sub_range.start: {} < range_start{}", + "subCS_{} sub_range.start ({}) < range_start ({})", i, sub_range.start, range_start @@ -188,7 +188,7 @@ pub fn create_proof< } if i == ranges.len() - 1 && sub_range.end > self.rw_rows.end { log::error!( - "subCS_{} sub_range.end: {} > self.rw_rows.end{}", + "subCS_{} sub_range.end ({}) > self.rw_rows.end ({})", i, sub_range.end, self.rw_rows.end diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index 770472849c..edfdfac3b2 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -1,7 +1,7 @@ #![allow(clippy::many_single_char_names)] #![allow(clippy::op_ref)] -use assert_matches::assert_matches; +// use assert_matches::assert_matches; use halo2_proofs::arithmetic::{Field, FieldExt}; use halo2_proofs::circuit::{Cell, Layouter, Region, SimpleFloorPlanner, Value}; use halo2_proofs::dev::MockProver; @@ -482,6 +482,7 @@ fn plonk_api() { }}; } + /* macro_rules! bad_keys { ($scheme:ident) => {{ let (_, _, lookup_table) = common!($scheme); @@ -511,6 +512,7 @@ fn plonk_api() { ); }}; } + */ fn keygen( params: &Scheme::ParamsProver, @@ -555,7 +557,7 @@ fn plonk_api() { create_plonk_proof::( params, pk, - &[circuit.clone(), circuit.clone()], + &[circuit.clone(), circuit], &[&[&[instance]], &[&[instance]]], rng, &mut transcript, @@ -596,7 +598,6 @@ fn plonk_api() { assert!(strategy.finalize()); } - #[test] fn test_plonk_api_gwc() { use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use halo2_proofs::poly::kzg::multiopen::{ProverGWC, VerifierGWC}; @@ -641,15 +642,14 @@ fn plonk_api() { >(verifier_params, pk.get_vk(), &proof[..]); } - #[test] fn test_plonk_api_shplonk() { use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; use halo2_proofs::poly::kzg::strategy::AccumulatorStrategy; use halo2curves::bn256::Bn256; - type Scheme = KZGCommitmentScheme; - bad_keys!(Scheme); + // type Scheme = KZGCommitmentScheme; + // bad_keys!(Scheme); let params = ParamsKZG::::new(K); let rng = OsRng; @@ -671,15 +671,14 @@ fn plonk_api() { >(verifier_params, pk.get_vk(), &proof[..]); } - #[test] fn test_plonk_api_ipa() { use halo2_proofs::poly::ipa::commitment::{IPACommitmentScheme, ParamsIPA}; use halo2_proofs::poly::ipa::multiopen::{ProverIPA, VerifierIPA}; use halo2_proofs::poly::ipa::strategy::AccumulatorStrategy; use halo2curves::pasta::EqAffine; - type Scheme = IPACommitmentScheme; - bad_keys!(Scheme); + // type Scheme = IPACommitmentScheme; + // bad_keys!(Scheme); let params = ParamsIPA::::new(K); let rng = OsRng; @@ -701,409 +700,413 @@ fn plonk_api() { >(verifier_params, pk.get_vk(), &proof[..]); // Check that the verification key has not changed unexpectedly - { - //panic!("{:#?}", pk.get_vk().pinned()); - assert_eq!( - format!("{:#?}", pk.get_vk().pinned()), - r#####"PinnedVerificationKey { - base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", - scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", - domain: PinnedEvaluationDomain { - k: 5, - extended_k: 7, - omega: 0x0cc3380dc616f2e1daf29ad1560833ed3baea3393eceb7bc8fa36376929b78cc, - }, - cs: PinnedConstraintSystem { - num_fixed_columns: 7, - num_advice_columns: 5, - num_instance_columns: 1, - num_selectors: 0, - gates: [ - Sum( - Sum( + // we comment this out because the circuit is already changed + /* + { + //panic!("{:#?}", pk.get_vk().pinned()); + assert_eq!( + format!("{:#?}", pk.get_vk().pinned()), + r#####"PinnedVerificationKey { + base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", + scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", + domain: PinnedEvaluationDomain { + k: 5, + extended_k: 7, + omega: 0x0cc3380dc616f2e1daf29ad1560833ed3baea3393eceb7bc8fa36376929b78cc, + }, + cs: PinnedConstraintSystem { + num_fixed_columns: 7, + num_advice_columns: 5, + num_instance_columns: 1, + num_selectors: 0, + gates: [ Sum( Sum( - Product( - Advice { - query_index: 0, - column_index: 1, - rotation: Rotation( - 0, + Sum( + Sum( + Product( + Advice { + query_index: 0, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 2, + column_index: 2, + rotation: Rotation( + 0, + ), + }, ), - }, - Fixed { - query_index: 2, - column_index: 2, - rotation: Rotation( - 0, + Product( + Advice { + query_index: 1, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, ), - }, - ), - Product( - Advice { - query_index: 1, - column_index: 2, - rotation: Rotation( - 0, - ), - }, - Fixed { - query_index: 3, - column_index: 3, - rotation: Rotation( - 0, + ), + Product( + Product( + Advice { + query_index: 0, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 1, + column_index: 2, + rotation: Rotation( + 0, + ), + }, ), - }, + Fixed { + query_index: 5, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Product( + Advice { + query_index: 2, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 4, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), ), ), Product( + Fixed { + query_index: 1, + column_index: 0, + rotation: Rotation( + 0, + ), + }, Product( Advice { - query_index: 0, - column_index: 1, + query_index: 3, + column_index: 4, rotation: Rotation( - 0, + 1, ), }, Advice { - query_index: 1, - column_index: 2, + query_index: 4, + column_index: 0, rotation: Rotation( - 0, + -1, ), }, ), - Fixed { - query_index: 5, - column_index: 1, - rotation: Rotation( - 0, - ), - }, ), ), - Negated( - Product( + Product( + Fixed { + query_index: 6, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Sum( Advice { - query_index: 2, - column_index: 3, - rotation: Rotation( - 0, - ), - }, - Fixed { - query_index: 4, - column_index: 4, + query_index: 0, + column_index: 1, rotation: Rotation( 0, ), }, + Negated( + Instance { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), ), ), - ), - Product( - Fixed { - query_index: 1, - column_index: 0, - rotation: Rotation( + ], + advice_queries: [ + ( + Column { + index: 1, + column_type: Advice, + }, + Rotation( 0, ), - }, - Product( - Advice { - query_index: 3, - column_index: 4, - rotation: Rotation( - 1, - ), + ), + ( + Column { + index: 2, + column_type: Advice, }, - Advice { - query_index: 4, - column_index: 0, - rotation: Rotation( - -1, - ), + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Advice, }, + Rotation( + 0, + ), ), - ), - ), - Product( - Fixed { - query_index: 6, - column_index: 5, - rotation: Rotation( - 0, + ( + Column { + index: 4, + column_type: Advice, + }, + Rotation( + 1, + ), ), - }, - Sum( - Advice { - query_index: 0, - column_index: 1, - rotation: Rotation( + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( 0, ), - }, - Negated( - Instance { - query_index: 0, - column_index: 0, - rotation: Rotation( - 0, - ), + ), + ( + Column { + index: 4, + column_type: Advice, }, + Rotation( + 0, + ), ), - ), - ), - ], - advice_queries: [ - ( - Column { - index: 1, - column_type: Advice, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 2, - column_type: Advice, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 3, - column_type: Advice, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 4, - column_type: Advice, - }, - Rotation( - 1, - ), - ), - ( - Column { - index: 0, - column_type: Advice, - }, - Rotation( - -1, - ), - ), - ( - Column { - index: 0, - column_type: Advice, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 4, - column_type: Advice, - }, - Rotation( - 0, - ), - ), - ], - instance_queries: [ - ( - Column { - index: 0, - column_type: Instance, - }, - Rotation( - 0, - ), - ), - ], - fixed_queries: [ - ( - Column { - index: 6, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 0, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 2, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 3, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 4, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 1, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 5, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ], - permutation: Argument { - columns: [ - Column { - index: 1, - column_type: Advice, - }, - Column { - index: 2, - column_type: Advice, - }, - Column { - index: 3, - column_type: Advice, - }, - Column { - index: 0, - column_type: Fixed, - }, - Column { - index: 0, - column_type: Advice, - }, - Column { - index: 4, - column_type: Advice, - }, - Column { - index: 0, - column_type: Instance, - }, - Column { - index: 1, - column_type: Fixed, - }, - Column { - index: 2, - column_type: Fixed, - }, - Column { - index: 3, - column_type: Fixed, - }, - Column { - index: 4, - column_type: Fixed, - }, - Column { - index: 5, - column_type: Fixed, - }, - ], - }, - lookups: [ - Argument { - input_expressions: [ - Advice { - query_index: 0, - column_index: 1, - rotation: Rotation( + ], + instance_queries: [ + ( + Column { + index: 0, + column_type: Instance, + }, + Rotation( 0, ), - }, + ), ], - table_expressions: [ - Fixed { - query_index: 0, - column_index: 6, - rotation: Rotation( + fixed_queries: [ + ( + Column { + index: 6, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 1, + column_type: Fixed, + }, + Rotation( 0, ), + ), + ( + Column { + index: 5, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ], + permutation: Argument { + columns: [ + Column { + index: 1, + column_type: Advice, + }, + Column { + index: 2, + column_type: Advice, + }, + Column { + index: 3, + column_type: Advice, + }, + Column { + index: 0, + column_type: Fixed, + }, + Column { + index: 0, + column_type: Advice, + }, + Column { + index: 4, + column_type: Advice, + }, + Column { + index: 0, + column_type: Instance, + }, + Column { + index: 1, + column_type: Fixed, + }, + Column { + index: 2, + column_type: Fixed, + }, + Column { + index: 3, + column_type: Fixed, + }, + Column { + index: 4, + column_type: Fixed, + }, + Column { + index: 5, + column_type: Fixed, + }, + ], + }, + lookups: [ + Argument { + input_expressions: [ + Advice { + query_index: 0, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ], + table_expressions: [ + Fixed { + query_index: 0, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ], }, ], + constants: [], + minimum_degree: None, }, - ], - constants: [], - minimum_degree: None, - }, - fixed_commitments: [ - (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), - (0x2bf5082b105b2156ed0e9c5b8e42bf2a240b058f74a464d080e9585274dd1e84, 0x222ad83cee7777e7a160585e212140e5e770dd8d1df788d869b5ee483a5864fb), - (0x374a656456a0aae7429b23336f825752b575dd5a44290ff614946ee59d6a20c0, 0x054491e187e6e3460e7601fb54ae10836d34d420026f96316f0c5c62f86db9b8), - (0x374a656456a0aae7429b23336f825752b575dd5a44290ff614946ee59d6a20c0, 0x054491e187e6e3460e7601fb54ae10836d34d420026f96316f0c5c62f86db9b8), - (0x02e62cd68370b13711139a08cbcdd889e800a272b9ea10acc90880fff9d89199, 0x1a96c468cb0ce77065d3a58f1e55fea9b72d15e44c01bba1e110bd0cbc6e9bc6), - (0x224ef42758215157d3ee48fb8d769da5bddd35e5929a90a4a89736f5c4b5ae9b, 0x11bc3a1e08eb320cde764f1492ecef956d71e996e2165f7a9a30ad2febb511c1), - (0x2d5415bf917fcac32bfb705f8ca35cb12d9bad52aa33ccca747350f9235d3a18, 0x2b2921f815fad504052512743963ef20ed5b401d20627793b006413e73fe4dd4), - ], - permutation: VerifyingKey { - commitments: [ - (0x1347b4b385837977a96b87f199c6a9a81520015539d1e8fa79429bb4ca229a00, 0x2168e404cabef513654d6ff516cde73f0ba87e3dc84e4b940ed675b5f66f3884), - (0x0e6d69cd2455ec43be640f6397ed65c9e51b1d8c0fd2216339314ff37ade122a, 0x222ed6dc8cfc9ea26dcc10b9d4add791ada60f2b5a63ee1e4635f88aa0c96654), - (0x13c447846f48c41a5e0675ccf88ebc0cdef2c96c51446d037acb866d24255785, 0x1f0b5414fc5e8219dbfab996eed6129d831488b2386a8b1a63663938903bd63a), - (0x1aae6470aa662b8fda003894ddef5fedd03af318b3231683039d2fac9cab05b9, 0x08832d91ae69e99cd07d096c7a4a284a69e6a16227cbb07932a0cdc56914f3a6), - (0x0850521b0f8ac7dd0550fe3e25c840837076e9635067ed623b81d5cbac5944d9, 0x0c25d65d1038d0a92c72e5fccd96c1caf07801c3c8233290bb292e0c38c256fa), - (0x12febcf696badd970750eabf75dd3ced4c2f54f93519bcee23849025177d2014, 0x0a05ab3cd42c9fbcc1bbfcf9269951640cc9920761c87cf8e211ba73c8d9f90f), - (0x053904bdde8cfead3b517bb4f6ded3e699f8b94ca6156a9dd2f92a2a05a7ec5a, 0x16753ff97c0d82ff586bb7a07bf7f27a92df90b3617fa5e75d4f55c3b0ef8711), - (0x3804548f6816452747a5b542fa5656353fc989db40d69e9e27d6f973b5deebb0, 0x389a44d5037866dd83993af75831a5f90a18ad5244255aa5bd2c922cc5853055), - (0x003a9f9ca71c7c0b832c802220915f6fc8d840162bdde6b0ea05d25fb95559e3, 0x091247ca19d6b73887cd7f68908cbf0db0b47459b7c82276bbdb8a1c937e2438), - (0x3eaa38689d9e391c8a8fafab9568f20c45816321d38f309d4cc37f4b1601af72, 0x247f8270a462ea88450221a56aa6b55d2bc352b80b03501e99ea983251ceea13), - (0x394437571f9de32dccdc546fd4737772d8d92593c85438aa3473243997d5acc8, 0x14924ec6e3174f1fab7f0ce7070c22f04bbd0a0ecebdfc5c94be857f25493e95), - (0x3d907e0591343bd285c2c846f3e871a6ac70d80ec29e9500b8cb57f544e60202, 0x1034e48df35830244cabea076be8a16d67d7896e27c6ac22b285d017105da9c3), - ], - }, -}"##### - ); - } + fixed_commitments: [ + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x2bf5082b105b2156ed0e9c5b8e42bf2a240b058f74a464d080e9585274dd1e84, 0x222ad83cee7777e7a160585e212140e5e770dd8d1df788d869b5ee483a5864fb), + (0x374a656456a0aae7429b23336f825752b575dd5a44290ff614946ee59d6a20c0, 0x054491e187e6e3460e7601fb54ae10836d34d420026f96316f0c5c62f86db9b8), + (0x374a656456a0aae7429b23336f825752b575dd5a44290ff614946ee59d6a20c0, 0x054491e187e6e3460e7601fb54ae10836d34d420026f96316f0c5c62f86db9b8), + (0x02e62cd68370b13711139a08cbcdd889e800a272b9ea10acc90880fff9d89199, 0x1a96c468cb0ce77065d3a58f1e55fea9b72d15e44c01bba1e110bd0cbc6e9bc6), + (0x224ef42758215157d3ee48fb8d769da5bddd35e5929a90a4a89736f5c4b5ae9b, 0x11bc3a1e08eb320cde764f1492ecef956d71e996e2165f7a9a30ad2febb511c1), + (0x2d5415bf917fcac32bfb705f8ca35cb12d9bad52aa33ccca747350f9235d3a18, 0x2b2921f815fad504052512743963ef20ed5b401d20627793b006413e73fe4dd4), + ], + permutation: VerifyingKey { + commitments: [ + (0x1347b4b385837977a96b87f199c6a9a81520015539d1e8fa79429bb4ca229a00, 0x2168e404cabef513654d6ff516cde73f0ba87e3dc84e4b940ed675b5f66f3884), + (0x0e6d69cd2455ec43be640f6397ed65c9e51b1d8c0fd2216339314ff37ade122a, 0x222ed6dc8cfc9ea26dcc10b9d4add791ada60f2b5a63ee1e4635f88aa0c96654), + (0x13c447846f48c41a5e0675ccf88ebc0cdef2c96c51446d037acb866d24255785, 0x1f0b5414fc5e8219dbfab996eed6129d831488b2386a8b1a63663938903bd63a), + (0x1aae6470aa662b8fda003894ddef5fedd03af318b3231683039d2fac9cab05b9, 0x08832d91ae69e99cd07d096c7a4a284a69e6a16227cbb07932a0cdc56914f3a6), + (0x0850521b0f8ac7dd0550fe3e25c840837076e9635067ed623b81d5cbac5944d9, 0x0c25d65d1038d0a92c72e5fccd96c1caf07801c3c8233290bb292e0c38c256fa), + (0x12febcf696badd970750eabf75dd3ced4c2f54f93519bcee23849025177d2014, 0x0a05ab3cd42c9fbcc1bbfcf9269951640cc9920761c87cf8e211ba73c8d9f90f), + (0x053904bdde8cfead3b517bb4f6ded3e699f8b94ca6156a9dd2f92a2a05a7ec5a, 0x16753ff97c0d82ff586bb7a07bf7f27a92df90b3617fa5e75d4f55c3b0ef8711), + (0x3804548f6816452747a5b542fa5656353fc989db40d69e9e27d6f973b5deebb0, 0x389a44d5037866dd83993af75831a5f90a18ad5244255aa5bd2c922cc5853055), + (0x003a9f9ca71c7c0b832c802220915f6fc8d840162bdde6b0ea05d25fb95559e3, 0x091247ca19d6b73887cd7f68908cbf0db0b47459b7c82276bbdb8a1c937e2438), + (0x3eaa38689d9e391c8a8fafab9568f20c45816321d38f309d4cc37f4b1601af72, 0x247f8270a462ea88450221a56aa6b55d2bc352b80b03501e99ea983251ceea13), + (0x394437571f9de32dccdc546fd4737772d8d92593c85438aa3473243997d5acc8, 0x14924ec6e3174f1fab7f0ce7070c22f04bbd0a0ecebdfc5c94be857f25493e95), + (0x3d907e0591343bd285c2c846f3e871a6ac70d80ec29e9500b8cb57f544e60202, 0x1034e48df35830244cabea076be8a16d67d7896e27c6ac22b285d017105da9c3), + ], + }, + }"##### + ); + } + */ } + env_logger::init(); - // test_plonk_api_ipa(); + test_plonk_api_ipa(); test_plonk_api_gwc(); - // test_plonk_api_shplonk(); + test_plonk_api_shplonk(); } From 7012b49da3f886cac3edacfd6f9c913391116ee4 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Fri, 21 Jul 2023 17:13:27 +0800 Subject: [PATCH 32/54] change ConstraintSystem::general_column_annotations from hashmap to btreemap --- 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 80eb37048a..99cbbed033 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -1,7 +1,7 @@ use core::cmp::max; use core::ops::{Add, Mul}; use ff::Field; -use std::collections::HashMap; +use std::collections::BTreeMap; use std::ops::Range; use std::{ convert::TryFrom, @@ -1407,7 +1407,7 @@ pub struct ConstraintSystem { pub 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, + pub(crate) general_column_annotations: BTreeMap, // Vector of fixed columns, which can be used to store constant values // that are copied into advice columns. @@ -1493,7 +1493,7 @@ impl Default for ConstraintSystem { instance_queries: Vec::new(), permutation: permutation::Argument::new(), lookups: Vec::new(), - general_column_annotations: HashMap::new(), + general_column_annotations: BTreeMap::new(), constants: vec![], minimum_degree: None, } From 4d8a405a97ce445c88fc8ec40f9a2dd0a661c697 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Fri, 21 Jul 2023 17:39:32 +0800 Subject: [PATCH 33/54] derive Eq for cs --- halo2_proofs/src/plonk/circuit.rs | 14 +++++++------- halo2_proofs/src/plonk/lookup.rs | 2 +- halo2_proofs/src/plonk/permutation.rs | 2 +- halo2_proofs/src/poly.rs | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 99cbbed033..b64e103405 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -390,7 +390,7 @@ impl Selector { } /// Query of fixed column at a certain relative location -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct FixedQuery { /// Query index pub(crate) index: usize, @@ -417,7 +417,7 @@ impl FixedQuery { } /// Query of advice column at a certain relative location -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct AdviceQuery { /// Query index pub(crate) index: usize, @@ -451,7 +451,7 @@ impl AdviceQuery { } /// Query of instance column at a certain relative location -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct InstanceQuery { /// Query index pub(crate) index: usize, @@ -698,7 +698,7 @@ pub trait Circuit { } /// Low-degree expression representing an identity that must hold over the committed columns. -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub enum Expression { /// This is a constant polynomial Constant(F), @@ -1210,7 +1210,7 @@ pub(crate) struct PointIndex(pub usize); /// A "virtual cell" is a PLONK cell that has been queried at a particular relative offset /// within a custom gate. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct VirtualCell { pub(crate) column: Column, pub(crate) rotation: Rotation, @@ -1336,7 +1336,7 @@ impl>, Iter: IntoIterator> IntoIterato } /// Gate -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Gate { name: &'static str, constraint_names: Vec<&'static str>, @@ -1372,7 +1372,7 @@ impl Gate { /// This is a description of the circuit environment, such as the gate, column and /// permutation arrangements. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct ConstraintSystem { pub num_fixed_columns: usize, pub num_advice_columns: usize, diff --git a/halo2_proofs/src/plonk/lookup.rs b/halo2_proofs/src/plonk/lookup.rs index e0d0db5c0c..c1c4d0ea31 100644 --- a/halo2_proofs/src/plonk/lookup.rs +++ b/halo2_proofs/src/plonk/lookup.rs @@ -5,7 +5,7 @@ use std::fmt::{self, Debug}; pub(crate) mod prover; pub(crate) mod verifier; -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct Argument { pub name: &'static str, pub input_expressions: Vec>, diff --git a/halo2_proofs/src/plonk/permutation.rs b/halo2_proofs/src/plonk/permutation.rs index 6912199570..b353493c57 100644 --- a/halo2_proofs/src/plonk/permutation.rs +++ b/halo2_proofs/src/plonk/permutation.rs @@ -17,7 +17,7 @@ pub(crate) mod verifier; use std::io; /// A permutation argument. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Argument { /// A sequence of columns involved in the argument. pub columns: Vec>, diff --git a/halo2_proofs/src/poly.rs b/halo2_proofs/src/poly.rs index f72bb58e3c..84089482aa 100644 --- a/halo2_proofs/src/poly.rs +++ b/halo2_proofs/src/poly.rs @@ -307,7 +307,7 @@ impl<'a, F: Field, B: Basis> Sub for &'a Polynomial { /// Describes the relative rotation of a vector. Negative numbers represent /// reverse (leftmost) rotations and positive numbers represent forward (rightmost) /// rotations. Zero represents no rotation. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Rotation(pub i32); impl Rotation { From 01f0b5260445a9190299af7b06b766c1e925fdaf Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Mon, 7 Aug 2023 18:58:03 +0800 Subject: [PATCH 34/54] MockProver can report phase error better --- halo2_proofs/src/dev.rs | 7 ++++--- halo2_proofs/src/plonk/circuit.rs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 7f4201492b..aadca90b5d 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -704,10 +704,11 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { } fn get_challenge(&self, challenge: Challenge) -> circuit::Value { - match self.challenges.get(challenge.index()) { - None => circuit::Value::unknown(), - Some(v) => circuit::Value::known(*v), + if self.current_phase <= challenge.phase { + return circuit::Value::unknown(); } + + circuit::Value::known(self.challenges[challenge.index()]) } fn push_namespace(&mut self, _: N) diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index b64e103405..8f1ec3da8c 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -509,7 +509,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 { From b612b1e2a9fa2ccd150a6cb99e67592c8d62cd99 Mon Sep 17 00:00:00 2001 From: xkx Date: Thu, 17 Aug 2023 12:37:36 +0800 Subject: [PATCH 35/54] Fix: false alarm in phase check of mock prover (#61) * fix false alarm in phase check of mock prover * fix clippy * clippy --- halo2_proofs/src/dev.rs | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index aadca90b5d..ff1fa6d623 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -540,7 +540,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { fn assign_advice( &mut self, - _: A, + anno: A, column: Column, row: usize, to: V, @@ -551,6 +551,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { A: FnOnce() -> AR, AR: Into, { + // column of 2nd phase does not need to be assigned when synthesis at 1st phase if self.current_phase.0 < column.column_type().phase.0 { return Ok(()); } @@ -578,7 +579,18 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { .or_default(); } - let assigned = CellValue::Assigned(to().into_field().evaluate().assign()?); + let advice_anno = anno().into(); + let val_res = to().into_field().evaluate().assign(); + if val_res.is_err() { + log::debug!( + "[{}] assign to advice {:?} at row {} failed at phase {:?}", + advice_anno, + column, + row, + self.current_phase + ); + } + let assigned = CellValue::Assigned(val_res?); *self .advice .get_mut(column.index()) @@ -830,12 +842,16 @@ impl<'a, F: FieldExt> MockProver<'a, F> { for current_phase in prover.cs.phases() { prover.current_phase = current_phase; prover.advice_prev = last_advice; - ConcreteCircuit::FloorPlanner::synthesize( + let syn_res = ConcreteCircuit::FloorPlanner::synthesize( &mut prover, circuit, config.clone(), constants.clone(), - )?; + ); + if syn_res.is_err() { + log::error!("mock prover syn failed at phase {:?}", current_phase); + } + syn_res?; for (index, phase) in prover.cs.challenge_phase.iter().enumerate() { if current_phase == *phase { @@ -861,6 +877,11 @@ impl<'a, F: FieldExt> MockProver<'a, F> { panic!("wrong phase assignment"); } } + if current_phase.0 < prover.cs.max_phase() { + // only keep the regions that we got during last phase's synthesis + // as we do not need to verify these regions. + prover.regions.clear(); + } last_advice = prover.advice_vec.as_ref().clone(); } } @@ -1309,6 +1330,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { // Check that within each region, all cells used in instantiated gates have been // assigned to. + log::debug!("regions.len() = {}", self.regions.len()); let selector_errors = self.regions.iter().enumerate().flat_map(|(r_i, r)| { r.enabled_selectors.iter().flat_map(move |(selector, at)| { // Find the gates enabled by this selector From 19de67c07a9b9b567580466763f93ebfbc3bb799 Mon Sep 17 00:00:00 2001 From: Velaciela Date: Fri, 18 Aug 2023 20:24:57 +0800 Subject: [PATCH 36/54] Perf: batch invert on CellValue for MockProver (#62) * mock prover batch invert * middle * parallelize * unwrap() * fmt * fix clippy error * reviewers' suggestions * refactor --------- Co-authored-by: kunxian xia --- halo2_proofs/src/dev.rs | 143 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 136 insertions(+), 7 deletions(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index ff1fa6d623..ead9abb07a 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -9,7 +9,7 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use blake2b_simd::blake2b; -use ff::Field; +use ff::{BatchInvert, Field}; use crate::plonk::permutation::keygen::Assembly; use crate::plonk::sealed::SealedPhase; @@ -97,16 +97,135 @@ impl Region { } /// The value of a particular cell within the circuit. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug)] pub enum CellValue { /// An unassigned cell. Unassigned, /// A cell that has been assigned a value. Assigned(F), + /// A value stored as a fraction to enable batch inversion. + Rational(F, F), /// A unique poisoned cell. Poison(usize), } +impl PartialEq for CellValue { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Unassigned, Self::Unassigned) => true, + (Self::Assigned(a), Self::Assigned(b)) => a == b, + (Self::Rational(a, b), Self::Rational(c, d)) => *a * d == *b * c, + (Self::Assigned(a), Self::Rational(n, d)) => *a * *d == *n, + (Self::Rational(n, d), Self::Assigned(a)) => *a * *d == *n, + (Self::Poison(a), Self::Poison(b)) => a == b, + _ => false, + } + } +} + +impl CellValue { + /// Returns the numerator. + pub fn numerator(&self) -> Option { + match self { + Self::Rational(numerator, _) => Some(*numerator), + _ => None, + } + } + + /// Returns the denominator + pub fn denominator(&self) -> Option { + match self { + Self::Rational(_, denominator) => Some(*denominator), + _ => None, + } + } +} + +impl From> for CellValue { + fn from(value: Assigned) -> Self { + match value { + Assigned::Zero => CellValue::Unassigned, + Assigned::Trivial(value) => CellValue::Assigned(value), + Assigned::Rational(numerator, denominator) => { + CellValue::Rational(numerator, denominator) + } + } + } +} + +fn calculate_assigned_values( + cell_values: &mut [CellValue], + inv_denoms: &[Option], +) { + assert_eq!(inv_denoms.len(), cell_values.len()); + for (value, inv_den) in cell_values.iter_mut().zip(inv_denoms.iter()) { + // if numerator and denominator exist, calculate the assigned value + // otherwise, return the original CellValue + *value = match value { + CellValue::Rational(numerator, _) => CellValue::Assigned(*numerator * inv_den.unwrap()), + _ => *value, + }; + } +} + +fn batch_invert_cellvalues(cell_values: &mut [Vec>]) { + let mut denominators: Vec<_> = cell_values + .iter() + .map(|f| { + f.par_iter() + .map(|value| value.denominator()) + .collect::>() + }) + .collect(); + let denominators_len: usize = denominators.iter().map(|f| f.len()).sum(); + + let mut_denominators = denominators + .iter_mut() + .flat_map(|f| { + f.iter_mut() + // If the denominator is trivial, we can skip it, reducing the + // size of the batch inversion. + .filter_map(|d| d.as_mut()) + }) + .collect::>(); + + log::info!( + "num of denominators: {} / {}", + mut_denominators.len(), + denominators_len + ); + if mut_denominators.is_empty() { + return; + } + + let num_threads = rayon::current_num_threads(); + let chunk_size = (mut_denominators.len() + num_threads - 1) / num_threads; + let mut_denominators = + mut_denominators + .into_iter() + .enumerate() + .fold(vec![vec![]], |mut acc, (i, denom)| { + let len = acc.len(); + if i % chunk_size == 0 { + acc.push(vec![denom]) + } else { + acc[len - 1].push(denom); + } + acc + }); + rayon::scope(|scope| { + for chunk in mut_denominators { + scope.spawn(|_| { + chunk.batch_invert(); + }); + } + }); + + for (cell_values, inv_denoms) in cell_values.iter_mut().zip(denominators.iter()) { + calculate_assigned_values(cell_values, inv_denoms); + } +} + /// A value within an expression. #[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)] enum Value { @@ -120,6 +239,7 @@ impl From> for Value { // Cells that haven't been explicitly assigned to, default to zero. CellValue::Unassigned => Value::Real(F::zero()), CellValue::Assigned(v) => Value::Real(v), + CellValue::Rational(n, d) => Value::Real(n * d.invert().unwrap()), CellValue::Poison(_) => Value::Poison, } } @@ -580,7 +700,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { } let advice_anno = anno().into(); - let val_res = to().into_field().evaluate().assign(); + let val_res = to().into_field().assign(); if val_res.is_err() { log::debug!( "[{}] assign to advice {:?} at row {} failed at phase {:?}", @@ -590,7 +710,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { self.current_phase ); } - let assigned = CellValue::Assigned(val_res?); + let assigned = CellValue::from(val_res?); *self .advice .get_mut(column.index()) @@ -653,15 +773,15 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { .or_default(); } - let fix_cell = self + let assigned = self .fixed .get_mut(column.index()) .and_then(|v| v.get_mut(row - self.rw_rows.start)) .ok_or(Error::BoundsFailure); - if fix_cell.is_err() { + if assigned.is_err() { println!("fix cell is none: {}, row: {}", column.index(), row); } - *fix_cell? = CellValue::Assigned(to().into_field().evaluate().assign()?); + *assigned? = CellValue::from(to().into_field().assign()?); Ok(()) } @@ -897,6 +1017,15 @@ impl<'a, F: FieldExt> MockProver<'a, F> { .cs .compress_selectors(prover.selectors_vec.as_ref().clone()); prover.cs = cs; + + // batch invert + batch_invert_cellvalues( + Arc::get_mut(&mut prover.advice_vec).expect("get_mut prover.advice_vec"), + ); + batch_invert_cellvalues( + Arc::get_mut(&mut prover.fixed_vec).expect("get_mut prover.fixed_vec"), + ); + // add selector polys Arc::get_mut(&mut prover.fixed_vec) .expect("get_mut prover.fixed_vec") .extend(selector_polys.into_iter().map(|poly| { From aa86c107aeb62282d81ebce5c4930ec0c0aa540b Mon Sep 17 00:00:00 2001 From: Velaciela Date: Wed, 30 Aug 2023 13:35:11 +0800 Subject: [PATCH 37/54] feature flag: mock-batch-inv (#63) --- halo2_proofs/Cargo.toml | 1 + halo2_proofs/src/dev.rs | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index 9afcc0caec..148088899b 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -90,6 +90,7 @@ gwc = [] parallel_syn = [] phase-check = [] profile = ["ark-std/print-trace"] +mock-batch-inv = [] [lib] bench = false diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index ead9abb07a..94d7da90a1 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -104,6 +104,7 @@ pub enum CellValue { /// A cell that has been assigned a value. Assigned(F), /// A value stored as a fraction to enable batch inversion. + #[cfg(feature = "mock-batch-inv")] Rational(F, F), /// A unique poisoned cell. Poison(usize), @@ -114,8 +115,11 @@ impl PartialEq for CellValue { match (self, other) { (Self::Unassigned, Self::Unassigned) => true, (Self::Assigned(a), Self::Assigned(b)) => a == b, + #[cfg(feature = "mock-batch-inv")] (Self::Rational(a, b), Self::Rational(c, d)) => *a * d == *b * c, + #[cfg(feature = "mock-batch-inv")] (Self::Assigned(a), Self::Rational(n, d)) => *a * *d == *n, + #[cfg(feature = "mock-batch-inv")] (Self::Rational(n, d), Self::Assigned(a)) => *a * *d == *n, (Self::Poison(a), Self::Poison(b)) => a == b, _ => false, @@ -123,6 +127,7 @@ impl PartialEq for CellValue { } } +#[cfg(feature = "mock-batch-inv")] impl CellValue { /// Returns the numerator. pub fn numerator(&self) -> Option { @@ -141,6 +146,7 @@ impl CellValue { } } +#[cfg(feature = "mock-batch-inv")] impl From> for CellValue { fn from(value: Assigned) -> Self { match value { @@ -153,6 +159,7 @@ impl From> for CellValue { } } +#[cfg(feature = "mock-batch-inv")] fn calculate_assigned_values( cell_values: &mut [CellValue], inv_denoms: &[Option], @@ -168,6 +175,7 @@ fn calculate_assigned_values( } } +#[cfg(feature = "mock-batch-inv")] fn batch_invert_cellvalues(cell_values: &mut [Vec>]) { let mut denominators: Vec<_> = cell_values .iter() @@ -239,6 +247,7 @@ impl From> for Value { // Cells that haven't been explicitly assigned to, default to zero. CellValue::Unassigned => Value::Real(F::zero()), CellValue::Assigned(v) => Value::Real(v), + #[cfg(feature = "mock-batch-inv")] CellValue::Rational(n, d) => Value::Real(n * d.invert().unwrap()), CellValue::Poison(_) => Value::Poison, } @@ -700,6 +709,9 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { } let advice_anno = anno().into(); + #[cfg(not(feature = "mock-batch-inv"))] + let val_res = to().into_field().evaluate().assign(); + #[cfg(feature = "mock-batch-inv")] let val_res = to().into_field().assign(); if val_res.is_err() { log::debug!( @@ -710,7 +722,11 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { self.current_phase ); } + #[cfg(not(feature = "mock-batch-inv"))] + let assigned = CellValue::Assigned(val_res?); + #[cfg(feature = "mock-batch-inv")] let assigned = CellValue::from(val_res?); + *self .advice .get_mut(column.index()) @@ -781,7 +797,15 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { if assigned.is_err() { println!("fix cell is none: {}, row: {}", column.index(), row); } - *assigned? = CellValue::from(to().into_field().assign()?); + + #[cfg(not(feature = "mock-batch-inv"))] + { + *assigned? = CellValue::Assigned(to().into_field().evaluate().assign()?); + } + #[cfg(feature = "mock-batch-inv")] + { + *assigned? = CellValue::from(to().into_field().assign()?); + } Ok(()) } @@ -1019,12 +1043,15 @@ impl<'a, F: FieldExt> MockProver<'a, F> { prover.cs = cs; // batch invert - batch_invert_cellvalues( - Arc::get_mut(&mut prover.advice_vec).expect("get_mut prover.advice_vec"), - ); - batch_invert_cellvalues( - Arc::get_mut(&mut prover.fixed_vec).expect("get_mut prover.fixed_vec"), - ); + #[cfg(feature = "mock-batch-inv")] + { + batch_invert_cellvalues( + Arc::get_mut(&mut prover.advice_vec).expect("get_mut prover.advice_vec"), + ); + batch_invert_cellvalues( + Arc::get_mut(&mut prover.fixed_vec).expect("get_mut prover.fixed_vec"), + ); + } // add selector polys Arc::get_mut(&mut prover.fixed_vec) .expect("get_mut prover.fixed_vec") From ca3066c88546d7fcae0416c17efd0db632d5b954 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 19 Sep 2023 08:04:36 +0800 Subject: [PATCH 38/54] expose param field for re-randomization (#67) --- halo2_proofs/src/poly/kzg/commitment.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/halo2_proofs/src/poly/kzg/commitment.rs b/halo2_proofs/src/poly/kzg/commitment.rs index 27d188aa5c..08665667b3 100644 --- a/halo2_proofs/src/poly/kzg/commitment.rs +++ b/halo2_proofs/src/poly/kzg/commitment.rs @@ -21,12 +21,12 @@ use super::msm::MSMKZG; /// These are the public parameters for the polynomial commitment scheme. #[derive(Debug, Clone)] pub struct ParamsKZG { - pub(crate) k: u32, + pub k: u32, pub n: u64, - pub(crate) g: Vec, + pub g: Vec, pub g_lagrange: Vec, - pub(crate) g2: E::G2Affine, - pub(crate) s_g2: E::G2Affine, + pub g2: E::G2Affine, + pub s_g2: E::G2Affine, } /// Umbrella commitment scheme construction for all KZG variants From e3fe25eadd714fd991f35190d17ff0b8fb031188 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Wed, 20 Sep 2023 15:06:17 +0800 Subject: [PATCH 39/54] change log level --- halo2_proofs/src/circuit/floor_planner/single_pass.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index a11b4155a9..0761957bfc 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -250,7 +250,7 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a // Do actual synthesis of sub-regions in parallel let cs_fork_time = Instant::now(); let mut sub_cs = self.cs.fork(&ranges)?; - log::info!( + log::debug!( "CS forked into {} subCS took {:?}", sub_cs.len(), cs_fork_time.elapsed() @@ -275,7 +275,7 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a let result = assignment(region_ref.into()); let constant = region.constants.clone(); sub_layouter.cs.exit_region(); - log::info!( + log::debug!( "region {} 2nd pass synthesis took {:?}", region_name, sub_region_2nd_pass.elapsed() @@ -294,12 +294,12 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a let cs_merge_time = Instant::now(); let num_sub_cs = sub_cs.len(); self.cs.merge(sub_cs)?; - log::info!( + log::debug!( "Merge {} subCS back took {:?}", num_sub_cs, cs_merge_time.elapsed() ); - log::info!( + log::debug!( "{} sub_regions of {} 2nd pass synthesis took {:?}", ranges.len(), region_name, From 92fe9b3e2420ee51336b39513e397df7c8175cf9 Mon Sep 17 00:00:00 2001 From: alannotnerd Date: Tue, 17 Oct 2023 22:13:36 +0800 Subject: [PATCH 40/54] Use thread pool for assign_regions (#57) * feat: use rayon threadpool * feat: add UT for many subregions * refact: move common struct out to module level * refact: reuse common configure code * fix ci errors --------- Co-authored-by: kunxian xia --- .gitignore | 2 +- .../src/circuit/floor_planner/single_pass.rs | 55 +- halo2_proofs/tests/plonk_api.rs | 1364 +++++++---------- 3 files changed, 584 insertions(+), 837 deletions(-) diff --git a/.gitignore b/.gitignore index 317814d1e4..cd5bdf5ef1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ **/*.rs.bk .vscode **/*.html -.DS_Store +.DS_Store \ No newline at end of file diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index 0761957bfc..3c445230d3 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -6,6 +6,8 @@ use std::ops::Range; use std::sync::{Arc, Mutex}; use std::time::Instant; +use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}; + use ff::Field; use ark_std::{end_timer, start_timer}; @@ -258,39 +260,28 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a let ref_sub_cs = sub_cs.iter_mut().collect(); let sub_layouters = self.fork(ref_sub_cs)?; let regions_2nd_pass = Instant::now(); - let ret = crossbeam::scope(|scope| { - let mut handles = vec![]; - for (i, (mut assignment, mut sub_layouter)) in assignments - .into_iter() - .zip(sub_layouters.into_iter()) - .enumerate() - { + let ret = assignments + .into_par_iter() + .zip(sub_layouters.into_par_iter()) + .enumerate() + .map(|(i, (mut assignment, mut sub_layouter))| { let region_name = format!("{}_{}", region_name, i); - handles.push(scope.spawn(move |_| { - let sub_region_2nd_pass = Instant::now(); - sub_layouter.cs.enter_region(|| region_name.clone()); - let mut region = - SingleChipLayouterRegion::new(&mut sub_layouter, (region_index + i).into()); - let region_ref: &mut dyn RegionLayouter = &mut region; - let result = assignment(region_ref.into()); - let constant = region.constants.clone(); - sub_layouter.cs.exit_region(); - log::debug!( - "region {} 2nd pass synthesis took {:?}", - region_name, - sub_region_2nd_pass.elapsed() - ); - - (result, constant) - })); - } - - handles - .into_iter() - .map(|handle| handle.join().expect("handle.join should never fail")) - .collect::>() - }) - .expect("scope should not fail"); + let sub_region_2nd_pass = Instant::now(); + sub_layouter.cs.enter_region(|| region_name.clone()); + let mut region = + SingleChipLayouterRegion::new(&mut sub_layouter, (region_index + i).into()); + let region_ref: &mut dyn RegionLayouter = &mut region; + let result = assignment(region_ref.into()); + let constant = region.constants.clone(); + sub_layouter.cs.exit_region(); + log::debug!( + "region {} 2nd pass synthesis took {:?}", + region_name, + sub_region_2nd_pass.elapsed() + ); + (result, constant) + }) + .collect::>(); let cs_merge_time = Instant::now(); let num_sub_cs = sub_cs.len(); self.cs.merge(sub_cs)?; diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index edfdfac3b2..778cf840fb 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -3,7 +3,9 @@ // use assert_matches::assert_matches; use halo2_proofs::arithmetic::{Field, FieldExt}; -use halo2_proofs::circuit::{Cell, Layouter, Region, SimpleFloorPlanner, Value}; +#[cfg(feature = "parallel_syn")] +use halo2_proofs::circuit::Region; +use halo2_proofs::circuit::{Cell, Layouter, SimpleFloorPlanner, Value}; use halo2_proofs::dev::MockProver; use halo2_proofs::plonk::{ create_proof as create_plonk_proof, keygen_pk, keygen_vk, verify_proof as verify_plonk_proof, @@ -11,260 +13,375 @@ use halo2_proofs::plonk::{ VerifyingKey, }; use halo2_proofs::poly::commitment::{CommitmentScheme, ParamsProver, Prover, Verifier}; +use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; +use halo2_proofs::poly::kzg::multiopen::{ProverGWC, VerifierGWC}; +use halo2_proofs::poly::kzg::strategy::AccumulatorStrategy; use halo2_proofs::poly::Rotation; use halo2_proofs::poly::VerificationStrategy; use halo2_proofs::transcript::{ Blake2bRead, Blake2bWrite, Challenge255, EncodedChallenge, TranscriptReadBuffer, TranscriptWriterBuffer, }; +use halo2curves::bn256::Bn256; use rand_core::{OsRng, RngCore}; use std::marker::PhantomData; use std::time::Instant; -#[test] -fn plonk_api() { - const K: u32 = 17; +const K: u32 = 17; + +/// This represents an advice column at a certain row in the ConstraintSystem +#[derive(Copy, Clone, Debug)] +pub struct Variable(Column, usize); + +#[derive(Clone)] +struct PlonkConfig { + a: Column, + b: Column, + c: Column, + d: Column, + e: Column, + + sa: Column, + sb: Column, + sc: Column, + sm: Column, + sp: Column, + sl: TableColumn, +} - /// This represents an advice column at a certain row in the ConstraintSystem - #[derive(Copy, Clone, Debug)] - pub struct Variable(Column, usize); +impl PlonkConfig { + pub fn construct(meta: &mut ConstraintSystem) -> Self { + let e = meta.advice_column(); + let a = meta.advice_column(); + let b = meta.advice_column(); + let sf = meta.fixed_column(); + let c = meta.advice_column(); + let d = meta.advice_column(); + let p = meta.instance_column(); + + meta.enable_equality(a); + meta.enable_equality(b); + meta.enable_equality(c); + + let sm = meta.fixed_column(); + let sa = meta.fixed_column(); + let sb = meta.fixed_column(); + let sc = meta.fixed_column(); + let sp = meta.fixed_column(); + let sl = meta.lookup_table_column(); - #[derive(Clone)] - struct PlonkConfig { - a: Column, - b: Column, - c: Column, - d: Column, - e: Column, - - sa: Column, - sb: Column, - sc: Column, - sm: Column, - sp: Column, - sl: TableColumn, - } - - #[allow(clippy::type_complexity)] - trait StandardCs { - fn raw_multiply( - &self, - layouter: &mut impl Layouter, - f: F, - ) -> Result<(Cell, Cell, Cell), Error> - where - F: FnMut() -> Value<(Assigned, Assigned, Assigned)>; - fn raw_add( - &self, - layouter: &mut impl Layouter, - f: F, - ) -> Result<(Cell, Cell, Cell), Error> - where - F: FnMut() -> Value<(Assigned, Assigned, Assigned)>; - fn copy(&self, layouter: &mut impl Layouter, a: Cell, b: Cell) -> Result<(), Error>; - fn public_input(&self, layouter: &mut impl Layouter, f: F) -> Result - where - F: FnMut() -> Value; - fn lookup_table( - &self, - layouter: &mut impl Layouter, - values: &[FF], - ) -> Result<(), Error>; + /* + * A B ... sl + * [ + * instance 0 ... 0 + * a a ... 0 + * a a^2 ... 0 + * a a ... 0 + * a a^2 ... 0 + * ... ... ... ... + * ... ... ... instance + * ... ... ... a + * ... ... ... a + * ... ... ... 0 + * ] + */ + + meta.lookup("lookup", |meta| { + let a_ = meta.query_any(a, Rotation::cur()); + vec![(a_, sl)] + }); + + meta.create_gate("Combined add-mult", |meta| { + let d = meta.query_advice(d, Rotation::next()); + let a = meta.query_advice(a, Rotation::cur()); + let sf = meta.query_fixed(sf, Rotation::cur()); + let e = meta.query_advice(e, Rotation::prev()); + let b = meta.query_advice(b, Rotation::cur()); + let c = meta.query_advice(c, Rotation::cur()); + + let sa = meta.query_fixed(sa, Rotation::cur()); + let sb = meta.query_fixed(sb, Rotation::cur()); + let sc = meta.query_fixed(sc, Rotation::cur()); + let sm = meta.query_fixed(sm, Rotation::cur()); + + vec![a.clone() * sa + b.clone() * sb + a * b * sm - (c * sc) + sf * (d * e)] + }); + + meta.create_gate("Public input", |meta| { + let a = meta.query_advice(a, Rotation::cur()); + let p = meta.query_instance(p, Rotation::cur()); + let sp = meta.query_fixed(sp, Rotation::cur()); + + vec![sp * (a - p)] + }); + + meta.enable_equality(sf); + meta.enable_equality(e); + meta.enable_equality(d); + meta.enable_equality(p); + meta.enable_equality(sm); + meta.enable_equality(sa); + meta.enable_equality(sb); + meta.enable_equality(sc); + meta.enable_equality(sp); + + PlonkConfig { + a, + b, + c, + d, + e, + sa, + sb, + sc, + sm, + sp, + sl, + } } +} - #[derive(Clone)] - struct MyCircuit { - a: Value, - lookup_table: Vec, - } +#[allow(clippy::type_complexity)] +trait StandardCs { + fn raw_multiply( + &self, + layouter: &mut impl Layouter, + f: F, + ) -> Result<(Cell, Cell, Cell), Error> + where + F: FnMut() -> Value<(Assigned, Assigned, Assigned)>; + fn raw_add( + &self, + layouter: &mut impl Layouter, + f: F, + ) -> Result<(Cell, Cell, Cell), Error> + where + F: FnMut() -> Value<(Assigned, Assigned, Assigned)>; + fn copy(&self, layouter: &mut impl Layouter, a: Cell, b: Cell) -> Result<(), Error>; + fn public_input(&self, layouter: &mut impl Layouter, f: F) -> Result + where + F: FnMut() -> Value; + fn lookup_table(&self, layouter: &mut impl Layouter, values: &[FF]) -> Result<(), Error>; +} - struct StandardPlonk { - config: PlonkConfig, - _marker: PhantomData, - } +struct StandardPlonk { + config: PlonkConfig, + _marker: PhantomData, +} - impl StandardPlonk { - fn new(config: PlonkConfig) -> Self { - StandardPlonk { - config, - _marker: PhantomData, - } +impl StandardPlonk { + fn new(config: PlonkConfig) -> Self { + StandardPlonk { + config, + _marker: PhantomData, } } +} - impl StandardCs for StandardPlonk { - fn raw_multiply( - &self, - layouter: &mut impl Layouter, - mut f: F, - ) -> Result<(Cell, Cell, Cell), Error> - where - F: FnMut() -> Value<(Assigned, Assigned, Assigned)>, - { - layouter.assign_region( - || "raw_multiply", - |mut region| { - let mut value = None; - let lhs = region.assign_advice( - || "lhs", - self.config.a, - 0, - || { - value = Some(f()); - value.unwrap().map(|v| v.0) - }, - )?; - region.assign_advice( - || "lhs^4", - self.config.d, - 0, - || value.unwrap().map(|v| v.0).square().square(), - )?; - let rhs = region.assign_advice( - || "rhs", - self.config.b, - 0, - || value.unwrap().map(|v| v.1), - )?; - region.assign_advice( - || "rhs^4", - self.config.e, - 0, - || value.unwrap().map(|v| v.1).square().square(), - )?; - let out = region.assign_advice( - || "out", - self.config.c, - 0, - || value.unwrap().map(|v| v.2), +impl StandardCs for StandardPlonk { + fn raw_multiply( + &self, + layouter: &mut impl Layouter, + mut f: F, + ) -> Result<(Cell, Cell, Cell), Error> + where + F: FnMut() -> Value<(Assigned, Assigned, Assigned)>, + { + layouter.assign_region( + || "raw_multiply", + |mut region| { + let mut value = None; + let lhs = region.assign_advice( + || "lhs", + self.config.a, + 0, + || { + value = Some(f()); + value.unwrap().map(|v| v.0) + }, + )?; + region.assign_advice( + || "lhs^4", + self.config.d, + 0, + || value.unwrap().map(|v| v.0).square().square(), + )?; + let rhs = region.assign_advice( + || "rhs", + self.config.b, + 0, + || value.unwrap().map(|v| v.1), + )?; + region.assign_advice( + || "rhs^4", + self.config.e, + 0, + || value.unwrap().map(|v| v.1).square().square(), + )?; + let out = region.assign_advice( + || "out", + self.config.c, + 0, + || value.unwrap().map(|v| v.2), + )?; + + region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::zero()))?; + region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::zero()))?; + region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::one()))?; + region.assign_fixed(|| "a * b", self.config.sm, 0, || Value::known(FF::one()))?; + Ok((lhs.cell(), rhs.cell(), out.cell())) + }, + ) + } + fn raw_add( + &self, + layouter: &mut impl Layouter, + mut f: F, + ) -> Result<(Cell, Cell, Cell), Error> + where + F: FnMut() -> Value<(Assigned, Assigned, Assigned)>, + { + layouter.assign_region( + || "raw_add", + |mut region| { + let mut value = None; + let lhs = region.assign_advice( + || "lhs", + self.config.a, + 0, + || { + value = Some(f()); + value.unwrap().map(|v| v.0) + }, + )?; + region.assign_advice( + || "lhs^4", + self.config.d, + 0, + || value.unwrap().map(|v| v.0).square().square(), + )?; + let rhs = region.assign_advice( + || "rhs", + self.config.b, + 0, + || value.unwrap().map(|v| v.1), + )?; + region.assign_advice( + || "rhs^4", + self.config.e, + 0, + || value.unwrap().map(|v| v.1).square().square(), + )?; + let out = region.assign_advice( + || "out", + self.config.c, + 0, + || value.unwrap().map(|v| v.2), + )?; + + region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::one()))?; + region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::one()))?; + region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::one()))?; + region.assign_fixed(|| "a * b", self.config.sm, 0, || Value::known(FF::zero()))?; + Ok((lhs.cell(), rhs.cell(), out.cell())) + }, + ) + } + fn copy(&self, layouter: &mut impl Layouter, left: Cell, right: Cell) -> Result<(), Error> { + layouter.assign_region( + || "copy", + |mut region| { + region.constrain_equal(left, right)?; + region.constrain_equal(left, right) + }, + ) + } + fn public_input(&self, layouter: &mut impl Layouter, mut f: F) -> Result + where + F: FnMut() -> Value, + { + layouter.assign_region( + || "public_input", + |mut region| { + let value = region.assign_advice(|| "value", self.config.a, 0, &mut f)?; + region.assign_fixed(|| "public", self.config.sp, 0, || Value::known(FF::one()))?; + + Ok(value.cell()) + }, + ) + } + fn lookup_table(&self, layouter: &mut impl Layouter, values: &[FF]) -> Result<(), Error> { + layouter.assign_table( + || "", + |mut table| { + for (index, &value) in values.iter().enumerate() { + table.assign_cell( + || "table col", + self.config.sl, + index, + || Value::known(value), )?; + } + Ok(()) + }, + )?; + Ok(()) + } +} - region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::zero()))?; - region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::zero()))?; - region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::one()))?; - region.assign_fixed( - || "a * b", - self.config.sm, - 0, - || Value::known(FF::one()), - )?; - Ok((lhs.cell(), rhs.cell(), out.cell())) - }, - ) - } - fn raw_add( - &self, - layouter: &mut impl Layouter, - mut f: F, - ) -> Result<(Cell, Cell, Cell), Error> - where - F: FnMut() -> Value<(Assigned, Assigned, Assigned)>, - { - layouter.assign_region( - || "raw_add", - |mut region| { - let mut value = None; - let lhs = region.assign_advice( - || "lhs", - self.config.a, - 0, - || { - value = Some(f()); - value.unwrap().map(|v| v.0) - }, - )?; - region.assign_advice( - || "lhs^4", - self.config.d, - 0, - || value.unwrap().map(|v| v.0).square().square(), - )?; - let rhs = region.assign_advice( - || "rhs", - self.config.b, - 0, - || value.unwrap().map(|v| v.1), - )?; - region.assign_advice( - || "rhs^4", - self.config.e, - 0, - || value.unwrap().map(|v| v.1).square().square(), - )?; - let out = region.assign_advice( - || "out", - self.config.c, - 0, - || value.unwrap().map(|v| v.2), - )?; +macro_rules! common { + ($scheme:ident) => {{ + let a = <$scheme as CommitmentScheme>::Scalar::from(2834758237) + * <$scheme as CommitmentScheme>::Scalar::ZETA; + let instance = <$scheme as CommitmentScheme>::Scalar::one() + + <$scheme as CommitmentScheme>::Scalar::one(); + let lookup_table = vec![ + instance, + a, + a, + <$scheme as CommitmentScheme>::Scalar::zero(), + ]; + (a, instance, lookup_table) + }}; +} - region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::one()))?; - region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::one()))?; - region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::one()))?; - region.assign_fixed( - || "a * b", - self.config.sm, - 0, - || Value::known(FF::zero()), - )?; - Ok((lhs.cell(), rhs.cell(), out.cell())) - }, - ) - } - fn copy( - &self, - layouter: &mut impl Layouter, - left: Cell, - right: Cell, - ) -> Result<(), Error> { - layouter.assign_region( - || "copy", - |mut region| { - region.constrain_equal(left, right)?; - region.constrain_equal(left, right) - }, - ) - } - fn public_input(&self, layouter: &mut impl Layouter, mut f: F) -> Result - where - F: FnMut() -> Value, - { - layouter.assign_region( - || "public_input", - |mut region| { - let value = region.assign_advice(|| "value", self.config.a, 0, &mut f)?; - region.assign_fixed( - || "public", - self.config.sp, - 0, - || Value::known(FF::one()), - )?; +fn verify_proof< + 'a, + 'params, + Scheme: CommitmentScheme, + V: Verifier<'params, Scheme>, + E: EncodedChallenge, + T: TranscriptReadBuffer<&'a [u8], Scheme::Curve, E>, + Strategy: VerificationStrategy<'params, Scheme, V, Output = Strategy>, +>( + params_verifier: &'params Scheme::ParamsVerifier, + vk: &VerifyingKey, + proof: &'a [u8], +) { + let (_, instance, _) = common!(Scheme); + let pubinputs = vec![instance]; + + let mut transcript = T::init(proof); + + let strategy = Strategy::new(params_verifier); + let strategy = verify_plonk_proof( + params_verifier, + vk, + strategy, + &[&[&pubinputs[..]], &[&pubinputs[..]]], + &mut transcript, + ) + .unwrap(); + + assert!(strategy.finalize()); +} - Ok(value.cell()) - }, - ) - } - fn lookup_table( - &self, - layouter: &mut impl Layouter, - values: &[FF], - ) -> Result<(), Error> { - layouter.assign_table( - || "", - |mut table| { - for (index, &value) in values.iter().enumerate() { - table.assign_cell( - || "table col", - self.config.sl, - index, - || Value::known(value), - )?; - } - Ok(()) - }, - )?; - Ok(()) - } +#[test] +fn plonk_api() { + #[derive(Clone)] + struct MyCircuit { + a: Value, + lookup_table: Vec, } impl Circuit for MyCircuit { @@ -279,93 +396,7 @@ fn plonk_api() { } fn configure(meta: &mut ConstraintSystem) -> PlonkConfig { - let e = meta.advice_column(); - let a = meta.advice_column(); - let b = meta.advice_column(); - let sf = meta.fixed_column(); - let c = meta.advice_column(); - let d = meta.advice_column(); - let p = meta.instance_column(); - - meta.enable_equality(a); - meta.enable_equality(b); - meta.enable_equality(c); - - let sm = meta.fixed_column(); - let sa = meta.fixed_column(); - let sb = meta.fixed_column(); - let sc = meta.fixed_column(); - let sp = meta.fixed_column(); - let sl = meta.lookup_table_column(); - - /* - * A B ... sl - * [ - * instance 0 ... 0 - * a a ... 0 - * a a^2 ... 0 - * a a ... 0 - * a a^2 ... 0 - * ... ... ... ... - * ... ... ... instance - * ... ... ... a - * ... ... ... a - * ... ... ... 0 - * ] - */ - - meta.lookup("lookup", |meta| { - let a_ = meta.query_any(a, Rotation::cur()); - vec![(a_, sl)] - }); - - meta.create_gate("Combined add-mult", |meta| { - let d = meta.query_advice(d, Rotation::next()); - let a = meta.query_advice(a, Rotation::cur()); - let sf = meta.query_fixed(sf, Rotation::cur()); - let e = meta.query_advice(e, Rotation::prev()); - let b = meta.query_advice(b, Rotation::cur()); - let c = meta.query_advice(c, Rotation::cur()); - - let sa = meta.query_fixed(sa, Rotation::cur()); - let sb = meta.query_fixed(sb, Rotation::cur()); - let sc = meta.query_fixed(sc, Rotation::cur()); - let sm = meta.query_fixed(sm, Rotation::cur()); - - vec![a.clone() * sa + b.clone() * sb + a * b * sm - (c * sc) + sf * (d * e)] - }); - - meta.create_gate("Public input", |meta| { - let a = meta.query_advice(a, Rotation::cur()); - let p = meta.query_instance(p, Rotation::cur()); - let sp = meta.query_fixed(sp, Rotation::cur()); - - vec![sp * (a - p)] - }); - - meta.enable_equality(sf); - meta.enable_equality(e); - meta.enable_equality(d); - meta.enable_equality(p); - meta.enable_equality(sm); - meta.enable_equality(sa); - meta.enable_equality(sb); - meta.enable_equality(sc); - meta.enable_equality(sp); - - PlonkConfig { - a, - b, - c, - d, - e, - sa, - sb, - sc, - sm, - sp, - sl, - } + PlonkConfig::construct(meta) } fn synthesize( @@ -465,55 +496,6 @@ fn plonk_api() { Ok(()) } } - - macro_rules! common { - ($scheme:ident) => {{ - let a = <$scheme as CommitmentScheme>::Scalar::from(2834758237) - * <$scheme as CommitmentScheme>::Scalar::ZETA; - let instance = <$scheme as CommitmentScheme>::Scalar::one() - + <$scheme as CommitmentScheme>::Scalar::one(); - let lookup_table = vec![ - instance, - a, - a, - <$scheme as CommitmentScheme>::Scalar::zero(), - ]; - (a, instance, lookup_table) - }}; - } - - /* - macro_rules! bad_keys { - ($scheme:ident) => {{ - let (_, _, lookup_table) = common!($scheme); - let empty_circuit: MyCircuit<<$scheme as CommitmentScheme>::Scalar> = MyCircuit { - a: Value::unknown(), - lookup_table: lookup_table.clone(), - }; - - // Check that we get an error if we try to initialize the proving key with a value of - // k that is too small for the minimum required number of rows. - let much_too_small_params= <$scheme as CommitmentScheme>::ParamsProver::new(1); - assert_matches!( - keygen_vk(&much_too_small_params, &empty_circuit), - Err(Error::NotEnoughRowsAvailable { - current_k, - }) if current_k == 1 - ); - - // Check that we get an error if we try to initialize the proving key with a value of - // k that is too small for the number of rows the circuit uses. - let slightly_too_small_params = <$scheme as CommitmentScheme>::ParamsProver::new(K-1); - assert_matches!( - keygen_vk(&slightly_too_small_params, &empty_circuit), - Err(Error::NotEnoughRowsAvailable { - current_k, - }) if current_k == K - 1 - ); - }}; - } - */ - fn keygen( params: &Scheme::ParamsProver, ) -> ProvingKey { @@ -567,37 +549,6 @@ fn plonk_api() { transcript.finalize() } - fn verify_proof< - 'a, - 'params, - Scheme: CommitmentScheme, - V: Verifier<'params, Scheme>, - E: EncodedChallenge, - T: TranscriptReadBuffer<&'a [u8], Scheme::Curve, E>, - Strategy: VerificationStrategy<'params, Scheme, V, Output = Strategy>, - >( - params_verifier: &'params Scheme::ParamsVerifier, - vk: &VerifyingKey, - proof: &'a [u8], - ) { - let (_, instance, _) = common!(Scheme); - let pubinputs = vec![instance]; - - let mut transcript = T::init(proof); - - let strategy = Strategy::new(params_verifier); - let strategy = verify_plonk_proof( - params_verifier, - vk, - strategy, - &[&[&pubinputs[..]], &[&pubinputs[..]]], - &mut transcript, - ) - .unwrap(); - - assert!(strategy.finalize()); - } - fn test_plonk_api_gwc() { use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use halo2_proofs::poly::kzg::multiopen::{ProverGWC, VerifierGWC}; @@ -698,411 +649,6 @@ fn plonk_api() { Blake2bRead<_, _, Challenge255<_>>, AccumulatorStrategy<_>, >(verifier_params, pk.get_vk(), &proof[..]); - - // Check that the verification key has not changed unexpectedly - // we comment this out because the circuit is already changed - /* - { - //panic!("{:#?}", pk.get_vk().pinned()); - assert_eq!( - format!("{:#?}", pk.get_vk().pinned()), - r#####"PinnedVerificationKey { - base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", - scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", - domain: PinnedEvaluationDomain { - k: 5, - extended_k: 7, - omega: 0x0cc3380dc616f2e1daf29ad1560833ed3baea3393eceb7bc8fa36376929b78cc, - }, - cs: PinnedConstraintSystem { - num_fixed_columns: 7, - num_advice_columns: 5, - num_instance_columns: 1, - num_selectors: 0, - gates: [ - Sum( - Sum( - Sum( - Sum( - Product( - Advice { - query_index: 0, - column_index: 1, - rotation: Rotation( - 0, - ), - }, - Fixed { - query_index: 2, - column_index: 2, - rotation: Rotation( - 0, - ), - }, - ), - Product( - Advice { - query_index: 1, - column_index: 2, - rotation: Rotation( - 0, - ), - }, - Fixed { - query_index: 3, - column_index: 3, - rotation: Rotation( - 0, - ), - }, - ), - ), - Product( - Product( - Advice { - query_index: 0, - column_index: 1, - rotation: Rotation( - 0, - ), - }, - Advice { - query_index: 1, - column_index: 2, - rotation: Rotation( - 0, - ), - }, - ), - Fixed { - query_index: 5, - column_index: 1, - rotation: Rotation( - 0, - ), - }, - ), - ), - Negated( - Product( - Advice { - query_index: 2, - column_index: 3, - rotation: Rotation( - 0, - ), - }, - Fixed { - query_index: 4, - column_index: 4, - rotation: Rotation( - 0, - ), - }, - ), - ), - ), - Product( - Fixed { - query_index: 1, - column_index: 0, - rotation: Rotation( - 0, - ), - }, - Product( - Advice { - query_index: 3, - column_index: 4, - rotation: Rotation( - 1, - ), - }, - Advice { - query_index: 4, - column_index: 0, - rotation: Rotation( - -1, - ), - }, - ), - ), - ), - Product( - Fixed { - query_index: 6, - column_index: 5, - rotation: Rotation( - 0, - ), - }, - Sum( - Advice { - query_index: 0, - column_index: 1, - rotation: Rotation( - 0, - ), - }, - Negated( - Instance { - query_index: 0, - column_index: 0, - rotation: Rotation( - 0, - ), - }, - ), - ), - ), - ], - advice_queries: [ - ( - Column { - index: 1, - column_type: Advice, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 2, - column_type: Advice, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 3, - column_type: Advice, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 4, - column_type: Advice, - }, - Rotation( - 1, - ), - ), - ( - Column { - index: 0, - column_type: Advice, - }, - Rotation( - -1, - ), - ), - ( - Column { - index: 0, - column_type: Advice, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 4, - column_type: Advice, - }, - Rotation( - 0, - ), - ), - ], - instance_queries: [ - ( - Column { - index: 0, - column_type: Instance, - }, - Rotation( - 0, - ), - ), - ], - fixed_queries: [ - ( - Column { - index: 6, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 0, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 2, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 3, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 4, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 1, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ( - Column { - index: 5, - column_type: Fixed, - }, - Rotation( - 0, - ), - ), - ], - permutation: Argument { - columns: [ - Column { - index: 1, - column_type: Advice, - }, - Column { - index: 2, - column_type: Advice, - }, - Column { - index: 3, - column_type: Advice, - }, - Column { - index: 0, - column_type: Fixed, - }, - Column { - index: 0, - column_type: Advice, - }, - Column { - index: 4, - column_type: Advice, - }, - Column { - index: 0, - column_type: Instance, - }, - Column { - index: 1, - column_type: Fixed, - }, - Column { - index: 2, - column_type: Fixed, - }, - Column { - index: 3, - column_type: Fixed, - }, - Column { - index: 4, - column_type: Fixed, - }, - Column { - index: 5, - column_type: Fixed, - }, - ], - }, - lookups: [ - Argument { - input_expressions: [ - Advice { - query_index: 0, - column_index: 1, - rotation: Rotation( - 0, - ), - }, - ], - table_expressions: [ - Fixed { - query_index: 0, - column_index: 6, - rotation: Rotation( - 0, - ), - }, - ], - }, - ], - constants: [], - minimum_degree: None, - }, - fixed_commitments: [ - (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), - (0x2bf5082b105b2156ed0e9c5b8e42bf2a240b058f74a464d080e9585274dd1e84, 0x222ad83cee7777e7a160585e212140e5e770dd8d1df788d869b5ee483a5864fb), - (0x374a656456a0aae7429b23336f825752b575dd5a44290ff614946ee59d6a20c0, 0x054491e187e6e3460e7601fb54ae10836d34d420026f96316f0c5c62f86db9b8), - (0x374a656456a0aae7429b23336f825752b575dd5a44290ff614946ee59d6a20c0, 0x054491e187e6e3460e7601fb54ae10836d34d420026f96316f0c5c62f86db9b8), - (0x02e62cd68370b13711139a08cbcdd889e800a272b9ea10acc90880fff9d89199, 0x1a96c468cb0ce77065d3a58f1e55fea9b72d15e44c01bba1e110bd0cbc6e9bc6), - (0x224ef42758215157d3ee48fb8d769da5bddd35e5929a90a4a89736f5c4b5ae9b, 0x11bc3a1e08eb320cde764f1492ecef956d71e996e2165f7a9a30ad2febb511c1), - (0x2d5415bf917fcac32bfb705f8ca35cb12d9bad52aa33ccca747350f9235d3a18, 0x2b2921f815fad504052512743963ef20ed5b401d20627793b006413e73fe4dd4), - ], - permutation: VerifyingKey { - commitments: [ - (0x1347b4b385837977a96b87f199c6a9a81520015539d1e8fa79429bb4ca229a00, 0x2168e404cabef513654d6ff516cde73f0ba87e3dc84e4b940ed675b5f66f3884), - (0x0e6d69cd2455ec43be640f6397ed65c9e51b1d8c0fd2216339314ff37ade122a, 0x222ed6dc8cfc9ea26dcc10b9d4add791ada60f2b5a63ee1e4635f88aa0c96654), - (0x13c447846f48c41a5e0675ccf88ebc0cdef2c96c51446d037acb866d24255785, 0x1f0b5414fc5e8219dbfab996eed6129d831488b2386a8b1a63663938903bd63a), - (0x1aae6470aa662b8fda003894ddef5fedd03af318b3231683039d2fac9cab05b9, 0x08832d91ae69e99cd07d096c7a4a284a69e6a16227cbb07932a0cdc56914f3a6), - (0x0850521b0f8ac7dd0550fe3e25c840837076e9635067ed623b81d5cbac5944d9, 0x0c25d65d1038d0a92c72e5fccd96c1caf07801c3c8233290bb292e0c38c256fa), - (0x12febcf696badd970750eabf75dd3ced4c2f54f93519bcee23849025177d2014, 0x0a05ab3cd42c9fbcc1bbfcf9269951640cc9920761c87cf8e211ba73c8d9f90f), - (0x053904bdde8cfead3b517bb4f6ded3e699f8b94ca6156a9dd2f92a2a05a7ec5a, 0x16753ff97c0d82ff586bb7a07bf7f27a92df90b3617fa5e75d4f55c3b0ef8711), - (0x3804548f6816452747a5b542fa5656353fc989db40d69e9e27d6f973b5deebb0, 0x389a44d5037866dd83993af75831a5f90a18ad5244255aa5bd2c922cc5853055), - (0x003a9f9ca71c7c0b832c802220915f6fc8d840162bdde6b0ea05d25fb95559e3, 0x091247ca19d6b73887cd7f68908cbf0db0b47459b7c82276bbdb8a1c937e2438), - (0x3eaa38689d9e391c8a8fafab9568f20c45816321d38f309d4cc37f4b1601af72, 0x247f8270a462ea88450221a56aa6b55d2bc352b80b03501e99ea983251ceea13), - (0x394437571f9de32dccdc546fd4737772d8d92593c85438aa3473243997d5acc8, 0x14924ec6e3174f1fab7f0ce7070c22f04bbd0a0ecebdfc5c94be857f25493e95), - (0x3d907e0591343bd285c2c846f3e871a6ac70d80ec29e9500b8cb57f544e60202, 0x1034e48df35830244cabea076be8a16d67d7896e27c6ac22b285d017105da9c3), - ], - }, - }"##### - ); - } - */ } env_logger::init(); @@ -1110,3 +656,213 @@ fn plonk_api() { test_plonk_api_gwc(); test_plonk_api_shplonk(); } + +#[test] +fn plonk_api_with_many_subregions() { + #[derive(Clone)] + struct MyCircuit { + a: Value, + lookup_table: Vec, + } + + impl Circuit for MyCircuit { + type Config = PlonkConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self { + a: Value::unknown(), + lookup_table: self.lookup_table.clone(), + } + } + + fn configure(meta: &mut ConstraintSystem) -> PlonkConfig { + PlonkConfig::construct(meta) + } + + fn synthesize( + &self, + config: PlonkConfig, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let cs = StandardPlonk::new(config); + + let _ = cs.public_input(&mut layouter, || Value::known(F::one() + F::one()))?; + + let a: Value> = self.a.into(); + let parallel_regions_time = Instant::now(); + #[cfg(feature = "parallel_syn")] + layouter.assign_regions( + || "regions", + (0..(1 << 14)) + .into_iter() + .map(|_| { + let mut is_first_pass = true; + move |mut region: Region<'_, F>| -> Result<(), Error> { + let n = 1 << 1; + for i in 0..n { + // skip the assign of rows except the last row in the first pass + if is_first_pass && i < n - 1 { + is_first_pass = false; + continue; + } + let a0 = + region.assign_advice(|| "config.a", cs.config.a, i, || a)?; + let a1 = + region.assign_advice(|| "config.b", cs.config.b, i, || a)?; + region.assign_advice( + || "config.c", + cs.config.c, + i, + || a.double(), + )?; + + region.assign_fixed( + || "a", + cs.config.sa, + i, + || Value::known(F::one()), + )?; + region.assign_fixed( + || "b", + cs.config.sb, + i, + || Value::known(F::one()), + )?; + region.assign_fixed( + || "c", + cs.config.sc, + i, + || Value::known(F::one()), + )?; + region.assign_fixed( + || "a * b", + cs.config.sm, + i, + || Value::known(F::zero()), + )?; + + region.constrain_equal(a0.cell(), a1.cell())?; + } + is_first_pass = false; + Ok(()) + } + }) + .collect(), + )?; + log::info!( + "parallel_regions assign took {:?}", + parallel_regions_time.elapsed() + ); + + for _ in 0..10 { + let a: Value> = self.a.into(); + let mut a_squared = Value::unknown(); + let (a0, _, c0) = cs.raw_multiply(&mut layouter, || { + a_squared = a.square(); + a.zip(a_squared).map(|(a, a_squared)| (a, a, a_squared)) + })?; + let (a1, b1, _) = cs.raw_add(&mut layouter, || { + let fin = a_squared + a; + a.zip(a_squared) + .zip(fin) + .map(|((a, a_squared), fin)| (a, a_squared, fin)) + })?; + cs.copy(&mut layouter, a0, a1)?; + cs.copy(&mut layouter, b1, c0)?; + } + + cs.lookup_table(&mut layouter, &self.lookup_table)?; + + Ok(()) + } + } + fn keygen( + params: &Scheme::ParamsProver, + ) -> ProvingKey { + let (_, _, lookup_table) = common!(Scheme); + let empty_circuit: MyCircuit = MyCircuit { + a: Value::unknown(), + lookup_table, + }; + + // Initialize the proving key + let vk = keygen_vk(params, &empty_circuit).expect("keygen_vk should not fail"); + log::info!("keygen vk succeed"); + + let pk = keygen_pk(params, vk, &empty_circuit).expect("keygen_pk should not fail"); + log::info!("keygen pk succeed"); + + pk + } + + fn create_proof< + 'params, + Scheme: CommitmentScheme, + P: Prover<'params, Scheme>, + E: EncodedChallenge, + R: RngCore, + T: TranscriptWriterBuffer, Scheme::Curve, E>, + >( + rng: R, + params: &'params Scheme::ParamsProver, + pk: &ProvingKey, + ) -> Vec { + let (a, instance, lookup_table) = common!(Scheme); + + let circuit: MyCircuit = MyCircuit { + a: Value::known(a), + lookup_table, + }; + + let mut transcript = T::init(vec![]); + + create_plonk_proof::( + params, + pk, + &[circuit.clone(), circuit], + &[&[&[instance]], &[&[instance]]], + rng, + &mut transcript, + ) + .expect("proof generation should not fail"); + + transcript.finalize() + } + + type Scheme = KZGCommitmentScheme; + // bad_keys!(Scheme); + + env_logger::try_init().unwrap(); + let (a, instance, lookup_table) = common!(Scheme); + + let circuit: MyCircuit<::Scalar> = MyCircuit { + a: Value::known(a), + lookup_table, + }; + + // Check this circuit is satisfied. + let prover = match MockProver::run(K, &circuit, vec![vec![instance]]) { + Ok(prover) => prover, + Err(e) => panic!("{:?}", e), + }; + assert_eq!(prover.verify_par(), Ok(())); + log::info!("mock proving succeed!"); + + let params = ParamsKZG::::new(K); + let rng = OsRng; + + let pk = keygen::>(¶ms); + + let proof = create_proof::<_, ProverGWC<_>, _, _, Blake2bWrite<_, _, Challenge255<_>>>( + rng, ¶ms, &pk, + ); + + let verifier_params = params.verifier_params(); + + verify_proof::<_, VerifierGWC<_>, _, Blake2bRead<_, _, Challenge255<_>>, AccumulatorStrategy<_>>( + verifier_params, + pk.get_vk(), + &proof[..], + ); +} From 5cf9a3726525810af41ef416e0292ec999b34030 Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 7 Nov 2023 22:13:26 +0800 Subject: [PATCH 41/54] Move `env_logger` dependency to dev-depdendencies (only for test). (#69) --- halo2_proofs/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index 148088899b..42807f79a9 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -67,11 +67,11 @@ log = "0.4.17" # timer ark-std = { version = "0.3.0" } -env_logger = "0.8.0" [dev-dependencies] assert_matches = "1.5" criterion = "0.3" +env_logger = "0.8.0" gumdrop = "0.8" proptest = "1" rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } From ae6e02cf54e6bcaa056427c5acc61e33c7bfb66d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20P=C3=A9rez?= <37264926+CPerezz@users.noreply.github.com> Date: Tue, 7 Mar 2023 17:29:37 +0100 Subject: [PATCH 42/54] sync ff/group 0.13 --- Cargo.lock | 71 +- halo2_gadgets/Cargo.toml | 6 +- halo2_gadgets/benches/poseidon.rs | 6 +- halo2_gadgets/src/ecc/chip/add.rs | 3 +- halo2_gadgets/src/ecc/chip/constants.rs | 13 +- halo2_gadgets/src/ecc/chip/mul.rs | 19 +- halo2_gadgets/src/ecc/chip/mul/incomplete.rs | 3 +- halo2_gadgets/src/ecc/chip/mul/overflow.rs | 4 +- halo2_gadgets/src/ecc/chip/mul_fixed.rs | 4 +- .../src/ecc/chip/mul_fixed/base_field_elem.rs | 2 +- .../src/ecc/chip/mul_fixed/full_width.rs | 2 +- halo2_gadgets/src/ecc/chip/mul_fixed/short.rs | 16 +- halo2_gadgets/src/poseidon.rs | 24 +- halo2_gadgets/src/poseidon/pow5.rs | 36 +- halo2_gadgets/src/poseidon/primitives.rs | 90 +- .../src/poseidon/primitives/grain.rs | 13 +- halo2_gadgets/src/poseidon/primitives/mds.rs | 10 +- .../src/poseidon/primitives/p128pow5t3.rs | 28 +- halo2_gadgets/src/sha256.rs | 8 +- .../table16/compression/compression_gates.rs | 38 +- halo2_gadgets/src/sha256/table16/gates.rs | 17 +- .../message_schedule/schedule_gates.rs | 22 +- .../src/sha256/table16/spread_table.rs | 80 +- halo2_gadgets/src/sinsemilla.rs | 6 +- .../src/sinsemilla/chip/generator_table.rs | 3 +- .../src/sinsemilla/chip/hash_to_point.rs | 16 +- halo2_gadgets/src/sinsemilla/merkle/chip.rs | 2 +- halo2_gadgets/src/sinsemilla/message.rs | 14 +- halo2_gadgets/src/utilities.rs | 26 +- halo2_gadgets/src/utilities/cond_swap.rs | 19 +- .../src/utilities/decompose_running_sum.rs | 19 +- .../src/utilities/lookup_range_check.rs | 30 +- halo2_proofs/Cargo.toml | 8 +- halo2_proofs/benches/dev_lookup.rs | 8 +- halo2_proofs/benches/plonk.rs | 34 +- halo2_proofs/examples/circuit-layout.rs | 29 +- halo2_proofs/examples/shuffle.rs | 42 +- halo2_proofs/examples/simple-example.rs | 18 +- halo2_proofs/examples/two-chip.rs | 43 +- halo2_proofs/src/arithmetic.rs | 117 +- halo2_proofs/src/circuit.rs | 9 +- halo2_proofs/src/circuit/layouter.rs | 2 +- halo2_proofs/src/dev.rs | 47 +- halo2_proofs/src/dev/failure.rs | 7 +- halo2_proofs/src/dev/util.rs | 18 +- halo2_proofs/src/helpers.rs | 17 +- halo2_proofs/src/plonk.rs | 23 +- halo2_proofs/src/plonk/assigned.rs | 14 +- halo2_proofs/src/plonk/circuit.rs | 9 +- .../src/plonk/circuit/compress_selectors.rs | 12 +- halo2_proofs/src/plonk/evaluation.rs | 24 +- halo2_proofs/src/plonk/keygen.rs | 14 +- halo2_proofs/src/plonk/lookup/prover.rs | 17 +- halo2_proofs/src/plonk/lookup/verifier.rs | 10 +- halo2_proofs/src/plonk/permutation/keygen.rs | 10 +- halo2_proofs/src/plonk/permutation/prover.rs | 11 +- .../src/plonk/permutation/verifier.rs | 15 +- halo2_proofs/src/plonk/prover.rs | 11 +- halo2_proofs/src/plonk/vanishing/prover.rs | 10 +- halo2_proofs/src/plonk/vanishing/verifier.rs | 6 +- halo2_proofs/src/plonk/verifier.rs | 15 +- halo2_proofs/src/plonk/verifier/batch.rs | 6 +- halo2_proofs/src/poly.rs | 13 +- halo2_proofs/src/poly/commitment.rs | 24 +- halo2_proofs/src/poly/domain.rs | 160 +- halo2_proofs/src/poly/evaluator.rs | 50 +- halo2_proofs/src/poly/ipa/commitment.rs | 14 +- .../src/poly/ipa/commitment/prover.rs | 4 +- .../src/poly/ipa/commitment/verifier.rs | 4 +- halo2_proofs/src/poly/ipa/msm.rs | 2 +- halo2_proofs/src/poly/ipa/multiopen.rs | 12 +- halo2_proofs/src/poly/ipa/multiopen/prover.rs | 6 +- .../src/poly/ipa/multiopen/verifier.rs | 10 +- halo2_proofs/src/poly/ipa/strategy.rs | 4 +- halo2_proofs/src/poly/kzg/commitment.rs | 27 +- halo2_proofs/src/poly/kzg/msm.rs | 2 +- halo2_proofs/src/poly/kzg/multiopen/gwc.rs | 8 +- .../src/poly/kzg/multiopen/gwc/prover.rs | 5 +- .../src/poly/kzg/multiopen/gwc/verifier.rs | 7 +- .../src/poly/kzg/multiopen/shplonk.rs | 24 +- .../src/poly/kzg/multiopen/shplonk/prover.rs | 11 +- .../poly/kzg/multiopen/shplonk/verifier.rs | 14 +- halo2_proofs/src/poly/kzg/strategy.rs | 5 +- halo2_proofs/src/poly/multiopen_test.rs | 21 +- halo2_proofs/src/transcript.rs | 38 +- halo2_proofs/src/transcript/poseidon.rs | 31 +- halo2_proofs/tests/plonk_api.rs | 1388 ++++++++++------- 87 files changed, 1742 insertions(+), 1398 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ec56f19b08..9a6ee62d9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -666,9 +666,9 @@ dependencies = [ [[package]] name = "ff" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df689201f395c6b90dfe87127685f8dbfc083a5e779e613575d8bd7314300c3e" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ "bitvec", "rand_core", @@ -807,11 +807,10 @@ checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" [[package]] name = "group" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7391856def869c1c81063a03457c676fbcd419709c3dfb33d8d319de484b154d" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "byteorder", "ff", "rand_core", "subtle", @@ -860,7 +859,7 @@ dependencies = [ "ff", "group", "halo2_proofs", - "halo2curves 0.2.1", + "halo2curves 0.3.2", "lazy_static", "plotters", "pprof", @@ -886,7 +885,7 @@ dependencies = [ "getrandom", "group", "gumdrop", - "halo2curves 0.3.1 (git+https://github.com/scroll-tech/halo2curves.git?branch=0.3.1-derive-serde)", + "halo2curves 0.1.0", "log", "num-bigint", "num-integer", @@ -903,42 +902,30 @@ dependencies = [ [[package]] name = "halo2curves" -version = "0.2.1" -source = "git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.3.0#83c72d49762343ffc9576ca11a2aa615efe1029b" -dependencies = [ - "ff", - "group", - "lazy_static", - "num-bigint", - "num-traits", - "pasta_curves", - "rand", - "rand_core", - "static_assertions", - "subtle", -] - -[[package]] -name = "halo2curves" -version = "0.3.1" -source = "git+https://github.com/privacy-scaling-explorations/halo2curves.git?tag=0.3.1#9b67e19bca30a35208b0c1b41c1723771e2c9f49" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b1142bd1059aacde1b477e0c80c142910f1ceae67fc619311d6a17428007ab" dependencies = [ + "blake2b_simd", "ff", "group", "lazy_static", "num-bigint", "num-traits", "pasta_curves", + "paste", "rand", "rand_core", + "serde", + "serde_arrays", "static_assertions", "subtle", ] [[package]] name = "halo2curves" -version = "0.3.1" -source = "git+https://github.com/scroll-tech/halo2curves.git?branch=0.3.1-derive-serde#c0ac1935e5da2a620204b5b011be2c924b1e0155" +version = "0.3.2" +source = "git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.3.2#9f5c50810bbefe779ee5cf1d852b2fe85dc35d5e" dependencies = [ "ff", "group", @@ -949,7 +936,6 @@ dependencies = [ "paste", "rand", "rand_core", - "serde", "static_assertions", "subtle", ] @@ -1090,6 +1076,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -1303,9 +1292,9 @@ dependencies = [ [[package]] name = "pasta_curves" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "369d7785168ad7ff0cbe467d968ca3e19a927d8536b11ef9c21b4e454b15ba42" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" dependencies = [ "blake2b_simd", "ff", @@ -1423,10 +1412,9 @@ dependencies = [ [[package]] name = "poseidon" version = "0.2.0" -source = "git+https://github.com/scroll-tech/poseidon.git?branch=scroll-dev-0220#2fb4a2385bada39b50dce12fe50cb80d2fd33476" +source = "git+https://github.com/scroll-tech/poseidon.git?branch=sync-ff-0.13#5787dd3d2ce7a9e9601a035c396ac0c03449b54d" dependencies = [ - "group", - "halo2curves 0.3.1 (git+https://github.com/privacy-scaling-explorations/halo2curves.git?tag=0.3.1)", + "halo2curves 0.1.0", "subtle", ] @@ -1737,6 +1725,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_arrays" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38636132857f68ec3d5f3eb121166d2af33cb55174c4d5ff645db6165cbef0fd" +dependencies = [ + "serde", +] + [[package]] name = "serde_cbor" version = "0.11.2" @@ -1808,6 +1805,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "stable_deref_trait" version = "1.2.0" diff --git a/halo2_gadgets/Cargo.toml b/halo2_gadgets/Cargo.toml index 6025ef7297..136ef63a16 100644 --- a/halo2_gadgets/Cargo.toml +++ b/halo2_gadgets/Cargo.toml @@ -24,11 +24,11 @@ rustdoc-args = ["--cfg", "docsrs", "--html-in-header", "katex-header.html"] [dependencies] arrayvec = "0.7.0" bitvec = "1" -ff = "0.12" -group = "0.12" +ff = { version = "0.13", features = ["bits"] } +group = "0.13" halo2_proofs = { version = "0.2", path = "../halo2_proofs" } lazy_static = "1" -halo2curves = { git = 'https://github.com/privacy-scaling-explorations/halo2curves', tag = '0.3.0' } +halo2curves = { git = 'https://github.com/privacy-scaling-explorations/halo2curves', tag = "0.3.2" } proptest = { version = "1.0.0", optional = true } rand = "0.8" subtle = "2.3" diff --git a/halo2_gadgets/benches/poseidon.rs b/halo2_gadgets/benches/poseidon.rs index e8cfa08714..4494e77a0f 100644 --- a/halo2_gadgets/benches/poseidon.rs +++ b/halo2_gadgets/benches/poseidon.rs @@ -21,7 +21,7 @@ use halo2_proofs::{ use halo2curves::pasta::{pallas, vesta, EqAffine, Fp}; use halo2_gadgets::poseidon::{ - primitives::{self as poseidon, ConstantLength, Spec}, + primitives::{self as poseidon, generate_constants, ConstantLength, Mds, Spec}, Hash, Pow5Chip, Pow5Config, }; use std::convert::TryInto; @@ -139,6 +139,10 @@ impl Spec for MySpec usize { 0 } + + fn constants() -> (Vec<[Fp; WIDTH]>, Mds, Mds) { + generate_constants::<_, Self, WIDTH, RATE>() + } } const K: u32 = 7; diff --git a/halo2_gadgets/src/ecc/chip/add.rs b/halo2_gadgets/src/ecc/chip/add.rs index 9f24d0d7dd..11661d51e2 100644 --- a/halo2_gadgets/src/ecc/chip/add.rs +++ b/halo2_gadgets/src/ecc/chip/add.rs @@ -1,10 +1,11 @@ use super::EccPoint; +use ff::PrimeField; use halo2_proofs::{ circuit::Region, plonk::{Advice, Assigned, Column, ConstraintSystem, Constraints, Error, Expression, Selector}, poly::Rotation, }; -use halo2curves::{pasta::pallas, FieldExt}; +use halo2curves::pasta::pallas; use std::collections::HashSet; #[derive(Clone, Copy, Debug, Eq, PartialEq)] diff --git a/halo2_gadgets/src/ecc/chip/constants.rs b/halo2_gadgets/src/ecc/chip/constants.rs index cecbbae99a..6296165464 100644 --- a/halo2_gadgets/src/ecc/chip/constants.rs +++ b/halo2_gadgets/src/ecc/chip/constants.rs @@ -6,7 +6,7 @@ use group::{ Curve, }; use halo2_proofs::arithmetic::lagrange_interpolate; -use halo2curves::{pasta::pallas, CurveAffine, FieldExt}; +use halo2curves::{pasta::pallas, CurveAffine}; /// Window size for fixed-base scalar multiplication pub const FIXED_BASE_WINDOW_SIZE: usize = 3; @@ -61,7 +61,7 @@ fn compute_window_table(base: C, num_windows: usize) -> Vec<[C; // Generate window table entries for the last window, w = `num_windows - 1`. // For the last window, we compute [k * (2^3)^w - sum]B, where sum is defined // as sum = \sum_{j = 0}^{`num_windows - 2`} 2^{3j+1} - let sum = (0..(num_windows - 1)).fold(C::Scalar::zero(), |acc, j| { + let sum = (0..(num_windows - 1)).fold(C::Scalar::ZERO, |acc, j| { acc + C::Scalar::from(2).pow(&[FIXED_BASE_WINDOW_SIZE as u64 * j as u64 + 1, 0, 0, 0]) }); window_table.push( @@ -181,7 +181,7 @@ pub fn test_lagrange_coeffs(base: C, num_windows: usize) { .rev() .cloned() .reduce(|acc, coeff| acc * x + coeff) - .unwrap_or_else(C::Base::zero) + .unwrap_or(C::Base::ZERO) } let lagrange_coeffs = compute_lagrange_coeffs(base, num_windows); @@ -213,7 +213,7 @@ pub fn test_lagrange_coeffs(base: C, num_windows: usize) { // Compute the actual x-coordinate of the multiple [k * (8^84) - offset]B, // where offset = \sum_{j = 0}^{83} 2^{3j+1} - let offset = (0..(num_windows - 1)).fold(C::Scalar::zero(), |acc, w| { + let offset = (0..(num_windows - 1)).fold(C::Scalar::ZERO, |acc, w| { acc + C::Scalar::from(2).pow(&[FIXED_BASE_WINDOW_SIZE as u64 * w as u64 + 1, 0, 0, 0]) }); let scalar = C::Scalar::from(bits as u64) @@ -229,8 +229,9 @@ pub fn test_lagrange_coeffs(base: C, num_windows: usize) { #[cfg(test)] mod tests { + use ff::FromUniformBytes; use group::{ff::Field, Curve, Group}; - use halo2curves::{pasta::pallas, CurveAffine, FieldExt}; + use halo2curves::{pasta::pallas, CurveAffine}; use proptest::prelude::*; use super::{compute_window_table, find_zs_and_us, test_lagrange_coeffs, H, NUM_WINDOWS}; @@ -241,7 +242,7 @@ mod tests { // Instead of rejecting out-of-range bytes, let's reduce them. let mut buf = [0; 64]; buf[..32].copy_from_slice(&bytes); - let scalar = pallas::Scalar::from_bytes_wide(&buf); + let scalar = pallas::Scalar::from_uniform_bytes(&buf); pallas::Point::generator() * scalar } } diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs index 26c705a17c..7896bf58bd 100644 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ b/halo2_gadgets/src/ecc/chip/mul.rs @@ -8,16 +8,15 @@ use std::{ ops::{Deref, Range}, }; -use ff::PrimeField; use halo2_proofs::{ - arithmetic::FieldExt, + arithmetic::Field, circuit::{AssignedCell, Layouter, Region, Value}, plonk::{Advice, Assigned, Column, ConstraintSystem, Constraints, Error, Selector}, poly::Rotation, }; -use uint::construct_uint; - +use halo2curves::group::ff::PrimeField; use halo2curves::pasta::pallas; +use uint::construct_uint; mod complete; pub(super) mod incomplete; @@ -389,8 +388,8 @@ impl Config { #[derive(Clone, Debug)] // `x`-coordinate of the accumulator. -struct X(AssignedCell, F>); -impl Deref for X { +struct X(AssignedCell, F>); +impl Deref for X { type Target = AssignedCell, F>; fn deref(&self) -> &Self::Target { @@ -400,8 +399,8 @@ impl Deref for X { #[derive(Clone, Debug)] // `y`-coordinate of the accumulator. -struct Y(AssignedCell, F>); -impl Deref for Y { +struct Y(AssignedCell, F>); +impl Deref for Y { type Target = AssignedCell, F>; fn deref(&self) -> &Self::Target { @@ -411,8 +410,8 @@ impl Deref for Y { #[derive(Clone, Debug)] // Cumulative sum `z` used to decompose the scalar. -struct Z(AssignedCell); -impl Deref for Z { +struct Z(AssignedCell); +impl Deref for Z { type Target = AssignedCell; fn deref(&self) -> &Self::Target { diff --git a/halo2_gadgets/src/ecc/chip/mul/incomplete.rs b/halo2_gadgets/src/ecc/chip/mul/incomplete.rs index bfe51c7e2e..9b1d7494e6 100644 --- a/halo2_gadgets/src/ecc/chip/mul/incomplete.rs +++ b/halo2_gadgets/src/ecc/chip/mul/incomplete.rs @@ -1,6 +1,7 @@ use super::super::NonIdentityEccPoint; use super::{X, Y, Z}; use crate::utilities::bool_check; +use ff::PrimeField; use halo2_proofs::{ circuit::{Region, Value}, plonk::{ @@ -8,7 +9,7 @@ use halo2_proofs::{ }, poly::Rotation, }; -use halo2curves::{pasta::pallas, FieldExt}; +use halo2curves::pasta::pallas; /// A helper struct for implementing single-row double-and-add using incomplete addition. #[derive(Copy, Clone, Debug, Eq, PartialEq)] diff --git a/halo2_gadgets/src/ecc/chip/mul/overflow.rs b/halo2_gadgets/src/ecc/chip/mul/overflow.rs index 0d7bd69692..3625ff73db 100644 --- a/halo2_gadgets/src/ecc/chip/mul/overflow.rs +++ b/halo2_gadgets/src/ecc/chip/mul/overflow.rs @@ -9,8 +9,8 @@ use halo2_proofs::{ plonk::{Advice, Assigned, Column, ConstraintSystem, Constraints, Error, Expression, Selector}, poly::Rotation, }; - -use halo2curves::{pasta::pallas, FieldExt}; +use halo2curves::group::ff::PrimeField; +use halo2curves::pasta::pallas; use std::iter; diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed.rs b/halo2_gadgets/src/ecc/chip/mul_fixed.rs index 909dd171d3..0005a108bb 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed.rs @@ -7,7 +7,7 @@ use crate::utilities::decompose_running_sum::RunningSumConfig; use std::marker::PhantomData; use group::{ - ff::{PrimeField, PrimeFieldBits}, + ff::{Field, PrimeField, PrimeFieldBits}, Curve, }; use halo2_proofs::{ @@ -18,7 +18,7 @@ use halo2_proofs::{ }, poly::Rotation, }; -use halo2curves::{pasta::pallas, CurveAffine, FieldExt}; +use halo2curves::{pasta::pallas, CurveAffine}; use lazy_static::lazy_static; pub mod base_field_elem; diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs index 08fd34e313..91671847a2 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs @@ -13,7 +13,7 @@ use halo2_proofs::{ plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector}, poly::Rotation, }; -use halo2curves::{pasta::pallas, FieldExt}; +use halo2curves::pasta::pallas; use std::convert::TryInto; diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs index b82620c283..607c51e534 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs @@ -295,7 +295,7 @@ pub mod tests { // [-1]B is the largest scalar field element. { - let scalar_fixed = -pallas::Scalar::one(); + let scalar_fixed = -pallas::Scalar::ONE; let neg_1 = ScalarFixed::new( chip.clone(), layouter.namespace(|| "-1"), diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs index 844d88d134..4c92becb86 100644 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs @@ -209,6 +209,7 @@ impl> Config { // tested at the circuit-level. { use super::super::FixedPoint; + use ff::Field; use group::{ff::PrimeField, Curve}; scalar @@ -228,9 +229,9 @@ impl> Config { let magnitude = pallas::Scalar::from_repr(magnitude.to_repr()).unwrap(); let sign = if sign == &&pallas::Base::one() { - pallas::Scalar::one() + pallas::Scalar::ONE } else { - -pallas::Scalar::one() + -pallas::Scalar::ONE }; magnitude * sign @@ -248,13 +249,16 @@ impl> Config { #[cfg(test)] pub mod tests { - use group::{ff::PrimeField, Curve}; + use group::{ + ff::{Field, PrimeField}, + Curve, + }; use halo2_proofs::{ arithmetic::CurveAffine, circuit::{AssignedCell, Chip, Layouter, Value}, plonk::{Any, Error}, }; - use halo2curves::{pasta::pallas, FieldExt}; + use halo2curves::pasta::pallas; use crate::{ ecc::{ @@ -359,9 +363,9 @@ pub mod tests { let scalar = { let magnitude = pallas::Scalar::from_repr(magnitude.to_repr()).unwrap(); let sign = if *sign == pallas::Base::one() { - pallas::Scalar::one() + pallas::Scalar::ONE } else { - -pallas::Scalar::one() + -pallas::Scalar::ONE }; magnitude * sign }; diff --git a/halo2_gadgets/src/poseidon.rs b/halo2_gadgets/src/poseidon.rs index 1350075146..ffd745ad6d 100644 --- a/halo2_gadgets/src/poseidon.rs +++ b/halo2_gadgets/src/poseidon.rs @@ -4,9 +4,9 @@ use std::convert::TryInto; use std::fmt; use std::marker::PhantomData; +use ff::PrimeField; use group::ff::Field; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{AssignedCell, Chip, Layouter}, plonk::Error, }; @@ -27,7 +27,7 @@ pub enum PaddedWord { } /// The set of circuit instructions required to use the Poseidon permutation. -pub trait PoseidonInstructions, const T: usize, const RATE: usize>: +pub trait PoseidonInstructions, const T: usize, const RATE: usize>: Chip { /// Variable representing the word over which the Poseidon permutation operates. @@ -45,7 +45,7 @@ pub trait PoseidonInstructions, const T: usize, /// /// [`Hash`]: self::Hash pub trait PoseidonSpongeInstructions< - F: FieldExt, + F: Field, S: Spec, D: Domain, const T: usize, @@ -71,7 +71,7 @@ pub trait PoseidonSpongeInstructions< /// A word over which the Poseidon permutation operates. #[derive(Debug)] pub struct Word< - F: FieldExt, + F: Field, PoseidonChip: PoseidonInstructions, S: Spec, const T: usize, @@ -81,7 +81,7 @@ pub struct Word< } impl< - F: FieldExt, + F: Field, PoseidonChip: PoseidonInstructions, S: Spec, const T: usize, @@ -100,7 +100,7 @@ impl< } fn poseidon_sponge< - F: FieldExt, + F: Field, PoseidonChip: PoseidonSpongeInstructions, S: Spec, D: Domain, @@ -122,7 +122,7 @@ fn poseidon_sponge< /// A Poseidon sponge. #[derive(Debug)] pub struct Sponge< - F: FieldExt, + F: Field, PoseidonChip: PoseidonSpongeInstructions, S: Spec, M: SpongeMode, @@ -137,7 +137,7 @@ pub struct Sponge< } impl< - F: FieldExt, + F: Field, PoseidonChip: PoseidonSpongeInstructions, S: Spec, D: Domain, @@ -210,7 +210,7 @@ impl< } impl< - F: FieldExt, + F: Field, PoseidonChip: PoseidonSpongeInstructions, S: Spec, D: Domain, @@ -241,7 +241,7 @@ impl< /// A Poseidon hash function, built around a sponge. #[derive(Debug)] pub struct Hash< - F: FieldExt, + F: Field, PoseidonChip: PoseidonSpongeInstructions, S: Spec, D: Domain, @@ -252,7 +252,7 @@ pub struct Hash< } impl< - F: FieldExt, + F: Field, PoseidonChip: PoseidonSpongeInstructions, S: Spec, D: Domain, @@ -267,7 +267,7 @@ impl< } impl< - F: FieldExt, + F: PrimeField, PoseidonChip: PoseidonSpongeInstructions, T, RATE>, S: Spec, const T: usize, diff --git a/halo2_gadgets/src/poseidon/pow5.rs b/halo2_gadgets/src/poseidon/pow5.rs index 7b9862e5b6..52b0d27312 100644 --- a/halo2_gadgets/src/poseidon/pow5.rs +++ b/halo2_gadgets/src/poseidon/pow5.rs @@ -2,7 +2,7 @@ use std::convert::TryInto; use std::iter; use halo2_proofs::{ - arithmetic::FieldExt, + arithmetic::Field, circuit::{AssignedCell, Cell, Chip, Layouter, Region, Value}, plonk::{ Advice, Any, Column, ConstraintSystem, Constraints, Error, Expression, Fixed, Selector, @@ -18,7 +18,7 @@ use crate::utilities::Var; /// Configuration for a [`Pow5Chip`]. #[derive(Clone, Debug)] -pub struct Pow5Config { +pub struct Pow5Config { pub(crate) state: [Column; WIDTH], partial_sbox: Column, rc_a: [Column; WIDTH], @@ -40,11 +40,11 @@ pub struct Pow5Config { /// The chip is implemented using a single round per row for full rounds, and two rounds /// per row for partial rounds. #[derive(Debug)] -pub struct Pow5Chip { +pub struct Pow5Chip { config: Pow5Config, } -impl Pow5Chip { +impl Pow5Chip { /// Configures this chip for use in a circuit. /// /// # Side-effects @@ -209,7 +209,7 @@ impl Pow5Chip Chip for Pow5Chip { +impl Chip for Pow5Chip { type Config = Pow5Config; type Loaded = (); @@ -222,7 +222,7 @@ impl Chip for Pow5Chip, const WIDTH: usize, const RATE: usize> +impl, const WIDTH: usize, const RATE: usize> PoseidonInstructions for Pow5Chip { type Word = StateWord; @@ -273,7 +273,7 @@ impl, const WIDTH: usize, const RATE: usize } impl< - F: FieldExt, + F: Field, S: Spec, D: Domain, const WIDTH: usize, @@ -302,7 +302,7 @@ impl< }; for i in 0..RATE { - load_state_word(i, F::zero())?; + load_state_word(i, F::ZERO)?; } load_state_word(RATE, D::initial_capacity_element())?; @@ -372,7 +372,7 @@ impl< .get(i) .map(|word| word.0.value().cloned()) // The capacity element is never altered by the input. - .unwrap_or_else(|| Value::known(F::zero())); + .unwrap_or_else(|| Value::known(F::ZERO)); region .assign_advice( || format!("load output_{}", i), @@ -403,21 +403,21 @@ impl< /// A word in the Poseidon state. #[derive(Clone, Debug)] -pub struct StateWord(AssignedCell); +pub struct StateWord(AssignedCell); -impl From> for AssignedCell { +impl From> for AssignedCell { fn from(state_word: StateWord) -> AssignedCell { state_word.0 } } -impl From> for StateWord { +impl From> for StateWord { fn from(cell_value: AssignedCell) -> StateWord { StateWord(cell_value) } } -impl Var for StateWord { +impl Var for StateWord { fn cell(&self) -> Cell { self.0.cell() } @@ -428,9 +428,9 @@ impl Var for StateWord { } #[derive(Debug)] -struct Pow5State([StateWord; WIDTH]); +struct Pow5State([StateWord; WIDTH]); -impl Pow5State { +impl Pow5State { fn full_round( self, region: &mut Region, @@ -450,7 +450,7 @@ impl Pow5State { r.as_ref().map(|r| { r.iter() .enumerate() - .fold(F::zero(), |acc, (j, r_j)| acc + m_i[j] * r_j) + .fold(F::ZERO, |acc, (j, r_j)| acc + m_i[j] * r_j) }) }); @@ -491,7 +491,7 @@ impl Pow5State { r.as_ref().map(|r| { m_i.iter() .zip(r.iter()) - .fold(F::zero(), |acc, (m_ij, r_j)| acc + *m_ij * r_j) + .fold(F::ZERO, |acc, (m_ij, r_j)| acc + *m_ij * r_j) }) }) .collect(); @@ -524,7 +524,7 @@ impl Pow5State { r_mid.as_ref().map(|r| { m_i.iter() .zip(r.iter()) - .fold(F::zero(), |acc, (m_ij, r_j)| acc + *m_ij * r_j) + .fold(F::ZERO, |acc, (m_ij, r_j)| acc + *m_ij * r_j) }) }) .collect(); diff --git a/halo2_gadgets/src/poseidon/primitives.rs b/halo2_gadgets/src/poseidon/primitives.rs index 4d7d5b038a..a8662a00e8 100644 --- a/halo2_gadgets/src/poseidon/primitives.rs +++ b/halo2_gadgets/src/poseidon/primitives.rs @@ -5,7 +5,9 @@ use std::fmt; use std::iter; use std::marker::PhantomData; -use halo2_proofs::arithmetic::FieldExt; +use ff::FromUniformBytes; +use ff::PrimeField; +use halo2_proofs::arithmetic::Field; pub(crate) mod fp; pub(crate) mod fq; @@ -27,10 +29,10 @@ pub(crate) type State = [F; T]; pub(crate) type SpongeRate = [Option; RATE]; /// The type used to hold the MDS matrix and its inverse. -pub(crate) type Mds = [[F; T]; T]; +pub type Mds = [[F; T]; T]; /// A specification for a Poseidon permutation. -pub trait Spec: fmt::Debug { +pub trait Spec: fmt::Debug { /// The number of full rounds for this specification. /// /// This must be an even number. @@ -50,33 +52,41 @@ pub trait Spec: fmt::Debug { fn secure_mds() -> usize; /// Generates `(round_constants, mds, mds^-1)` corresponding to this specification. - fn constants() -> (Vec<[F; T]>, Mds, Mds) { - let r_f = Self::full_rounds(); - let r_p = Self::partial_rounds(); - - let mut grain = grain::Grain::new(SboxType::Pow, T as u16, r_f as u16, r_p as u16); - - let round_constants = (0..(r_f + r_p)) - .map(|_| { - let mut rc_row = [F::zero(); T]; - for (rc, value) in rc_row - .iter_mut() - .zip((0..T).map(|_| grain.next_field_element())) - { - *rc = value; - } - rc_row - }) - .collect(); + fn constants() -> (Vec<[F; T]>, Mds, Mds); +} + +/// Generates `(round_constants, mds, mds^-1)` corresponding to this specification. +pub fn generate_constants< + F: FromUniformBytes<64> + Ord, + S: Spec, + const T: usize, + const RATE: usize, +>() -> (Vec<[F; T]>, Mds, Mds) { + let r_f = S::full_rounds(); + let r_p = S::partial_rounds(); - let (mds, mds_inv) = mds::generate_mds::(&mut grain, Self::secure_mds()); + let mut grain = grain::Grain::new(SboxType::Pow, T as u16, r_f as u16, r_p as u16); - (round_constants, mds, mds_inv) - } + let round_constants = (0..(r_f + r_p)) + .map(|_| { + let mut rc_row = [F::ZERO; T]; + for (rc, value) in rc_row + .iter_mut() + .zip((0..T).map(|_| grain.next_field_element())) + { + *rc = value; + } + rc_row + }) + .collect(); + + let (mds, mds_inv) = mds::generate_mds::(&mut grain, S::secure_mds()); + + (round_constants, mds, mds_inv) } /// Runs the Poseidon permutation on the given state. -pub(crate) fn permute, const T: usize, const RATE: usize>( +pub(crate) fn permute, const T: usize, const RATE: usize>( state: &mut State, mds: &Mds, round_constants: &[[F; T]], @@ -85,7 +95,7 @@ pub(crate) fn permute, const T: usize, const RA let r_p = S::partial_rounds(); let apply_mds = |state: &mut State| { - let mut new_state = [F::zero(); T]; + let mut new_state = [F::ZERO; T]; // Matrix multiplication #[allow(clippy::needless_range_loop)] for i in 0..T { @@ -123,7 +133,7 @@ pub(crate) fn permute, const T: usize, const RA }); } -fn poseidon_sponge, const T: usize, const RATE: usize>( +fn poseidon_sponge, const T: usize, const RATE: usize>( state: &mut State, input: Option<&Absorbing>, mds_matrix: &Mds, @@ -180,7 +190,7 @@ impl Absorbing { /// A Poseidon sponge. pub(crate) struct Sponge< - F: FieldExt, + F: Field, S: Spec, M: SpongeMode, const T: usize, @@ -193,7 +203,7 @@ pub(crate) struct Sponge< _marker: PhantomData, } -impl, const T: usize, const RATE: usize> +impl, const T: usize, const RATE: usize> Sponge, T, RATE> { /// Constructs a new sponge for the given Poseidon specification. @@ -201,7 +211,7 @@ impl, const T: usize, const RATE: usize> let (round_constants, mds_matrix, _) = S::constants(); let mode = Absorbing([None; RATE]); - let mut state = [F::zero(); T]; + let mut state = [F::ZERO; T]; state[RATE] = initial_capacity_element; Sponge { @@ -251,7 +261,7 @@ impl, const T: usize, const RATE: usize> } } -impl, const T: usize, const RATE: usize> +impl, const T: usize, const RATE: usize> Sponge, T, RATE> { /// Squeezes an element from the sponge. @@ -275,7 +285,7 @@ impl, const T: usize, const RATE: usize> } /// A domain in which a Poseidon hash function is being used. -pub trait Domain { +pub trait Domain { /// Iterator that outputs padding field elements. type Padding: IntoIterator; @@ -295,7 +305,7 @@ pub trait Domain { #[derive(Clone, Copy, Debug)] pub struct ConstantLength; -impl Domain for ConstantLength { +impl Domain for ConstantLength { type Padding = iter::Take>; fn name() -> String { @@ -315,13 +325,13 @@ impl Domain for Constan // Poseidon authors encode the constant length into the capacity element, ensuring // that inputs of different lengths do not share the same permutation. let k = (L + RATE - 1) / RATE; - iter::repeat(F::zero()).take(k * RATE - L) + iter::repeat(F::ZERO).take(k * RATE - L) } } /// A Poseidon hash function, built around a sponge. pub struct Hash< - F: FieldExt, + F: Field, S: Spec, D: Domain, const T: usize, @@ -331,7 +341,7 @@ pub struct Hash< _domain: PhantomData, } -impl, D: Domain, const T: usize, const RATE: usize> +impl, D: Domain, const T: usize, const RATE: usize> fmt::Debug for Hash { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -345,7 +355,7 @@ impl, D: Domain, const T: usize, const } } -impl, D: Domain, const T: usize, const RATE: usize> +impl, D: Domain, const T: usize, const RATE: usize> Hash { /// Initializes a new hasher. @@ -357,7 +367,7 @@ impl, D: Domain, const T: usize, const } } -impl, const T: usize, const RATE: usize, const L: usize> +impl, const T: usize, const RATE: usize, const L: usize> Hash, T, RATE> { /// Hashes the given input. @@ -374,9 +384,9 @@ impl, const T: usize, const RATE: usize, const #[cfg(test)] mod tests { - use halo2curves::{pasta::pallas, FieldExt}; - use super::{permute, ConstantLength, Hash, P128Pow5T3 as OrchardNullifier, Spec}; + use ff::PrimeField; + use halo2curves::pasta::pallas; #[test] fn orchard_spec_equivalence() { diff --git a/halo2_gadgets/src/poseidon/primitives/grain.rs b/halo2_gadgets/src/poseidon/primitives/grain.rs index f3cf94f761..99711f97f3 100644 --- a/halo2_gadgets/src/poseidon/primitives/grain.rs +++ b/halo2_gadgets/src/poseidon/primitives/grain.rs @@ -3,7 +3,8 @@ use std::marker::PhantomData; use bitvec::prelude::*; -use halo2_proofs::arithmetic::FieldExt; +use ff::{FromUniformBytes, PrimeField}; +use halo2_proofs::arithmetic::Field; const STATE: usize = 80; @@ -43,13 +44,13 @@ impl SboxType { } } -pub(super) struct Grain { +pub(super) struct Grain { state: BitArr!(for 80, in u8, Msb0), next_bit: usize, _field: PhantomData, } -impl Grain { +impl Grain { pub(super) fn new(sbox: SboxType, t: u16, r_f: u16, r_p: u16) -> Self { // Initialize the LFSR state. let mut state = bitarr![u8, Msb0; 1; STATE]; @@ -135,7 +136,9 @@ impl Grain { } } } +} +impl> Grain { /// Returns the next field element from this Grain instantiation, without using /// rejection sampling. pub(super) fn next_field_element_without_rejection(&mut self) -> F { @@ -161,11 +164,11 @@ impl Grain { view[i / 8] |= if bit { 1 << (i % 8) } else { 0 }; } - F::from_bytes_wide(&bytes) + F::from_uniform_bytes(&bytes) } } -impl Iterator for Grain { +impl Iterator for Grain { type Item = bool; fn next(&mut self) -> Option { diff --git a/halo2_gadgets/src/poseidon/primitives/mds.rs b/halo2_gadgets/src/poseidon/primitives/mds.rs index fb809e3a79..892ee11f6b 100644 --- a/halo2_gadgets/src/poseidon/primitives/mds.rs +++ b/halo2_gadgets/src/poseidon/primitives/mds.rs @@ -1,8 +1,8 @@ -use halo2_proofs::arithmetic::FieldExt; +use ff::FromUniformBytes; use super::{grain::Grain, Mds}; -pub(super) fn generate_mds( +pub(super) fn generate_mds + Ord, const T: usize>( grain: &mut Grain, mut select: usize, ) -> (Mds, Mds) { @@ -48,7 +48,7 @@ pub(super) fn generate_mds( // However, the Poseidon paper and reference impl use the positive formulation, // and we want to rely on the reference impl for MDS security, so we use the same // formulation. - let mut mds = [[F::zero(); T]; T]; + let mut mds = [[F::ZERO; T]; T]; #[allow(clippy::needless_range_loop)] for i in 0..T { for j in 0..T { @@ -74,10 +74,10 @@ pub(super) fn generate_mds( // where A_i(x) and B_i(x) are the Lagrange polynomials for xs and ys respectively. // // We adapt this to the positive Cauchy formulation by negating ys. - let mut mds_inv = [[F::zero(); T]; T]; + let mut mds_inv = [[F::ZERO; T]; T]; let l = |xs: &[F], j, x: F| { let x_j = xs[j]; - xs.iter().enumerate().fold(F::one(), |acc, (m, x_m)| { + xs.iter().enumerate().fold(F::ONE, |acc, (m, x_m)| { if m == j { acc } else { diff --git a/halo2_gadgets/src/poseidon/primitives/p128pow5t3.rs b/halo2_gadgets/src/poseidon/primitives/p128pow5t3.rs index 379c399b4e..c8d54d9afd 100644 --- a/halo2_gadgets/src/poseidon/primitives/p128pow5t3.rs +++ b/halo2_gadgets/src/poseidon/primitives/p128pow5t3.rs @@ -66,29 +66,31 @@ impl Spec for P128Pow5T3 { #[cfg(test)] mod tests { - use ff::PrimeField; - use std::marker::PhantomData; - - use halo2curves::FieldExt; - use super::{ super::{fp, fq}, Fp, Fq, }; - use crate::poseidon::primitives::{permute, ConstantLength, Hash, Spec}; + use crate::poseidon::primitives::{ + generate_constants, permute, ConstantLength, Hash, Mds, Spec, + }; + use ff::PrimeField; + use ff::{Field, FromUniformBytes}; + use std::marker::PhantomData; /// The same Poseidon specification as poseidon::P128Pow5T3, but constructed /// such that its constants will be generated at runtime. #[derive(Debug)] - pub struct P128Pow5T3Gen(PhantomData); + pub struct P128Pow5T3Gen(PhantomData); - impl P128Pow5T3Gen { + impl P128Pow5T3Gen { pub fn new() -> Self { P128Pow5T3Gen(PhantomData::default()) } } - impl Spec for P128Pow5T3Gen { + impl + Ord, const SECURE_MDS: usize> Spec + for P128Pow5T3Gen + { fn full_rounds() -> usize { 8 } @@ -98,17 +100,21 @@ mod tests { } fn sbox(val: F) -> F { - val.pow_vartime(&[5]) + val.pow_vartime([5]) } fn secure_mds() -> usize { SECURE_MDS } + + fn constants() -> (Vec<[F; 3]>, Mds, Mds) { + generate_constants::<_, Self, 3, 2>() + } } #[test] fn verify_constants() { - fn verify_constants_helper( + fn verify_constants_helper + Ord>( expected_round_constants: [[F; 3]; 64], expected_mds: [[F; 3]; 3], expected_mds_inv: [[F; 3]; 3], diff --git a/halo2_gadgets/src/sha256.rs b/halo2_gadgets/src/sha256.rs index 19a658df3a..391020a3d3 100644 --- a/halo2_gadgets/src/sha256.rs +++ b/halo2_gadgets/src/sha256.rs @@ -7,7 +7,7 @@ use std::convert::TryInto; use std::fmt; use halo2_proofs::{ - arithmetic::FieldExt, + arithmetic::Field, circuit::{Chip, Layouter}, plonk::Error, }; @@ -22,7 +22,7 @@ pub const BLOCK_SIZE: usize = 16; const DIGEST_SIZE: usize = 8; /// The set of circuit instructions required to use the [`Sha256`] gadget. -pub trait Sha256Instructions: Chip { +pub trait Sha256Instructions: Chip { /// Variable representing the SHA-256 internal state. type State: Clone + fmt::Debug; /// Variable representing a 32-bit word of the input block to the SHA-256 compression @@ -63,14 +63,14 @@ pub struct Sha256Digest([BlockWord; DIGEST_SIZE]); /// A gadget that constrains a SHA-256 invocation. It supports input at a granularity of /// 32 bits. #[derive(Debug)] -pub struct Sha256> { +pub struct Sha256> { chip: CS, state: CS::State, cur_block: Vec, length: usize, } -impl> Sha256 { +impl> Sha256 { /// Create a new hasher instance. pub fn new(chip: Sha256Chip, mut layouter: impl Layouter) -> Result { let state = chip.initialization_vector(&mut layouter)?; diff --git a/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs b/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs index e22a10210c..1cf6a605d7 100644 --- a/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs +++ b/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs @@ -1,15 +1,13 @@ use super::super::{util::*, Gate}; -use halo2_proofs::{ - arithmetic::FieldExt, - plonk::{Constraint, Constraints, Expression}, -}; +use ff::PrimeField; +use halo2_proofs::plonk::{Constraint, Constraints, Expression}; use std::marker::PhantomData; -pub struct CompressionGate(PhantomData); +pub struct CompressionGate(PhantomData); -impl CompressionGate { +impl CompressionGate { fn ones() -> Expression { - Expression::Constant(F::one()) + Expression::Constant(F::ONE) } // Decompose `A,B,C,D` words @@ -59,16 +57,16 @@ impl CompressionGate { + c_mid * F::from(1 << 16) + c_hi * F::from(1 << 19) + d * F::from(1 << 22) - + word_lo * (-F::one()) - + word_hi * F::from(1 << 16) * (-F::one()); + + word_lo * (-F::ONE) + + word_hi * F::from(1 << 16) * (-F::ONE); let spread_check = spread_a + spread_b * F::from(1 << 4) + spread_c_lo * F::from(1 << 26) + spread_c_mid * F::from(1 << 32) + spread_c_hi * F::from(1 << 38) + spread_d * F::from(1 << 44) - + spread_word_lo * (-F::one()) - + spread_word_hi * F::from(1 << 32) * (-F::one()); + + spread_word_lo * (-F::ONE) + + spread_word_hi * F::from(1 << 32) * (-F::ONE); Constraints::with_selector( s_decompose_abcd, @@ -130,16 +128,16 @@ impl CompressionGate { + b_hi * F::from(1 << 8) + c * F::from(1 << 11) + d * F::from(1 << 25) - + word_lo * (-F::one()) - + word_hi * F::from(1 << 16) * (-F::one()); + + word_lo * (-F::ONE) + + word_hi * F::from(1 << 16) * (-F::ONE); let spread_check = spread_a_lo + spread_a_hi * F::from(1 << 6) + spread_b_lo * F::from(1 << 12) + spread_b_hi * F::from(1 << 16) + spread_c * F::from(1 << 22) + spread_d * F::from(1 << 50) - + spread_word_lo * (-F::one()) - + spread_word_hi * F::from(1 << 32) * (-F::one()); + + spread_word_lo * (-F::ONE) + + spread_word_hi * F::from(1 << 32) * (-F::ONE); Constraints::with_selector( s_decompose_efgh, @@ -189,7 +187,7 @@ impl CompressionGate { + spread_c_mid * F::from(1 << 52) + spread_c_hi * F::from(1 << 58); let xor = xor_0 + xor_1 + xor_2; - let check = spread_witness + (xor * -F::one()); + let check = spread_witness + (xor * -F::ONE); Some(("s_upper_sigma_0", s_upper_sigma_0 * check)) } @@ -233,7 +231,7 @@ impl CompressionGate { + spread_b_hi * F::from(1 << 30) + spread_c * F::from(1 << 36); let xor = xor_0 + xor_1 + xor_2; - let check = spread_witness + (xor * -F::one()); + let check = spread_witness + (xor * -F::ONE); Some(("s_upper_sigma_1", s_upper_sigma_1 * check)) } @@ -259,7 +257,7 @@ impl CompressionGate { let rhs_odd = spread_p0_odd + spread_p1_odd * F::from(1 << 32); let rhs = rhs_even + rhs_odd * F::from(2); - let check = lhs + rhs * -F::one(); + let check = lhs + rhs * -F::ONE; Some(("s_ch", s_ch * check)) } @@ -286,9 +284,9 @@ impl CompressionGate { let neg_check = { let evens = Self::ones() * F::from(MASK_EVEN_32 as u64); // evens - spread_e_lo = spread_e_neg_lo - let lo_check = spread_e_neg_lo.clone() + spread_e_lo + (evens.clone() * (-F::one())); + let lo_check = spread_e_neg_lo.clone() + spread_e_lo + (evens.clone() * (-F::ONE)); // evens - spread_e_hi = spread_e_neg_hi - let hi_check = spread_e_neg_hi.clone() + spread_e_hi + (evens * (-F::one())); + let hi_check = spread_e_neg_hi.clone() + spread_e_hi + (evens * (-F::ONE)); std::iter::empty() .chain(Some(("lo_check", lo_check))) diff --git a/halo2_gadgets/src/sha256/table16/gates.rs b/halo2_gadgets/src/sha256/table16/gates.rs index 4f268092db..d5f3840a57 100644 --- a/halo2_gadgets/src/sha256/table16/gates.rs +++ b/halo2_gadgets/src/sha256/table16/gates.rs @@ -1,10 +1,11 @@ -use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; +use ff::PrimeField; +use halo2_proofs::{arithmetic::Field, plonk::Expression}; -pub struct Gate(pub Expression); +pub struct Gate(pub Expression); -impl Gate { +impl Gate { fn ones() -> Expression { - Expression::Constant(F::one()) + Expression::Constant(F::ONE) } // Helper gates @@ -32,7 +33,7 @@ impl Gate { for i in 0..deg { let i = i as u64; if i != idx { - expr = expr * (Self::ones() * (-F::one()) * F::from(i) + var.clone()); + expr = expr * (Self::ones() * (-F::ONE) * F::from(i) + var.clone()); } } expr * F::from(u64::from(eval)) @@ -46,13 +47,13 @@ impl Gate { } } if denom < 0 { - -F::one() * F::from(factor / (-denom as u64)) + -F::ONE * F::from(factor / (-denom as u64)) } else { F::from(factor / (denom as u64)) } }; - let mut expr = Self::ones() * F::zero(); + let mut expr = Self::ones() * F::ZERO; for ((idx, _), eval) in points.iter().enumerate().zip(evals.iter()) { expr = expr + numerator(var.clone(), *eval, idx as u64) * denominator(idx as i32) } @@ -63,7 +64,7 @@ impl Gate { pub fn range_check(value: Expression, lower_range: u64, upper_range: u64) -> Expression { let mut expr = Self::ones(); for i in lower_range..(upper_range + 1) { - expr = expr * (Self::ones() * (-F::one()) * F::from(i) + value.clone()) + expr = expr * (Self::ones() * (-F::ONE) * F::from(i) + value.clone()) } expr } diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/schedule_gates.rs b/halo2_gadgets/src/sha256/table16/message_schedule/schedule_gates.rs index fab51bd373..cf6a917261 100644 --- a/halo2_gadgets/src/sha256/table16/message_schedule/schedule_gates.rs +++ b/halo2_gadgets/src/sha256/table16/message_schedule/schedule_gates.rs @@ -1,10 +1,11 @@ use super::super::Gate; -use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; +use ff::PrimeField; +use halo2_proofs::plonk::Expression; use std::marker::PhantomData; -pub struct ScheduleGate(PhantomData); +pub struct ScheduleGate(PhantomData); -impl ScheduleGate { +impl ScheduleGate { /// s_word for W_16 to W_63 #[allow(clippy::too_many_arguments)] pub fn s_word( @@ -25,8 +26,8 @@ impl ScheduleGate { let word_check = lo + hi * F::from(1 << 16) - + (carry.clone() * F::from(1 << 32) * (-F::one())) - + (word * (-F::one())); + + (carry.clone() * F::from(1 << 32) * (-F::ONE)) + + (word * (-F::ONE)); let carry_check = Gate::range_check(carry, 0, 3); [("word_check", word_check), ("carry_check", carry_check)] @@ -58,11 +59,8 @@ impl ScheduleGate { tag_d: Expression, word: Expression, ) -> impl Iterator)> { - let decompose_check = a - + b * F::from(1 << 3) - + c * F::from(1 << 7) - + d * F::from(1 << 18) - + word * (-F::one()); + let decompose_check = + a + b * F::from(1 << 3) + c * F::from(1 << 7) + d * F::from(1 << 18) + word * (-F::ONE); let range_check_tag_c = Gate::range_check(tag_c, 0, 2); let range_check_tag_d = Gate::range_check(tag_d, 0, 4); @@ -99,7 +97,7 @@ impl ScheduleGate { + e * F::from(1 << 17) + f * F::from(1 << 18) + g * F::from(1 << 19) - + word * (-F::one()); + + word * (-F::ONE); let range_check_tag_d = Gate::range_check(tag_d, 0, 0); let range_check_tag_g = Gate::range_check(tag_g, 0, 3); @@ -129,7 +127,7 @@ impl ScheduleGate { + b * F::from(1 << 10) + c * F::from(1 << 17) + d * F::from(1 << 19) - + word * (-F::one()); + + word * (-F::ONE); let range_check_tag_a = Gate::range_check(tag_a, 0, 1); let range_check_tag_d = Gate::range_check(tag_d, 0, 3); diff --git a/halo2_gadgets/src/sha256/table16/spread_table.rs b/halo2_gadgets/src/sha256/table16/spread_table.rs index 3e1488e9ac..031f088084 100644 --- a/halo2_gadgets/src/sha256/table16/spread_table.rs +++ b/halo2_gadgets/src/sha256/table16/spread_table.rs @@ -1,6 +1,7 @@ use super::{util::*, AssignedBits}; +use ff::PrimeField; use halo2_proofs::{ - arithmetic::FieldExt, + arithmetic::Field, circuit::{Chip, Layouter, Region, Value}, plonk::{Advice, Column, ConstraintSystem, Error, TableColumn}, poly::Rotation, @@ -153,12 +154,12 @@ pub(super) struct SpreadTableConfig { } #[derive(Clone, Debug)] -pub(super) struct SpreadTableChip { +pub(super) struct SpreadTableChip { config: SpreadTableConfig, _marker: PhantomData, } -impl Chip for SpreadTableChip { +impl Chip for SpreadTableChip { type Config = SpreadTableConfig; type Loaded = (); @@ -171,7 +172,7 @@ impl Chip for SpreadTableChip { } } -impl SpreadTableChip { +impl SpreadTableChip { pub fn configure( meta: &mut ConstraintSystem, input_tag: Column, @@ -250,45 +251,42 @@ impl SpreadTableChip { } impl SpreadTableConfig { - fn generate() -> impl Iterator { - (1..=(1 << 16)).scan( - (F::zero(), F::zero(), F::zero()), - |(tag, dense, spread), i| { - // We computed this table row in the previous iteration. - let res = (*tag, *dense, *spread); - - // i holds the zero-indexed row number for the next table row. - match i { - BITS_7 | BITS_10 | BITS_11 | BITS_13 | BITS_14 => *tag += F::one(), - _ => (), - } - *dense += F::one(); - if i & 1 == 0 { - // On even-numbered rows we recompute the spread. - *spread = F::zero(); - for b in 0..16 { - if (i >> b) & 1 != 0 { - *spread += F::from(1 << (2 * b)); - } + fn generate() -> impl Iterator { + (1..=(1 << 16)).scan((F::ZERO, F::ZERO, F::ZERO), |(tag, dense, spread), i| { + // We computed this table row in the previous iteration. + let res = (*tag, *dense, *spread); + + // i holds the zero-indexed row number for the next table row. + match i { + BITS_7 | BITS_10 | BITS_11 | BITS_13 | BITS_14 => *tag += F::ONE, + _ => (), + } + *dense += F::ONE; + if i & 1 == 0 { + // On even-numbered rows we recompute the spread. + *spread = F::ZERO; + for b in 0..16 { + if (i >> b) & 1 != 0 { + *spread += F::from(1 << (2 * b)); } - } else { - // On odd-numbered rows we add one. - *spread += F::one(); } + } else { + // On odd-numbered rows we add one. + *spread += F::ONE; + } - Some(res) - }, - ) + Some(res) + }) } } #[cfg(test)] mod tests { use super::{get_tag, SpreadTableChip, SpreadTableConfig}; + use ff::PrimeField; use rand::Rng; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Layouter, SimpleFloorPlanner, Value}, dev::MockProver, plonk::{Advice, Circuit, Column, ConstraintSystem, Error}, @@ -303,7 +301,7 @@ mod tests { struct MyCircuit {} - impl Circuit for MyCircuit { + impl Circuit for MyCircuit { type Config = SpreadTableConfig; type FloorPlanner = SimpleFloorPlanner; @@ -354,20 +352,20 @@ mod tests { }; // Test the first few small values. - add_row(F::zero(), F::from(0b000), F::from(0b000000))?; - add_row(F::zero(), F::from(0b001), F::from(0b000001))?; - add_row(F::zero(), F::from(0b010), F::from(0b000100))?; - add_row(F::zero(), F::from(0b011), F::from(0b000101))?; - add_row(F::zero(), F::from(0b100), F::from(0b010000))?; - add_row(F::zero(), F::from(0b101), F::from(0b010001))?; + add_row(F::ZERO, F::from(0b000), F::from(0b000000))?; + add_row(F::ZERO, F::from(0b001), F::from(0b000001))?; + add_row(F::ZERO, F::from(0b010), F::from(0b000100))?; + add_row(F::ZERO, F::from(0b011), F::from(0b000101))?; + add_row(F::ZERO, F::from(0b100), F::from(0b010000))?; + add_row(F::ZERO, F::from(0b101), F::from(0b010001))?; // Test the tag boundaries: // 7-bit - add_row(F::zero(), F::from(0b1111111), F::from(0b01010101010101))?; - add_row(F::one(), F::from(0b10000000), F::from(0b0100000000000000))?; + add_row(F::ZERO, F::from(0b1111111), F::from(0b01010101010101))?; + add_row(F::ONE, F::from(0b10000000), F::from(0b0100000000000000))?; // - 10-bit add_row( - F::one(), + F::ONE, F::from(0b1111111111), F::from(0b01010101010101010101), )?; diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs index 3cec450ea1..2670529229 100644 --- a/halo2_gadgets/src/sinsemilla.rs +++ b/halo2_gadgets/src/sinsemilla.rs @@ -203,9 +203,9 @@ where let to_base_field = |bits: &[Value]| -> Value { let bits: Value> = bits.iter().cloned().collect(); bits.map(|bits| { - bits.into_iter().rev().fold(C::Base::zero(), |acc, bit| { + bits.into_iter().rev().fold(C::Base::ZERO, |acc, bit| { if bit { - acc.double() + C::Base::one() + acc.double() + C::Base::ONE } else { acc.double() } @@ -243,7 +243,7 @@ where subpieces: impl IntoIterator>>, ) -> Result { let (field_elem, total_bits) = subpieces.into_iter().fold( - (Value::known(C::Base::zero()), 0), + (Value::known(C::Base::ZERO), 0), |(acc, bits), subpiece| { assert!(bits < 64); let subpiece_shifted = subpiece diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs index a653c13b35..a50a687e88 100644 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs @@ -6,7 +6,8 @@ use halo2_proofs::{ use super::{CommitDomains, FixedPoints, HashDomains}; use crate::sinsemilla::primitives::{self as sinsemilla, SINSEMILLA_S}; -use halo2curves::{pasta::pallas, FieldExt}; +use ff::PrimeField; +use halo2curves::pasta::pallas; /// Table containing independent generators S[0..2^k] #[derive(Eq, PartialEq, Copy, Clone, Debug)] diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs index 70eab6b86d..9c15dd111a 100644 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs @@ -10,8 +10,8 @@ use halo2_proofs::{ plonk::{Assigned, Error}, }; -use group::ff::{PrimeField, PrimeFieldBits}; -use halo2curves::{pasta::pallas, CurveAffine, FieldExt}; +use group::ff::{Field, PrimeField, PrimeFieldBits}; +use halo2curves::{pasta::pallas, CurveAffine}; use std::ops::Deref; @@ -376,15 +376,15 @@ where } /// The x-coordinate of the accumulator in a Sinsemilla hash instance. -struct X(AssignedCell, F>); +struct X(AssignedCell, F>); -impl From, F>> for X { +impl From, F>> for X { fn from(cell_value: AssignedCell, F>) -> Self { X(cell_value) } } -impl Deref for X { +impl Deref for X { type Target = AssignedCell, F>; fn deref(&self) -> &AssignedCell, F> { @@ -397,15 +397,15 @@ impl Deref for X { /// This is never actually witnessed until the last round, since it /// can be derived from other variables. Thus it only exists as a field /// element, not a `CellValue`. -struct Y(Value>); +struct Y(Value>); -impl From>> for Y { +impl From>> for Y { fn from(value: Value>) -> Self { Y(value) } } -impl Deref for Y { +impl Deref for Y { type Target = Value>; fn deref(&self) -> &Value> { diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs index 97da766d0c..bb042a5aee 100644 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ b/halo2_gadgets/src/sinsemilla/merkle/chip.rs @@ -5,7 +5,7 @@ use halo2_proofs::{ plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector}, poly::Rotation, }; -use halo2curves::{pasta::pallas, FieldExt}; +use halo2curves::pasta::pallas; use super::MerkleInstructions; diff --git a/halo2_gadgets/src/sinsemilla/message.rs b/halo2_gadgets/src/sinsemilla/message.rs index 6bb72e2f1e..62696834ab 100644 --- a/halo2_gadgets/src/sinsemilla/message.rs +++ b/halo2_gadgets/src/sinsemilla/message.rs @@ -1,17 +1,17 @@ //! Gadget and chips for the Sinsemilla hash function. use ff::PrimeFieldBits; use halo2_proofs::{ - arithmetic::FieldExt, + arithmetic::Field, circuit::{AssignedCell, Cell, Value}, }; use std::fmt::Debug; /// A [`Message`] composed of several [`MessagePiece`]s. #[derive(Clone, Debug)] -pub struct Message(Vec>); +pub struct Message(Vec>); -impl - From>> for Message +impl From>> + for Message { fn from(pieces: Vec>) -> Self { // A message cannot contain more than `MAX_WORDS` words. @@ -20,7 +20,7 @@ impl } } -impl std::ops::Deref +impl std::ops::Deref for Message { type Target = [MessagePiece]; @@ -35,13 +35,13 @@ impl std:: /// The piece must fit within a base field element, which means its length /// cannot exceed the base field's `NUM_BITS`. #[derive(Clone, Debug)] -pub struct MessagePiece { +pub struct MessagePiece { cell_value: AssignedCell, /// The number of K-bit words in this message piece. num_words: usize, } -impl MessagePiece { +impl MessagePiece { pub fn new(cell_value: AssignedCell, num_words: usize) -> Self { assert!(num_words * K < F::NUM_BITS as usize); Self { diff --git a/halo2_gadgets/src/utilities.rs b/halo2_gadgets/src/utilities.rs index fa50f7e8e8..683a553b7e 100644 --- a/halo2_gadgets/src/utilities.rs +++ b/halo2_gadgets/src/utilities.rs @@ -1,11 +1,10 @@ //! Utility gadgets. -use ff::{Field, PrimeFieldBits}; +use ff::{Field, PrimeField, PrimeFieldBits}; use halo2_proofs::{ circuit::{AssignedCell, Cell, Layouter, Value}, plonk::{Advice, Column, Error, Expression}, }; -use halo2curves::FieldExt; use std::marker::PhantomData; use std::ops::Range; @@ -32,7 +31,7 @@ impl FieldValue for AssignedCell { } /// Trait for a variable in the circuit. -pub trait Var: Clone + std::fmt::Debug + From> { +pub trait Var: Clone + std::fmt::Debug + From> { /// The cell at which this variable was allocated. fn cell(&self) -> Cell; @@ -40,7 +39,7 @@ pub trait Var: Clone + std::fmt::Debug + From> { fn value(&self) -> Value; } -impl Var for AssignedCell { +impl Var for AssignedCell { fn cell(&self) -> Cell { self.cell() } @@ -51,7 +50,7 @@ impl Var for AssignedCell { } /// Trait for utilities used across circuits. -pub trait UtilitiesInstructions { +pub trait UtilitiesInstructions { /// Variable in the circuit. type Var: Var; @@ -130,15 +129,15 @@ impl RangeConstrained> { } /// Checks that an expression is either 1 or 0. -pub fn bool_check(value: Expression) -> Expression { +pub fn bool_check(value: Expression) -> Expression { range_check(value, 2) } /// If `a` then `b`, else `c`. Returns (a * b) + (1 - a) * c. /// /// `a` must be a boolean-constrained expression. -pub fn ternary(a: Expression, b: Expression, c: Expression) -> Expression { - let one_minus_a = Expression::Constant(F::one()) - a.clone(); +pub fn ternary(a: Expression, b: Expression, c: Expression) -> Expression { + let one_minus_a = Expression::Constant(F::ONE) - a.clone(); a * b + one_minus_a * c } @@ -156,9 +155,9 @@ pub fn bitrange_subset(field_elem: &F, bitrange: Range .skip(bitrange.start) .take(bitrange.end - bitrange.start) .rev() - .fold(F::zero(), |acc, bit| { + .fold(F::ZERO, |acc, bit| { if bit { - acc.double() + F::one() + acc.double() + F::ONE } else { acc.double() } @@ -167,7 +166,7 @@ pub fn bitrange_subset(field_elem: &F, bitrange: Range /// Check that an expression is in the small range [0..range), /// i.e. 0 ≤ word < range. -pub fn range_check(word: Expression, range: usize) -> Expression { +pub fn range_check(word: Expression, range: usize) -> Expression { (1..range).fold(word.clone(), |acc, i| { acc * (Expression::Constant(F::from(i as u64)) - word.clone()) }) @@ -240,6 +239,7 @@ pub fn i2lebsp(int: u64) -> [bool; NUM_BITS] { #[cfg(test)] mod tests { use super::*; + use ff::FromUniformBytes; use group::ff::{Field, PrimeField}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, @@ -247,7 +247,7 @@ mod tests { plonk::{Any, Circuit, ConstraintSystem, Constraints, Error, Selector}, poly::Rotation, }; - use halo2curves::{pasta::pallas, FieldExt}; + use halo2curves::pasta::pallas; use proptest::prelude::*; use rand::rngs::OsRng; use std::convert::TryInto; @@ -420,7 +420,7 @@ mod tests { // Instead of rejecting out-of-range bytes, let's reduce them. let mut buf = [0; 64]; buf[..32].copy_from_slice(&bytes); - pallas::Scalar::from_bytes_wide(&buf) + pallas::Scalar::from_uniform_bytes(&buf) } } diff --git a/halo2_gadgets/src/utilities/cond_swap.rs b/halo2_gadgets/src/utilities/cond_swap.rs index 9dc1afa3ef..2dc96d5904 100644 --- a/halo2_gadgets/src/utilities/cond_swap.rs +++ b/halo2_gadgets/src/utilities/cond_swap.rs @@ -1,16 +1,16 @@ //! Gadget and chip for a conditional swap utility. use super::{bool_check, ternary, UtilitiesInstructions}; +use ff::{Field, PrimeField}; use halo2_proofs::{ circuit::{AssignedCell, Chip, Layouter, Value}, plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector}, poly::Rotation, }; -use halo2curves::FieldExt; use std::marker::PhantomData; /// Instructions for a conditional swap gadget. -pub trait CondSwapInstructions: UtilitiesInstructions { +pub trait CondSwapInstructions: UtilitiesInstructions { #[allow(clippy::type_complexity)] /// Given an input pair (a,b) and a `swap` boolean flag, returns /// (b,a) if `swap` is set, else (a,b) if `swap` is not set. @@ -32,7 +32,7 @@ pub struct CondSwapChip { _marker: PhantomData, } -impl Chip for CondSwapChip { +impl Chip for CondSwapChip { type Config = CondSwapConfig; type Loaded = (); @@ -63,11 +63,11 @@ impl CondSwapConfig { } } -impl UtilitiesInstructions for CondSwapChip { +impl UtilitiesInstructions for CondSwapChip { type Var = AssignedCell; } -impl CondSwapInstructions for CondSwapChip { +impl CondSwapInstructions for CondSwapChip { #[allow(clippy::type_complexity)] fn swap( &self, @@ -122,7 +122,7 @@ impl CondSwapInstructions for CondSwapChip { } } -impl CondSwapChip { +impl CondSwapChip { /// Configures this chip for use in a circuit. /// /// # Side-effects @@ -195,25 +195,26 @@ impl CondSwapChip { mod tests { use super::super::UtilitiesInstructions; use super::{CondSwapChip, CondSwapConfig, CondSwapInstructions}; + use ff::PrimeField; use group::ff::Field; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, dev::MockProver, plonk::{Circuit, ConstraintSystem, Error}, }; - use halo2curves::{pasta::pallas::Base, FieldExt}; + use halo2curves::pasta::pallas::Base; use rand::rngs::OsRng; #[test] fn cond_swap() { #[derive(Default)] - struct MyCircuit { + struct MyCircuit { a: Value, b: Value, swap: Value, } - impl Circuit for MyCircuit { + impl Circuit for MyCircuit { type Config = CondSwapConfig; type FloorPlanner = SimpleFloorPlanner; diff --git a/halo2_gadgets/src/utilities/decompose_running_sum.rs b/halo2_gadgets/src/utilities/decompose_running_sum.rs index 89508f176c..96fd279942 100644 --- a/halo2_gadgets/src/utilities/decompose_running_sum.rs +++ b/halo2_gadgets/src/utilities/decompose_running_sum.rs @@ -30,13 +30,12 @@ use halo2_proofs::{ }; use super::range_check; -use halo2curves::FieldExt; use std::marker::PhantomData; /// The running sum $[z_0, ..., z_W]$. If created in strict mode, $z_W = 0$. #[derive(Debug)] -pub struct RunningSum(Vec>); -impl std::ops::Deref for RunningSum { +pub struct RunningSum(Vec>); +impl std::ops::Deref for RunningSum { type Target = Vec>; fn deref(&self) -> &Vec> { @@ -46,15 +45,13 @@ impl std::ops::Deref for RunningSum { /// Configuration that provides methods for running sum decomposition. #[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct RunningSumConfig { +pub struct RunningSumConfig { q_range_check: Selector, z: Column, _marker: PhantomData, } -impl - RunningSumConfig -{ +impl RunningSumConfig { /// Returns the q_range_check selector of this [`RunningSumConfig`]. pub(crate) fn q_range_check(&self) -> Selector { self.q_range_check @@ -200,7 +197,7 @@ impl if strict { // Constrain the final running sum output to be zero. - region.constrain_constant(zs.last().unwrap().cell(), F::zero())?; + region.constrain_constant(zs.last().unwrap().cell(), F::ZERO)?; } Ok(RunningSum(zs)) @@ -216,7 +213,7 @@ mod tests { dev::{FailureLocation, MockProver, VerifyFailure}, plonk::{Any, Circuit, ConstraintSystem, Error}, }; - use halo2curves::{pasta::pallas, FieldExt}; + use halo2curves::pasta::pallas; use rand::rngs::OsRng; use crate::ecc::chip::{ @@ -228,7 +225,7 @@ mod tests { #[test] fn test_running_sum() { struct MyCircuit< - F: FieldExt + PrimeFieldBits, + F: PrimeFieldBits, const WORD_NUM_BITS: usize, const WINDOW_NUM_BITS: usize, const NUM_WINDOWS: usize, @@ -238,7 +235,7 @@ mod tests { } impl< - F: FieldExt + PrimeFieldBits, + F: PrimeFieldBits, const WORD_NUM_BITS: usize, const WINDOW_NUM_BITS: usize, const NUM_WINDOWS: usize, diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs index f97654c38b..36be7c7745 100644 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ b/halo2_gadgets/src/utilities/lookup_range_check.rs @@ -14,8 +14,8 @@ use super::*; /// The running sum $[z_0, ..., z_W]$. If created in strict mode, $z_W = 0$. #[derive(Debug)] -pub struct RunningSum(Vec>); -impl std::ops::Deref for RunningSum { +pub struct RunningSum(Vec>); +impl std::ops::Deref for RunningSum { type Target = Vec>; fn deref(&self) -> &Vec> { @@ -23,7 +23,7 @@ impl std::ops::Deref for RunningSum { } } -impl RangeConstrained> { +impl RangeConstrained> { /// Witnesses a subset of the bits in `value` and constrains them to be the correct /// number of bits. /// @@ -56,7 +56,7 @@ impl RangeConstrained> { /// Configuration that provides methods for a lookup range check. #[derive(Eq, PartialEq, Debug, Clone, Copy)] -pub struct LookupRangeCheckConfig { +pub struct LookupRangeCheckConfig { q_lookup: Selector, q_running: Selector, q_bitshift: Selector, @@ -65,7 +65,7 @@ pub struct LookupRangeCheckConfig _marker: PhantomData, } -impl LookupRangeCheckConfig { +impl LookupRangeCheckConfig { /// The `running_sum` advice column breaks the field element into `K`-bit /// words. It is used to construct the input expression to the lookup /// argument. @@ -118,7 +118,7 @@ impl LookupRangeCheckConfig // In the short range check, the word is directly witnessed. let short_lookup = { let short_word = z_cur; - let q_short = Expression::Constant(F::one()) - q_running; + let q_short = Expression::Constant(F::ONE) - q_running; q_short * short_word }; @@ -285,7 +285,7 @@ impl LookupRangeCheckConfig if strict { // Constrain the final `z` to be zero. - region.constrain_constant(zs.last().unwrap().cell(), F::zero())?; + region.constrain_constant(zs.last().unwrap().cell(), F::ZERO)?; } Ok(RunningSum(zs)) @@ -395,19 +395,19 @@ mod tests { dev::{FailureLocation, MockProver, VerifyFailure}, plonk::{Circuit, ConstraintSystem, Error}, }; - use halo2curves::{pasta::pallas, FieldExt}; + use halo2curves::pasta::pallas; use std::{convert::TryInto, marker::PhantomData}; #[test] fn lookup_range_check() { #[derive(Clone, Copy)] - struct MyCircuit { + struct MyCircuit { num_words: usize, _marker: PhantomData, } - impl Circuit for MyCircuit { + impl Circuit for MyCircuit { type Config = LookupRangeCheckConfig; type FloorPlanner = SimpleFloorPlanner; @@ -434,11 +434,11 @@ mod tests { // Lookup constraining element to be no longer than num_words * K bits. let elements_and_expected_final_zs = [ - (F::from((1 << (self.num_words * K)) - 1), F::zero(), true), // a word that is within self.num_words * K bits long - (F::from(1 << (self.num_words * K)), F::one(), false), // a word that is just over self.num_words * K bits long + (F::from((1 << (self.num_words * K)) - 1), F::ZERO, true), // a word that is within self.num_words * K bits long + (F::from(1 << (self.num_words * K)), F::ONE, false), // a word that is just over self.num_words * K bits long ]; - fn expected_zs( + fn expected_zs( element: F, num_words: usize, ) -> Vec { @@ -498,12 +498,12 @@ mod tests { #[test] fn short_range_check() { - struct MyCircuit { + struct MyCircuit { element: Value, num_bits: usize, } - impl Circuit for MyCircuit { + impl Circuit for MyCircuit { type Config = LookupRangeCheckConfig; type FloorPlanner = SimpleFloorPlanner; diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index 42807f79a9..5eabdd43bc 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -46,16 +46,16 @@ harness = false [dependencies] backtrace = { version = "0.3", optional = true } rayon = "1.5.1" -ff = "0.12" -group = "0.12" -halo2curves = { git = 'https://github.com/scroll-tech/halo2curves.git', branch = "0.3.1-derive-serde" } +ff = "0.13" +group = "0.13" +halo2curves = { version = "0.1.0", features = [ "derive_serde" ] } rand_core = { version = "0.6", default-features = false } tracing = "0.1" blake2b_simd = "1" sha3 = "0.9.1" subtle = "2.3" cfg-if = "0.1" -poseidon = { git = "https://github.com/scroll-tech/poseidon.git", branch = "scroll-dev-0220" } +poseidon = { git = "https://github.com/scroll-tech/poseidon.git", branch = "sync-ff-0.13" } num-integer = "0.1" num-bigint = { version = "0.4", features = ["rand"] } diff --git a/halo2_proofs/benches/dev_lookup.rs b/halo2_proofs/benches/dev_lookup.rs index bb6cfdadbf..745a36b928 100644 --- a/halo2_proofs/benches/dev_lookup.rs +++ b/halo2_proofs/benches/dev_lookup.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate criterion; -use halo2_proofs::arithmetic::FieldExt; +use ff::{Field, PrimeField}; use halo2_proofs::circuit::{Layouter, SimpleFloorPlanner, Value}; use halo2_proofs::dev::MockProver; use halo2_proofs::plonk::*; @@ -14,7 +14,7 @@ use criterion::{BenchmarkId, Criterion}; fn criterion_benchmark(c: &mut Criterion) { #[derive(Clone, Default)] - struct MyCircuit { + struct MyCircuit { _marker: PhantomData, } @@ -25,7 +25,7 @@ fn criterion_benchmark(c: &mut Criterion) { advice: Column, } - impl Circuit for MyCircuit { + impl Circuit for MyCircuit { type Config = MyConfig; type FloorPlanner = SimpleFloorPlanner; @@ -42,7 +42,7 @@ fn criterion_benchmark(c: &mut Criterion) { meta.lookup("lookup", |meta| { let selector = meta.query_selector(config.selector); - let not_selector = Expression::Constant(F::one()) - selector.clone(); + let not_selector = Expression::Constant(F::ONE) - selector.clone(); let advice = meta.query_advice(config.advice, Rotation::cur()); vec![(selector * advice + not_selector, config.table)] }); diff --git a/halo2_proofs/benches/plonk.rs b/halo2_proofs/benches/plonk.rs index a679961463..cf02cf87e8 100644 --- a/halo2_proofs/benches/plonk.rs +++ b/halo2_proofs/benches/plonk.rs @@ -2,7 +2,6 @@ extern crate criterion; use group::ff::Field; -use halo2_proofs::arithmetic::FieldExt; use halo2_proofs::circuit::{Cell, Layouter, SimpleFloorPlanner, Value}; use halo2_proofs::plonk::*; use halo2_proofs::poly::{commitment::ParamsProver, Rotation}; @@ -43,7 +42,7 @@ fn criterion_benchmark(c: &mut Criterion) { sm: Column, } - trait StandardCs { + trait StandardCs { fn raw_multiply( &self, layouter: &mut impl Layouter, @@ -62,17 +61,17 @@ fn criterion_benchmark(c: &mut Criterion) { } #[derive(Clone)] - struct MyCircuit { + struct MyCircuit { a: Value, k: u32, } - struct StandardPlonk { + struct StandardPlonk { config: PlonkConfig, _marker: PhantomData, } - impl StandardPlonk { + impl StandardPlonk { fn new(config: PlonkConfig) -> Self { StandardPlonk { config, @@ -81,7 +80,7 @@ fn criterion_benchmark(c: &mut Criterion) { } } - impl StandardCs for StandardPlonk { + impl StandardCs for StandardPlonk { fn raw_multiply( &self, layouter: &mut impl Layouter, @@ -116,15 +115,10 @@ fn criterion_benchmark(c: &mut Criterion) { || value.unwrap().map(|v| v.2), )?; - region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::zero()))?; - region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::zero()))?; - region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::one()))?; - region.assign_fixed( - || "a * b", - self.config.sm, - 0, - || Value::known(FF::one()), - )?; + region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::ZERO))?; + region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::ZERO))?; + region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "a * b", self.config.sm, 0, || Value::known(FF::ONE))?; Ok((lhs.cell(), rhs.cell(), out.cell())) }, ) @@ -163,14 +157,14 @@ fn criterion_benchmark(c: &mut Criterion) { || value.unwrap().map(|v| v.2), )?; - region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::one()))?; - region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::one()))?; - region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::one()))?; + region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::ONE))?; region.assign_fixed( || "a * b", self.config.sm, 0, - || Value::known(FF::zero()), + || Value::known(FF::ZERO), )?; Ok((lhs.cell(), rhs.cell(), out.cell())) }, @@ -186,7 +180,7 @@ fn criterion_benchmark(c: &mut Criterion) { } } - impl Circuit for MyCircuit { + impl Circuit for MyCircuit { type Config = PlonkConfig; type FloorPlanner = SimpleFloorPlanner; diff --git a/halo2_proofs/examples/circuit-layout.rs b/halo2_proofs/examples/circuit-layout.rs index beb99502bd..6a73f51ff8 100644 --- a/halo2_proofs/examples/circuit-layout.rs +++ b/halo2_proofs/examples/circuit-layout.rs @@ -1,6 +1,5 @@ use ff::Field; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{Cell, Layouter, Region, SimpleFloorPlanner, Value}, plonk::{Advice, Assigned, Circuit, Column, ConstraintSystem, Error, Fixed, TableColumn}, poly::Rotation, @@ -28,7 +27,7 @@ struct PlonkConfig { sl: TableColumn, } -trait StandardCs { +trait StandardCs { fn raw_multiply(&self, region: &mut Region, f: F) -> Result<(Cell, Cell, Cell), Error> where F: FnMut() -> Value<(Assigned, Assigned, Assigned)>; @@ -39,17 +38,17 @@ trait StandardCs { fn lookup_table(&self, layouter: &mut impl Layouter, values: &[FF]) -> Result<(), Error>; } -struct MyCircuit { +struct MyCircuit { a: Value, lookup_table: Vec, } -struct StandardPlonk { +struct StandardPlonk { config: PlonkConfig, _marker: PhantomData, } -impl StandardPlonk { +impl StandardPlonk { fn new(config: PlonkConfig) -> Self { StandardPlonk { config, @@ -58,7 +57,7 @@ impl StandardPlonk { } } -impl StandardCs for StandardPlonk { +impl StandardCs for StandardPlonk { fn raw_multiply( &self, region: &mut Region, @@ -94,10 +93,10 @@ impl StandardCs for StandardPlonk { let out = region.assign_advice(|| "out", self.config.c, 0, || value.unwrap().map(|v| v.2))?; - region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::zero()))?; - region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::zero()))?; - region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::one()))?; - region.assign_fixed(|| "a * b", self.config.sm, 0, || Value::known(FF::one()))?; + region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::ZERO))?; + region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::ZERO))?; + region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "a * b", self.config.sm, 0, || Value::known(FF::ONE))?; Ok((lhs.cell(), rhs.cell(), out.cell())) } fn raw_add(&self, region: &mut Region, mut f: F) -> Result<(Cell, Cell, Cell), Error> @@ -131,10 +130,10 @@ impl StandardCs for StandardPlonk { let out = region.assign_advice(|| "out", self.config.c, 0, || value.unwrap().map(|v| v.2))?; - region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::one()))?; - region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::one()))?; - region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::one()))?; - region.assign_fixed(|| "a * b", self.config.sm, 0, || Value::known(FF::zero()))?; + region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "a * b", self.config.sm, 0, || Value::known(FF::ZERO))?; Ok((lhs.cell(), rhs.cell(), out.cell())) } fn copy(&self, region: &mut Region, left: Cell, right: Cell) -> Result<(), Error> { @@ -159,7 +158,7 @@ impl StandardCs for StandardPlonk { } } -impl Circuit for MyCircuit { +impl Circuit for MyCircuit { type Config = PlonkConfig; type FloorPlanner = SimpleFloorPlanner; diff --git a/halo2_proofs/examples/shuffle.rs b/halo2_proofs/examples/shuffle.rs index 1926074371..08d16b9f27 100644 --- a/halo2_proofs/examples/shuffle.rs +++ b/halo2_proofs/examples/shuffle.rs @@ -1,6 +1,6 @@ -use ff::BatchInvert; +use ff::{BatchInvert, FromUniformBytes}; use halo2_proofs::{ - arithmetic::{CurveAffine, FieldExt}, + arithmetic::{CurveAffine, Field}, circuit::{floor_planner::V1, Layouter, Value}, dev::{metadata, FailureLocation, MockProver, VerifyFailure}, halo2curves::pasta::EqAffine, @@ -21,13 +21,11 @@ use halo2_proofs::{ use rand_core::{OsRng, RngCore}; use std::iter; -fn rand_2d_array( - rng: &mut R, -) -> [[F; H]; W] { +fn rand_2d_array(rng: &mut R) -> [[F; H]; W] { [(); W].map(|_| [(); H].map(|_| F::random(&mut *rng))) } -fn shuffled( +fn shuffled( original: [[F; H]; W], rng: &mut R, ) -> [[F; H]; W] { @@ -56,7 +54,7 @@ struct MyConfig { } impl MyConfig { - fn configure(meta: &mut ConstraintSystem) -> Self { + fn configure(meta: &mut ConstraintSystem) -> Self { let [q_shuffle, q_first, q_last] = [(); 3].map(|_| meta.selector()); // First phase let original = [(); W].map(|_| meta.advice_column_in(FirstPhase)); @@ -68,7 +66,7 @@ impl MyConfig { 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()); + let one = Expression::Constant(F::ONE); vec![q_first * (one - z)] }); @@ -76,7 +74,7 @@ impl MyConfig { 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()); + let one = Expression::Constant(F::ONE); vec![q_last * (one - z)] }); @@ -118,12 +116,12 @@ impl MyConfig { } #[derive(Clone, Default)] -struct MyCircuit { +struct MyCircuit { original: Value<[[F; H]; W]>, shuffled: Value<[[F; H]; W]>, } -impl MyCircuit { +impl MyCircuit { fn rand(rng: &mut R) -> Self { let original = rand_2d_array::(rng); let shuffled = shuffled(original, rng); @@ -135,7 +133,7 @@ impl MyCircuit { } } -impl Circuit for MyCircuit { +impl Circuit for MyCircuit { type Config = MyConfig; type FloorPlanner = V1; @@ -200,9 +198,9 @@ impl Circuit for MyCircuit Circuit for MyCircuit Circuit for MyCircuit>(); #[cfg(feature = "sanity-checks")] - assert_eq!(F::one(), *z.last().unwrap()); + assert_eq!(F::ONE, *z.last().unwrap()); z }, @@ -253,12 +251,12 @@ impl Circuit for MyCircuit( +fn test_mock_prover, const W: usize, const H: usize>( k: u32, circuit: MyCircuit, expected: Result<(), Vec<(metadata::Constraint, FailureLocation)>>, ) { - let prover = MockProver::run::<_>(k, &circuit, vec![]).unwrap(); + let prover = MockProver::run(k, &circuit, vec![]).unwrap(); match (prover.verify(), expected) { (Ok(_), Ok(_)) => {} (Err(err), Err(expected)) => { @@ -284,7 +282,9 @@ fn test_prover( k: u32, circuit: MyCircuit, expected: bool, -) { +) where + C::Scalar: FromUniformBytes<64>, +{ let params = ParamsIPA::::new(k); let vk = keygen_vk(¶ms, &circuit).unwrap(); let pk = keygen_pk(¶ms, vk, &circuit).unwrap(); diff --git a/halo2_proofs/examples/simple-example.rs b/halo2_proofs/examples/simple-example.rs index c5e7a9f282..2273ce9759 100644 --- a/halo2_proofs/examples/simple-example.rs +++ b/halo2_proofs/examples/simple-example.rs @@ -1,14 +1,14 @@ use std::marker::PhantomData; use halo2_proofs::{ - arithmetic::FieldExt, + arithmetic::Field, circuit::{AssignedCell, Chip, Layouter, Region, SimpleFloorPlanner, Value}, plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance, Selector}, poly::Rotation, }; // ANCHOR: instructions -trait NumericInstructions: Chip { +trait NumericInstructions: Chip { /// Variable representing a number. type Num; @@ -39,7 +39,7 @@ trait NumericInstructions: Chip { // ANCHOR: chip /// The chip that will implement our instructions! Chips store their own /// config, as well as type markers if necessary. -struct FieldChip { +struct FieldChip { config: FieldConfig, _marker: PhantomData, } @@ -65,7 +65,7 @@ struct FieldConfig { s_mul: Selector, } -impl FieldChip { +impl FieldChip { fn construct(config: >::Config) -> Self { Self { config, @@ -126,7 +126,7 @@ impl FieldChip { // ANCHOR_END: chip-config // ANCHOR: chip-impl -impl Chip for FieldChip { +impl Chip for FieldChip { type Config = FieldConfig; type Loaded = (); @@ -143,9 +143,9 @@ impl Chip for FieldChip { // ANCHOR: instructions-impl /// A variable representing a number. #[derive(Clone)] -struct Number(AssignedCell); +struct Number(AssignedCell); -impl NumericInstructions for FieldChip { +impl NumericInstructions for FieldChip { type Num = Number; fn load_private( @@ -238,13 +238,13 @@ impl NumericInstructions for FieldChip { /// 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 { +struct MyCircuit { constant: F, a: Value, b: Value, } -impl Circuit for MyCircuit { +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; diff --git a/halo2_proofs/examples/two-chip.rs b/halo2_proofs/examples/two-chip.rs index 61d40f93ca..4113d94143 100644 --- a/halo2_proofs/examples/two-chip.rs +++ b/halo2_proofs/examples/two-chip.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use halo2_proofs::{ - arithmetic::FieldExt, + arithmetic::Field, circuit::{AssignedCell, Chip, Layouter, Region, SimpleFloorPlanner, Value}, plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Instance, Selector}, poly::Rotation, @@ -10,9 +10,9 @@ use halo2_proofs::{ // ANCHOR: field-instructions /// A variable representing a number. #[derive(Clone)] -struct Number(AssignedCell); +struct Number(AssignedCell); -trait FieldInstructions: AddInstructions + MulInstructions { +trait FieldInstructions: AddInstructions + MulInstructions { /// Variable representing a number. type Num; @@ -43,7 +43,7 @@ trait FieldInstructions: AddInstructions + MulInstructions { // ANCHOR_END: field-instructions // ANCHOR: add-instructions -trait AddInstructions: Chip { +trait AddInstructions: Chip { /// Variable representing a number. type Num; @@ -58,7 +58,7 @@ trait AddInstructions: Chip { // ANCHOR_END: add-instructions // ANCHOR: mul-instructions -trait MulInstructions: Chip { +trait MulInstructions: Chip { /// Variable representing a number. type Num; @@ -108,28 +108,28 @@ struct MulConfig { // ANCHOR: field-chip /// The top-level chip that will implement the `FieldInstructions`. -struct FieldChip { +struct FieldChip { config: FieldConfig, _marker: PhantomData, } // ANCHOR_END: field-chip // ANCHOR: add-chip -struct AddChip { +struct AddChip { config: AddConfig, _marker: PhantomData, } // ANCHOR END: add-chip // ANCHOR: mul-chip -struct MulChip { +struct MulChip { config: MulConfig, _marker: PhantomData, } // ANCHOR_END: mul-chip // ANCHOR: add-chip-trait-impl -impl Chip for AddChip { +impl Chip for AddChip { type Config = AddConfig; type Loaded = (); @@ -144,7 +144,7 @@ impl Chip for AddChip { // ANCHOR END: add-chip-trait-impl // ANCHOR: add-chip-impl -impl AddChip { +impl AddChip { fn construct(config: >::Config, _loaded: >::Loaded) -> Self { Self { config, @@ -174,7 +174,7 @@ impl AddChip { // ANCHOR END: add-chip-impl // ANCHOR: add-instructions-impl -impl AddInstructions for FieldChip { +impl AddInstructions for FieldChip { type Num = Number; fn add( &self, @@ -189,7 +189,7 @@ impl AddInstructions for FieldChip { } } -impl AddInstructions for AddChip { +impl AddInstructions for AddChip { type Num = Number; fn add( @@ -231,7 +231,7 @@ impl AddInstructions for AddChip { // ANCHOR END: add-instructions-impl // ANCHOR: mul-chip-trait-impl -impl Chip for MulChip { +impl Chip for MulChip { type Config = MulConfig; type Loaded = (); @@ -246,7 +246,7 @@ impl Chip for MulChip { // ANCHOR END: mul-chip-trait-impl // ANCHOR: mul-chip-impl -impl MulChip { +impl MulChip { fn construct(config: >::Config, _loaded: >::Loaded) -> Self { Self { config, @@ -296,7 +296,7 @@ impl MulChip { // ANCHOR_END: mul-chip-impl // ANCHOR: mul-instructions-impl -impl MulInstructions for FieldChip { +impl MulInstructions for FieldChip { type Num = Number; fn mul( &self, @@ -310,7 +310,7 @@ impl MulInstructions for FieldChip { } } -impl MulInstructions for MulChip { +impl MulInstructions for MulChip { type Num = Number; fn mul( @@ -352,7 +352,7 @@ impl MulInstructions for MulChip { // ANCHOR END: mul-instructions-impl // ANCHOR: field-chip-trait-impl -impl Chip for FieldChip { +impl Chip for FieldChip { type Config = FieldConfig; type Loaded = (); @@ -367,7 +367,7 @@ impl Chip for FieldChip { // ANCHOR_END: field-chip-trait-impl // ANCHOR: field-chip-impl -impl FieldChip { +impl FieldChip { fn construct(config: >::Config, _loaded: >::Loaded) -> Self { Self { config, @@ -396,7 +396,7 @@ impl FieldChip { // ANCHOR_END: field-chip-impl // ANCHOR: field-instructions-impl -impl FieldInstructions for FieldChip { +impl FieldInstructions for FieldChip { type Num = Number; fn load_private( @@ -448,13 +448,13 @@ impl FieldInstructions for FieldChip { /// they won't have any value during key generation. During proving, if any of these /// were `Value::unknown()` we would get an error. #[derive(Default)] -struct MyCircuit { +struct MyCircuit { a: Value, b: Value, c: Value, } -impl Circuit for MyCircuit { +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; @@ -496,7 +496,6 @@ impl Circuit for MyCircuit { #[allow(clippy::many_single_char_names)] fn main() { - use group::ff::Field; use halo2_proofs::dev::MockProver; use halo2curves::pasta::Fp; use rand_core::OsRng; diff --git a/halo2_proofs/src/arithmetic.rs b/halo2_proofs/src/arithmetic.rs index c06575b549..56ca5fd90c 100644 --- a/halo2_proofs/src/arithmetic.rs +++ b/halo2_proofs/src/arithmetic.rs @@ -5,10 +5,25 @@ use super::multicore; pub use ff::Field; use group::{ ff::{BatchInvert, PrimeField}, - Curve, Group as _, + Curve, Group, GroupOpsOwned, ScalarMulOwned, }; -pub use halo2curves::{CurveAffine, CurveExt, FieldExt, Group}; +pub use halo2curves::{CurveAffine, CurveExt}; + +/// This represents an element of a group with basic operations that can be +/// performed. This allows an FFT implementation (for example) to operate +/// generically over either a field or elliptic curve group. +pub trait FftGroup: + Copy + Send + Sync + 'static + GroupOpsOwned + ScalarMulOwned +{ +} + +impl FftGroup for T +where + Scalar: Field, + T: Copy + Send + Sync + 'static + GroupOpsOwned + ScalarMulOwned, +{ +} pub const SPARSE_TWIDDLE_DEGREE: u32 = 10; @@ -170,7 +185,7 @@ pub fn best_multiexp(coeffs: &[C::Scalar], bases: &[C]) -> C::Cu /// by $n$. /// /// This will use multithreading if beneficial. -pub fn best_fft(a: &mut [G], omega: G::Scalar, log_n: u32) { +pub fn best_fft>(a: &mut [G], omega: Scalar, log_n: u32) { let threads = multicore::current_num_threads(); let log_split = log2_floor(threads) as usize; let n = a.len() as usize; @@ -193,7 +208,7 @@ fn bitreverse(mut n: usize, l: usize) -> usize { r } -fn serial_fft(a: &mut [G], omega: G::Scalar, log_n: u32) { +fn serial_fft>(a: &mut [G], omega: Scalar, log_n: u32) { let n = a.len() as u32; assert_eq!(n, 1 << log_n); @@ -210,13 +225,13 @@ fn serial_fft(a: &mut [G], omega: G::Scalar, log_n: u32) { let mut k = 0; while k < n { - let mut w = G::Scalar::one(); + let mut w = Scalar::ONE; for j in 0..m { let mut t = a[(k + j + m) as usize]; - t.group_scale(&w); + t *= &w; a[(k + j + m) as usize] = a[(k + j) as usize]; - a[(k + j + m) as usize].group_sub(&t); - a[(k + j) as usize].group_add(&t); + a[(k + j + m) as usize] -= &t; + a[(k + j) as usize] += &t; w *= &w_m; } @@ -227,9 +242,9 @@ fn serial_fft(a: &mut [G], omega: G::Scalar, log_n: u32) { } } -fn serial_split_fft( +fn serial_split_fft>( a: &mut [G], - twiddle_lut: &[G::Scalar], + twiddle_lut: &[Scalar], twiddle_scale: usize, log_n: u32, ) { @@ -248,13 +263,13 @@ fn serial_split_fft( let mut k = 0; while k < n { - let mut w = G::Scalar::one(); + let mut w = Scalar::ONE; for j in 0..m { let mut t = a[(k + j + m) as usize]; - t.group_scale(&w); + t *= &w; a[(k + j + m) as usize] = a[(k + j) as usize]; - a[(k + j + m) as usize].group_sub(&t); - a[(k + j) as usize].group_add(&t); + a[(k + j + m) as usize] -= &t; + a[(k + j) as usize] += &t; w *= &w_m; } @@ -265,10 +280,10 @@ fn serial_split_fft( } } -fn split_radix_fft( +fn split_radix_fft>( tmp: &mut [G], a: &[G], - twiddle_lut: &[G::Scalar], + twiddle_lut: &[Scalar], n: usize, sub_fft_offset: usize, log_split: usize, @@ -278,10 +293,15 @@ fn split_radix_fft( // we use out-place bitreverse here, split_m <= num_threads, so the buffer spase is small // and it's is good for data locality - let mut t1 = vec![G::group_zero(); split_m]; + // COPY `a` to init temp buffer, + // it's a workaround for G: FftGroup, + // used to be: vec![G::identity; split_m]; + // let mut t1 = a.clone(); // if unsafe code is allowed, a 10% performance improvement can be achieved - // let mut t1: Vec = Vec::with_capacity(split_m as usize); - // unsafe{ t1.set_len(split_m as usize); } + let mut t1: Vec = Vec::with_capacity(split_m as usize); + unsafe { + t1.set_len(split_m as usize); + } for i in 0..split_m { t1[bitreverse(i, log_split)] = a[(i * sub_n + sub_fft_offset)]; } @@ -295,9 +315,9 @@ fn split_radix_fft( if high_idx > 0 { omega = omega * twiddle_lut[(1 << sparse_degree) + high_idx]; } - let mut w_m = G::Scalar::one(); + let mut w_m = Scalar::ONE; for i in 0..split_m { - t1[i].group_scale(&w_m); + t1[i] *= &w_m; tmp[i] = t1[i]; w_m = w_m * omega; } @@ -314,7 +334,7 @@ pub fn generate_twiddle_lookup_table( // dense if is_lut_len_large { - let mut twiddle_lut = vec![F::zero(); (1 << log_n) as usize]; + let mut twiddle_lut = vec![F::ZERO; (1 << log_n) as usize]; parallelize(&mut twiddle_lut, |twiddle_lut, start| { let mut w_n = omega.pow_vartime([start as u64, 0, 0, 0]); for twiddle_lut in twiddle_lut.iter_mut() { @@ -328,7 +348,7 @@ pub fn generate_twiddle_lookup_table( // sparse let low_degree_lut_len = 1 << sparse_degree; let high_degree_lut_len = 1 << (log_n - sparse_degree - without_last_level as u32); - let mut twiddle_lut = vec![F::zero(); (low_degree_lut_len + high_degree_lut_len) as usize]; + let mut twiddle_lut = vec![F::ZERO; (low_degree_lut_len + high_degree_lut_len) as usize]; parallelize( &mut twiddle_lut[..low_degree_lut_len], |twiddle_lut, start| { @@ -353,7 +373,7 @@ pub fn generate_twiddle_lookup_table( twiddle_lut } -pub fn parallel_fft(a: &mut [G], omega: G::Scalar, log_n: u32) { +pub fn parallel_fft>(a: &mut [G], omega: Scalar, log_n: u32) { let n = a.len() as usize; assert_eq!(n, 1 << log_n); @@ -363,10 +383,15 @@ pub fn parallel_fft(a: &mut [G], omega: G::Scalar, log_n: u32) { let twiddle_lut = generate_twiddle_lookup_table(omega, log_n, SPARSE_TWIDDLE_DEGREE, true); // split fft - let mut tmp = vec![G::group_zero(); n]; + // COPY `a` to init temp buffer, + // it's a workaround for G: FftGroup, + // used to be: vec![G::identity; n]; + // let mut tmp = a.clone(); // if unsafe code is allowed, a 10% performance improvement can be achieved - // let mut tmp: Vec = Vec::with_capacity(n); - // unsafe{ tmp.set_len(n); } + let mut tmp: Vec = Vec::with_capacity(n); + unsafe { + tmp.set_len(n); + } multicore::scope(|scope| { let a = &*a; let twiddle_lut = &*twiddle_lut; @@ -449,7 +474,7 @@ pub fn eval_polynomial(poly: &[F], point: F) -> F { fn evaluate(poly: &[F], point: F) -> F { poly.iter() .rev() - .fold(F::zero(), |acc, coeff| acc * point + coeff) + .fold(F::ZERO, |acc, coeff| acc * point + coeff) } let n = poly.len(); let num_threads = multicore::current_num_threads(); @@ -457,7 +482,7 @@ pub fn eval_polynomial(poly: &[F], point: F) -> F { evaluate(poly, point) } else { let chunk_size = (n + num_threads - 1) / num_threads; - let mut parts = vec![F::zero(); num_threads]; + let mut parts = vec![F::ZERO; num_threads]; multicore::scope(|scope| { for (chunk_idx, (out, poly)) in parts.chunks_mut(1).zip(poly.chunks(chunk_size)).enumerate() @@ -468,7 +493,7 @@ pub fn eval_polynomial(poly: &[F], point: F) -> F { }); } }); - parts.iter().fold(F::zero(), |acc, coeff| acc + coeff) + parts.iter().fold(F::ZERO, |acc, coeff| acc + coeff) } } @@ -479,7 +504,7 @@ pub fn compute_inner_product(a: &[F], b: &[F]) -> F { // TODO: parallelize? assert_eq!(a.len(), b.len()); - let mut acc = F::zero(); + let mut acc = F::ZERO; for (a, b) in a.iter().zip(b.iter()) { acc += (*a) * (*b); } @@ -496,9 +521,9 @@ where b = -b; let a = a.into_iter(); - let mut q = vec![F::zero(); a.len() - 1]; + let mut q = vec![F::ZERO; a.len() - 1]; - let mut tmp = F::zero(); + let mut tmp = F::ZERO; for (q, r) in q.iter_mut().rev().zip(a.rev()) { let mut lead_coeff = *r; lead_coeff.sub_assign(&tmp); @@ -546,7 +571,7 @@ fn log2_floor(num: usize) -> u32 { /// Returns coefficients of an n - 1 degree polynomial given a set of n points /// and their evaluations. This function will panic if two values in `points` /// are the same. -pub fn lagrange_interpolate(points: &[F], evals: &[F]) -> Vec { +pub fn lagrange_interpolate(points: &[F], evals: &[F]) -> Vec { assert_eq!(points.len(), evals.len()); if points.len() == 1 { // Constant polynomial @@ -568,11 +593,11 @@ pub fn lagrange_interpolate(points: &[F], evals: &[F]) -> Vec { // Compute (x_j - x_k)^(-1) for each j != i denoms.iter_mut().flat_map(|v| v.iter_mut()).batch_invert(); - let mut final_poly = vec![F::zero(); points.len()]; + let mut final_poly = vec![F::ZERO; points.len()]; for (j, (denoms, eval)) in denoms.into_iter().zip(evals.iter()).enumerate() { let mut tmp: Vec = Vec::with_capacity(points.len()); let mut product = Vec::with_capacity(points.len() - 1); - tmp.push(F::one()); + tmp.push(F::ONE); for (x_k, denom) in points .iter() .enumerate() @@ -580,11 +605,11 @@ pub fn lagrange_interpolate(points: &[F], evals: &[F]) -> Vec { .map(|a| a.1) .zip(denoms.into_iter()) { - product.resize(tmp.len() + 1, F::zero()); + product.resize(tmp.len() + 1, F::ZERO); for ((a, b), product) in tmp .iter() - .chain(std::iter::once(&F::zero())) - .zip(std::iter::once(&F::zero()).chain(tmp.iter())) + .chain(std::iter::once(&F::ZERO)) + .zip(std::iter::once(&F::ZERO).chain(tmp.iter())) .zip(product.iter_mut()) { *product = *a * (-denom * x_k) + *b * denom; @@ -601,9 +626,9 @@ pub fn lagrange_interpolate(points: &[F], evals: &[F]) -> Vec { } } -pub(crate) fn evaluate_vanishing_polynomial(roots: &[F], z: F) -> F { - fn evaluate(roots: &[F], z: F) -> F { - roots.iter().fold(F::one(), |acc, point| (z - point) * acc) +pub(crate) fn evaluate_vanishing_polynomial(roots: &[F], z: F) -> F { + fn evaluate(roots: &[F], z: F) -> F { + roots.iter().fold(F::ONE, |acc, point| (z - point) * acc) } let n = roots.len(); let num_threads = multicore::current_num_threads(); @@ -611,18 +636,18 @@ pub(crate) fn evaluate_vanishing_polynomial(roots: &[F], z: F) -> F evaluate(roots, z) } else { let chunk_size = (n + num_threads - 1) / num_threads; - let mut parts = vec![F::one(); num_threads]; + let mut parts = vec![F::ONE; num_threads]; multicore::scope(|scope| { for (out, roots) in parts.chunks_mut(1).zip(roots.chunks(chunk_size)) { scope.spawn(move |_| out[0] = evaluate(roots, z)); } }); - parts.iter().fold(F::one(), |acc, part| acc * part) + parts.iter().fold(F::ONE, |acc, part| acc * part) } } -pub(crate) fn powers(base: F) -> impl Iterator { - std::iter::successors(Some(F::one()), move |power| Some(base * power)) +pub(crate) fn powers(base: F) -> impl Iterator { + std::iter::successors(Some(F::ONE), move |power| Some(base * power)) } #[cfg(test)] diff --git a/halo2_proofs/src/circuit.rs b/halo2_proofs/src/circuit.rs index 52db772c94..508820f029 100644 --- a/halo2_proofs/src/circuit.rs +++ b/halo2_proofs/src/circuit.rs @@ -4,11 +4,8 @@ use std::{convert::TryInto, fmt, marker::PhantomData}; use ff::Field; -use crate::{ - arithmetic::FieldExt, - plonk::{ - Advice, Any, Assigned, Challenge, Column, Error, Fixed, Instance, Selector, TableColumn, - }, +use crate::plonk::{ + Advice, Any, Assigned, Challenge, Column, Error, Fixed, Instance, Selector, TableColumn, }; mod value; @@ -28,7 +25,7 @@ pub mod layouter; /// The chip also loads any fixed configuration needed at synthesis time /// using its own implementation of `load`, and stores it in [`Chip::Loaded`]. /// This can be accessed via [`Chip::loaded`]. -pub trait Chip: Sized { +pub trait Chip: Sized { /// A type that holds the configuration for this chip, and any other state it may need /// during circuit synthesis, that can be derived during [`Circuit::configure`]. /// diff --git a/halo2_proofs/src/circuit/layouter.rs b/halo2_proofs/src/circuit/layouter.rs index f73d7d7d73..4b9d74b69a 100644 --- a/halo2_proofs/src/circuit/layouter.rs +++ b/halo2_proofs/src/circuit/layouter.rs @@ -14,7 +14,7 @@ use crate::plonk::{Advice, Any, Assigned, Column, Error, Fixed, Instance, Select /// This trait is used for implementing region assignments: /// /// ```ignore -/// impl<'a, F: FieldExt, C: Chip, CS: Assignment + 'a> Layouter for MyLayouter<'a, C, CS> { +/// impl<'a, F: Field, C: Chip, CS: Assignment + 'a> Layouter for MyLayouter<'a, C, CS> { /// fn assign_region( /// &mut self, /// assignment: impl FnOnce(Region<'_, F, C>) -> Result<(), Error>, diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 94d7da90a1..b72f8c03c5 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -9,14 +9,15 @@ use std::sync::Arc; use std::time::{Duration, Instant}; use blake2b_simd::blake2b; +use ff::FromUniformBytes; use ff::{BatchInvert, Field}; +use group::Group; use crate::plonk::permutation::keygen::Assembly; use crate::plonk::sealed::SealedPhase; use crate::plonk::FirstPhase; use crate::plonk::ThirdPhase; use crate::{ - arithmetic::{FieldExt, Group}, circuit, plonk::{ permutation, Advice, Any, Assigned, Assignment, Challenge, Circuit, Column, ColumnType, @@ -98,7 +99,7 @@ impl Region { /// The value of a particular cell within the circuit. #[derive(Clone, Copy, Debug)] -pub enum CellValue { +pub enum CellValue { /// An unassigned cell. Unassigned, /// A cell that has been assigned a value. @@ -110,7 +111,7 @@ pub enum CellValue { Poison(usize), } -impl PartialEq for CellValue { +impl PartialEq for CellValue { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Unassigned, Self::Unassigned) => true, @@ -236,16 +237,16 @@ fn batch_invert_cellvalues(cell_values: &mut [Vec /// A value within an expression. #[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)] -enum Value { +enum Value { Real(F), Poison, } -impl From> for Value { +impl From> for Value { fn from(value: CellValue) -> Self { match value { // Cells that haven't been explicitly assigned to, default to zero. - CellValue::Unassigned => Value::Real(F::zero()), + CellValue::Unassigned => Value::Real(F::ZERO), CellValue::Assigned(v) => Value::Real(v), #[cfg(feature = "mock-batch-inv")] CellValue::Rational(n, d) => Value::Real(n * d.invert().unwrap()), @@ -254,7 +255,7 @@ impl From> for Value { } } -impl Neg for Value { +impl Neg for Value { type Output = Self; fn neg(self) -> Self::Output { @@ -265,7 +266,7 @@ impl Neg for Value { } } -impl Add for Value { +impl Add for Value { type Output = Self; fn add(self, rhs: Self) -> Self::Output { @@ -276,7 +277,7 @@ impl Add for Value { } } -impl Mul for Value { +impl Mul for Value { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { @@ -287,14 +288,14 @@ impl Mul for Value { (Value::Real(x), Value::Poison) | (Value::Poison, Value::Real(x)) if x.is_zero_vartime() => { - Value::Real(F::zero()) + Value::Real(F::ZERO) } _ => Value::Poison, } } } -impl Mul for Value { +impl Mul for Value { type Output = Self; fn mul(self, rhs: F) -> Self::Output { @@ -302,7 +303,7 @@ impl Mul for Value { Value::Real(lhs) => Value::Real(lhs * rhs), // If poison is multiplied by zero, then we treat the poison as unconstrained // and we don't propagate it. - Value::Poison if rhs.is_zero_vartime() => Value::Real(F::zero()), + Value::Poison if rhs.is_zero_vartime() => Value::Real(F::ZERO), _ => Value::Poison, } } @@ -320,12 +321,12 @@ impl Mul for Value { /// /// ``` /// use halo2_proofs::{ -/// arithmetic::FieldExt, /// circuit::{Layouter, SimpleFloorPlanner, Value}, /// dev::{FailureLocation, MockProver, VerifyFailure}, /// plonk::{Advice, Any, Circuit, Column, ConstraintSystem, Error, Selector}, /// poly::Rotation, /// }; +/// use ff::PrimeField; /// use halo2curves::pasta::Fp; /// const K: u32 = 5; /// @@ -343,7 +344,7 @@ impl Mul for Value { /// b: Value, /// } /// -/// impl Circuit for MyCircuit { +/// impl Circuit for MyCircuit { /// type Config = MyConfig; /// type FloorPlanner = SimpleFloorPlanner; /// @@ -422,7 +423,7 @@ impl Mul for Value { /// )); /// ``` #[derive(Debug)] -pub struct MockProver<'a, F: Group + Field> { +pub struct MockProver<'a, F: Field> { k: u32, n: u32, cs: ConstraintSystem, @@ -460,7 +461,7 @@ pub struct MockProver<'a, F: Group + Field> { current_phase: crate::plonk::sealed::Phase, } -impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { +impl<'a, F: Field> Assignment for MockProver<'a, F> { fn enter_region(&mut self, name: N) where NR: Into, @@ -880,7 +881,7 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { } } -impl<'a, F: FieldExt> MockProver<'a, F> { +impl<'a, F: FromUniformBytes<64> + Ord> MockProver<'a, F> { /// Runs a synthetic keygen-and-prove operation on the given circuit, collecting data /// about the constraints and their assignments. pub fn run>( @@ -909,7 +910,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { return Err(Error::InstanceTooLarge); } - instance.resize(n, F::zero()); + instance.resize(n, F::ZERO); Ok(instance) }) .collect::, _>>()?; @@ -945,7 +946,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { let mut hash: [u8; 64] = blake2b(b"Halo2-MockProver").as_bytes().try_into().unwrap(); iter::repeat_with(|| { hash = blake2b(&hash).as_bytes().try_into().unwrap(); - F::from_bytes_wide(&hash) + F::from_uniform_bytes(&hash) }) .take(cs.num_challenges) .collect() @@ -1190,7 +1191,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { &|a, b| a + b, &|a, b| a * b, &|a, scalar| a * scalar, - &Value::Real(F::zero()), + &Value::Real(F::ZERO), ) { Value::Real(x) if x.is_zero_vartime() => None, Value::Real(_) => Some(VerifyFailure::ConstraintNotSatisfied { @@ -1285,7 +1286,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { &|a, b| a + b, &|a, b| a * b, &|a, scalar| a * scalar, - &Value::Real(F::zero()), + &Value::Real(F::ZERO), ) }; @@ -1576,7 +1577,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { &|a, b| a + b, &|a, b| a * b, &|a, scalar| a * scalar, - &Value::Real(F::zero()), + &Value::Real(F::ZERO), ) { Value::Real(x) if x.is_zero_vartime() => None, Value::Real(_) => Some(VerifyFailure::ConstraintNotSatisfied { @@ -1664,7 +1665,7 @@ impl<'a, F: FieldExt> MockProver<'a, F> { &|a, b| a + b, &|a, b| a * b, &|a, scalar| a * scalar, - &Value::Real(F::zero()), + &Value::Real(F::ZERO), ) }; diff --git a/halo2_proofs/src/dev/failure.rs b/halo2_proofs/src/dev/failure.rs index 229cb171f4..54b7a473db 100644 --- a/halo2_proofs/src/dev/failure.rs +++ b/halo2_proofs/src/dev/failure.rs @@ -2,7 +2,6 @@ use std::collections::{BTreeMap, HashSet}; use std::fmt::{self, Debug}; use group::ff::Field; -use halo2curves::FieldExt; use super::metadata::{DebugColumn, DebugVirtualCell}; use super::MockProver; @@ -444,7 +443,7 @@ fn render_constraint_not_satisfied( /// | x0 = 0x5 /// | x1 = 1 /// ``` -fn render_lookup( +fn render_lookup( prover: &MockProver, name: &str, lookup_index: usize, @@ -510,7 +509,7 @@ fn render_lookup( ) }); - fn cell_value<'a, F: FieldExt, Q: Into + Copy>( + fn cell_value<'a, F: Field, Q: Into + Copy>( load: impl Fn(Q) -> Value + 'a, ) -> impl Fn(Q) -> BTreeMap + 'a { move |query| { @@ -624,7 +623,7 @@ fn render_lookup( impl VerifyFailure { /// Emits this failure in pretty-printed format to stderr. - pub(super) fn emit(&self, prover: &MockProver) { + pub(super) fn emit(&self, prover: &MockProver) { match self { Self::CellNotAssigned { gate, diff --git a/halo2_proofs/src/dev/util.rs b/halo2_proofs/src/dev/util.rs index 83126e79c7..f4cd83c34a 100644 --- a/halo2_proofs/src/dev/util.rs +++ b/halo2_proofs/src/dev/util.rs @@ -1,7 +1,5 @@ -use std::collections::BTreeMap; - use group::ff::Field; -use halo2curves::FieldExt; +use std::collections::BTreeMap; use super::{metadata, CellValue, Value}; use crate::{ @@ -59,9 +57,9 @@ impl From for AnyQuery { pub(super) fn format_value(v: F) -> String { if v.is_zero_vartime() { "0".into() - } else if v == F::one() { + } else if v == F::ONE { "1".into() - } else if v == -F::one() { + } else if v == -F::ONE { "-1".into() } else { // Format value as hex. @@ -74,7 +72,7 @@ pub(super) fn format_value(v: F) -> String { } /* -pub(super) fn load<'a, F: FieldExt, T: ColumnType, Q: Into + Copy>( +pub(super) fn load<'a, F: Field, T: ColumnType, Q: Into + Copy>( n: i32, row: i32, queries: &'a [(Column, Rotation)], @@ -88,7 +86,7 @@ pub(super) fn load<'a, F: FieldExt, T: ColumnType, Q: Into + Copy>( } */ -pub(super) fn load_slice<'a, F: FieldExt, T: ColumnType, Q: Into + Copy>( +pub(super) fn load_slice<'a, F: Field, T: ColumnType, Q: Into + Copy>( n: i32, row: i32, queries: &'a [(Column, Rotation)], @@ -101,7 +99,7 @@ pub(super) fn load_slice<'a, F: FieldExt, T: ColumnType, Q: Into + Cop } } -pub(super) fn load_instance<'a, F: FieldExt, T: ColumnType, Q: Into + Copy>( +pub(super) fn load_instance<'a, F: Field, T: ColumnType, Q: Into + Copy>( n: i32, row: i32, queries: &'a [(Column, Rotation)], @@ -114,7 +112,7 @@ pub(super) fn load_instance<'a, F: FieldExt, T: ColumnType, Q: Into + } } -fn cell_value<'a, F: FieldExt, Q: Into + Copy>( +fn cell_value<'a, F: Field, Q: Into + Copy>( virtual_cells: &'a [VirtualCell], load: impl Fn(Q) -> Value + 'a, ) -> impl Fn(Q) -> BTreeMap + 'a { @@ -147,7 +145,7 @@ fn cell_value<'a, F: FieldExt, Q: Into + Copy>( } } -pub(super) fn cell_values<'a, F: FieldExt>( +pub(super) fn cell_values<'a, F: Field>( gate: &Gate, poly: &Expression, load_fixed: impl Fn(FixedQuery) -> Value + 'a, diff --git a/halo2_proofs/src/helpers.rs b/halo2_proofs/src/helpers.rs index f58ec9b100..57238ec382 100644 --- a/halo2_proofs/src/helpers.rs +++ b/halo2_proofs/src/helpers.rs @@ -1,8 +1,7 @@ use crate::plonk::{Any, Column}; use crate::poly::Polynomial; -use ff::Field; use ff::PrimeField; -use halo2curves::FieldExt; +use ff::{Field, FromUniformBytes}; use halo2curves::{pairing::Engine, serde::SerdeObject, CurveAffine}; use num_bigint::BigUint; use std::io; @@ -42,24 +41,30 @@ pub(crate) trait CurveRead: CurveAffine { } impl CurveRead for C {} -pub fn field_to_bn(f: &F) -> BigUint { +pub fn field_to_bn(f: &F) -> BigUint { BigUint::from_bytes_le(f.to_repr().as_ref()) } /// Input a big integer `bn`, compute a field element `f` /// such that `f == bn % F::MODULUS`. -pub fn bn_to_field(bn: &BigUint) -> F { +pub fn bn_to_field(bn: &BigUint) -> F +where + F: FromUniformBytes<64>, +{ let mut buf = bn.to_bytes_le(); buf.resize(64, 0u8); let mut buf_array = [0u8; 64]; buf_array.copy_from_slice(buf.as_ref()); - F::from_bytes_wide(&buf_array) + F::from_uniform_bytes(&buf_array) } /// Input a base field element `b`, output a scalar field /// element `s` s.t. `s == b % ScalarField::MODULUS` -pub(crate) fn base_to_scalar(base: &C::Base) -> C::Scalar { +pub(crate) fn base_to_scalar(base: &C::Base) -> C::Scalar +where + C::Scalar: FromUniformBytes<64>, +{ let bn = field_to_bn(base); // bn_to_field will perform a mod reduction bn_to_field(&bn) diff --git a/halo2_proofs/src/plonk.rs b/halo2_proofs/src/plonk.rs index d1aecca38e..dc80092f7b 100644 --- a/halo2_proofs/src/plonk.rs +++ b/halo2_proofs/src/plonk.rs @@ -6,11 +6,10 @@ //! [plonk]: https://eprint.iacr.org/2019/953 use blake2b_simd::Params as Blake2bParams; -use ff::PrimeField; -use group::ff::Field; +use group::ff::{Field, FromUniformBytes, PrimeField}; use halo2curves::pairing::Engine; -use crate::arithmetic::{CurveAffine, FieldExt}; +use crate::arithmetic::CurveAffine; use crate::helpers::{ polynomial_slice_byte_length, read_polynomial_vec, write_polynomial_slice, SerdeCurveAffine, SerdePrimeField, @@ -61,7 +60,7 @@ pub struct VerifyingKey { impl VerifyingKey where - C::Scalar: SerdePrimeField, + C::Scalar: SerdePrimeField + FromUniformBytes<64>, { /// Writes a verifying key to a buffer. /// @@ -151,7 +150,10 @@ where } } -impl VerifyingKey { +impl VerifyingKey +where + C::ScalarExt: FromUniformBytes<64>, +{ fn bytes_length(&self) -> usize { 8 + (self.fixed_commitments.len() * C::default().to_bytes().as_ref().len()) + self.permutation.bytes_length() @@ -182,7 +184,7 @@ impl VerifyingKey { cs, cs_degree, // Temporary, this is not pinned. - transcript_repr: C::Scalar::zero(), + transcript_repr: C::Scalar::ZERO, //selectors, }; @@ -197,7 +199,7 @@ impl VerifyingKey { hasher.update(s.as_bytes()); // Hash in final Blake2bState - vk.transcript_repr = C::Scalar::from_bytes_wide(hasher.finalize().as_array()); + vk.transcript_repr = C::Scalar::from_uniform_bytes(hasher.finalize().as_array()); vk } @@ -267,7 +269,10 @@ pub struct ProvingKey { ev: Evaluator, } -impl ProvingKey { +impl ProvingKey +where + C::Scalar: FromUniformBytes<64>, +{ /// Get the underlying [`VerifyingKey`]. pub fn get_vk(&self) -> &VerifyingKey { &self.vk @@ -288,7 +293,7 @@ impl ProvingKey { impl ProvingKey where - C::Scalar: SerdePrimeField, + C::Scalar: SerdePrimeField + FromUniformBytes<64>, { /// Writes a proving key to a buffer. /// diff --git a/halo2_proofs/src/plonk/assigned.rs b/halo2_proofs/src/plonk/assigned.rs index 7524291e4c..46d527b915 100644 --- a/halo2_proofs/src/plonk/assigned.rs +++ b/halo2_proofs/src/plonk/assigned.rs @@ -280,7 +280,7 @@ impl Assigned { /// Returns the numerator. pub fn numerator(&self) -> F { match self { - Self::Zero => F::zero(), + Self::Zero => F::ZERO, Self::Trivial(x) => *x, Self::Rational(numerator, _) => *numerator, } @@ -341,7 +341,7 @@ impl Assigned { pub fn invert(&self) -> Self { match self { Self::Zero => Self::Zero, - Self::Trivial(x) => Self::Rational(F::one(), *x), + Self::Trivial(x) => Self::Rational(F::ONE, *x), Self::Rational(numerator, denominator) => Self::Rational(*denominator, *numerator), } } @@ -352,13 +352,13 @@ impl Assigned { /// If the denominator is zero, this returns zero. pub fn evaluate(self) -> F { match self { - Self::Zero => F::zero(), + Self::Zero => F::ZERO, Self::Trivial(x) => x, Self::Rational(numerator, denominator) => { - if denominator == F::one() { + if denominator == F::ONE { numerator } else { - numerator * denominator.invert().unwrap_or(F::zero()) + numerator * denominator.invert().unwrap_or(F::ZERO) } } } @@ -451,7 +451,7 @@ mod proptests { }; use group::ff::Field; - use halo2curves::{pasta::Fp, FieldExt}; + use halo2curves::pasta::Fp; use proptest::{collection::vec, prelude::*, sample::select}; use super::Assigned; @@ -477,7 +477,7 @@ mod proptests { } fn inv0(&self) -> Self { - self.invert().unwrap_or(F::zero()) + self.invert().unwrap_or(F::ZERO) } } diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 8f1ec3da8c..b3450e0881 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -349,11 +349,10 @@ impl TryFrom> for Column { /// row when required: /// ``` /// use halo2_proofs::{ -/// arithmetic::FieldExt, /// circuit::{Chip, Layouter, Value}, /// plonk::{Advice, Column, Error, Selector}, /// }; -/// # use ff::Field; +/// use ff::Field; /// # use halo2_proofs::plonk::Fixed; /// /// struct Config { @@ -362,12 +361,12 @@ 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| { -/// region.assign_advice(|| "a", config.a, 0, || Value::known(F::one()))?; -/// region.assign_advice(|| "a", config.b, 1, || Value::known(F::one()))?; +/// region.assign_advice(|| "a", config.a, 0, || Value::known(F::ONE))?; +/// region.assign_advice(|| "a", config.b, 1, || Value::known(F::ONE))?; /// config.s.enable(&mut region, 1) /// })?; /// Ok(()) diff --git a/halo2_proofs/src/plonk/circuit/compress_selectors.rs b/halo2_proofs/src/plonk/circuit/compress_selectors.rs index 0e8db9ffc8..60898d3950 100644 --- a/halo2_proofs/src/plonk/circuit/compress_selectors.rs +++ b/halo2_proofs/src/plonk/circuit/compress_selectors.rs @@ -81,7 +81,7 @@ where let combination_assignment = selector .activations .iter() - .map(|b| if *b { F::one() } else { F::zero() }) + .map(|b| if *b { F::ONE } else { F::ZERO }) .collect::>(); let combination_index = combination_assignments.len(); combination_assignments.push(combination_assignment); @@ -179,12 +179,12 @@ where } // Now, compute the selector and combination assignments. - let mut combination_assignment = vec![F::zero(); n]; + let mut combination_assignment = vec![F::ZERO; n]; let combination_len = combination.len(); let combination_index = combination_assignments.len(); let query = allocate_fixed_column(); - let mut assigned_root = F::one(); + let mut assigned_root = F::ONE; selector_assignments.extend(combination.into_iter().map(|selector| { // Compute the expression for substitution. This produces an expression of the // form @@ -194,12 +194,12 @@ where // `assigned_root`. In particular, rows set to 0 correspond to all selectors // being disabled. let mut expression = query.clone(); - let mut root = F::one(); + let mut root = F::ONE; for _ in 0..combination_len { if root != assigned_root { expression = expression * (Expression::Constant(root) - query.clone()); } - root += F::one(); + root += F::ONE; } // Update the combination assignment @@ -214,7 +214,7 @@ where } } - assigned_root += F::one(); + assigned_root += F::ONE; SelectorAssignment { selector: selector.selector, diff --git a/halo2_proofs/src/plonk/evaluation.rs b/halo2_proofs/src/plonk/evaluation.rs index c9c9a5cbf1..2f08a43e01 100644 --- a/halo2_proofs/src/plonk/evaluation.rs +++ b/halo2_proofs/src/plonk/evaluation.rs @@ -4,7 +4,7 @@ use crate::plonk::permutation::Argument; use crate::plonk::{lookup, permutation, AdviceQuery, Any, FixedQuery, InstanceQuery, ProvingKey}; use crate::poly::Basis; use crate::{ - arithmetic::{eval_polynomial, parallelize, CurveAffine, FieldExt}, + arithmetic::{eval_polynomial, parallelize, CurveAffine}, poly::{ commitment::Params, Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, ProverQuery, Rotation, @@ -13,7 +13,7 @@ use crate::{ }; use group::prime::PrimeCurve; use group::{ - ff::{BatchInvert, Field}, + ff::{BatchInvert, Field, PrimeField, WithSmallOrderMulGroup}, Curve, }; use std::any::TypeId; @@ -296,7 +296,7 @@ impl Evaluator { let extended_omega = domain.get_extended_omega(); let omega = domain.get_omega(); let isize = size as i32; - let one = C::ScalarExt::one(); + let one = C::ScalarExt::ONE; let p = &pk.vk.cs.permutation; let num_parts = domain.extended_len() >> domain.k(); @@ -527,7 +527,7 @@ impl Evaluator { &gamma, &theta, &y, - &C::ScalarExt::zero(), + &C::ScalarExt::ZERO, idx, rot_scale, isize, @@ -587,8 +587,8 @@ impl Default for GraphEvaluator { Self { // Fixed positions to allow easy access constants: vec![ - C::ScalarExt::zero(), - C::ScalarExt::one(), + C::ScalarExt::ZERO, + C::ScalarExt::ONE, C::ScalarExt::from(2u64), ], rotations: Vec::new(), @@ -736,9 +736,9 @@ impl GraphEvaluator { } } Expression::Scaled(a, f) => { - if *f == C::ScalarExt::zero() { + if *f == C::ScalarExt::ZERO { ValueSource::Constant(0) - } else if *f == C::ScalarExt::one() { + } else if *f == C::ScalarExt::ONE { self.add_expression(a) } else { let cst = self.add_constant(f); @@ -752,7 +752,7 @@ impl GraphEvaluator { /// Creates a new evaluation structure pub fn instance(&self) -> EvaluationData { EvaluationData { - intermediates: vec![C::ScalarExt::zero(); self.num_intermediates], + intermediates: vec![C::ScalarExt::ZERO; self.num_intermediates], rotations: vec![0usize; self.rotations.len()], } } @@ -800,13 +800,13 @@ impl GraphEvaluator { if let Some(calc) = self.calculations.last() { data.intermediates[calc.target] } else { - C::ScalarExt::zero() + C::ScalarExt::ZERO } } } /// Simple evaluation of an expression -pub fn evaluate( +pub fn evaluate( expression: &Expression, size: usize, rot_scale: i32, @@ -815,7 +815,7 @@ pub fn evaluate( instance: &[Polynomial], challenges: &[F], ) -> Vec { - let mut values = vec![F::zero(); size]; + let mut values = vec![F::ZERO; size]; let isize = size as i32; parallelize(&mut values, |values, start| { for (i, value) in values.iter_mut().enumerate() { diff --git a/halo2_proofs/src/plonk/keygen.rs b/halo2_proofs/src/plonk/keygen.rs index 2f461491f6..db7123ef3b 100644 --- a/halo2_proofs/src/plonk/keygen.rs +++ b/halo2_proofs/src/plonk/keygen.rs @@ -3,7 +3,7 @@ use std::ops::Range; use std::sync::Arc; -use ff::Field; +use ff::{Field, FromUniformBytes}; use group::Curve; use super::{ @@ -329,6 +329,7 @@ where C: CurveAffine, P: Params<'params, C>, ConcreteCircuit: Circuit, + C::Scalar: FromUniformBytes<64>, { let (domain, cs, config) = create_domain::(params.k()); @@ -423,6 +424,7 @@ where C: CurveAffine, P: Params<'params, C>, ConcreteCircuit: Circuit, + C::Scalar: FromUniformBytes<64>, { keygen_pk_impl(params, None, circuit) } @@ -437,6 +439,7 @@ where C: CurveAffine, P: Params<'params, C>, ConcreteCircuit: Circuit, + C::Scalar: FromUniformBytes<64>, { keygen_pk_impl(params, Some(vk), circuit) } @@ -451,6 +454,7 @@ where C: CurveAffine, P: Params<'params, C>, ConcreteCircuit: Circuit, + C::Scalar: FromUniformBytes<64>, { let (domain, cs, config) = create_domain::(params.k()); @@ -540,23 +544,23 @@ where // Compute l_0(X) // TODO: this can be done more efficiently let mut l0 = vk.domain.empty_lagrange(); - l0[0] = C::Scalar::one(); + l0[0] = C::Scalar::ONE; let l0 = vk.domain.lagrange_to_coeff(l0); // Compute l_blind(X) which evaluates to 1 for each blinding factor row // and 0 otherwise over the domain. let mut l_blind = vk.domain.empty_lagrange(); for evaluation in l_blind[..].iter_mut().rev().take(cs.blinding_factors()) { - *evaluation = C::Scalar::one(); + *evaluation = C::Scalar::ONE; } // Compute l_last(X) which evaluates to 1 on the first inactive row (just // before the blinding factors) and 0 otherwise over the domain let mut l_last = vk.domain.empty_lagrange(); - l_last[params.n() as usize - cs.blinding_factors() - 1] = C::Scalar::one(); + l_last[params.n() as usize - cs.blinding_factors() - 1] = C::Scalar::ONE; // Compute l_active_row(X) - let one = C::Scalar::one(); + let one = C::Scalar::ONE; let mut l_active_row = vk.domain.empty_lagrange(); parallelize(&mut l_active_row, |values, start| { for (i, value) in values.iter_mut().enumerate() { diff --git a/halo2_proofs/src/plonk/lookup/prover.rs b/halo2_proofs/src/plonk/lookup/prover.rs index f5d87d061e..0f0c85d7e3 100644 --- a/halo2_proofs/src/plonk/lookup/prover.rs +++ b/halo2_proofs/src/plonk/lookup/prover.rs @@ -5,7 +5,7 @@ use super::super::{ use super::Argument; use crate::plonk::evaluation::evaluate; use crate::{ - arithmetic::{eval_polynomial, parallelize, CurveAffine, FieldExt}, + arithmetic::{eval_polynomial, parallelize, CurveAffine}, poly::{ commitment::{Blind, Params}, Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, ProverQuery, @@ -13,6 +13,7 @@ use crate::{ }, transcript::{EncodedChallenge, TranscriptWrite}, }; +use ff::WithSmallOrderMulGroup; use group::{ ff::{BatchInvert, Field}, Curve, @@ -51,7 +52,7 @@ pub(in crate::plonk) struct Evaluated { constructed: Committed, } -impl Argument { +impl> Argument { /// Given a Lookup with input expressions [A_0, A_1, ..., A_{m-1}] and table expressions /// [S_0, S_1, ..., S_{m-1}], this method /// - constructs A_compressed = \theta^{m-1} A_0 + theta^{m-2} A_1 + ... + \theta A_{m-2} + A_{m-1} @@ -191,7 +192,7 @@ impl Permuted { // s_j(X) is the jth table expression in this lookup, // s'(X) is the compression of the permuted table expressions, // and i is the ith row of the expression. - let mut lookup_product = vec![C::Scalar::zero(); params.n() as usize]; + let mut lookup_product = vec![C::Scalar::ZERO; params.n() as usize]; // Denominator uses the permuted input expression and permuted table expression parallelize(&mut lookup_product, |lookup_product, start| { for ((lookup_product, permuted_input_value), permuted_table_value) in lookup_product @@ -234,9 +235,9 @@ impl Permuted { // Compute the evaluations of the lookup product polynomial // over our domain, starting with z[0] = 1 - let z = iter::once(C::Scalar::one()) + let z = iter::once(C::Scalar::ONE) .chain(lookup_product) - .scan(C::Scalar::one(), |state, cur| { + .scan(C::Scalar::ONE, |state, cur| { *state *= &cur; Some(*state) }) @@ -257,7 +258,7 @@ impl Permuted { let u = (params.n() as usize) - (blinding_factors + 1); // l_0(X) * (1 - z(X)) = 0 - assert_eq!(z[0], C::Scalar::one()); + assert_eq!(z[0], C::Scalar::ONE); // z(\omega X) (a'(X) + \beta) (s'(X) + \gamma) // - z(X) (\theta^{m-1} a_0(X) + ... + a_{m-1}(X) + \beta) (\theta^{m-1} s_0(X) + ... + s_{m-1}(X) + \gamma) @@ -284,7 +285,7 @@ impl Permuted { // l_last(X) * (z(X)^2 - z(X)) = 0 // Assertion will fail only when soundness is broken, in which // case this z[u] value will be zero. (bad!) - assert_eq!(z[u], C::Scalar::one()); + assert_eq!(z[u], C::Scalar::ONE); } let product_blind = Blind(C::Scalar::random(rng)); @@ -413,7 +414,7 @@ fn permute_expression_pair<'params, C: CurveAffine, P: Params<'params, C>, R: Rn *acc.entry(*coeff).or_insert(0) += 1; acc }); - let mut permuted_table_coeffs = vec![C::Scalar::zero(); usable_rows]; + let mut permuted_table_coeffs = vec![C::Scalar::ZERO; usable_rows]; let mut repeated_input_rows = permuted_input_expression .iter() diff --git a/halo2_proofs/src/plonk/lookup/verifier.rs b/halo2_proofs/src/plonk/lookup/verifier.rs index add4e592c9..990866b786 100644 --- a/halo2_proofs/src/plonk/lookup/verifier.rs +++ b/halo2_proofs/src/plonk/lookup/verifier.rs @@ -5,7 +5,7 @@ use super::super::{ }; use super::Argument; use crate::{ - arithmetic::{CurveAffine, FieldExt}, + arithmetic::CurveAffine, plonk::{Error, VerifyingKey}, poly::{commitment::MSM, Rotation, VerifierQuery}, transcript::{EncodedChallenge, TranscriptRead}, @@ -34,7 +34,7 @@ pub struct Evaluated { pub permuted_table_eval: C::Scalar, } -impl Argument { +impl Argument { pub fn read_permuted_commitments< C: CurveAffine, E: EncodedChallenge, @@ -104,7 +104,7 @@ impl Evaluated { instance_evals: &[C::Scalar], challenges: &[C::Scalar], ) -> impl Iterator + 'a { - let active_rows = C::Scalar::one() - (l_last + l_blind); + let active_rows = C::Scalar::ONE - (l_last + l_blind); let product_expression = || { // z(\omega X) (a'(X) + \beta) (s'(X) + \gamma) @@ -130,7 +130,7 @@ impl Evaluated { &|a, scalar| a * &scalar, ) }) - .fold(C::Scalar::zero(), |acc, eval| acc * &*theta + &eval) + .fold(C::Scalar::ZERO, |acc, eval| acc * &*theta + &eval) }; let right = self.product_eval * &(compress_expressions(&argument.input_expressions) + &*beta) @@ -142,7 +142,7 @@ impl Evaluated { std::iter::empty() .chain( // l_0(X) * (1 - z'(X)) = 0 - Some(l_0 * &(C::Scalar::one() - &self.product_eval)), + Some(l_0 * &(C::Scalar::ONE - &self.product_eval)), ) .chain( // l_last(X) * (z(X)^2 - z(X)) = 0 diff --git a/halo2_proofs/src/plonk/permutation/keygen.rs b/halo2_proofs/src/plonk/permutation/keygen.rs index 58ba4878cc..1d73c82b42 100644 --- a/halo2_proofs/src/plonk/permutation/keygen.rs +++ b/halo2_proofs/src/plonk/permutation/keygen.rs @@ -1,9 +1,9 @@ -use ff::Field; +use ff::{Field, PrimeField}; use group::Curve; use super::{Argument, ProvingKey, VerifyingKey}; use crate::{ - arithmetic::{parallelize, CurveAffine, FieldExt}, + arithmetic::{parallelize, CurveAffine}, plonk::{Any, Column, Error}, poly::{ commitment::{Blind, CommitmentScheme, Params}, @@ -109,7 +109,7 @@ impl Assembly { p: &Argument, ) -> VerifyingKey { // Compute [omega^0, omega^1, ..., omega^{params.n - 1}] - let mut omega_powers = vec![C::Scalar::zero(); params.n() as usize]; + let mut omega_powers = vec![C::Scalar::ZERO; params.n() as usize]; { let omega = domain.get_omega(); parallelize(&mut omega_powers, |o, start| { @@ -130,7 +130,7 @@ impl Assembly { for v in omega_powers { *v *= &cur; } - cur *= &C::Scalar::DELTA; + cur *= &::DELTA; } }); } @@ -171,7 +171,7 @@ impl Assembly { p: &Argument, ) -> ProvingKey { // Compute [omega^0, omega^1, ..., omega^{params.n - 1}] - let mut omega_powers = vec![C::Scalar::zero(); params.n() as usize]; + let mut omega_powers = vec![C::Scalar::ZERO; params.n() as usize]; { let omega = domain.get_omega(); parallelize(&mut omega_powers, |o, start| { diff --git a/halo2_proofs/src/plonk/permutation/prover.rs b/halo2_proofs/src/plonk/permutation/prover.rs index ad94b02574..0618952f5a 100644 --- a/halo2_proofs/src/plonk/permutation/prover.rs +++ b/halo2_proofs/src/plonk/permutation/prover.rs @@ -1,3 +1,4 @@ +use ff::PrimeField; use group::{ ff::{BatchInvert, Field}, Curve, @@ -8,7 +9,7 @@ use std::iter::{self, ExactSizeIterator}; use super::super::{circuit::Any, ChallengeBeta, ChallengeGamma, ChallengeX}; use super::{Argument, ProvingKey}; use crate::{ - arithmetic::{eval_polynomial, parallelize, CurveAffine, FieldExt}, + arithmetic::{eval_polynomial, parallelize, CurveAffine}, plonk::{self, Error}, poly::{ self, @@ -72,10 +73,10 @@ impl Argument { let blinding_factors = pk.vk.cs.blinding_factors(); // Each column gets its own delta power. - let mut deltaomega = C::Scalar::one(); + let mut deltaomega = C::Scalar::ONE; // Track the "last" value from the previous column set - let mut last_z = C::Scalar::one(); + let mut last_z = C::Scalar::ONE; let mut sets = vec![]; @@ -92,7 +93,7 @@ impl Argument { // where p_j(X) is the jth column in this permutation, // and i is the ith row of the column. - let mut modified_values = vec![C::Scalar::one(); params.n() as usize]; + let mut modified_values = vec![C::Scalar::ONE; params.n() as usize]; // Iterate over each column of the permutation for (&column, permuted_column_values) in columns.iter().zip(permutations.iter()) { @@ -135,7 +136,7 @@ impl Argument { deltaomega *= ω } }); - deltaomega *= &C::Scalar::DELTA; + deltaomega *= &::DELTA; } // The modified_values vector is a vector of products of fractions diff --git a/halo2_proofs/src/plonk/permutation/verifier.rs b/halo2_proofs/src/plonk/permutation/verifier.rs index a33b210e13..ecdef3f59a 100644 --- a/halo2_proofs/src/plonk/permutation/verifier.rs +++ b/halo2_proofs/src/plonk/permutation/verifier.rs @@ -1,10 +1,10 @@ -use ff::Field; +use ff::{Field, PrimeField}; use std::iter; use super::super::{circuit::Any, ChallengeBeta, ChallengeGamma, ChallengeX}; use super::{Argument, VerifyingKey}; use crate::{ - arithmetic::{CurveAffine, FieldExt}, + arithmetic::CurveAffine, plonk::{self, Error}, poly::{commitment::MSM, Rotation, VerifierQuery}, transcript::{EncodedChallenge, TranscriptRead}, @@ -123,9 +123,9 @@ impl Evaluated { // Enforce only for the first set. // l_0(X) * (1 - z_0(X)) = 0 .chain( - self.sets.first().map(|first_set| { - l_0 * &(C::Scalar::one() - &first_set.permutation_product_eval) - }), + self.sets + .first() + .map(|first_set| l_0 * &(C::Scalar::ONE - &first_set.permutation_product_eval)), ) // Enforce only for the last set. // l_last(X) * (z_l(X)^2 - z_l(X)) = 0 @@ -182,7 +182,8 @@ impl Evaluated { let mut right = set.permutation_product_eval; let mut current_delta = (*beta * &*x) - * &(C::Scalar::DELTA.pow_vartime([(chunk_index * chunk_len) as u64])); + * &(::DELTA + .pow_vartime(&[(chunk_index * chunk_len) as u64])); for eval in columns.iter().map(|&column| match column.column_type() { Any::Advice(_) => { advice_evals[vk.cs.get_any_query_index(column, Rotation::cur())] @@ -198,7 +199,7 @@ impl Evaluated { current_delta *= &C::Scalar::DELTA; } - (left - &right) * (C::Scalar::one() - &(l_last + &l_blind)) + (left - &right) * (C::Scalar::ONE - &(l_last + &l_blind)) }), ) } diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index 7c176e576a..c522947820 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -1,4 +1,4 @@ -use ff::Field; +use ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; use group::Curve; use halo2curves::CurveExt; use rand_core::RngCore; @@ -20,7 +20,7 @@ use super::{ ChallengeY, Error, Expression, ProvingKey, }; use crate::{ - arithmetic::{eval_polynomial, CurveAffine, FieldExt}, + arithmetic::{eval_polynomial, CurveAffine}, circuit::Value, plonk::Assigned, poly::{ @@ -55,7 +55,10 @@ pub fn create_proof< instances: &[&[&[Scheme::Scalar]]], mut rng: R, transcript: &mut T, -) -> Result<(), Error> { +) -> Result<(), Error> +where + Scheme::Scalar: WithSmallOrderMulGroup<3> + FromUniformBytes<64>, +{ for instance in instances.iter() { if instance.len() != pk.vk.cs.num_instance_columns { return Err(Error::InvalidInstances); @@ -463,7 +466,7 @@ pub fn create_proof< //*cell = C::Scalar::one(); //} let idx = advice_values.len() - 1; - advice_values[idx] = Scheme::Scalar::one(); + advice_values[idx] = Scheme::Scalar::ONE; } // Compute commitments to advice column polynomials diff --git a/halo2_proofs/src/plonk/vanishing/prover.rs b/halo2_proofs/src/plonk/vanishing/prover.rs index aa43a07c0f..d394b8c0de 100644 --- a/halo2_proofs/src/plonk/vanishing/prover.rs +++ b/halo2_proofs/src/plonk/vanishing/prover.rs @@ -6,7 +6,7 @@ use rand_core::RngCore; use super::Argument; use crate::{ - arithmetic::{eval_polynomial, CurveAffine, FieldExt}, + arithmetic::{eval_polynomial, CurveAffine}, plonk::{ChallengeX, ChallengeY, Error}, poly::{ self, @@ -50,10 +50,10 @@ impl Argument { transcript: &mut T, ) -> Result, Error> { // Sample a random polynomial of degree n - 1 - let random_poly = domain.constant_lagrange(C::Scalar::one()); + let random_poly = domain.constant_lagrange(C::Scalar::ONE); let random_poly = domain.lagrange_to_coeff(random_poly); // Sample a random blinding factor - let random_blind = Blind(C::Scalar::zero()); + let random_blind = Blind(C::Scalar::ZERO); let c = params.commit(&random_poly, random_blind).to_affine(); // We write the identity point to the transcript which // is the commitment of the zero polynomial. @@ -139,9 +139,7 @@ impl Constructed { .h_blinds .iter() .rev() - .fold(Blind(C::Scalar::zero()), |acc, eval| { - acc * Blind(xn) + *eval - }); + .fold(Blind(C::Scalar::ZERO), |acc, eval| acc * Blind(xn) + *eval); let random_eval = eval_polynomial(&self.committed.random_poly, *x); transcript.write_scalar(random_eval)?; diff --git a/halo2_proofs/src/plonk/vanishing/verifier.rs b/halo2_proofs/src/plonk/vanishing/verifier.rs index 3570dee6c1..0881dfb2c0 100644 --- a/halo2_proofs/src/plonk/vanishing/verifier.rs +++ b/halo2_proofs/src/plonk/vanishing/verifier.rs @@ -94,8 +94,8 @@ impl PartiallyEvaluated { y: ChallengeY, xn: C::Scalar, ) -> Evaluated { - let expected_h_eval = expressions.fold(C::Scalar::zero(), |h_eval, v| h_eval * &*y + &v); - let expected_h_eval = expected_h_eval * ((xn - C::Scalar::one()).invert().unwrap()); + let expected_h_eval = expressions.fold(C::Scalar::ZERO, |h_eval, v| h_eval * &*y + &v); + let expected_h_eval = expected_h_eval * ((xn - C::Scalar::ONE).invert().unwrap()); let h_commitment = self.h_commitments @@ -104,7 +104,7 @@ impl PartiallyEvaluated { .fold(params.empty_msm(), |mut acc, commitment| { acc.scale(xn); let commitment: C::CurveExt = (*commitment).into(); - acc.append_term(C::Scalar::one(), commitment); + acc.append_term(C::Scalar::ONE, commitment); acc }); diff --git a/halo2_proofs/src/plonk/verifier.rs b/halo2_proofs/src/plonk/verifier.rs index e6a2327e7b..f5984d2c79 100644 --- a/halo2_proofs/src/plonk/verifier.rs +++ b/halo2_proofs/src/plonk/verifier.rs @@ -1,4 +1,4 @@ -use ff::Field; +use ff::{Field, FromUniformBytes, WithSmallOrderMulGroup}; use group::Curve; use rand_core::RngCore; use std::iter; @@ -7,7 +7,7 @@ use super::{ vanishing, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, ChallengeY, Error, VerifyingKey, }; -use crate::arithmetic::{compute_inner_product, CurveAffine, FieldExt}; +use crate::arithmetic::{compute_inner_product, CurveAffine}; use crate::poly::commitment::{CommitmentScheme, Verifier}; use crate::poly::VerificationStrategy; use crate::poly::{ @@ -37,7 +37,10 @@ pub fn verify_proof< strategy: Strategy, instances: &[&[&[Scheme::Scalar]]], transcript: &mut T, -) -> Result { +) -> Result +where + Scheme::Scalar: WithSmallOrderMulGroup<3> + FromUniformBytes<64>, +{ // Check that instances matches the expected number of instance columns for instances in instances.iter() { if instances.len() != vk.cs.num_instance_columns { @@ -56,7 +59,7 @@ pub fn verify_proof< return Err(Error::InstanceTooLarge); } let mut poly = instance.to_vec(); - poly.resize(params.n() as usize, Scheme::Scalar::zero()); + poly.resize(params.n() as usize, Scheme::Scalar::ZERO); let poly = vk.domain.lagrange_from_vec(poly); Ok(params.commit_lagrange(&poly, Blind::default()).to_affine()) @@ -94,7 +97,7 @@ pub fn verify_proof< let (advice_commitments, challenges) = { let mut advice_commitments = vec![vec![Scheme::Curve::default(); vk.cs.num_advice_columns]; num_proofs]; - let mut challenges = vec![Scheme::Scalar::zero(); vk.cs.num_challenges]; + let mut challenges = vec![Scheme::Scalar::ZERO; vk.cs.num_challenges]; for current_phase in vk.cs.phases() { for advice_commitments in advice_commitments.iter_mut() { @@ -253,7 +256,7 @@ pub fn verify_proof< let l_last = l_evals[0]; let l_blind: Scheme::Scalar = l_evals[1..(1 + blinding_factors)] .iter() - .fold(Scheme::Scalar::zero(), |acc, eval| acc + eval); + .fold(Scheme::Scalar::ZERO, |acc, eval| acc + eval); let l_0 = l_evals[1 + blinding_factors]; // Compute the expected value of h(x) diff --git a/halo2_proofs/src/plonk/verifier/batch.rs b/halo2_proofs/src/plonk/verifier/batch.rs index f07ba4141f..04e08be4af 100644 --- a/halo2_proofs/src/plonk/verifier/batch.rs +++ b/halo2_proofs/src/plonk/verifier/batch.rs @@ -1,5 +1,6 @@ use std::{io, marker::PhantomData}; +use ff::FromUniformBytes; use group::ff::Field; use halo2curves::CurveAffine; use rand_core::{OsRng, RngCore}; @@ -67,7 +68,10 @@ pub struct BatchVerifier { items: Vec>, } -impl BatchVerifier { +impl BatchVerifier +where + C::Scalar: FromUniformBytes<64>, +{ /// Constructs a new batch verifier. pub fn new() -> Self { Self { items: vec![] } diff --git a/halo2_proofs/src/poly.rs b/halo2_proofs/src/poly.rs index 84089482aa..42e43b2e29 100644 --- a/halo2_proofs/src/poly.rs +++ b/halo2_proofs/src/poly.rs @@ -9,7 +9,6 @@ use crate::SerdeFormat; use ff::PrimeField; use group::ff::{BatchInvert, Field}; -use halo2curves::FieldExt; use std::fmt::Debug; use std::io; use std::marker::PhantomData; @@ -177,7 +176,7 @@ impl Polynomial { } } -pub(crate) fn batch_invert_assigned( +pub(crate) fn batch_invert_assigned( assigned: Vec, LagrangeCoeff>>, ) -> Vec> { let mut assigned_denominators: Vec<_> = assigned @@ -202,9 +201,7 @@ pub(crate) fn batch_invert_assigned( assigned .iter() .zip(assigned_denominators.into_iter()) - .map(|(poly, inv_denoms)| { - poly.invert(inv_denoms.into_iter().map(|d| d.unwrap_or_else(F::one))) - }) + .map(|(poly, inv_denoms)| poly.invert(inv_denoms.into_iter().map(|d| d.unwrap_or(F::ONE)))) .collect() } @@ -274,13 +271,13 @@ impl Mul for Polynomial { type Output = Polynomial; fn mul(mut self, rhs: F) -> Polynomial { - if rhs == F::zero() { + if rhs == F::ZERO { return Polynomial { - values: vec![F::zero(); self.len()], + values: vec![F::ZERO; self.len()], _marker: PhantomData, }; } - if rhs == F::one() { + if rhs == F::ONE { return self; } diff --git a/halo2_proofs/src/poly/commitment.rs b/halo2_proofs/src/poly/commitment.rs index e82515cfff..3a0b68f62a 100644 --- a/halo2_proofs/src/poly/commitment.rs +++ b/halo2_proofs/src/poly/commitment.rs @@ -6,8 +6,8 @@ use super::{ use crate::poly::Error; use crate::transcript::{EncodedChallenge, TranscriptRead, TranscriptWrite}; use ff::Field; -use group::Curve; -use halo2curves::{CurveAffine, CurveExt, FieldExt}; +use group::{Curve, Group}; +use halo2curves::{CurveAffine, CurveExt}; use rand_core::RngCore; use std::{ fmt::Debug, @@ -18,7 +18,7 @@ use std::{ /// Defines components of a commitment scheme. pub trait CommitmentScheme { /// Application field of this commitment scheme - type Scalar: FieldExt + halo2curves::Group; + type Scalar: Field; /// Elliptic curve used to commit the application and witnesses type Curve: CurveAffine; @@ -192,20 +192,20 @@ pub trait Verifier<'params, Scheme: CommitmentScheme> { #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub struct Blind(pub F); -impl Default for Blind { +impl Default for Blind { fn default() -> Self { - Blind(F::one()) + Blind(F::ONE) } } -impl Blind { +impl Blind { /// Given `rng` creates new blinding scalar pub fn new(rng: &mut R) -> Self { Blind(F::random(rng)) } } -impl Add for Blind { +impl Add for Blind { type Output = Self; fn add(self, rhs: Blind) -> Self { @@ -213,7 +213,7 @@ impl Add for Blind { } } -impl Mul for Blind { +impl Mul for Blind { type Output = Self; fn mul(self, rhs: Blind) -> Self { @@ -221,25 +221,25 @@ impl Mul for Blind { } } -impl AddAssign for Blind { +impl AddAssign for Blind { fn add_assign(&mut self, rhs: Blind) { self.0 += rhs.0; } } -impl MulAssign for Blind { +impl MulAssign for Blind { fn mul_assign(&mut self, rhs: Blind) { self.0 *= rhs.0; } } -impl AddAssign for Blind { +impl AddAssign for Blind { fn add_assign(&mut self, rhs: F) { self.0 += rhs; } } -impl MulAssign for Blind { +impl MulAssign for Blind { fn mul_assign(&mut self, rhs: F) { self.0 *= rhs; } diff --git a/halo2_proofs/src/poly/domain.rs b/halo2_proofs/src/poly/domain.rs index cd1a0cdc9c..e99c7f6c59 100644 --- a/halo2_proofs/src/poly/domain.rs +++ b/halo2_proofs/src/poly/domain.rs @@ -2,13 +2,16 @@ //! domain that is of a suitable size for the application. use crate::{ - arithmetic::{best_fft, parallelize, FieldExt, Group}, + arithmetic::{best_fft, parallelize}, plonk::Assigned, }; use super::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, Rotation}; - -use group::ff::{BatchInvert, Field, PrimeField}; +use ff::WithSmallOrderMulGroup; +use group::{ + ff::{BatchInvert, Field, PrimeField}, + Group, +}; use std::marker::PhantomData; @@ -16,24 +19,24 @@ use std::marker::PhantomData; /// performing operations on an evaluation domain of size $2^k$ and an extended /// domain of size $2^{k} * j$ with $j \neq 0$. #[derive(Clone, Debug)] -pub struct EvaluationDomain { +pub struct EvaluationDomain { n: u64, k: u32, extended_k: u32, - omega: G::Scalar, - omega_inv: G::Scalar, - extended_omega: G::Scalar, - extended_omega_inv: G::Scalar, - g_coset: G::Scalar, - g_coset_inv: G::Scalar, + omega: F, + omega_inv: F, + extended_omega: F, + extended_omega_inv: F, + g_coset: F, + g_coset_inv: F, quotient_poly_degree: u64, - ifft_divisor: G::Scalar, - extended_ifft_divisor: G::Scalar, - t_evaluations: Vec, - barycentric_weight: G::Scalar, + ifft_divisor: F, + extended_ifft_divisor: F, + t_evaluations: Vec, + barycentric_weight: F, } -impl EvaluationDomain { +impl> EvaluationDomain { /// This constructs a new evaluation domain object based on the provided /// values $j, k$. pub fn new(j: u32, k: u32) -> Self { @@ -51,12 +54,12 @@ impl EvaluationDomain { extended_k += 1; } - let mut extended_omega = G::Scalar::root_of_unity(); + let mut extended_omega = F::ROOT_OF_UNITY; // Get extended_omega, the 2^{extended_k}'th root of unity // The loop computes extended_omega = omega^{2 ^ (S - extended_k)} // Notice that extended_omega ^ {2 ^ extended_k} = omega ^ {2^S} = 1. - for _ in extended_k..G::Scalar::S { + for _ in extended_k..F::S { extended_omega = extended_omega.square(); } let extended_omega = extended_omega; @@ -78,15 +81,15 @@ impl EvaluationDomain { // already. // The coset evaluation domain is: // zeta {1, extended_omega, extended_omega^2, ..., extended_omega^{(2^extended_k) - 1}} - let g_coset = G::Scalar::ZETA; + let g_coset = F::ZETA; let g_coset_inv = g_coset.square(); let mut t_evaluations = Vec::with_capacity(1 << (extended_k - k)); { // Compute the evaluations of t(X) = X^n - 1 in the coset evaluation domain. // We don't have to compute all of them, because it will repeat. - let orig = G::Scalar::ZETA.pow_vartime([n as u64, 0, 0, 0]); - let step = extended_omega.pow_vartime([n as u64, 0, 0, 0]); + let orig = F::ZETA.pow_vartime(&[n as u64, 0, 0, 0]); + let step = extended_omega.pow_vartime(&[n as u64, 0, 0, 0]); let mut cur = orig; loop { t_evaluations.push(cur); @@ -99,19 +102,19 @@ impl EvaluationDomain { // Subtract 1 from each to give us t_evaluations[i] = t(zeta * extended_omega^i) for coeff in &mut t_evaluations { - *coeff -= &G::Scalar::one(); + *coeff -= &F::ONE; } // Invert, because we're dividing by this polynomial. // We invert in a batch, below. } - let mut ifft_divisor = G::Scalar::from(1 << k); // Inversion computed later - let mut extended_ifft_divisor = G::Scalar::from(1 << extended_k); // Inversion computed later + let mut ifft_divisor = F::from(1 << k); // Inversion computed later + let mut extended_ifft_divisor = F::from(1 << extended_k); // Inversion computed later // The barycentric weight of 1 over the evaluation domain // 1 / \prod_{i != 0} (1 - omega^i) - let mut barycentric_weight = G::Scalar::from(n); // Inversion computed later + let mut barycentric_weight = F::from(n); // Inversion computed later // Compute batch inversion t_evaluations @@ -144,7 +147,7 @@ impl EvaluationDomain { /// Obtains a polynomial in Lagrange form when given a vector of Lagrange /// coefficients of size `n`; panics if the provided vector is the wrong /// length. - pub fn lagrange_from_vec(&self, values: Vec) -> Polynomial { + pub fn lagrange_from_vec(&self, values: Vec) -> Polynomial { assert_eq!(values.len(), self.n as usize); Polynomial { @@ -156,7 +159,7 @@ impl EvaluationDomain { /// Obtains a polynomial in coefficient form when given a vector of /// coefficients of size `n`; panics if the provided vector is the wrong /// length. - pub fn coeff_from_vec(&self, values: Vec) -> Polynomial { + pub fn coeff_from_vec(&self, values: Vec) -> Polynomial { assert_eq!(values.len(), self.n as usize); Polynomial { @@ -170,13 +173,13 @@ impl EvaluationDomain { /// provided vector is the wrong length. pub fn extended_from_lagrange_vec( &self, - values: Vec>, - ) -> Polynomial { + values: Vec>, + ) -> Polynomial { assert_eq!(values.len(), (self.extended_len() >> self.k) as usize); assert_eq!(values[0].len(), self.n as usize); // transpose the values in parallel - let mut transposed = vec![vec![G::group_zero(); values.len()]; self.n as usize]; + let mut transposed = vec![vec![F::ZERO; values.len()]; self.n as usize]; values.into_iter().enumerate().for_each(|(i, p)| { parallelize(&mut transposed, |transposed, start| { for (transposed, p) in transposed.iter_mut().zip(p.values[start..].iter()) { @@ -192,35 +195,32 @@ impl EvaluationDomain { } /// Returns an empty (zero) polynomial in the coefficient basis - pub fn empty_coeff(&self) -> Polynomial { + pub fn empty_coeff(&self) -> Polynomial { Polynomial { - values: vec![G::group_zero(); self.n as usize], + values: vec![F::ZERO; self.n as usize], _marker: PhantomData, } } /// Returns an empty (zero) polynomial in the Lagrange coefficient basis - pub fn empty_lagrange(&self) -> Polynomial { + pub fn empty_lagrange(&self) -> Polynomial { Polynomial { - values: vec![G::group_zero(); self.n as usize], + values: vec![F::ZERO; self.n as usize], _marker: PhantomData, } } /// Returns an empty (zero) polynomial in the Lagrange coefficient basis, with /// deferred inversions. - pub(crate) fn empty_lagrange_assigned(&self) -> Polynomial, LagrangeCoeff> - where - G: Field, - { + pub(crate) fn empty_lagrange_assigned(&self) -> Polynomial, LagrangeCoeff> { Polynomial { - values: vec![G::group_zero().into(); self.n as usize], + values: vec![F::ZERO.into(); self.n as usize], _marker: PhantomData, } } /// Returns a constant polynomial in the Lagrange coefficient basis - pub fn constant_lagrange(&self, scalar: G) -> Polynomial { + pub fn constant_lagrange(&self, scalar: F) -> Polynomial { Polynomial { values: vec![scalar; self.n as usize], _marker: PhantomData, @@ -229,16 +229,16 @@ impl EvaluationDomain { /// Returns an empty (zero) polynomial in the extended Lagrange coefficient /// basis - pub fn empty_extended(&self) -> Polynomial { + pub fn empty_extended(&self) -> Polynomial { Polynomial { - values: vec![G::group_zero(); self.extended_len()], + values: vec![F::ZERO; self.extended_len()], _marker: PhantomData, } } /// Returns a constant polynomial in the extended Lagrange coefficient /// basis - pub fn constant_extended(&self, scalar: G) -> Polynomial { + pub fn constant_extended(&self, scalar: F) -> Polynomial { Polynomial { values: vec![scalar; self.extended_len()], _marker: PhantomData, @@ -249,7 +249,7 @@ impl EvaluationDomain { /// /// This function will panic if the provided vector is not the correct /// length. - pub fn lagrange_to_coeff(&self, mut a: Polynomial) -> Polynomial { + pub fn lagrange_to_coeff(&self, mut a: Polynomial) -> Polynomial { assert_eq!(a.values.len(), 1 << self.k); // Perform inverse FFT to obtain the polynomial in coefficient form @@ -265,12 +265,12 @@ impl EvaluationDomain { /// evaluation domain, rotating by `rotation` if desired. pub fn coeff_to_extended( &self, - mut a: Polynomial, - ) -> Polynomial { + mut a: Polynomial, + ) -> Polynomial { assert_eq!(a.values.len(), 1 << self.k); self.distribute_powers_zeta(&mut a.values, true); - a.values.resize(self.extended_len(), G::group_zero()); + a.values.resize(self.extended_len(), F::ZERO); best_fft(&mut a.values, self.extended_omega, self.extended_k); Polynomial { @@ -289,12 +289,12 @@ impl EvaluationDomain { /// `FFT(f(zeta * extended_omega^{m-1} * X), n)` pub fn coeff_to_extended_parts( &self, - a: &Polynomial, - ) -> Vec> { + a: &Polynomial, + ) -> Vec> { assert_eq!(a.values.len(), 1 << self.k); let num_parts = self.extended_len() >> self.k; - let mut extended_omega_factor = G::Scalar::one(); + let mut extended_omega_factor = F::ONE; (0..num_parts) .map(|_| { let part = self.coeff_to_extended_part(a.clone(), extended_omega_factor); @@ -314,11 +314,11 @@ impl EvaluationDomain { /// `FFT(f(zeta * extended_omega^{m-1} * X), n)` pub fn batched_coeff_to_extended_parts( &self, - a: &[Polynomial], - ) -> Vec>> { + a: &[Polynomial], + ) -> Vec>> { assert_eq!(a[0].values.len(), 1 << self.k); - let mut extended_omega_factor = G::Scalar::one(); + let mut extended_omega_factor = F::ONE; let num_parts = self.extended_len() >> self.k; (0..num_parts) .map(|_| { @@ -340,9 +340,9 @@ impl EvaluationDomain { /// where `extended_omega_factor` is `extended_omega^i` with `i` in `[0, m)`. pub fn coeff_to_extended_part( &self, - mut a: Polynomial, - extended_omega_factor: G::Scalar, - ) -> Polynomial { + mut a: Polynomial, + extended_omega_factor: F, + ) -> Polynomial { assert_eq!(a.values.len(), 1 << self.k); self.distribute_powers(&mut a.values, self.g_coset * extended_omega_factor); @@ -357,9 +357,9 @@ impl EvaluationDomain { /// Rotate the extended domain polynomial over the original domain. pub fn rotate_extended( &self, - poly: &Polynomial, + poly: &Polynomial, rotation: Rotation, - ) -> Polynomial { + ) -> Polynomial { let new_rotation = ((1 << (self.extended_k - self.k)) * rotation.0.abs()) as usize; let mut poly = poly.clone(); @@ -379,7 +379,7 @@ impl EvaluationDomain { /// This function will panic if the provided vector is not the correct /// length. // TODO/FIXME: caller should be responsible for truncating - pub fn extended_to_coeff(&self, mut a: Polynomial) -> Vec { + pub fn extended_to_coeff(&self, mut a: Polynomial) -> Vec { assert_eq!(a.values.len(), self.extended_len()); // Inverse FFT @@ -407,15 +407,15 @@ impl EvaluationDomain { /// polynomial of the $2^k$ size domain. pub fn divide_by_vanishing_poly( &self, - mut a: Polynomial, - ) -> Polynomial { + mut a: Polynomial, + ) -> Polynomial { assert_eq!(a.values.len(), self.extended_len()); // Divide to obtain the quotient polynomial in the coset evaluation // domain. parallelize(&mut a.values, |h, mut index| { for h in h { - h.group_scale(&self.t_evaluations[index % self.t_evaluations.len()]); + *h *= &self.t_evaluations[index % self.t_evaluations.len()]; index += 1; } }); @@ -433,7 +433,7 @@ impl EvaluationDomain { /// /// `into_coset` should be set to `true` when moving into the coset, /// and `false` when moving out. This toggles the choice of `zeta`. - fn distribute_powers_zeta(&self, a: &mut [G], into_coset: bool) { + fn distribute_powers_zeta(&self, a: &mut [F], into_coset: bool) { let coset_powers = if into_coset { [self.g_coset, self.g_coset_inv] } else { @@ -444,7 +444,7 @@ impl EvaluationDomain { // Distribute powers to move into/from coset let i = index % (coset_powers.len() + 1); if i != 0 { - a.group_scale(&coset_powers[i - 1]); + *a *= &coset_powers[i - 1]; } index += 1; } @@ -454,22 +454,22 @@ impl EvaluationDomain { /// Given a slice of group elements `[a_0, a_1, a_2, ...]`, this returns /// `[a_0, [c]a_1, [c^2]a_2, [c^3]a_3, [c^4]a_4, ...]`, /// - fn distribute_powers(&self, a: &mut [G], c: G::Scalar) { + fn distribute_powers(&self, a: &mut [F], c: F) { parallelize(a, |a, index| { let mut c_power = c.pow_vartime(&[index as u64, 0, 0, 0]); for a in a { - a.group_scale(&c_power); + *a = *a * c_power; c_power = c_power * c; } }); } - fn ifft(a: &mut [G], omega_inv: G::Scalar, log_n: u32, divisor: G::Scalar) { + fn ifft(a: &mut [F], omega_inv: F, log_n: u32, divisor: F) { best_fft(a, omega_inv, log_n); parallelize(a, |a, _| { for a in a { // Finish iFFT - a.group_scale(&divisor); + *a *= &divisor; } }); } @@ -490,24 +490,24 @@ impl EvaluationDomain { } /// Get $\omega$, the generator of the $2^k$ order multiplicative subgroup. - pub fn get_omega(&self) -> G::Scalar { + pub fn get_omega(&self) -> F { self.omega } /// Get $\omega^{-1}$, the inverse of the generator of the $2^k$ order /// multiplicative subgroup. - pub fn get_omega_inv(&self) -> G::Scalar { + pub fn get_omega_inv(&self) -> F { self.omega_inv } /// Get the generator of the extended domain's multiplicative subgroup. - pub fn get_extended_omega(&self) -> G::Scalar { + pub fn get_extended_omega(&self) -> F { self.extended_omega } /// Multiplies a value by some power of $\omega$, essentially rotating over /// the domain. - pub fn rotate_omega(&self, value: G::Scalar, rotation: Rotation) -> G::Scalar { + pub fn rotate_omega(&self, value: F, rotation: Rotation) -> F { let mut point = value; if rotation.0 >= 0 { point *= &self.get_omega().pow_vartime([rotation.0 as u64]); @@ -548,23 +548,23 @@ impl EvaluationDomain { /// which is the barycentric weight of $\omega^i$. pub fn l_i_range + Clone>( &self, - x: G::Scalar, - xn: G::Scalar, + x: F, + xn: F, rotations: I, - ) -> Vec { + ) -> Vec { let mut results; { let rotations = rotations.clone().into_iter(); results = Vec::with_capacity(rotations.size_hint().1.unwrap_or(0)); for rotation in rotations { let rotation = Rotation(rotation); - let result = x - self.rotate_omega(G::Scalar::one(), rotation); + let result = x - self.rotate_omega(F::ONE, rotation); results.push(result); } results.iter_mut().batch_invert(); } - let common = (xn - G::Scalar::one()) * self.barycentric_weight; + let common = (xn - F::ONE) * self.barycentric_weight; for (rotation, result) in rotations.into_iter().zip(results.iter_mut()) { let rotation = Rotation(rotation); *result = self.rotate_omega(*result * common, rotation); @@ -581,7 +581,7 @@ impl EvaluationDomain { /// Obtain a pinned version of this evaluation domain; a structure with the /// minimal parameters needed to determine the rest of the evaluation /// domain. - pub fn pinned(&self) -> PinnedEvaluationDomain<'_, G> { + pub fn pinned(&self) -> PinnedEvaluationDomain<'_, F> { PinnedEvaluationDomain { k: &self.k, extended_k: &self.extended_k, @@ -593,10 +593,10 @@ impl EvaluationDomain { /// Represents the minimal parameters that determine an `EvaluationDomain`. #[allow(dead_code)] #[derive(Debug)] -pub struct PinnedEvaluationDomain<'a, G: Group> { +pub struct PinnedEvaluationDomain<'a, F: Field> { k: &'a u32, extended_k: &'a u32, - omega: &'a G::Scalar, + omega: &'a F, } #[test] @@ -655,7 +655,7 @@ fn test_l_i() { } for i in 0..8 { let mut l_i = vec![Scalar::zero(); 8]; - l_i[i] = Scalar::one(); + l_i[i] = Scalar::ONE; let l_i = lagrange_interpolate(&points[..], &l_i[..]); l.push(l_i); } diff --git a/halo2_proofs/src/poly/evaluator.rs b/halo2_proofs/src/poly/evaluator.rs index d1ba853c47..5d20221255 100644 --- a/halo2_proofs/src/poly/evaluator.rs +++ b/halo2_proofs/src/poly/evaluator.rs @@ -9,7 +9,7 @@ use std::{ }; use group::ff::Field; -use halo2curves::FieldExt; +use halo2curves::Field; use super::{ Basis, Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, Rotation, @@ -135,7 +135,7 @@ impl Evaluator { ) -> Polynomial where E: Copy + Send + Sync, - F: FieldExt, + F: Field, B: BasisOps, { // Traverse `ast` to collect the used leaves. @@ -192,7 +192,7 @@ impl Evaluator { }) .collect(); - struct AstContext<'a, E, F: FieldExt, B: Basis> { + struct AstContext<'a, E, F: Field, B: Basis> { domain: &'a EvaluationDomain, poly_len: usize, chunk_size: usize, @@ -200,7 +200,7 @@ impl Evaluator { leaves: &'a HashMap, &'a [F]>, } - fn recurse( + fn recurse( ast: &Ast, ctx: &AstContext<'_, E, F, B>, ) -> Vec { @@ -230,7 +230,7 @@ impl Evaluator { lhs } Ast::DistributePowers(terms, base) => terms.iter().fold( - B::constant_term(ctx.poly_len, ctx.chunk_size, ctx.chunk_index, F::zero()), + B::constant_term(ctx.poly_len, ctx.chunk_size, ctx.chunk_index, F::ZERO), |mut acc, term| { let term = recurse(term, ctx); for (acc, term) in acc.iter_mut().zip(term) { @@ -347,7 +347,7 @@ impl From> for Ast { impl Ast { pub(crate) fn one() -> Self { - Self::ConstantTerm(F::one()) + Self::ConstantTerm(F::ONE) } } @@ -355,7 +355,7 @@ impl Neg for Ast { type Output = Ast; fn neg(self) -> Self::Output { - Ast::Scale(Arc::new(self), -F::one()) + Ast::Scale(Arc::new(self), -F::ONE) } } @@ -489,21 +489,21 @@ impl MulAssign for Ast { /// Operations which can be performed over a given basis. pub(crate) trait BasisOps: Basis { - fn empty_poly(domain: &EvaluationDomain) -> Polynomial; - fn constant_term( + fn empty_poly(domain: &EvaluationDomain) -> Polynomial; + fn constant_term( poly_len: usize, chunk_size: usize, chunk_index: usize, scalar: F, ) -> Vec; - fn linear_term( + fn linear_term( domain: &EvaluationDomain, poly_len: usize, chunk_size: usize, chunk_index: usize, scalar: F, ) -> Vec; - fn rotate( + fn rotate( domain: &EvaluationDomain, poly: &Polynomial, rotation: Rotation, @@ -511,31 +511,31 @@ pub(crate) trait BasisOps: Basis { } impl BasisOps for Coeff { - fn empty_poly(domain: &EvaluationDomain) -> Polynomial { + fn empty_poly(domain: &EvaluationDomain) -> Polynomial { domain.empty_coeff() } - fn constant_term( + fn constant_term( poly_len: usize, chunk_size: usize, chunk_index: usize, scalar: F, ) -> Vec { - let mut chunk = vec![F::zero(); cmp::min(chunk_size, poly_len - chunk_size * chunk_index)]; + let mut chunk = vec![F::ZERO; cmp::min(chunk_size, poly_len - chunk_size * chunk_index)]; if chunk_index == 0 { chunk[0] = scalar; } chunk } - fn linear_term( + fn linear_term( _: &EvaluationDomain, poly_len: usize, chunk_size: usize, chunk_index: usize, scalar: F, ) -> Vec { - let mut chunk = vec![F::zero(); cmp::min(chunk_size, poly_len - chunk_size * chunk_index)]; + let mut chunk = vec![F::ZERO; cmp::min(chunk_size, poly_len - chunk_size * chunk_index)]; // If the chunk size is 1 (e.g. if we have a small k and many threads), then the // linear coefficient is the second chunk. Otherwise, the chunk size is greater // than one, and the linear coefficient is the second element of the first chunk. @@ -550,7 +550,7 @@ impl BasisOps for Coeff { chunk } - fn rotate( + fn rotate( _: &EvaluationDomain, _: &Polynomial, _: Rotation, @@ -560,11 +560,11 @@ impl BasisOps for Coeff { } impl BasisOps for LagrangeCoeff { - fn empty_poly(domain: &EvaluationDomain) -> Polynomial { + fn empty_poly(domain: &EvaluationDomain) -> Polynomial { domain.empty_lagrange() } - fn constant_term( + fn constant_term( poly_len: usize, chunk_size: usize, chunk_index: usize, @@ -573,7 +573,7 @@ impl BasisOps for LagrangeCoeff { vec![scalar; cmp::min(chunk_size, poly_len - chunk_size * chunk_index)] } - fn linear_term( + fn linear_term( domain: &EvaluationDomain, poly_len: usize, chunk_size: usize, @@ -592,7 +592,7 @@ impl BasisOps for LagrangeCoeff { .collect() } - fn rotate( + fn rotate( _: &EvaluationDomain, poly: &Polynomial, rotation: Rotation, @@ -602,11 +602,11 @@ impl BasisOps for LagrangeCoeff { } impl BasisOps for ExtendedLagrangeCoeff { - fn empty_poly(domain: &EvaluationDomain) -> Polynomial { + fn empty_poly(domain: &EvaluationDomain) -> Polynomial { domain.empty_extended() } - fn constant_term( + fn constant_term( poly_len: usize, chunk_size: usize, chunk_index: usize, @@ -615,7 +615,7 @@ impl BasisOps for ExtendedLagrangeCoeff { vec![scalar; cmp::min(chunk_size, poly_len - chunk_size * chunk_index)] } - fn linear_term( + fn linear_term( domain: &EvaluationDomain, poly_len: usize, chunk_size: usize, @@ -637,7 +637,7 @@ impl BasisOps for ExtendedLagrangeCoeff { .collect() } - fn rotate( + fn rotate( domain: &EvaluationDomain, poly: &Polynomial, rotation: Rotation, diff --git a/halo2_proofs/src/poly/ipa/commitment.rs b/halo2_proofs/src/poly/ipa/commitment.rs index 9060e8315c..f9b4ad059b 100644 --- a/halo2_proofs/src/poly/ipa/commitment.rs +++ b/halo2_proofs/src/poly/ipa/commitment.rs @@ -4,7 +4,7 @@ //! [halo]: https://eprint.iacr.org/2019/1021 use crate::arithmetic::{ - best_fft, best_multiexp, g_to_lagrange, parallelize, CurveAffine, CurveExt, FieldExt, Group, + best_fft, best_multiexp, g_to_lagrange, parallelize, CurveAffine, CurveExt, }; use crate::helpers::CurveRead; use crate::poly::commitment::{Blind, CommitmentScheme, Params, ParamsProver, ParamsVerifier, MSM}; @@ -12,7 +12,7 @@ use crate::poly::ipa::msm::MSMIPA; use crate::poly::{Coeff, LagrangeCoeff, Polynomial}; use ff::{Field, PrimeField}; -use group::{prime::PrimeCurveAffine, Curve, Group as _}; +use group::{prime::PrimeCurveAffine, Curve, Group}; use std::marker::PhantomData; use std::ops::{Add, AddAssign, Mul, MulAssign}; @@ -234,9 +234,7 @@ impl<'params, C: CurveAffine> ParamsProver<'params, C> for ParamsIPA { #[cfg(test)] mod test { - use crate::arithmetic::{ - best_fft, best_multiexp, parallelize, CurveAffine, CurveExt, FieldExt, Group, - }; + use crate::arithmetic::{best_fft, best_multiexp, parallelize, CurveAffine, CurveExt}; use crate::helpers::CurveRead; use crate::poly::commitment::ParamsProver; use crate::poly::commitment::{Blind, CommitmentScheme, Params, MSM}; @@ -245,7 +243,7 @@ mod test { use crate::poly::{Coeff, LagrangeCoeff, Polynomial}; use ff::{Field, PrimeField}; - use group::{prime::PrimeCurveAffine, Curve, Group as _}; + use group::{prime::PrimeCurveAffine, Curve, Group}; use std::marker::PhantomData; use std::ops::{Add, AddAssign, Mul, MulAssign}; @@ -309,7 +307,7 @@ mod test { use rand_core::OsRng; use super::super::commitment::{Blind, Params}; - use crate::arithmetic::{eval_polynomial, FieldExt}; + use crate::arithmetic::eval_polynomial; use crate::halo2curves::pasta::{EpAffine, Fq}; use crate::poly::EvaluationDomain; use crate::transcript::{ @@ -363,7 +361,7 @@ mod test { assert_eq!(v, v_prime); let mut commitment_msm = MSMIPA::new(¶ms); - commitment_msm.append_term(Field::one(), p.into()); + commitment_msm.append_term(Fq::one(), p.into()); let guard = verify_proof(¶ms, commitment_msm, &mut transcript, *x, v).unwrap(); let ch_verifier = transcript.squeeze_challenge(); diff --git a/halo2_proofs/src/poly/ipa/commitment/prover.rs b/halo2_proofs/src/poly/ipa/commitment/prover.rs index 3b22b31b36..d176987c96 100644 --- a/halo2_proofs/src/poly/ipa/commitment/prover.rs +++ b/halo2_proofs/src/poly/ipa/commitment/prover.rs @@ -3,7 +3,7 @@ use rand_core::RngCore; use super::{Params, ParamsIPA}; use crate::arithmetic::{ - best_multiexp, compute_inner_product, eval_polynomial, parallelize, CurveAffine, FieldExt, + best_multiexp, compute_inner_product, eval_polynomial, parallelize, CurveAffine, }; use crate::poly::commitment::ParamsProver; @@ -87,7 +87,7 @@ pub fn create_proof< // `p_prime` and `b` is the evaluation of the polynomial at `x_3`. let mut b = Vec::with_capacity(1 << params.k); { - let mut cur = C::Scalar::one(); + let mut cur = C::Scalar::ONE; for _ in 0..(1 << params.k) { b.push(cur); cur *= &x_3; diff --git a/halo2_proofs/src/poly/ipa/commitment/verifier.rs b/halo2_proofs/src/poly/ipa/commitment/verifier.rs index b3b30e0b4b..0b60842899 100644 --- a/halo2_proofs/src/poly/ipa/commitment/verifier.rs +++ b/halo2_proofs/src/poly/ipa/commitment/verifier.rs @@ -96,10 +96,10 @@ pub fn verify_proof<'params, C: CurveAffine, E: EncodedChallenge, T: Transcri /// Computes $\prod\limits_{i=0}^{k-1} (1 + u_{k - 1 - i} x^{2^i})$. fn compute_b(x: F, u: &[F]) -> F { - let mut tmp = F::one(); + let mut tmp = F::ONE; let mut cur = x; for u_j in u.iter().rev() { - tmp *= F::one() + &(*u_j * &cur); + tmp *= F::ONE + &(*u_j * &cur); cur *= cur; } tmp diff --git a/halo2_proofs/src/poly/ipa/msm.rs b/halo2_proofs/src/poly/ipa/msm.rs index 63f994b46e..3316e25337 100644 --- a/halo2_proofs/src/poly/ipa/msm.rs +++ b/halo2_proofs/src/poly/ipa/msm.rs @@ -191,7 +191,7 @@ impl<'a, C: CurveAffine> MSMIPA<'a, C> { if let Some(g_scalars) = self.g_scalars.as_mut() { g_scalars[0] += &constant; } else { - let mut g_scalars = vec![C::Scalar::zero(); self.params.n as usize]; + let mut g_scalars = vec![C::Scalar::ZERO; self.params.n as usize]; g_scalars[0] += &constant; self.g_scalars = Some(g_scalars); } diff --git a/halo2_proofs/src/poly/ipa/multiopen.rs b/halo2_proofs/src/poly/ipa/multiopen.rs index b724139a8f..fd6aa78544 100644 --- a/halo2_proofs/src/poly/ipa/multiopen.rs +++ b/halo2_proofs/src/poly/ipa/multiopen.rs @@ -3,14 +3,10 @@ //! //! [halo]: https://eprint.iacr.org/2019/1021 -use std::collections::{BTreeMap, BTreeSet}; - use super::*; -use crate::{ - arithmetic::{CurveAffine, FieldExt}, - poly::query::Query, - transcript::ChallengeScalar, -}; +use crate::{arithmetic::CurveAffine, poly::query::Query, transcript::ChallengeScalar}; +use ff::Field; +use std::collections::{BTreeMap, BTreeSet}; mod prover; mod verifier; @@ -63,7 +59,7 @@ type IntermediateSets = ( Vec>, ); -fn construct_intermediate_sets>(queries: I) -> IntermediateSets +fn construct_intermediate_sets>(queries: I) -> IntermediateSets where I: IntoIterator + Clone, { diff --git a/halo2_proofs/src/poly/ipa/multiopen/prover.rs b/halo2_proofs/src/poly/ipa/multiopen/prover.rs index bba038c93a..6d65e7ae64 100644 --- a/halo2_proofs/src/poly/ipa/multiopen/prover.rs +++ b/halo2_proofs/src/poly/ipa/multiopen/prover.rs @@ -1,7 +1,7 @@ use super::{ construct_intermediate_sets, ChallengeX1, ChallengeX2, ChallengeX3, ChallengeX4, Query, }; -use crate::arithmetic::{eval_polynomial, kate_division, CurveAffine, FieldExt}; +use crate::arithmetic::{eval_polynomial, kate_division, CurveAffine}; use crate::poly::commitment::ParamsProver; use crate::poly::commitment::{Blind, Params, Prover}; use crate::poly::ipa::commitment::{self, IPACommitmentScheme, ParamsIPA}; @@ -47,7 +47,7 @@ impl<'params, C: CurveAffine> Prover<'params, IPACommitmentScheme> for Prover // Collapse openings at same point sets together into single openings using // x_1 challenge. let mut q_polys: Vec>> = vec![None; point_sets.len()]; - let mut q_blinds = vec![Blind(C::Scalar::zero()); point_sets.len()]; + let mut q_blinds = vec![Blind(C::Scalar::ZERO); point_sets.len()]; { let mut accumulate = |set_idx: usize, @@ -80,7 +80,7 @@ impl<'params, C: CurveAffine> Prover<'params, IPACommitmentScheme> for Prover .fold(poly.clone().unwrap().values, |poly, point| { kate_division(&poly, *point) }); - poly.resize(self.params.n as usize, C::Scalar::zero()); + poly.resize(self.params.n as usize, C::Scalar::ZERO); let poly = Polynomial { values: poly, _marker: PhantomData, diff --git a/halo2_proofs/src/poly/ipa/multiopen/verifier.rs b/halo2_proofs/src/poly/ipa/multiopen/verifier.rs index ff4c7626f6..391f89e15b 100644 --- a/halo2_proofs/src/poly/ipa/multiopen/verifier.rs +++ b/halo2_proofs/src/poly/ipa/multiopen/verifier.rs @@ -8,7 +8,7 @@ use rand_core::RngCore; use super::{ construct_intermediate_sets, ChallengeX1, ChallengeX2, ChallengeX3, ChallengeX4, Query, }; -use crate::arithmetic::{eval_polynomial, lagrange_interpolate, CurveAffine, FieldExt}; +use crate::arithmetic::{eval_polynomial, lagrange_interpolate, CurveAffine}; use crate::poly::commitment::{Params, Verifier, MSM}; use crate::poly::ipa::commitment::{IPACommitmentScheme, ParamsIPA, ParamsVerifierIPA}; use crate::poly::ipa::msm::MSMIPA; @@ -63,7 +63,7 @@ impl<'params, C: CurveAffine> Verifier<'params, IPACommitmentScheme> // while the inner vec corresponds to the points in a particular set. let mut q_eval_sets = Vec::with_capacity(point_sets.len()); for point_set in point_sets.iter() { - q_eval_sets.push(vec![C::Scalar::zero(); point_set.len()]); + q_eval_sets.push(vec![C::Scalar::ZERO; point_set.len()]); } { let mut accumulate = |set_idx: usize, @@ -72,7 +72,7 @@ impl<'params, C: CurveAffine> Verifier<'params, IPACommitmentScheme> q_commitments[set_idx].scale(*x_1); match new_commitment { CommitmentReference::Commitment(c) => { - q_commitments[set_idx].append_term(C::Scalar::one(), (*c).into()); + q_commitments[set_idx].append_term(C::Scalar::ONE, (*c).into()); } CommitmentReference::MSM(msm) => { q_commitments[set_idx].add_msm(msm); @@ -116,7 +116,7 @@ impl<'params, C: CurveAffine> Verifier<'params, IPACommitmentScheme> .zip(q_eval_sets.iter()) .zip(u.iter()) .fold( - C::Scalar::zero(), + C::Scalar::ZERO, |msm_eval, ((points, evals), proof_eval)| { let r_poly = lagrange_interpolate(points, evals); let r_eval = eval_polynomial(&r_poly, *x_3); @@ -132,7 +132,7 @@ impl<'params, C: CurveAffine> Verifier<'params, IPACommitmentScheme> let x_4: ChallengeX4<_> = transcript.squeeze_challenge_scalar(); // Compute the final commitment that has to be opened - msm.append_term(C::Scalar::one(), q_prime_commitment.into()); + msm.append_term(C::Scalar::ONE, q_prime_commitment.into()); let (msm, v) = q_commitments.into_iter().zip(u.iter()).fold( (msm, msm_eval), |(mut msm, msm_eval), (q_commitment, q_eval)| { diff --git a/halo2_proofs/src/poly/ipa/strategy.rs b/halo2_proofs/src/poly/ipa/strategy.rs index 6f3b4b7228..c8d385f90c 100644 --- a/halo2_proofs/src/poly/ipa/strategy.rs +++ b/halo2_proofs/src/poly/ipa/strategy.rs @@ -70,7 +70,7 @@ impl<'params, C: CurveAffine> GuardIPA<'params, C> { /// Computes G = ⟨s, params.g⟩ pub fn compute_g(&self) -> C { - let s = compute_s(&self.u, C::Scalar::one()); + let s = compute_s(&self.u, C::Scalar::ONE); best_multiexp(&s, &self.msm.params.g).to_affine() } @@ -160,7 +160,7 @@ impl<'params, C: CurveAffine> /// Computes the coefficients of $g(X) = \prod\limits_{i=0}^{k-1} (1 + u_{k - 1 - i} X^{2^i})$. fn compute_s(u: &[F], init: F) -> Vec { assert!(!u.is_empty()); - let mut v = vec![F::zero(); 1 << u.len()]; + let mut v = vec![F::ZERO; 1 << u.len()]; v[0] = init; for (len, u_j) in u.iter().rev().enumerate().map(|(i, u_j)| (1 << i, u_j)) { diff --git a/halo2_proofs/src/poly/kzg/commitment.rs b/halo2_proofs/src/poly/kzg/commitment.rs index 08665667b3..f9fc508c6a 100644 --- a/halo2_proofs/src/poly/kzg/commitment.rs +++ b/halo2_proofs/src/poly/kzg/commitment.rs @@ -1,5 +1,5 @@ use crate::arithmetic::{ - best_fft, best_multiexp, g_to_lagrange, parallelize, CurveAffine, CurveExt, FieldExt, Group, + best_fft, best_multiexp, g_to_lagrange, parallelize, CurveAffine, CurveExt, }; use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::{Blind, CommitmentScheme, Params, ParamsProver, ParamsVerifier, MSM}; @@ -7,7 +7,7 @@ use crate::poly::{Coeff, LagrangeCoeff, Polynomial}; use crate::SerdeFormat; use ff::{Field, PrimeField}; -use group::{prime::PrimeCurveAffine, Curve, Group as _}; +use group::{prime::PrimeCurveAffine, Curve, Group}; use halo2curves::pairing::Engine; use rand_core::{OsRng, RngCore}; use std::fmt::Debug; @@ -37,6 +37,7 @@ pub struct KZGCommitmentScheme { impl CommitmentScheme for KZGCommitmentScheme where + E::Scalar: PrimeField, E::G1Affine: SerdeCurveAffine, E::G2Affine: SerdeCurveAffine, { @@ -55,7 +56,10 @@ where } } -impl ParamsKZG { +impl ParamsKZG +where + E::Scalar: PrimeField, +{ /// Initializes parameters for the curve, draws toxic secret from given rng. /// MUST NOT be used in production. pub fn setup(k: u32, rng: R) -> Self { @@ -80,7 +84,7 @@ impl ParamsKZG { // Calculate g = [G1, [s] G1, [s^2] G1, ..., [s^(n-1)] G1] in parallel. let g1 = E::G1Affine::generator(); - let mut g_projective = vec![E::G1::group_zero(); n as usize]; + let mut g_projective = vec![E::G1::identity(); n as usize]; parallelize(&mut g_projective, |g, start| { let mut current_g: E::G1 = g1.into(); current_g *= s.pow_vartime([start as u64]); @@ -98,14 +102,14 @@ impl ParamsKZG { g }; - let mut g_lagrange_projective = vec![E::G1::group_zero(); n as usize]; + let mut g_lagrange_projective = vec![E::G1::identity(); n as usize]; let mut root = E::Scalar::ROOT_OF_UNITY_INV.invert().unwrap(); for _ in k..E::Scalar::S { root = root.square(); } let n_inv = Option::::from(E::Scalar::from(n).invert()) .expect("inversion should be ok for n = 1< = ParamsKZG; impl<'params, E: Engine + Debug> Params<'params, E::G1Affine> for ParamsKZG where + E::Scalar: PrimeField, E::G1Affine: SerdeCurveAffine, E::G2Affine: SerdeCurveAffine, { @@ -316,6 +321,7 @@ where impl<'params, E: Engine + Debug> ParamsVerifier<'params, E::G1Affine> for ParamsKZG where + E::Scalar: PrimeField, E::G1Affine: SerdeCurveAffine, E::G2Affine: SerdeCurveAffine, { @@ -323,6 +329,7 @@ where impl<'params, E: Engine + Debug> ParamsProver<'params, E::G1Affine> for ParamsKZG where + E::Scalar: PrimeField, E::G1Affine: SerdeCurveAffine, E::G2Affine: SerdeCurveAffine, { @@ -352,9 +359,7 @@ where #[cfg(test)] mod test { - use crate::arithmetic::{ - best_fft, best_multiexp, parallelize, CurveAffine, CurveExt, FieldExt, Group, - }; + use crate::arithmetic::{best_fft, best_multiexp, parallelize, CurveAffine, CurveExt}; use crate::poly::commitment::ParamsProver; use crate::poly::commitment::{Blind, CommitmentScheme, Params, MSM}; use crate::poly::kzg::commitment::{ParamsKZG, ParamsVerifierKZG}; @@ -363,7 +368,7 @@ mod test { use crate::poly::{Coeff, LagrangeCoeff, Polynomial}; use ff::{Field, PrimeField}; - use group::{prime::PrimeCurveAffine, Curve, Group as _}; + use group::{prime::PrimeCurveAffine, Curve, Group}; use halo2curves::bn256::G1Affine; use std::marker::PhantomData; use std::ops::{Add, AddAssign, Mul, MulAssign}; @@ -403,7 +408,7 @@ mod test { use rand_core::OsRng; use super::super::commitment::{Blind, Params}; - use crate::arithmetic::{eval_polynomial, FieldExt}; + use crate::arithmetic::eval_polynomial; use crate::halo2curves::bn256::{Bn256, Fr}; use crate::poly::EvaluationDomain; diff --git a/halo2_proofs/src/poly/kzg/msm.rs b/halo2_proofs/src/poly/kzg/msm.rs index 6cc90a5103..abd8309f56 100644 --- a/halo2_proofs/src/poly/kzg/msm.rs +++ b/halo2_proofs/src/poly/kzg/msm.rs @@ -27,7 +27,7 @@ impl MSMKZG { /// Prepares all scalars in the MSM to linear combination pub fn combine_with_base(&mut self, base: E::Scalar) { use ff::Field; - let mut acc = E::Scalar::one(); + let mut acc = E::Scalar::ONE; if !self.scalars.is_empty() { for scalar in self.scalars.iter_mut().rev() { *scalar *= &acc; diff --git a/halo2_proofs/src/poly/kzg/multiopen/gwc.rs b/halo2_proofs/src/poly/kzg/multiopen/gwc.rs index 4869238ae7..8e7d742fc0 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/gwc.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/gwc.rs @@ -5,7 +5,7 @@ pub use prover::ProverGWC; pub use verifier::VerifierGWC; use crate::{ - arithmetic::{eval_polynomial, CurveAffine, FieldExt}, + arithmetic::{eval_polynomial, CurveAffine}, poly::{ commitment::{Params, ParamsVerifier}, query::Query, @@ -13,7 +13,7 @@ use crate::{ }, transcript::ChallengeScalar, }; - +use ff::Field; use std::{ collections::{BTreeMap, BTreeSet}, marker::PhantomData, @@ -27,13 +27,13 @@ type ChallengeU = ChallengeScalar; struct V {} type ChallengeV = ChallengeScalar; -struct CommitmentData> { +struct CommitmentData> { queries: Vec, point: F, _marker: PhantomData, } -fn construct_intermediate_sets>(queries: I) -> Vec> +fn construct_intermediate_sets>(queries: I) -> Vec> where I: IntoIterator + Clone, { diff --git a/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs b/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs index ee8a549a00..d5d977fb2d 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs @@ -1,5 +1,5 @@ use super::{construct_intermediate_sets, ChallengeV, Query}; -use crate::arithmetic::{eval_polynomial, kate_division, powers, CurveAffine, FieldExt}; +use crate::arithmetic::{eval_polynomial, kate_division, powers, CurveAffine}; use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::ParamsProver; use crate::poly::commitment::Prover; @@ -12,7 +12,7 @@ use crate::poly::{ }; use crate::transcript::{EncodedChallenge, TranscriptWrite}; -use ff::Field; +use ff::{Field, PrimeField}; use group::Curve; use halo2curves::pairing::Engine; use rand_core::RngCore; @@ -29,6 +29,7 @@ pub struct ProverGWC<'params, E: Engine> { /// Create a multi-opening proof impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> for ProverGWC<'params, E> where + E::Scalar: PrimeField, E::G1Affine: SerdeCurveAffine, E::G2Affine: SerdeCurveAffine, { diff --git a/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs b/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs index 22fa139480..1d0c9468b4 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs @@ -3,7 +3,7 @@ use std::io::Read; use std::marker::PhantomData; use super::{construct_intermediate_sets, ChallengeU, ChallengeV}; -use crate::arithmetic::{eval_polynomial, lagrange_interpolate, powers, CurveAffine, FieldExt}; +use crate::arithmetic::{eval_polynomial, lagrange_interpolate, powers, CurveAffine}; use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::Verifier; use crate::poly::commitment::MSM; @@ -19,7 +19,7 @@ use crate::poly::{ }; use crate::transcript::{EncodedChallenge, TranscriptRead}; -use ff::Field; +use ff::{Field, PrimeField}; use group::Group; use halo2curves::pairing::{Engine, MillerLoopResult, MultiMillerLoop}; use rand_core::OsRng; @@ -33,6 +33,7 @@ pub struct VerifierGWC<'params, E: Engine> { impl<'params, E> Verifier<'params, KZGCommitmentScheme> for VerifierGWC<'params, E> where E: MultiMillerLoop + Debug, + E::Scalar: PrimeField, E::G1Affine: SerdeCurveAffine, E::G2Affine: SerdeCurveAffine, { @@ -70,7 +71,7 @@ where let u: ChallengeU<_> = transcript.squeeze_challenge_scalar(); let mut commitment_multi = MSMKZG::::new(); - let mut eval_multi = E::Scalar::zero(); + let mut eval_multi = E::Scalar::ZERO; let mut witness = MSMKZG::::new(); let mut witness_with_aux = MSMKZG::::new(); diff --git a/halo2_proofs/src/poly/kzg/multiopen/shplonk.rs b/halo2_proofs/src/poly/kzg/multiopen/shplonk.rs index 0b1a2492b1..d14132fb43 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/shplonk.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/shplonk.rs @@ -1,20 +1,20 @@ mod prover; mod verifier; -pub use prover::ProverSHPLONK; -pub use verifier::VerifierSHPLONK; - use crate::{ - arithmetic::{eval_polynomial, lagrange_interpolate, CurveAffine, FieldExt}, + arithmetic::{eval_polynomial, lagrange_interpolate, CurveAffine}, poly::{query::Query, Coeff, Polynomial}, transcript::ChallengeScalar, }; +use ff::Field; +pub use prover::ProverSHPLONK; use rayon::prelude::*; use std::{ collections::{btree_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet}, marker::PhantomData, sync::Arc, }; +pub use verifier::VerifierSHPLONK; #[derive(Clone, Copy, Debug)] struct U {} @@ -29,9 +29,9 @@ struct Y {} type ChallengeY = ChallengeScalar; #[derive(Debug, Clone, PartialEq)] -struct Commitment((T, Vec)); +struct Commitment((T, Vec)); -impl Commitment { +impl Commitment { fn get(&self) -> T { self.0 .0.clone() } @@ -42,18 +42,18 @@ impl Commitment { } #[derive(Debug, Clone, PartialEq)] -struct RotationSet { +struct RotationSet { commitments: Vec>, points: Vec, } #[derive(Debug, PartialEq)] -struct IntermediateSets> { +struct IntermediateSets> { rotation_sets: Vec>, super_point_set: BTreeSet, } -fn construct_intermediate_sets>( +fn construct_intermediate_sets>( queries: I, ) -> IntermediateSets where @@ -157,8 +157,8 @@ mod proptests { use super::{construct_intermediate_sets, Commitment, IntermediateSets}; use crate::poly::Rotation; - use halo2curves::{pasta::Fp, FieldExt}; - + use ff::{Field, FromUniformBytes}; + use halo2curves::pasta::Fp; use std::collections::BTreeMap; use std::convert::TryFrom; @@ -190,7 +190,7 @@ mod proptests { fn arb_point()( bytes in vec(any::(), 64) ) -> Fp { - Fp::from_bytes_wide(&<[u8; 64]>::try_from(bytes).unwrap()) + Fp::from_uniform_bytes(&<[u8; 64]>::try_from(bytes).unwrap()) } } diff --git a/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs b/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs index 3206364b8f..bb50eafe58 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs @@ -3,7 +3,7 @@ use super::{ }; use crate::arithmetic::{ eval_polynomial, evaluate_vanishing_polynomial, kate_division, lagrange_interpolate, - parallelize, powers, CurveAffine, FieldExt, + parallelize, powers, CurveAffine, }; use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::{Blind, ParamsProver, Prover}; @@ -13,7 +13,7 @@ use crate::poly::Rotation; use crate::poly::{commitment::Params, Coeff, Polynomial}; use crate::transcript::{EncodedChallenge, TranscriptWrite}; -use ff::Field; +use ff::{Field, PrimeField}; use group::Curve; use halo2curves::pairing::Engine; use rand_core::RngCore; @@ -23,7 +23,7 @@ use std::io::{self, Write}; use std::marker::PhantomData; use std::ops::MulAssign; -fn div_by_vanishing(poly: Polynomial, roots: &[F]) -> Vec { +fn div_by_vanishing(poly: Polynomial, roots: &[F]) -> Vec { let poly = roots .iter() .fold(poly.values, |poly, point| kate_division(&poly, *point)); @@ -105,6 +105,7 @@ impl<'a, E: Engine> ProverSHPLONK<'a, E> { impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> for ProverSHPLONK<'params, E> where + E::Scalar: Ord + PrimeField, E::G1Affine: SerdeCurveAffine, E::G2Affine: SerdeCurveAffine, { @@ -162,7 +163,7 @@ where // Q_i(X) = N_i(X) / Z_i(X) where // Z_i(X) = (x - r_i_0) * (x - r_i_1) * ... let mut poly = div_by_vanishing(n_x, points); - poly.resize(self.params.n as usize, E::Scalar::zero()); + poly.resize(self.params.n as usize, E::Scalar::ZERO); Polynomial { values: poly, @@ -261,7 +262,7 @@ where #[cfg(debug_assertions)] { let must_be_zero = eval_polynomial(&l_x.values[..], *u); - assert_eq!(must_be_zero, E::Scalar::zero()); + assert_eq!(must_be_zero, E::Scalar::ZERO); } let mut h_x = div_by_vanishing(l_x, &[*u]); diff --git a/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs b/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs index 11ffa880ef..d1d1660e9c 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs @@ -5,7 +5,6 @@ use super::ChallengeY; use super::{construct_intermediate_sets, ChallengeU, ChallengeV}; use crate::arithmetic::{ eval_polynomial, evaluate_vanishing_polynomial, lagrange_interpolate, powers, CurveAffine, - FieldExt, }; use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::Verifier; @@ -22,7 +21,7 @@ use crate::poly::{ Error, }; use crate::transcript::{EncodedChallenge, TranscriptRead}; -use ff::Field; +use ff::{Field, PrimeField}; use group::Group; use halo2curves::pairing::{Engine, MillerLoopResult, MultiMillerLoop}; use rand_core::OsRng; @@ -37,6 +36,7 @@ pub struct VerifierSHPLONK<'params, E: Engine> { impl<'params, E> Verifier<'params, KZGCommitmentScheme> for VerifierSHPLONK<'params, E> where E: MultiMillerLoop + Debug, + E::Scalar: PrimeField + Ord, E::G1Affine: SerdeCurveAffine, E::G2Affine: SerdeCurveAffine, { @@ -77,8 +77,8 @@ where let u: ChallengeU<_> = transcript.squeeze_challenge_scalar(); let h2 = transcript.read_point().map_err(|_| Error::SamplingError)?; - let (mut z_0_diff_inverse, mut z_0) = (E::Scalar::zero(), E::Scalar::zero()); - let (mut outer_msm, mut r_outer_acc) = (PreMSM::::new(), E::Scalar::zero()); + let (mut z_0_diff_inverse, mut z_0) = (E::Scalar::ZERO, E::Scalar::ZERO); + let (mut outer_msm, mut r_outer_acc) = (PreMSM::::new(), E::Scalar::ZERO); for (i, (rotation_set, power_of_v)) in rotation_sets.iter().zip(powers(*v)).enumerate() { let diffs: Vec = super_point_set .iter() @@ -91,7 +91,7 @@ where if i == 0 { z_0 = evaluate_vanishing_polynomial(&rotation_set.points[..], *u); z_0_diff_inverse = z_diff_i.invert().unwrap(); - z_diff_i = E::Scalar::one(); + z_diff_i = E::Scalar::ONE; } else { z_diff_i.mul_assign(z_0_diff_inverse); } @@ -137,9 +137,7 @@ where outer_msm.append_term(-z_0, h1.into()); outer_msm.append_term(*u, h2.into()); - msm_accumulator - .left - .append_term(E::Scalar::one(), h2.into()); + msm_accumulator.left.append_term(E::Scalar::ONE, h2.into()); msm_accumulator.right.add_msm(&outer_msm); diff --git a/halo2_proofs/src/poly/kzg/strategy.rs b/halo2_proofs/src/poly/kzg/strategy.rs index ca4b4fb18a..15cdba2069 100644 --- a/halo2_proofs/src/poly/kzg/strategy.rs +++ b/halo2_proofs/src/poly/kzg/strategy.rs @@ -15,7 +15,7 @@ use crate::{ }, transcript::{EncodedChallenge, TranscriptRead}, }; -use ff::Field; +use ff::{Field, PrimeField}; use group::Group; use halo2curves::{ pairing::{Engine, MillerLoopResult, MultiMillerLoop}, @@ -32,6 +32,7 @@ pub struct GuardKZG<'params, E: MultiMillerLoop + Debug> { /// Define accumulator type as `DualMSM` impl<'params, E> Guard> for GuardKZG<'params, E> where + E::Scalar: PrimeField, E: MultiMillerLoop + Debug, E::G1Affine: SerdeCurveAffine, E::G2Affine: SerdeCurveAffine, @@ -92,6 +93,7 @@ impl< >, > VerificationStrategy<'params, KZGCommitmentScheme, V> for AccumulatorStrategy<'params, E> where + E::Scalar: PrimeField, E::G1Affine: SerdeCurveAffine, E::G2Affine: SerdeCurveAffine, { @@ -130,6 +132,7 @@ impl< >, > VerificationStrategy<'params, KZGCommitmentScheme, V> for SingleStrategy<'params, E> where + E::Scalar: PrimeField, E::G1Affine: SerdeCurveAffine, E::G2Affine: SerdeCurveAffine, { diff --git a/halo2_proofs/src/poly/multiopen_test.rs b/halo2_proofs/src/poly/multiopen_test.rs index 8dd563b15a..d57243f712 100644 --- a/halo2_proofs/src/poly/multiopen_test.rs +++ b/halo2_proofs/src/poly/multiopen_test.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod test { - use crate::arithmetic::{eval_polynomial, FieldExt}; + use crate::arithmetic::eval_polynomial; use crate::plonk::Error; use crate::poly::commitment::ParamsProver; use crate::poly::commitment::{Blind, ParamsVerifier, MSM}; @@ -17,7 +17,7 @@ mod test { Keccak256Write, TranscriptRead, TranscriptReadBuffer, TranscriptWrite, TranscriptWriterBuffer, }; - use ff::Field; + use ff::{Field, PrimeField, WithSmallOrderMulGroup}; use group::{Curve, Group}; use halo2curves::CurveAffine; use rand_core::{OsRng, RngCore}; @@ -233,28 +233,25 @@ mod test { T: TranscriptWriterBuffer, Scheme::Curve, E>, >( params: &'params Scheme::ParamsProver, - ) -> Vec { + ) -> Vec + where + Scheme::Scalar: WithSmallOrderMulGroup<3>, + { let domain = EvaluationDomain::new(1, params.k()); let mut ax = domain.empty_coeff(); for (i, a) in ax.iter_mut().enumerate() { - *a = <::Curve as CurveAffine>::ScalarExt::from( - 10 + i as u64, - ); + *a = <::Scalar>::from(10 + i as u64); } let mut bx = domain.empty_coeff(); for (i, a) in bx.iter_mut().enumerate() { - *a = <::Curve as CurveAffine>::ScalarExt::from( - 100 + i as u64, - ); + *a = <::Scalar>::from(100 + i as u64); } let mut cx = domain.empty_coeff(); for (i, a) in cx.iter_mut().enumerate() { - *a = <::Curve as CurveAffine>::ScalarExt::from( - 100 + i as u64, - ); + *a = <::Scalar>::from(100 + i as u64); } let mut transcript = T::init(vec![]); diff --git a/halo2_proofs/src/transcript.rs b/halo2_proofs/src/transcript.rs index 8907f9779d..166b0e6f90 100644 --- a/halo2_proofs/src/transcript.rs +++ b/halo2_proofs/src/transcript.rs @@ -2,11 +2,11 @@ //! transcripts. use blake2b_simd::{Params as Blake2bParams, State as Blake2bState}; -use group::ff::PrimeField; +use group::ff::{FromUniformBytes, PrimeField}; use sha3::{Digest, Keccak256}; use std::convert::TryInto; -use halo2curves::{Coordinates, CurveAffine, FieldExt}; +use halo2curves::{Coordinates, CurveAffine}; use std::io::{self, Read, Write}; use std::marker::PhantomData; @@ -119,6 +119,8 @@ pub struct Keccak256Read> { impl TranscriptReadBuffer> for Blake2bRead> +where + C::Scalar: FromUniformBytes<64>, { /// Initialize a transcript given an input buffer. fn init(reader: R) -> Self { @@ -135,6 +137,8 @@ impl TranscriptReadBuffer> impl TranscriptReadBuffer> for Keccak256Read> +where + C::Scalar: FromUniformBytes<64>, { /// Initialize a transcript given an input buffer. fn init(reader: R) -> Self { @@ -150,6 +154,8 @@ impl TranscriptReadBuffer> impl TranscriptRead> for Blake2bRead> +where + C::Scalar: FromUniformBytes<64>, { fn read_point(&mut self) -> io::Result { let mut compressed = C::Repr::default(); @@ -179,6 +185,8 @@ impl TranscriptRead> impl TranscriptRead> for Keccak256Read> +where + C::Scalar: FromUniformBytes<64>, { fn read_point(&mut self) -> io::Result { let mut compressed = C::Repr::default(); @@ -206,8 +214,9 @@ impl TranscriptRead> } } -impl Transcript> - for Blake2bRead> +impl Transcript> for Blake2bRead> +where + C::Scalar: FromUniformBytes<64>, { fn squeeze_challenge(&mut self) -> Challenge255 { self.state.update(&[BLAKE2B_PREFIX_CHALLENGE]); @@ -240,6 +249,8 @@ impl Transcript> impl Transcript> for Keccak256Read> +where + C::Scalar: FromUniformBytes<64>, { fn squeeze_challenge(&mut self) -> Challenge255 { self.state.update(&[KECCAK256_PREFIX_CHALLENGE]); @@ -298,6 +309,8 @@ pub struct Keccak256Write> { impl TranscriptWriterBuffer> for Blake2bWrite> +where + C::Scalar: FromUniformBytes<64>, { /// Initialize a transcript given an output buffer. fn init(writer: W) -> Self { @@ -319,6 +332,8 @@ impl TranscriptWriterBuffer> impl TranscriptWriterBuffer> for Keccak256Write> +where + C::Scalar: FromUniformBytes<64>, { /// Initialize a transcript given an output buffer. fn init(writer: W) -> Self { @@ -340,6 +355,8 @@ impl TranscriptWriterBuffer> impl TranscriptWrite> for Blake2bWrite> +where + C::Scalar: FromUniformBytes<64>, { fn write_point(&mut self, point: C) -> io::Result<()> { self.common_point(point)?; @@ -355,6 +372,8 @@ impl TranscriptWrite> impl TranscriptWrite> for Keccak256Write> +where + C::Scalar: FromUniformBytes<64>, { fn write_point(&mut self, point: C) -> io::Result<()> { self.common_point(point)?; @@ -370,6 +389,8 @@ impl TranscriptWrite> impl Transcript> for Blake2bWrite> +where + C::Scalar: FromUniformBytes<64>, { fn squeeze_challenge(&mut self) -> Challenge255 { self.state.update(&[BLAKE2B_PREFIX_CHALLENGE]); @@ -402,6 +423,8 @@ impl Transcript> impl Transcript> for Keccak256Write> +where + C::Scalar: FromUniformBytes<64>, { fn squeeze_challenge(&mut self) -> Challenge255 { self.state.update(&[KECCAK256_PREFIX_CHALLENGE]); @@ -496,12 +519,15 @@ impl std::ops::Deref for Challenge255 { } } -impl EncodedChallenge for Challenge255 { +impl EncodedChallenge for Challenge255 +where + C::Scalar: FromUniformBytes<64>, +{ type Input = [u8; 64]; fn new(challenge_input: &[u8; 64]) -> Self { Challenge255( - C::Scalar::from_bytes_wide(challenge_input) + C::Scalar::from_uniform_bytes(challenge_input) .to_repr() .as_ref() .try_into() diff --git a/halo2_proofs/src/transcript/poseidon.rs b/halo2_proofs/src/transcript/poseidon.rs index d9da18a440..b6561d671d 100644 --- a/halo2_proofs/src/transcript/poseidon.rs +++ b/halo2_proofs/src/transcript/poseidon.rs @@ -1,9 +1,7 @@ use super::{Challenge255, EncodedChallenge, Transcript, TranscriptRead, TranscriptWrite}; use crate::helpers::base_to_scalar; -use ff::Field; -use group::ff::PrimeField; -use halo2curves::{Coordinates, CurveAffine, FieldExt}; -use num_bigint::BigUint; +use group::ff::{FromUniformBytes, PrimeField}; +use halo2curves::{Coordinates, CurveAffine}; use poseidon::Poseidon; use std::convert::TryInto; use std::io::{self, Read, Write}; @@ -15,13 +13,16 @@ const POSEIDON_T: usize = POSEIDON_RATE + 1usize; /// TODO #[derive(Debug, Clone)] pub struct PoseidonRead> { - state: Poseidon, + state: Poseidon, reader: R, _marker: PhantomData<(C, E)>, } /// TODO -impl> PoseidonRead { +impl> PoseidonRead +where + ::ScalarExt: FromUniformBytes<64>, +{ /// Initialize a transcript given an input buffer. pub fn init(reader: R) -> Self { PoseidonRead { @@ -34,6 +35,8 @@ impl> PoseidonRead { impl TranscriptRead> for PoseidonRead> +where + ::ScalarExt: FromUniformBytes<64>, { fn read_point(&mut self) -> io::Result { let mut compressed = C::Repr::default(); @@ -64,8 +67,9 @@ impl TranscriptRead> } } -impl Transcript> - for PoseidonRead> +impl Transcript> for PoseidonRead> +where + ::ScalarExt: FromUniformBytes<64>, { fn squeeze_challenge(&mut self) -> Challenge255 { //self.state.update(&[PREFIX_SQUEEZE]); @@ -101,12 +105,15 @@ impl Transcript> /// TODO #[derive(Debug, Clone)] pub struct PoseidonWrite> { - state: Poseidon, + state: Poseidon, writer: W, _marker: PhantomData<(C, E)>, } -impl> PoseidonWrite { +impl> PoseidonWrite +where + ::ScalarExt: FromUniformBytes<64>, +{ /// Initialize a transcript given an output buffer. pub fn init(writer: W) -> Self { PoseidonWrite { @@ -125,6 +132,8 @@ impl> PoseidonWrite { impl TranscriptWrite> for PoseidonWrite> +where + ::ScalarExt: FromUniformBytes<64>, { fn write_point(&mut self, point: C) -> io::Result<()> { self.common_point(point)?; @@ -140,6 +149,8 @@ impl TranscriptWrite> impl Transcript> for PoseidonWrite> +where + ::ScalarExt: FromUniformBytes<64>, { fn squeeze_challenge(&mut self) -> Challenge255 { //self.state.update(&[PREFIX_SQUEEZE]); diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index 778cf840fb..187280b034 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -1,10 +1,8 @@ #![allow(clippy::many_single_char_names)] #![allow(clippy::op_ref)] -// use assert_matches::assert_matches; -use halo2_proofs::arithmetic::{Field, FieldExt}; -#[cfg(feature = "parallel_syn")] -use halo2_proofs::circuit::Region; +use ff::{FromUniformBytes, WithSmallOrderMulGroup}; +use halo2_proofs::arithmetic::Field; use halo2_proofs::circuit::{Cell, Layouter, SimpleFloorPlanner, Value}; use halo2_proofs::dev::MockProver; use halo2_proofs::plonk::{ @@ -13,380 +11,265 @@ use halo2_proofs::plonk::{ VerifyingKey, }; use halo2_proofs::poly::commitment::{CommitmentScheme, ParamsProver, Prover, Verifier}; -use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; -use halo2_proofs::poly::kzg::multiopen::{ProverGWC, VerifierGWC}; -use halo2_proofs::poly::kzg::strategy::AccumulatorStrategy; use halo2_proofs::poly::Rotation; use halo2_proofs::poly::VerificationStrategy; use halo2_proofs::transcript::{ Blake2bRead, Blake2bWrite, Challenge255, EncodedChallenge, TranscriptReadBuffer, TranscriptWriterBuffer, }; -use halo2curves::bn256::Bn256; use rand_core::{OsRng, RngCore}; use std::marker::PhantomData; use std::time::Instant; -const K: u32 = 17; - -/// This represents an advice column at a certain row in the ConstraintSystem -#[derive(Copy, Clone, Debug)] -pub struct Variable(Column, usize); - -#[derive(Clone)] -struct PlonkConfig { - a: Column, - b: Column, - c: Column, - d: Column, - e: Column, - - sa: Column, - sb: Column, - sc: Column, - sm: Column, - sp: Column, - sl: TableColumn, -} - -impl PlonkConfig { - pub fn construct(meta: &mut ConstraintSystem) -> Self { - let e = meta.advice_column(); - let a = meta.advice_column(); - let b = meta.advice_column(); - let sf = meta.fixed_column(); - let c = meta.advice_column(); - let d = meta.advice_column(); - let p = meta.instance_column(); - - meta.enable_equality(a); - meta.enable_equality(b); - meta.enable_equality(c); - - let sm = meta.fixed_column(); - let sa = meta.fixed_column(); - let sb = meta.fixed_column(); - let sc = meta.fixed_column(); - let sp = meta.fixed_column(); - let sl = meta.lookup_table_column(); - - /* - * A B ... sl - * [ - * instance 0 ... 0 - * a a ... 0 - * a a^2 ... 0 - * a a ... 0 - * a a^2 ... 0 - * ... ... ... ... - * ... ... ... instance - * ... ... ... a - * ... ... ... a - * ... ... ... 0 - * ] - */ - - meta.lookup("lookup", |meta| { - let a_ = meta.query_any(a, Rotation::cur()); - vec![(a_, sl)] - }); - - meta.create_gate("Combined add-mult", |meta| { - let d = meta.query_advice(d, Rotation::next()); - let a = meta.query_advice(a, Rotation::cur()); - let sf = meta.query_fixed(sf, Rotation::cur()); - let e = meta.query_advice(e, Rotation::prev()); - let b = meta.query_advice(b, Rotation::cur()); - let c = meta.query_advice(c, Rotation::cur()); - - let sa = meta.query_fixed(sa, Rotation::cur()); - let sb = meta.query_fixed(sb, Rotation::cur()); - let sc = meta.query_fixed(sc, Rotation::cur()); - let sm = meta.query_fixed(sm, Rotation::cur()); - - vec![a.clone() * sa + b.clone() * sb + a * b * sm - (c * sc) + sf * (d * e)] - }); - - meta.create_gate("Public input", |meta| { - let a = meta.query_advice(a, Rotation::cur()); - let p = meta.query_instance(p, Rotation::cur()); - let sp = meta.query_fixed(sp, Rotation::cur()); - - vec![sp * (a - p)] - }); - - meta.enable_equality(sf); - meta.enable_equality(e); - meta.enable_equality(d); - meta.enable_equality(p); - meta.enable_equality(sm); - meta.enable_equality(sa); - meta.enable_equality(sb); - meta.enable_equality(sc); - meta.enable_equality(sp); - - PlonkConfig { - a, - b, - c, - d, - e, - sa, - sb, - sc, - sm, - sp, - sl, - } - } -} +#[cfg(feature = "parallel_syn")] +use halo2_proofs::circuit::Region; -#[allow(clippy::type_complexity)] -trait StandardCs { - fn raw_multiply( - &self, - layouter: &mut impl Layouter, - f: F, - ) -> Result<(Cell, Cell, Cell), Error> - where - F: FnMut() -> Value<(Assigned, Assigned, Assigned)>; - fn raw_add( - &self, - layouter: &mut impl Layouter, - f: F, - ) -> Result<(Cell, Cell, Cell), Error> - where - F: FnMut() -> Value<(Assigned, Assigned, Assigned)>; - fn copy(&self, layouter: &mut impl Layouter, a: Cell, b: Cell) -> Result<(), Error>; - fn public_input(&self, layouter: &mut impl Layouter, f: F) -> Result - where - F: FnMut() -> Value; - fn lookup_table(&self, layouter: &mut impl Layouter, values: &[FF]) -> Result<(), Error>; -} +#[test] +fn plonk_api() { + const K: u32 = 17; -struct StandardPlonk { - config: PlonkConfig, - _marker: PhantomData, -} + /// This represents an advice column at a certain row in the ConstraintSystem + #[derive(Copy, Clone, Debug)] + pub struct Variable(Column, usize); -impl StandardPlonk { - fn new(config: PlonkConfig) -> Self { - StandardPlonk { - config, - _marker: PhantomData, - } + #[derive(Clone)] + struct PlonkConfig { + a: Column, + b: Column, + c: Column, + d: Column, + e: Column, + + sa: Column, + sb: Column, + sc: Column, + sm: Column, + sp: Column, + sl: TableColumn, } -} -impl StandardCs for StandardPlonk { - fn raw_multiply( - &self, - layouter: &mut impl Layouter, - mut f: F, - ) -> Result<(Cell, Cell, Cell), Error> - where - F: FnMut() -> Value<(Assigned, Assigned, Assigned)>, - { - layouter.assign_region( - || "raw_multiply", - |mut region| { - let mut value = None; - let lhs = region.assign_advice( - || "lhs", - self.config.a, - 0, - || { - value = Some(f()); - value.unwrap().map(|v| v.0) - }, - )?; - region.assign_advice( - || "lhs^4", - self.config.d, - 0, - || value.unwrap().map(|v| v.0).square().square(), - )?; - let rhs = region.assign_advice( - || "rhs", - self.config.b, - 0, - || value.unwrap().map(|v| v.1), - )?; - region.assign_advice( - || "rhs^4", - self.config.e, - 0, - || value.unwrap().map(|v| v.1).square().square(), - )?; - let out = region.assign_advice( - || "out", - self.config.c, - 0, - || value.unwrap().map(|v| v.2), - )?; - - region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::zero()))?; - region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::zero()))?; - region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::one()))?; - region.assign_fixed(|| "a * b", self.config.sm, 0, || Value::known(FF::one()))?; - Ok((lhs.cell(), rhs.cell(), out.cell())) - }, - ) + #[allow(clippy::type_complexity)] + trait StandardCs { + fn raw_multiply( + &self, + layouter: &mut impl Layouter, + f: F, + ) -> Result<(Cell, Cell, Cell), Error> + where + F: FnMut() -> Value<(Assigned, Assigned, Assigned)>; + fn raw_add( + &self, + layouter: &mut impl Layouter, + f: F, + ) -> Result<(Cell, Cell, Cell), Error> + where + F: FnMut() -> Value<(Assigned, Assigned, Assigned)>; + fn copy(&self, layouter: &mut impl Layouter, a: Cell, b: Cell) -> Result<(), Error>; + fn public_input(&self, layouter: &mut impl Layouter, f: F) -> Result + where + F: FnMut() -> Value; + fn lookup_table( + &self, + layouter: &mut impl Layouter, + values: &[FF], + ) -> Result<(), Error>; } - fn raw_add( - &self, - layouter: &mut impl Layouter, - mut f: F, - ) -> Result<(Cell, Cell, Cell), Error> - where - F: FnMut() -> Value<(Assigned, Assigned, Assigned)>, - { - layouter.assign_region( - || "raw_add", - |mut region| { - let mut value = None; - let lhs = region.assign_advice( - || "lhs", - self.config.a, - 0, - || { - value = Some(f()); - value.unwrap().map(|v| v.0) - }, - )?; - region.assign_advice( - || "lhs^4", - self.config.d, - 0, - || value.unwrap().map(|v| v.0).square().square(), - )?; - let rhs = region.assign_advice( - || "rhs", - self.config.b, - 0, - || value.unwrap().map(|v| v.1), - )?; - region.assign_advice( - || "rhs^4", - self.config.e, - 0, - || value.unwrap().map(|v| v.1).square().square(), - )?; - let out = region.assign_advice( - || "out", - self.config.c, - 0, - || value.unwrap().map(|v| v.2), - )?; - - region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::one()))?; - region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::one()))?; - region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::one()))?; - region.assign_fixed(|| "a * b", self.config.sm, 0, || Value::known(FF::zero()))?; - Ok((lhs.cell(), rhs.cell(), out.cell())) - }, - ) + + #[derive(Clone)] + struct MyCircuit { + a: Value, + lookup_table: Vec, } - fn copy(&self, layouter: &mut impl Layouter, left: Cell, right: Cell) -> Result<(), Error> { - layouter.assign_region( - || "copy", - |mut region| { - region.constrain_equal(left, right)?; - region.constrain_equal(left, right) - }, - ) + + struct StandardPlonk { + config: PlonkConfig, + _marker: PhantomData, } - fn public_input(&self, layouter: &mut impl Layouter, mut f: F) -> Result - where - F: FnMut() -> Value, - { - layouter.assign_region( - || "public_input", - |mut region| { - let value = region.assign_advice(|| "value", self.config.a, 0, &mut f)?; - region.assign_fixed(|| "public", self.config.sp, 0, || Value::known(FF::one()))?; - Ok(value.cell()) - }, - ) + impl StandardPlonk { + fn new(config: PlonkConfig) -> Self { + StandardPlonk { + config, + _marker: PhantomData, + } + } } - fn lookup_table(&self, layouter: &mut impl Layouter, values: &[FF]) -> Result<(), Error> { - layouter.assign_table( - || "", - |mut table| { - for (index, &value) in values.iter().enumerate() { - table.assign_cell( - || "table col", - self.config.sl, - index, - || Value::known(value), + + impl StandardCs for StandardPlonk { + fn raw_multiply( + &self, + layouter: &mut impl Layouter, + mut f: F, + ) -> Result<(Cell, Cell, Cell), Error> + where + F: FnMut() -> Value<(Assigned, Assigned, Assigned)>, + { + layouter.assign_region( + || "raw_multiply", + |mut region| { + let mut value = None; + let lhs = region.assign_advice( + || "lhs", + self.config.a, + 0, + || { + value = Some(f()); + value.unwrap().map(|v| v.0) + }, + )?; + region.assign_advice( + || "lhs^4", + self.config.d, + 0, + || value.unwrap().map(|v| v.0).square().square(), + )?; + let rhs = region.assign_advice( + || "rhs", + self.config.b, + 0, + || value.unwrap().map(|v| v.1), + )?; + region.assign_advice( + || "rhs^4", + self.config.e, + 0, + || value.unwrap().map(|v| v.1).square().square(), + )?; + let out = region.assign_advice( + || "out", + self.config.c, + 0, + || value.unwrap().map(|v| v.2), )?; - } - Ok(()) - }, - )?; - Ok(()) - } -} -macro_rules! common { - ($scheme:ident) => {{ - let a = <$scheme as CommitmentScheme>::Scalar::from(2834758237) - * <$scheme as CommitmentScheme>::Scalar::ZETA; - let instance = <$scheme as CommitmentScheme>::Scalar::one() - + <$scheme as CommitmentScheme>::Scalar::one(); - let lookup_table = vec![ - instance, - a, - a, - <$scheme as CommitmentScheme>::Scalar::zero(), - ]; - (a, instance, lookup_table) - }}; -} + region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::ZERO))?; + region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::ZERO))?; + region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "a * b", self.config.sm, 0, || Value::known(FF::ONE))?; + Ok((lhs.cell(), rhs.cell(), out.cell())) + }, + ) + } + fn raw_add( + &self, + layouter: &mut impl Layouter, + mut f: F, + ) -> Result<(Cell, Cell, Cell), Error> + where + F: FnMut() -> Value<(Assigned, Assigned, Assigned)>, + { + layouter.assign_region( + || "raw_add", + |mut region| { + let mut value = None; + let lhs = region.assign_advice( + || "lhs", + self.config.a, + 0, + || { + value = Some(f()); + value.unwrap().map(|v| v.0) + }, + )?; + region.assign_advice( + || "lhs^4", + self.config.d, + 0, + || value.unwrap().map(|v| v.0).square().square(), + )?; + let rhs = region.assign_advice( + || "rhs", + self.config.b, + 0, + || value.unwrap().map(|v| v.1), + )?; + region.assign_advice( + || "rhs^4", + self.config.e, + 0, + || value.unwrap().map(|v| v.1).square().square(), + )?; + let out = region.assign_advice( + || "out", + self.config.c, + 0, + || value.unwrap().map(|v| v.2), + )?; -fn verify_proof< - 'a, - 'params, - Scheme: CommitmentScheme, - V: Verifier<'params, Scheme>, - E: EncodedChallenge, - T: TranscriptReadBuffer<&'a [u8], Scheme::Curve, E>, - Strategy: VerificationStrategy<'params, Scheme, V, Output = Strategy>, ->( - params_verifier: &'params Scheme::ParamsVerifier, - vk: &VerifyingKey, - proof: &'a [u8], -) { - let (_, instance, _) = common!(Scheme); - let pubinputs = vec![instance]; - - let mut transcript = T::init(proof); - - let strategy = Strategy::new(params_verifier); - let strategy = verify_plonk_proof( - params_verifier, - vk, - strategy, - &[&[&pubinputs[..]], &[&pubinputs[..]]], - &mut transcript, - ) - .unwrap(); - - assert!(strategy.finalize()); -} + region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::ONE))?; + region.assign_fixed( + || "a * b", + self.config.sm, + 0, + || Value::known(FF::ZERO), + )?; + Ok((lhs.cell(), rhs.cell(), out.cell())) + }, + ) + } + fn copy( + &self, + layouter: &mut impl Layouter, + left: Cell, + right: Cell, + ) -> Result<(), Error> { + layouter.assign_region( + || "copy", + |mut region| { + region.constrain_equal(left, right)?; + region.constrain_equal(left, right) + }, + ) + } + fn public_input(&self, layouter: &mut impl Layouter, mut f: F) -> Result + where + F: FnMut() -> Value, + { + layouter.assign_region( + || "public_input", + |mut region| { + let value = region.assign_advice(|| "value", self.config.a, 0, &mut f)?; + region.assign_fixed( + || "public", + self.config.sp, + 0, + || Value::known(FF::ONE), + )?; -#[test] -fn plonk_api() { - #[derive(Clone)] - struct MyCircuit { - a: Value, - lookup_table: Vec, + Ok(value.cell()) + }, + ) + } + fn lookup_table( + &self, + layouter: &mut impl Layouter, + values: &[FF], + ) -> Result<(), Error> { + layouter.assign_table( + || "", + |mut table| { + for (index, &value) in values.iter().enumerate() { + table.assign_cell( + || "table col", + self.config.sl, + index, + || Value::known(value), + )?; + } + Ok(()) + }, + )?; + Ok(()) + } } - impl Circuit for MyCircuit { + impl Circuit for MyCircuit { type Config = PlonkConfig; type FloorPlanner = SimpleFloorPlanner; + #[cfg(feature = "circuit-params")] + type Params = (); fn without_witnesses(&self) -> Self { Self { @@ -396,7 +279,93 @@ fn plonk_api() { } fn configure(meta: &mut ConstraintSystem) -> PlonkConfig { - PlonkConfig::construct(meta) + let e = meta.advice_column(); + let a = meta.advice_column(); + let b = meta.advice_column(); + let sf = meta.fixed_column(); + let c = meta.advice_column(); + let d = meta.advice_column(); + let p = meta.instance_column(); + + meta.enable_equality(a); + meta.enable_equality(b); + meta.enable_equality(c); + + let sm = meta.fixed_column(); + let sa = meta.fixed_column(); + let sb = meta.fixed_column(); + let sc = meta.fixed_column(); + let sp = meta.fixed_column(); + let sl = meta.lookup_table_column(); + + /* + * A B ... sl + * [ + * instance 0 ... 0 + * a a ... 0 + * a a^2 ... 0 + * a a ... 0 + * a a^2 ... 0 + * ... ... ... ... + * ... ... ... instance + * ... ... ... a + * ... ... ... a + * ... ... ... 0 + * ] + */ + + meta.lookup("lookup", |meta| { + let a_ = meta.query_any(a, Rotation::cur()); + vec![(a_, sl)] + }); + + meta.create_gate("Combined add-mult", |meta| { + let d = meta.query_advice(d, Rotation::next()); + let a = meta.query_advice(a, Rotation::cur()); + let sf = meta.query_fixed(sf, Rotation::cur()); + let e = meta.query_advice(e, Rotation::prev()); + let b = meta.query_advice(b, Rotation::cur()); + let c = meta.query_advice(c, Rotation::cur()); + + let sa = meta.query_fixed(sa, Rotation::cur()); + let sb = meta.query_fixed(sb, Rotation::cur()); + let sc = meta.query_fixed(sc, Rotation::cur()); + let sm = meta.query_fixed(sm, Rotation::cur()); + + vec![a.clone() * sa + b.clone() * sb + a * b * sm - (c * sc) + sf * (d * e)] + }); + + meta.create_gate("Public input", |meta| { + let a = meta.query_advice(a, Rotation::cur()); + let p = meta.query_instance(p, Rotation::cur()); + let sp = meta.query_fixed(sp, Rotation::cur()); + + vec![sp * (a - p)] + }); + + meta.enable_equality(sf); + meta.enable_equality(e); + meta.enable_equality(d); + meta.enable_equality(p); + meta.enable_equality(sm); + meta.enable_equality(sa); + meta.enable_equality(sb); + meta.enable_equality(sc); + meta.enable_equality(sp); + + PlonkConfig { + a, + b, + c, + d, + e, + sa, + sb, + sc, + sm, + sp, + sl, + } } fn synthesize( @@ -405,10 +374,13 @@ fn plonk_api() { mut layouter: impl Layouter, ) -> Result<(), Error> { let cs = StandardPlonk::new(config); + + #[cfg(feature = "parallel_syn")] let mut is_first_pass_vec = vec![true; 8]; - let _ = cs.public_input(&mut layouter, || Value::known(F::one() + F::one()))?; + let _ = cs.public_input(&mut layouter, || Value::known(F::ONE + F::ONE))?; + #[cfg(feature = "parallel_syn")] let a: Value> = self.a.into(); let parallel_regions_time = Instant::now(); #[cfg(feature = "parallel_syn")] @@ -440,25 +412,25 @@ fn plonk_api() { || "a", cs.config.sa, i, - || Value::known(F::one()), + || Value::known(F::ONE), )?; region.assign_fixed( || "b", cs.config.sb, i, - || Value::known(F::one()), + || Value::known(F::ONE), )?; region.assign_fixed( || "c", cs.config.sc, i, - || Value::known(F::one()), + || Value::known(F::ONE), )?; region.assign_fixed( || "a * b", cs.config.sm, i, - || Value::known(F::zero()), + || Value::known(F::ZERO), )?; region.constrain_equal(a0.cell(), a1.cell())?; @@ -496,9 +468,54 @@ fn plonk_api() { Ok(()) } } - fn keygen( - params: &Scheme::ParamsProver, - ) -> ProvingKey { + + macro_rules! common { + ($scheme:ident) => {{ + let a = <$scheme as CommitmentScheme>::Scalar::from(2834758237) + * <$scheme as CommitmentScheme>::Scalar::ZETA; + let instance = <$scheme as CommitmentScheme>::Scalar::ONE + + <$scheme as CommitmentScheme>::Scalar::ONE; + let lookup_table = vec![instance, a, a, <$scheme as CommitmentScheme>::Scalar::ZERO]; + (a, instance, lookup_table) + }}; + } + + /* + macro_rules! bad_keys { + ($scheme:ident) => {{ + let (_, _, lookup_table) = common!($scheme); + let empty_circuit: MyCircuit<<$scheme as CommitmentScheme>::Scalar> = MyCircuit { + a: Value::unknown(), + lookup_table: lookup_table.clone(), + }; + + // Check that we get an error if we try to initialize the proving key with a value of + // k that is too small for the minimum required number of rows. + let much_too_small_params= <$scheme as CommitmentScheme>::ParamsProver::new(1); + assert_matches!( + keygen_vk(&much_too_small_params, &empty_circuit), + Err(Error::NotEnoughRowsAvailable { + current_k, + }) if current_k == 1 + ); + + // Check that we get an error if we try to initialize the proving key with a value of + // k that is too small for the number of rows the circuit uses. + let slightly_too_small_params = <$scheme as CommitmentScheme>::ParamsProver::new(K-1); + assert_matches!( + keygen_vk(&slightly_too_small_params, &empty_circuit), + Err(Error::NotEnoughRowsAvailable { + current_k, + }) if current_k == K - 1 + ); + }}; + } + */ + + fn keygen(params: &Scheme::ParamsProver) -> ProvingKey + where + Scheme::Scalar: FromUniformBytes<64> + WithSmallOrderMulGroup<3>, + { let (_, _, lookup_table) = common!(Scheme); let empty_circuit: MyCircuit = MyCircuit { a: Value::unknown(), @@ -526,7 +543,10 @@ fn plonk_api() { rng: R, params: &'params Scheme::ParamsProver, pk: &ProvingKey, - ) -> Vec { + ) -> Vec + where + Scheme::Scalar: Ord + WithSmallOrderMulGroup<3> + FromUniformBytes<64>, + { let (a, instance, lookup_table) = common!(Scheme); let circuit: MyCircuit = MyCircuit { @@ -549,6 +569,39 @@ fn plonk_api() { transcript.finalize() } + fn verify_proof< + 'a, + 'params, + Scheme: CommitmentScheme, + V: Verifier<'params, Scheme>, + E: EncodedChallenge, + T: TranscriptReadBuffer<&'a [u8], Scheme::Curve, E>, + Strategy: VerificationStrategy<'params, Scheme, V, Output = Strategy>, + >( + params_verifier: &'params Scheme::ParamsVerifier, + vk: &VerifyingKey, + proof: &'a [u8], + ) where + Scheme::Scalar: Ord + WithSmallOrderMulGroup<3> + FromUniformBytes<64>, + { + let (_, instance, _) = common!(Scheme); + let pubinputs = [instance]; + + let mut transcript = T::init(proof); + + let strategy = Strategy::new(params_verifier); + let strategy = verify_plonk_proof( + params_verifier, + vk, + strategy, + &[&[&pubinputs[..]], &[&pubinputs[..]]], + &mut transcript, + ) + .unwrap(); + + assert!(strategy.finalize()); + } + fn test_plonk_api_gwc() { use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use halo2_proofs::poly::kzg::multiopen::{ProverGWC, VerifierGWC}; @@ -649,6 +702,411 @@ fn plonk_api() { Blake2bRead<_, _, Challenge255<_>>, AccumulatorStrategy<_>, >(verifier_params, pk.get_vk(), &proof[..]); + + // Check that the verification key has not changed unexpectedly + // we comment this out because the circuit is already changed + /* + { + //panic!("{:#?}", pk.get_vk().pinned()); + assert_eq!( + format!("{:#?}", pk.get_vk().pinned()), + r#####"PinnedVerificationKey { + base_modulus: "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", + scalar_modulus: "0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001", + domain: PinnedEvaluationDomain { + k: 5, + extended_k: 7, + omega: 0x0cc3380dc616f2e1daf29ad1560833ed3baea3393eceb7bc8fa36376929b78cc, + }, + cs: PinnedConstraintSystem { + num_fixed_columns: 7, + num_advice_columns: 5, + num_instance_columns: 1, + num_selectors: 0, + gates: [ + Sum( + Sum( + Sum( + Sum( + Product( + Advice { + query_index: 0, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 2, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Product( + Advice { + query_index: 1, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 3, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + ), + ), + Product( + Product( + Advice { + query_index: 0, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 1, + column_index: 2, + rotation: Rotation( + 0, + ), + }, + ), + Fixed { + query_index: 5, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ), + ), + Negated( + Product( + Advice { + query_index: 2, + column_index: 3, + rotation: Rotation( + 0, + ), + }, + Fixed { + query_index: 4, + column_index: 4, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Fixed { + query_index: 1, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Product( + Advice { + query_index: 3, + column_index: 4, + rotation: Rotation( + 1, + ), + }, + Advice { + query_index: 4, + column_index: 0, + rotation: Rotation( + -1, + ), + }, + ), + ), + ), + Product( + Fixed { + query_index: 6, + column_index: 5, + rotation: Rotation( + 0, + ), + }, + Sum( + Advice { + query_index: 0, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + Negated( + Instance { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ], + advice_queries: [ + ( + Column { + index: 1, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Advice, + }, + Rotation( + 1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + -1, + ), + ), + ( + Column { + index: 0, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Advice, + }, + Rotation( + 0, + ), + ), + ], + instance_queries: [ + ( + Column { + index: 0, + column_type: Instance, + }, + Rotation( + 0, + ), + ), + ], + fixed_queries: [ + ( + Column { + index: 6, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 0, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 2, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 3, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 4, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 1, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ( + Column { + index: 5, + column_type: Fixed, + }, + Rotation( + 0, + ), + ), + ], + permutation: Argument { + columns: [ + Column { + index: 1, + column_type: Advice, + }, + Column { + index: 2, + column_type: Advice, + }, + Column { + index: 3, + column_type: Advice, + }, + Column { + index: 0, + column_type: Fixed, + }, + Column { + index: 0, + column_type: Advice, + }, + Column { + index: 4, + column_type: Advice, + }, + Column { + index: 0, + column_type: Instance, + }, + Column { + index: 1, + column_type: Fixed, + }, + Column { + index: 2, + column_type: Fixed, + }, + Column { + index: 3, + column_type: Fixed, + }, + Column { + index: 4, + column_type: Fixed, + }, + Column { + index: 5, + column_type: Fixed, + }, + ], + }, + lookups: [ + Argument { + input_expressions: [ + Advice { + query_index: 0, + column_index: 1, + rotation: Rotation( + 0, + ), + }, + ], + table_expressions: [ + Fixed { + query_index: 0, + column_index: 6, + rotation: Rotation( + 0, + ), + }, + ], + }, + ], + constants: [], + minimum_degree: None, + }, + fixed_commitments: [ + (0x2bbc94ef7b22aebef24f9a4b0cc1831882548b605171366017d45c3e6fd92075, 0x082b801a6e176239943bfb759fb02138f47a5c8cc4aa7fa0af559fde4e3abd97), + (0x2bf5082b105b2156ed0e9c5b8e42bf2a240b058f74a464d080e9585274dd1e84, 0x222ad83cee7777e7a160585e212140e5e770dd8d1df788d869b5ee483a5864fb), + (0x374a656456a0aae7429b23336f825752b575dd5a44290ff614946ee59d6a20c0, 0x054491e187e6e3460e7601fb54ae10836d34d420026f96316f0c5c62f86db9b8), + (0x374a656456a0aae7429b23336f825752b575dd5a44290ff614946ee59d6a20c0, 0x054491e187e6e3460e7601fb54ae10836d34d420026f96316f0c5c62f86db9b8), + (0x02e62cd68370b13711139a08cbcdd889e800a272b9ea10acc90880fff9d89199, 0x1a96c468cb0ce77065d3a58f1e55fea9b72d15e44c01bba1e110bd0cbc6e9bc6), + (0x224ef42758215157d3ee48fb8d769da5bddd35e5929a90a4a89736f5c4b5ae9b, 0x11bc3a1e08eb320cde764f1492ecef956d71e996e2165f7a9a30ad2febb511c1), + (0x2d5415bf917fcac32bfb705f8ca35cb12d9bad52aa33ccca747350f9235d3a18, 0x2b2921f815fad504052512743963ef20ed5b401d20627793b006413e73fe4dd4), + ], + permutation: VerifyingKey { + commitments: [ + (0x1347b4b385837977a96b87f199c6a9a81520015539d1e8fa79429bb4ca229a00, 0x2168e404cabef513654d6ff516cde73f0ba87e3dc84e4b940ed675b5f66f3884), + (0x0e6d69cd2455ec43be640f6397ed65c9e51b1d8c0fd2216339314ff37ade122a, 0x222ed6dc8cfc9ea26dcc10b9d4add791ada60f2b5a63ee1e4635f88aa0c96654), + (0x13c447846f48c41a5e0675ccf88ebc0cdef2c96c51446d037acb866d24255785, 0x1f0b5414fc5e8219dbfab996eed6129d831488b2386a8b1a63663938903bd63a), + (0x1aae6470aa662b8fda003894ddef5fedd03af318b3231683039d2fac9cab05b9, 0x08832d91ae69e99cd07d096c7a4a284a69e6a16227cbb07932a0cdc56914f3a6), + (0x0850521b0f8ac7dd0550fe3e25c840837076e9635067ed623b81d5cbac5944d9, 0x0c25d65d1038d0a92c72e5fccd96c1caf07801c3c8233290bb292e0c38c256fa), + (0x12febcf696badd970750eabf75dd3ced4c2f54f93519bcee23849025177d2014, 0x0a05ab3cd42c9fbcc1bbfcf9269951640cc9920761c87cf8e211ba73c8d9f90f), + (0x053904bdde8cfead3b517bb4f6ded3e699f8b94ca6156a9dd2f92a2a05a7ec5a, 0x16753ff97c0d82ff586bb7a07bf7f27a92df90b3617fa5e75d4f55c3b0ef8711), + (0x3804548f6816452747a5b542fa5656353fc989db40d69e9e27d6f973b5deebb0, 0x389a44d5037866dd83993af75831a5f90a18ad5244255aa5bd2c922cc5853055), + (0x003a9f9ca71c7c0b832c802220915f6fc8d840162bdde6b0ea05d25fb95559e3, 0x091247ca19d6b73887cd7f68908cbf0db0b47459b7c82276bbdb8a1c937e2438), + (0x3eaa38689d9e391c8a8fafab9568f20c45816321d38f309d4cc37f4b1601af72, 0x247f8270a462ea88450221a56aa6b55d2bc352b80b03501e99ea983251ceea13), + (0x394437571f9de32dccdc546fd4737772d8d92593c85438aa3473243997d5acc8, 0x14924ec6e3174f1fab7f0ce7070c22f04bbd0a0ecebdfc5c94be857f25493e95), + (0x3d907e0591343bd285c2c846f3e871a6ac70d80ec29e9500b8cb57f544e60202, 0x1034e48df35830244cabea076be8a16d67d7896e27c6ac22b285d017105da9c3), + ], + }, + }"##### + ); + } + */ } env_logger::init(); @@ -656,213 +1114,3 @@ fn plonk_api() { test_plonk_api_gwc(); test_plonk_api_shplonk(); } - -#[test] -fn plonk_api_with_many_subregions() { - #[derive(Clone)] - struct MyCircuit { - a: Value, - lookup_table: Vec, - } - - impl Circuit for MyCircuit { - type Config = PlonkConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self { - a: Value::unknown(), - lookup_table: self.lookup_table.clone(), - } - } - - fn configure(meta: &mut ConstraintSystem) -> PlonkConfig { - PlonkConfig::construct(meta) - } - - fn synthesize( - &self, - config: PlonkConfig, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let cs = StandardPlonk::new(config); - - let _ = cs.public_input(&mut layouter, || Value::known(F::one() + F::one()))?; - - let a: Value> = self.a.into(); - let parallel_regions_time = Instant::now(); - #[cfg(feature = "parallel_syn")] - layouter.assign_regions( - || "regions", - (0..(1 << 14)) - .into_iter() - .map(|_| { - let mut is_first_pass = true; - move |mut region: Region<'_, F>| -> Result<(), Error> { - let n = 1 << 1; - for i in 0..n { - // skip the assign of rows except the last row in the first pass - if is_first_pass && i < n - 1 { - is_first_pass = false; - continue; - } - let a0 = - region.assign_advice(|| "config.a", cs.config.a, i, || a)?; - let a1 = - region.assign_advice(|| "config.b", cs.config.b, i, || a)?; - region.assign_advice( - || "config.c", - cs.config.c, - i, - || a.double(), - )?; - - region.assign_fixed( - || "a", - cs.config.sa, - i, - || Value::known(F::one()), - )?; - region.assign_fixed( - || "b", - cs.config.sb, - i, - || Value::known(F::one()), - )?; - region.assign_fixed( - || "c", - cs.config.sc, - i, - || Value::known(F::one()), - )?; - region.assign_fixed( - || "a * b", - cs.config.sm, - i, - || Value::known(F::zero()), - )?; - - region.constrain_equal(a0.cell(), a1.cell())?; - } - is_first_pass = false; - Ok(()) - } - }) - .collect(), - )?; - log::info!( - "parallel_regions assign took {:?}", - parallel_regions_time.elapsed() - ); - - for _ in 0..10 { - let a: Value> = self.a.into(); - let mut a_squared = Value::unknown(); - let (a0, _, c0) = cs.raw_multiply(&mut layouter, || { - a_squared = a.square(); - a.zip(a_squared).map(|(a, a_squared)| (a, a, a_squared)) - })?; - let (a1, b1, _) = cs.raw_add(&mut layouter, || { - let fin = a_squared + a; - a.zip(a_squared) - .zip(fin) - .map(|((a, a_squared), fin)| (a, a_squared, fin)) - })?; - cs.copy(&mut layouter, a0, a1)?; - cs.copy(&mut layouter, b1, c0)?; - } - - cs.lookup_table(&mut layouter, &self.lookup_table)?; - - Ok(()) - } - } - fn keygen( - params: &Scheme::ParamsProver, - ) -> ProvingKey { - let (_, _, lookup_table) = common!(Scheme); - let empty_circuit: MyCircuit = MyCircuit { - a: Value::unknown(), - lookup_table, - }; - - // Initialize the proving key - let vk = keygen_vk(params, &empty_circuit).expect("keygen_vk should not fail"); - log::info!("keygen vk succeed"); - - let pk = keygen_pk(params, vk, &empty_circuit).expect("keygen_pk should not fail"); - log::info!("keygen pk succeed"); - - pk - } - - fn create_proof< - 'params, - Scheme: CommitmentScheme, - P: Prover<'params, Scheme>, - E: EncodedChallenge, - R: RngCore, - T: TranscriptWriterBuffer, Scheme::Curve, E>, - >( - rng: R, - params: &'params Scheme::ParamsProver, - pk: &ProvingKey, - ) -> Vec { - let (a, instance, lookup_table) = common!(Scheme); - - let circuit: MyCircuit = MyCircuit { - a: Value::known(a), - lookup_table, - }; - - let mut transcript = T::init(vec![]); - - create_plonk_proof::( - params, - pk, - &[circuit.clone(), circuit], - &[&[&[instance]], &[&[instance]]], - rng, - &mut transcript, - ) - .expect("proof generation should not fail"); - - transcript.finalize() - } - - type Scheme = KZGCommitmentScheme; - // bad_keys!(Scheme); - - env_logger::try_init().unwrap(); - let (a, instance, lookup_table) = common!(Scheme); - - let circuit: MyCircuit<::Scalar> = MyCircuit { - a: Value::known(a), - lookup_table, - }; - - // Check this circuit is satisfied. - let prover = match MockProver::run(K, &circuit, vec![vec![instance]]) { - Ok(prover) => prover, - Err(e) => panic!("{:?}", e), - }; - assert_eq!(prover.verify_par(), Ok(())); - log::info!("mock proving succeed!"); - - let params = ParamsKZG::::new(K); - let rng = OsRng; - - let pk = keygen::>(¶ms); - - let proof = create_proof::<_, ProverGWC<_>, _, _, Blake2bWrite<_, _, Challenge255<_>>>( - rng, ¶ms, &pk, - ); - - let verifier_params = params.verifier_params(); - - verify_proof::<_, VerifierGWC<_>, _, Blake2bRead<_, _, Challenge255<_>>, AccumulatorStrategy<_>>( - verifier_params, - pk.get_vk(), - &proof[..], - ); -} From 0bfe0c94d27784cef407fe2d6a830db1df2d9bb9 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Mon, 13 Nov 2023 21:05:09 -0500 Subject: [PATCH 43/54] fix clippy --- halo2_proofs/src/circuit/floor_planner/single_pass.rs | 1 + halo2_proofs/src/dev.rs | 3 +++ halo2_proofs/src/lib.rs | 3 ++- halo2_proofs/src/plonk/prover.rs | 6 +++--- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index 3c445230d3..21ea01367a 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -83,6 +83,7 @@ impl<'a, F: Field, CS: Assignment + 'a> SingleChipLayouter<'a, F, CS> { Ok(ret) } + #[allow(dead_code)] fn fork(&self, sub_cs: Vec<&'a mut CS>) -> Result, Error> { Ok(sub_cs .into_iter() diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index b72f8c03c5..4550b29687 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -971,7 +971,10 @@ impl<'a, F: FromUniformBytes<64> + Ord> MockProver<'a, F> { instance, selectors_vec, selectors, + #[cfg(feature = "phase-check")] challenges: challenges.clone(), + #[cfg(not(feature = "phase-check"))] + challenges, permutation: Some(permutation), rw_rows: 0..usable_rows, usable_rows: 0..usable_rows, diff --git a/halo2_proofs/src/lib.rs b/halo2_proofs/src/lib.rs index 0ca61f64e4..6192272fc2 100644 --- a/halo2_proofs/src/lib.rs +++ b/halo2_proofs/src/lib.rs @@ -15,7 +15,8 @@ clippy::suspicious_arithmetic_impl, clippy::many_single_char_names, clippy::same_item_push, - clippy::upper_case_acronyms + clippy::upper_case_acronyms, + clippy::uninit_vec )] #![deny(broken_intra_doc_links)] #![deny(missing_debug_implementations)] diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index c522947820..0128f52f0c 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -389,7 +389,7 @@ where }) .collect::>(); - for (circuit_idx, ((circuit, advice), instances)) in circuits + for (_circuit_idx, ((circuit, advice), instances)) in circuits .iter() .zip(advice.iter_mut()) .zip(instances) @@ -428,7 +428,7 @@ where { for (idx, advice_col) in witness.advice_vec.iter().enumerate() { if pk.vk.cs.advice_column_phase[idx].0 < current_phase.0 - && advice_assignments[circuit_idx][idx].values != advice_col.values + && advice_assignments[_circuit_idx][idx].values != advice_col.values { log::error!( "advice column {}(at {:?}) changed when {:?}", @@ -449,7 +449,7 @@ where if column_indices.contains(&column_index) { #[cfg(feature = "phase-check")] { - advice_assignments[circuit_idx][column_index] = advice.clone(); + advice_assignments[_circuit_idx][column_index] = advice.clone(); } Some(advice) } else { From 6edad9dbf7051d08b1523e6221cabd80055d7383 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Mon, 20 Nov 2023 18:46:11 -0500 Subject: [PATCH 44/54] fix clippy --- halo2_proofs/src/dev.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 4550b29687..687763bedc 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -129,7 +129,7 @@ impl PartialEq for CellValue { } #[cfg(feature = "mock-batch-inv")] -impl CellValue { +impl CellValue { /// Returns the numerator. pub fn numerator(&self) -> Option { match self { @@ -148,7 +148,7 @@ impl CellValue { } #[cfg(feature = "mock-batch-inv")] -impl From> for CellValue { +impl From> for CellValue { fn from(value: Assigned) -> Self { match value { Assigned::Zero => CellValue::Unassigned, @@ -161,7 +161,7 @@ impl From> for CellValue { } #[cfg(feature = "mock-batch-inv")] -fn calculate_assigned_values( +fn calculate_assigned_values( cell_values: &mut [CellValue], inv_denoms: &[Option], ) { @@ -177,7 +177,7 @@ fn calculate_assigned_values( } #[cfg(feature = "mock-batch-inv")] -fn batch_invert_cellvalues(cell_values: &mut [Vec>]) { +fn batch_invert_cellvalues(cell_values: &mut [Vec>]) { let mut denominators: Vec<_> = cell_values .iter() .map(|f| { From 2f5ee1040e3cdef22e13d35865ecddce4a6130c7 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Mon, 20 Nov 2023 18:53:08 -0500 Subject: [PATCH 45/54] fmg --- halo2_proofs/src/dev.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 687763bedc..977a00ae15 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -161,10 +161,7 @@ impl From> for CellValue { } #[cfg(feature = "mock-batch-inv")] -fn calculate_assigned_values( - cell_values: &mut [CellValue], - inv_denoms: &[Option], -) { +fn calculate_assigned_values(cell_values: &mut [CellValue], inv_denoms: &[Option]) { assert_eq!(inv_denoms.len(), cell_values.len()); for (value, inv_den) in cell_values.iter_mut().zip(inv_denoms.iter()) { // if numerator and denominator exist, calculate the assigned value From d84c0833c2098f25969c6f9c2c0e8f29fd9d1a6c Mon Sep 17 00:00:00 2001 From: Ho Date: Thu, 30 Nov 2023 13:39:02 +0800 Subject: [PATCH 46/54] [FEAT] Upgrading table16 for SHA256 (#73) * upgrade sha256 * fix clippy --- halo2_gadgets/benches/sha256.rs | 2 +- halo2_gadgets/src/lib.rs | 4 +- halo2_gadgets/src/sha256/table16.rs | 183 ++++++--- .../src/sha256/table16/compression.rs | 346 ++++++++++-------- .../table16/compression/compression_gates.rs | 37 +- .../table16/compression/compression_util.rs | 226 ++++++------ .../table16/compression/subregion_digest.rs | 254 ++++++++----- .../table16/compression/subregion_initial.rs | 74 ++-- .../table16/compression/subregion_main.rs | 33 +- .../src/sha256/table16/message_schedule.rs | 44 ++- .../table16/message_schedule/schedule_util.rs | 47 ++- .../table16/message_schedule/subregion1.rs | 75 ++-- .../table16/message_schedule/subregion2.rs | 281 +++++++------- .../table16/message_schedule/subregion3.rs | 63 ++-- .../src/sha256/table16/spread_table.rs | 39 +- halo2_gadgets/src/sha256/table16/util.rs | 2 +- 16 files changed, 976 insertions(+), 734 deletions(-) diff --git a/halo2_gadgets/benches/sha256.rs b/halo2_gadgets/benches/sha256.rs index 670956cb0d..a702e84ebe 100644 --- a/halo2_gadgets/benches/sha256.rs +++ b/halo2_gadgets/benches/sha256.rs @@ -52,7 +52,7 @@ fn bench(name: &str, k: u32, c: &mut Criterion) { mut layouter: impl Layouter, ) -> Result<(), Error> { Table16Chip::load(config.clone(), &mut layouter)?; - let table16_chip = Table16Chip::construct(config); + let table16_chip = Table16Chip::construct::(config); // Test vector: "abc" let test_input = [ diff --git a/halo2_gadgets/src/lib.rs b/halo2_gadgets/src/lib.rs index 8d4d4292b0..446b16c5f6 100644 --- a/halo2_gadgets/src/lib.rs +++ b/halo2_gadgets/src/lib.rs @@ -25,8 +25,8 @@ pub mod ecc; pub mod poseidon; -#[cfg(feature = "unstable")] -#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] +//#[cfg(feature = "unstable")] +//#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] pub mod sha256; pub mod sinsemilla; pub mod utilities; diff --git a/halo2_gadgets/src/sha256/table16.rs b/halo2_gadgets/src/sha256/table16.rs index c4919158bc..33fb54f1a3 100644 --- a/halo2_gadgets/src/sha256/table16.rs +++ b/halo2_gadgets/src/sha256/table16.rs @@ -1,12 +1,9 @@ -use std::convert::TryInto; -use std::marker::PhantomData; - -use super::Sha256Instructions; +use halo2_proofs::arithmetic::FieldExt as Field; use halo2_proofs::{ circuit::{AssignedCell, Chip, Layouter, Region, Value}, plonk::{Advice, Any, Assigned, Column, ConstraintSystem, Error}, }; -use halo2curves::pasta::pallas; +use std::convert::TryInto; mod compression; mod gates; @@ -81,10 +78,10 @@ impl From<&Bits> for [bool; LEN] { } } -impl From<&Bits> for Assigned { - fn from(bits: &Bits) -> Assigned { +impl From<&Bits> for Assigned { + fn from(bits: &Bits) -> Assigned { assert!(LEN <= 64); - pallas::Base::from(lebs2ip(&bits.0)).into() + F::from(lebs2ip(&bits.0)).into() } } @@ -112,20 +109,21 @@ impl From for Bits<32> { } } +/// Assigned bits #[derive(Clone, Debug)] -pub struct AssignedBits(AssignedCell, pallas::Base>); +pub struct AssignedBits(pub AssignedCell, F>); -impl std::ops::Deref for AssignedBits { - type Target = AssignedCell, pallas::Base>; +impl std::ops::Deref for AssignedBits { + type Target = AssignedCell, F>; fn deref(&self) -> &Self::Target { &self.0 } } -impl AssignedBits { +impl AssignedBits { fn assign_bits + std::fmt::Debug + Clone>( - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, annotation: A, column: impl Into>, offset: usize, @@ -157,13 +155,13 @@ impl AssignedBits { } } -impl AssignedBits<16> { +impl AssignedBits { fn value_u16(&self) -> Value { self.value().map(|v| v.into()) } fn assign( - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, annotation: A, column: impl Into>, offset: usize, @@ -192,13 +190,13 @@ impl AssignedBits<16> { } } -impl AssignedBits<32> { +impl AssignedBits { fn value_u32(&self) -> Value { self.value().map(|v| v.into()) } fn assign( - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, annotation: A, column: impl Into>, offset: usize, @@ -235,14 +233,53 @@ pub struct Table16Config { compression: CompressionConfig, } +impl Table16Config { + pub(crate) fn initialize( + &self, + layouter: &mut impl Layouter, + init_state_assigned: [RoundWordDense; STATE], + ) -> Result, Error> { + self.compression.initialize(layouter, init_state_assigned) + } + + pub(crate) fn compress( + &self, + layouter: &mut impl Layouter, + initialized_state: State, + w_halves: [(AssignedBits, AssignedBits); ROUNDS], + ) -> Result, Error> { + self.compression + .compress(layouter, initialized_state, w_halves) + } + + pub(crate) fn digest( + &self, + layouter: &mut impl Layouter, + final_state: State, + initialized_state: State, + ) -> Result<[RoundWordDense; STATE], Error> { + self.compression + .digest(layouter, final_state, initialized_state) + } + + #[allow(clippy::type_complexity)] + pub(crate) fn message_process( + &self, + layouter: &mut impl Layouter, + input: [BlockWord; super::BLOCK_SIZE], + ) -> Result<[(AssignedBits, AssignedBits); ROUNDS], Error> { + let (_, w_halves) = self.message_schedule.process(layouter, input)?; + Ok(w_halves) + } +} + /// A chip that implements SHA-256 with a maximum lookup table size of $2^16$. #[derive(Clone, Debug)] pub struct Table16Chip { config: Table16Config, - _marker: PhantomData, } -impl Chip for Table16Chip { +impl Chip for Table16Chip { type Config = Table16Config; type Loaded = (); @@ -257,17 +294,12 @@ impl Chip for Table16Chip { impl Table16Chip { /// Reconstructs this chip from the given config. - pub fn construct(config: >::Config) -> Self { - Self { - config, - _marker: PhantomData, - } + pub fn construct(config: >::Config) -> Self { + Self { config } } /// Configures a circuit to include this chip. - pub fn configure( - meta: &mut ConstraintSystem, - ) -> >::Config { + pub fn configure(meta: &mut ConstraintSystem) -> >::Config { // Columns required by this chip: let message_schedule = meta.advice_column(); let extras = [ @@ -318,69 +350,114 @@ impl Table16Chip { } /// Loads the lookup table required by this chip into the circuit. - pub fn load( + pub fn load( config: Table16Config, - layouter: &mut impl Layouter, + layouter: &mut impl Layouter, ) -> Result<(), Error> { SpreadTableChip::load(config.lookup, layouter) } } -impl Sha256Instructions for Table16Chip { - type State = State; +/// composite of states in table16 +#[allow(clippy::large_enum_variant)] +#[derive(Clone, Debug)] +pub enum Table16State { + /// working state (with spread assignment) for compression rounds + Compress(Box>), + /// the dense state only carry hi-lo 16bit assigned cell used in digest and next block + Dense([RoundWordDense; STATE]), +} + +impl super::Sha256Instructions for Table16Chip { + type State = Table16State; type BlockWord = BlockWord; - fn initialization_vector( - &self, - layouter: &mut impl Layouter, - ) -> Result { - self.config().compression.initialize_with_iv(layouter, IV) + fn initialization_vector(&self, layouter: &mut impl Layouter) -> Result { + >::config(self) + .compression + .initialize_with_iv(layouter, IV) + .map(Box::new) + .map(Table16State::Compress) } fn initialization( &self, - layouter: &mut impl Layouter, + layouter: &mut impl Layouter, init_state: &Self::State, ) -> Result { - self.config() + let dense_state = match init_state.clone() { + Table16State::Compress(s) => { + let (a, b, c, d, e, f, g, h) = s.decompose(); + [ + a.into_dense(), + b.into_dense(), + c.into_dense(), + d, + e.into_dense(), + f.into_dense(), + g.into_dense(), + h, + ] + } + Table16State::Dense(s) => s, + }; + + >::config(self) .compression - .initialize_with_state(layouter, init_state.clone()) + .initialize(layouter, dense_state) + .map(Box::new) + .map(Table16State::Compress) } // Given an initialized state and an input message block, compress the // message block and return the final state. fn compress( &self, - layouter: &mut impl Layouter, + layouter: &mut impl Layouter, initialized_state: &Self::State, input: [Self::BlockWord; super::BLOCK_SIZE], ) -> Result { - let config = self.config(); + let config = >::config(self); let (_, w_halves) = config.message_schedule.process(layouter, input)?; + + let init_working_state = match initialized_state { + Table16State::Compress(s) => s.as_ref().clone(), + _ => panic!("unexpected state type"), + }; + + let final_state = + config + .compression + .compress(layouter, init_working_state.clone(), w_halves)?; + config .compression - .compress(layouter, initialized_state.clone(), w_halves) + .digest(layouter, final_state, init_working_state) + .map(Table16State::Dense) } fn digest( &self, - layouter: &mut impl Layouter, + _layouter: &mut impl Layouter, state: &Self::State, ) -> Result<[Self::BlockWord; super::DIGEST_SIZE], Error> { - // Copy the dense forms of the state variable chunks down to this gate. - // Reconstruct the 32-bit dense words. - self.config().compression.digest(layouter, state.clone()) + let digest_state = match state { + Table16State::Dense(s) => s.clone(), + _ => panic!("unexpected state type"), + }; + + Ok(digest_state.map(|s| s.value()).map(BlockWord)) } } /// Common assignment patterns used by Table16 regions. -trait Table16Assignment { +trait Table16Assignment { /// Assign cells for general spread computation used in sigma, ch, ch_neg, maj gates #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] fn assign_spread_outputs( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, lookup: &SpreadInputs, a_3: Column, row: usize, @@ -390,8 +467,8 @@ trait Table16Assignment { r_1_odd: Value<[bool; 16]>, ) -> Result< ( - (AssignedBits<16>, AssignedBits<16>), - (AssignedBits<16>, AssignedBits<16>), + (AssignedBits, AssignedBits), + (AssignedBits, AssignedBits), ), Error, > { @@ -432,7 +509,7 @@ trait Table16Assignment { #[allow(clippy::too_many_arguments)] fn assign_sigma_outputs( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, lookup: &SpreadInputs, a_3: Column, row: usize, @@ -440,7 +517,7 @@ trait Table16Assignment { r_0_odd: Value<[bool; 16]>, r_1_even: Value<[bool; 16]>, r_1_odd: Value<[bool; 16]>, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { + ) -> Result<(AssignedBits, AssignedBits), Error> { let (even, _odd) = self.assign_spread_outputs( region, lookup, a_3, row, r_0_even, r_0_odd, r_1_even, r_1_odd, )?; @@ -482,7 +559,7 @@ mod tests { config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { - let table16_chip = Table16Chip::construct(config.clone()); + let table16_chip = Table16Chip::construct::(config.clone()); Table16Chip::load(config, &mut layouter)?; // Test vector: "abc" diff --git a/halo2_gadgets/src/sha256/table16/compression.rs b/halo2_gadgets/src/sha256/table16/compression.rs index 62deb42937..9c2de95034 100644 --- a/halo2_gadgets/src/sha256/table16/compression.rs +++ b/halo2_gadgets/src/sha256/table16/compression.rs @@ -1,16 +1,13 @@ use super::{ - super::DIGEST_SIZE, util::{i2lebsp, lebs2ip}, - AssignedBits, BlockWord, SpreadInputs, SpreadVar, Table16Assignment, ROUNDS, STATE, + AssignedBits, Field, SpreadInputs, SpreadVar, Table16Assignment, ROUNDS, STATE, }; use halo2_proofs::{ circuit::{Layouter, Value}, plonk::{Advice, Column, ConstraintSystem, Error, Selector}, poly::Rotation, }; -use halo2curves::pasta::pallas; -use std::convert::TryInto; -use std::ops::Range; +use std::{convert::TryInto, ops::Range}; mod compression_gates; mod compression_util; @@ -72,24 +69,23 @@ pub trait UpperSigmaVar< /// A variable that represents the `[A,B,C,D]` words of the SHA-256 internal state. /// /// The structure of this variable is influenced by the following factors: -/// - In `Σ_0(A)` we need `A` to be split into pieces `(a,b,c,d)` of lengths `(2,11,9,10)` -/// bits respectively (counting from the little end), as well as their spread forms. -/// - `Maj(A,B,C)` requires having the bits of each input in spread form. For `A` we can -/// reuse the pieces from `Σ_0(A)`. Since `B` and `C` are assigned from `A` and `B` -/// respectively in each round, we therefore also have the same pieces in earlier rows. -/// We align the columns to make it efficient to copy-constrain these forms where they -/// are needed. +/// - In `Σ_0(A)` we need `A` to be split into pieces `(a,b,c,d)` of lengths `(2,11,9,10)` bits +/// respectively (counting from the little end), as well as their spread forms. +/// - `Maj(A,B,C)` requires having the bits of each input in spread form. For `A` we can reuse the +/// pieces from `Σ_0(A)`. Since `B` and `C` are assigned from `A` and `B` respectively in each +/// round, we therefore also have the same pieces in earlier rows. We align the columns to make it +/// efficient to copy-constrain these forms where they are needed. #[derive(Clone, Debug)] -pub struct AbcdVar { - a: SpreadVar<2, 4>, - b: SpreadVar<11, 22>, - c_lo: SpreadVar<3, 6>, - c_mid: SpreadVar<3, 6>, - c_hi: SpreadVar<3, 6>, - d: SpreadVar<10, 20>, +pub struct AbcdVar { + a: SpreadVar, + b: SpreadVar, + c_lo: SpreadVar, + c_mid: SpreadVar, + c_hi: SpreadVar, + d: SpreadVar, } -impl AbcdVar { +impl AbcdVar { fn a_range() -> Range { 0..2 } @@ -127,7 +123,7 @@ impl AbcdVar { } } -impl UpperSigmaVar<4, 22, 18, 20> for AbcdVar { +impl UpperSigmaVar<4, 22, 18, 20> for AbcdVar { fn spread_a(&self) -> Value<[bool; 4]> { self.a.spread.value().map(|v| v.0) } @@ -161,24 +157,23 @@ impl UpperSigmaVar<4, 22, 18, 20> for AbcdVar { /// A variable that represents the `[E,F,G,H]` words of the SHA-256 internal state. /// /// The structure of this variable is influenced by the following factors: -/// - In `Σ_1(E)` we need `E` to be split into pieces `(a,b,c,d)` of lengths `(6,5,14,7)` -/// bits respectively (counting from the little end), as well as their spread forms. -/// - `Ch(E,F,G)` requires having the bits of each input in spread form. For `E` we can -/// reuse the pieces from `Σ_1(E)`. Since `F` and `G` are assigned from `E` and `F` -/// respectively in each round, we therefore also have the same pieces in earlier rows. -/// We align the columns to make it efficient to copy-constrain these forms where they -/// are needed. +/// - In `Σ_1(E)` we need `E` to be split into pieces `(a,b,c,d)` of lengths `(6,5,14,7)` bits +/// respectively (counting from the little end), as well as their spread forms. +/// - `Ch(E,F,G)` requires having the bits of each input in spread form. For `E` we can reuse the +/// pieces from `Σ_1(E)`. Since `F` and `G` are assigned from `E` and `F` respectively in each +/// round, we therefore also have the same pieces in earlier rows. We align the columns to make it +/// efficient to copy-constrain these forms where they are needed. #[derive(Clone, Debug)] -pub struct EfghVar { - a_lo: SpreadVar<3, 6>, - a_hi: SpreadVar<3, 6>, - b_lo: SpreadVar<2, 4>, - b_hi: SpreadVar<3, 6>, - c: SpreadVar<14, 28>, - d: SpreadVar<7, 14>, +pub struct EfghVar { + a_lo: SpreadVar, + a_hi: SpreadVar, + b_lo: SpreadVar, + b_hi: SpreadVar, + c: SpreadVar, + d: SpreadVar, } -impl EfghVar { +impl EfghVar { fn a_lo_range() -> Range { 0..3 } @@ -216,7 +211,7 @@ impl EfghVar { } } -impl UpperSigmaVar<12, 10, 28, 14> for EfghVar { +impl UpperSigmaVar<12, 10, 28, 14> for EfghVar { fn spread_a(&self) -> Value<[bool; 12]> { self.a_lo .spread @@ -257,33 +252,37 @@ impl UpperSigmaVar<12, 10, 28, 14> for EfghVar { } #[derive(Clone, Debug)] -pub struct RoundWordDense(AssignedBits<16>, AssignedBits<16>); +pub struct RoundWordDense(AssignedBits, AssignedBits); -impl From<(AssignedBits<16>, AssignedBits<16>)> for RoundWordDense { - fn from(halves: (AssignedBits<16>, AssignedBits<16>)) -> Self { +impl From<(AssignedBits, AssignedBits)> for RoundWordDense { + fn from(halves: (AssignedBits, AssignedBits)) -> Self { Self(halves.0, halves.1) } } -impl RoundWordDense { +impl RoundWordDense { pub fn value(&self) -> Value { self.0 .value_u16() .zip(self.1.value_u16()) .map(|(lo, hi)| lo as u32 + (1 << 16) * hi as u32) } + + pub fn decompose(self) -> (AssignedBits, AssignedBits) { + (self.0, self.1) + } } #[derive(Clone, Debug)] -pub struct RoundWordSpread(AssignedBits<32>, AssignedBits<32>); +pub struct RoundWordSpread(AssignedBits, AssignedBits); -impl From<(AssignedBits<32>, AssignedBits<32>)> for RoundWordSpread { - fn from(halves: (AssignedBits<32>, AssignedBits<32>)) -> Self { +impl From<(AssignedBits, AssignedBits)> for RoundWordSpread { + fn from(halves: (AssignedBits, AssignedBits)) -> Self { Self(halves.0, halves.1) } } -impl RoundWordSpread { +impl RoundWordSpread { pub fn value(&self) -> Value { self.0 .value_u32() @@ -293,17 +292,17 @@ impl RoundWordSpread { } #[derive(Clone, Debug)] -pub struct RoundWordA { - pieces: Option, - dense_halves: RoundWordDense, - spread_halves: Option, +pub struct RoundWordA { + pieces: Option>, + dense_halves: RoundWordDense, + spread_halves: Option>, } -impl RoundWordA { +impl RoundWordA { pub fn new( - pieces: AbcdVar, - dense_halves: RoundWordDense, - spread_halves: RoundWordSpread, + pieces: AbcdVar, + dense_halves: RoundWordDense, + spread_halves: RoundWordSpread, ) -> Self { RoundWordA { pieces: Some(pieces), @@ -312,27 +311,31 @@ impl RoundWordA { } } - pub fn new_dense(dense_halves: RoundWordDense) -> Self { + pub fn new_dense(dense_halves: RoundWordDense) -> Self { RoundWordA { pieces: None, dense_halves, spread_halves: None, } } + + pub fn into_dense(self) -> RoundWordDense { + self.dense_halves + } } #[derive(Clone, Debug)] -pub struct RoundWordE { - pieces: Option, - dense_halves: RoundWordDense, - spread_halves: Option, +pub struct RoundWordE { + pieces: Option>, + dense_halves: RoundWordDense, + spread_halves: Option>, } -impl RoundWordE { +impl RoundWordE { pub fn new( - pieces: EfghVar, - dense_halves: RoundWordDense, - spread_halves: RoundWordSpread, + pieces: EfghVar, + dense_halves: RoundWordDense, + spread_halves: RoundWordSpread, ) -> Self { RoundWordE { pieces: Some(pieces), @@ -341,55 +344,63 @@ impl RoundWordE { } } - pub fn new_dense(dense_halves: RoundWordDense) -> Self { + pub fn new_dense(dense_halves: RoundWordDense) -> Self { RoundWordE { pieces: None, dense_halves, spread_halves: None, } } + + pub fn into_dense(self) -> RoundWordDense { + self.dense_halves + } } #[derive(Clone, Debug)] -pub struct RoundWord { - dense_halves: RoundWordDense, - spread_halves: RoundWordSpread, +pub struct RoundWord { + dense_halves: RoundWordDense, + spread_halves: RoundWordSpread, } -impl RoundWord { - pub fn new(dense_halves: RoundWordDense, spread_halves: RoundWordSpread) -> Self { +impl RoundWord { + pub fn new(dense_halves: RoundWordDense, spread_halves: RoundWordSpread) -> Self { RoundWord { dense_halves, spread_halves, } } + + pub fn into_dense(self) -> RoundWordDense { + self.dense_halves + } } /// The internal state for SHA-256. #[derive(Clone, Debug)] -pub struct State { - a: Option, - b: Option, - c: Option, - d: Option, - e: Option, - f: Option, - g: Option, - h: Option, +pub struct State { + a: Option>, + b: Option>, + c: Option>, + d: Option>, + e: Option>, + f: Option>, + g: Option>, + h: Option>, } -impl State { +impl State { #[allow(clippy::many_single_char_names)] #[allow(clippy::too_many_arguments)] pub fn new( - a: StateWord, - b: StateWord, - c: StateWord, - d: StateWord, - e: StateWord, - f: StateWord, - g: StateWord, - h: StateWord, + a: StateWord, + b: StateWord, + c: StateWord, + d: StateWord, + e: StateWord, + f: StateWord, + g: StateWord, + h: StateWord, ) -> Self { State { a: Some(a), @@ -415,18 +426,58 @@ impl State { h: None, } } + + #[allow(clippy::type_complexity)] + pub fn decompose( + self, + ) -> ( + RoundWordA, + RoundWord, + RoundWord, + RoundWordDense, + RoundWordE, + RoundWord, + RoundWord, + RoundWordDense, + ) { + compression_util::match_state(self) + } + + #[allow(clippy::many_single_char_names)] + #[allow(clippy::too_many_arguments)] + pub fn composite( + a: RoundWordA, + b: RoundWord, + c: RoundWord, + d: RoundWordDense, + e: RoundWordE, + f: RoundWord, + g: RoundWord, + h: RoundWordDense, + ) -> Self { + Self::new( + StateWord::A(a), + StateWord::B(b), + StateWord::C(c), + StateWord::D(d), + StateWord::E(e), + StateWord::F(f), + StateWord::G(g), + StateWord::H(h), + ) + } } #[derive(Clone, Debug)] -pub enum StateWord { - A(RoundWordA), - B(RoundWord), - C(RoundWord), - D(RoundWordDense), - E(RoundWordE), - F(RoundWord), - G(RoundWord), - H(RoundWordDense), +pub enum StateWord { + A(RoundWordA), + B(RoundWord), + C(RoundWord), + D(RoundWordDense), + E(RoundWordE), + F(RoundWord), + G(RoundWord), + H(RoundWordDense), } #[derive(Clone, Debug)] @@ -453,11 +504,11 @@ pub(super) struct CompressionConfig { s_digest: Selector, } -impl Table16Assignment for CompressionConfig {} +impl Table16Assignment for CompressionConfig {} impl CompressionConfig { - pub(super) fn configure( - meta: &mut ConstraintSystem, + pub(super) fn configure( + meta: &mut ConstraintSystem, lookup: SpreadInputs, message_schedule: Column, extras: [Column; 6], @@ -822,22 +873,25 @@ impl CompressionConfig { // s_digest for final round meta.create_gate("s_digest", |meta| { let s_digest = meta.query_selector(s_digest); - let lo_0 = meta.query_advice(a_3, Rotation::cur()); - let hi_0 = meta.query_advice(a_4, Rotation::cur()); - let word_0 = meta.query_advice(a_5, Rotation::cur()); - let lo_1 = meta.query_advice(a_6, Rotation::cur()); - let hi_1 = meta.query_advice(a_7, Rotation::cur()); - let word_1 = meta.query_advice(a_8, Rotation::cur()); - let lo_2 = meta.query_advice(a_3, Rotation::next()); - let hi_2 = meta.query_advice(a_4, Rotation::next()); - let word_2 = meta.query_advice(a_5, Rotation::next()); - let lo_3 = meta.query_advice(a_6, Rotation::next()); - let hi_3 = meta.query_advice(a_7, Rotation::next()); - let word_3 = meta.query_advice(a_8, Rotation::next()); + let digest_lo = meta.query_advice(a_1, Rotation::cur()); + let digest_hi = meta.query_advice(a_1, Rotation::next()); + let digest_word = meta.query_advice(a_5, Rotation::cur()); + let final_lo = meta.query_advice(a_3, Rotation::cur()); + let final_hi = meta.query_advice(a_3, Rotation::next()); + let initial_lo = meta.query_advice(a_6, Rotation::cur()); + let initial_hi = meta.query_advice(a_6, Rotation::next()); + let digest_carry = meta.query_advice(a_8, Rotation::cur()); CompressionGate::s_digest( - s_digest, lo_0, hi_0, word_0, lo_1, hi_1, word_1, lo_2, hi_2, word_2, lo_3, hi_3, - word_3, + s_digest, + digest_lo, + digest_hi, + digest_word, + final_lo, + final_hi, + initial_lo, + initial_hi, + digest_carry, ) }); @@ -861,11 +915,11 @@ impl CompressionConfig { /// Initialize compression with a constant Initialization Vector of 32-byte words. /// Returns an initialized state. - pub(super) fn initialize_with_iv( + pub(super) fn initialize_with_iv( &self, - layouter: &mut impl Layouter, + layouter: &mut impl Layouter, init_state: [u32; STATE], - ) -> Result { + ) -> Result, Error> { let mut new_state = State::empty_state(); layouter.assign_region( || "initialize_with_iv", @@ -877,18 +931,17 @@ impl CompressionConfig { Ok(new_state) } - /// Initialize compression with some initialized state. This could be a state - /// output from a previous compression round. - pub(super) fn initialize_with_state( + /// Initialize compression with the minimun assignment of state cell. + pub(crate) fn initialize( &self, - layouter: &mut impl Layouter, - init_state: State, - ) -> Result { + layouter: &mut impl Layouter, + init_state_assigned: [RoundWordDense; STATE], + ) -> Result, Error> { let mut new_state = State::empty_state(); layouter.assign_region( || "initialize_with_state", |mut region| { - new_state = self.initialize_state(&mut region, init_state.clone())?; + new_state = self.initialize_state(&mut region, init_state_assigned.clone())?; Ok(()) }, )?; @@ -896,12 +949,12 @@ impl CompressionConfig { } /// Given an initialized state and a message schedule, perform 64 compression rounds. - pub(super) fn compress( + pub(super) fn compress( &self, - layouter: &mut impl Layouter, - initialized_state: State, - w_halves: [(AssignedBits<16>, AssignedBits<16>); ROUNDS], - ) -> Result { + layouter: &mut impl Layouter, + initialized_state: State, + w_halves: [(AssignedBits, AssignedBits); ROUNDS], + ) -> Result, Error> { let mut state = State::empty_state(); layouter.assign_region( || "compress", @@ -917,21 +970,22 @@ impl CompressionConfig { } /// After the final round, convert the state into the final digest. - pub(super) fn digest( + pub(super) fn digest( &self, - layouter: &mut impl Layouter, - state: State, - ) -> Result<[BlockWord; DIGEST_SIZE], Error> { - let mut digest = [BlockWord(Value::known(0)); DIGEST_SIZE]; + layouter: &mut impl Layouter, + last_compress_state: State, + initial_state: State, + ) -> Result<[RoundWordDense; STATE], Error> { layouter.assign_region( || "digest", |mut region| { - digest = self.assign_digest(&mut region, state.clone())?; - - Ok(()) + self.complete_digest( + &mut region, + last_compress_state.clone(), + initial_state.clone(), + ) }, - )?; - Ok(digest) + ) } } @@ -978,15 +1032,17 @@ mod tests { let compression = config.compression.clone(); let initial_state = compression.initialize_with_iv(&mut layouter, IV)?; - let state = config - .compression - .compress(&mut layouter, initial_state, w_halves)?; + let state = + config + .compression + .compress(&mut layouter, initial_state.clone(), w_halves)?; - let digest = config.compression.digest(&mut layouter, state)?; + let digest = config + .compression + .digest(&mut layouter, state, initial_state)?; for (idx, digest_word) in digest.iter().enumerate() { - digest_word.0.assert_if_known(|digest_word| { - (*digest_word as u64 + IV[idx] as u64) as u32 - == super::compression_util::COMPRESSION_OUTPUT[idx] + digest_word.value().assert_if_known(|digest_word| { + *digest_word == super::compression_util::COMPRESSION_OUTPUT[idx] }); } @@ -998,7 +1054,7 @@ mod tests { let prover = match MockProver::::run(17, &circuit, vec![]) { Ok(prover) => prover, - Err(e) => panic!("{:?}", e), + Err(e) => panic!("{e:?}"), }; assert_eq!(prover.verify(), Ok(())); } diff --git a/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs b/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs index e22a10210c..eccdddfd6f 100644 --- a/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs +++ b/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs @@ -1,4 +1,5 @@ use super::super::{util::*, Gate}; +use crate::utilities::range_check; use halo2_proofs::{ arithmetic::FieldExt, plonk::{Constraint, Constraints, Expression}, @@ -414,30 +415,28 @@ impl CompressionGate { #[allow(clippy::too_many_arguments)] pub fn s_digest( s_digest: Expression, - lo_0: Expression, - hi_0: Expression, - word_0: Expression, - lo_1: Expression, - hi_1: Expression, - word_1: Expression, - lo_2: Expression, - hi_2: Expression, - word_2: Expression, - lo_3: Expression, - hi_3: Expression, - word_3: Expression, + digest_lo: Expression, + digest_hi: Expression, + digest_word: Expression, + final_lo: Expression, + final_hi: Expression, + initial_lo: Expression, + initial_hi: Expression, + digest_carry: Expression, ) -> impl IntoIterator> { - let check_lo_hi = |lo: Expression, hi: Expression, word: Expression| { - lo + hi * F::from(1 << 16) - word - }; + let check_lo_hi = digest_lo.clone() + digest_hi.clone() * F::from(1 << 16) - digest_word; + + let check = + digest_carry.clone() * F::from(1 << 32) + digest_hi * F::from(1 << 16) + digest_lo + - (final_hi + initial_hi) * F::from(1 << 16) + - (final_lo + initial_lo); Constraints::with_selector( s_digest, [ - ("check_lo_hi_0", check_lo_hi(lo_0, hi_0, word_0)), - ("check_lo_hi_1", check_lo_hi(lo_1, hi_1, word_1)), - ("check_lo_hi_2", check_lo_hi(lo_2, hi_2, word_2)), - ("check_lo_hi_3", check_lo_hi(lo_3, hi_3, word_3)), + ("check digest lo_hi", check_lo_hi), + ("digest check", check), + ("check carry bit", range_check(digest_carry, 2)), ], ) } diff --git a/halo2_gadgets/src/sha256/table16/compression/compression_util.rs b/halo2_gadgets/src/sha256/table16/compression/compression_util.rs index 324fe8f695..caa0fd7c5f 100644 --- a/halo2_gadgets/src/sha256/table16/compression/compression_util.rs +++ b/halo2_gadgets/src/sha256/table16/compression/compression_util.rs @@ -1,15 +1,12 @@ +use super::super::{util::*, AssignedBits, SpreadVar, SpreadWord, StateWord, Table16Assignment}; use super::{ - AbcdVar, CompressionConfig, EfghVar, RoundWord, RoundWordA, RoundWordDense, RoundWordE, + AbcdVar, CompressionConfig, EfghVar, Field, RoundWord, RoundWordA, RoundWordDense, RoundWordE, RoundWordSpread, State, UpperSigmaVar, }; -use crate::sha256::table16::{ - util::*, AssignedBits, SpreadVar, SpreadWord, StateWord, Table16Assignment, -}; use halo2_proofs::{ circuit::{Region, Value}, plonk::{Advice, Column, Error}, }; -use halo2curves::pasta::pallas; use std::convert::TryInto; // Test vector 'abc' @@ -111,7 +108,7 @@ pub fn get_round_row(round_idx: RoundIdx) -> usize { RoundIdx::Init => 0, RoundIdx::Main(MainRoundIdx(idx)) => { assert!(idx < 64); - (idx as usize) * SUBREGION_MAIN_WORD + idx * SUBREGION_MAIN_WORD } } } @@ -190,21 +187,17 @@ pub fn get_a_new_row(round_idx: MainRoundIdx) -> usize { get_maj_row(round_idx) } -pub fn get_digest_abcd_row() -> usize { +pub fn get_digest_first_row() -> usize { SUBREGION_MAIN_ROWS } -pub fn get_digest_efgh_row() -> usize { - get_digest_abcd_row() + 2 -} - impl CompressionConfig { - pub(super) fn decompose_abcd( + pub(super) fn decompose_abcd( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, row: usize, val: Value, - ) -> Result { + ) -> Result, Error> { self.s_decompose_abcd.enable(region, row)?; let a_3 = self.extras[0]; @@ -212,7 +205,7 @@ impl CompressionConfig { let a_5 = self.message_schedule; let a_6 = self.extras[2]; - let spread_pieces = val.map(AbcdVar::pieces); + let spread_pieces = val.map(AbcdVar::::pieces); let spread_pieces = spread_pieces.transpose_vec(6); let a = SpreadVar::without_lookup( @@ -270,12 +263,12 @@ impl CompressionConfig { }) } - pub(super) fn decompose_efgh( + pub(super) fn decompose_efgh( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, row: usize, val: Value, - ) -> Result { + ) -> Result, Error> { self.s_decompose_efgh.enable(region, row)?; let a_3 = self.extras[0]; @@ -283,7 +276,7 @@ impl CompressionConfig { let a_5 = self.message_schedule; let a_6 = self.extras[2]; - let spread_pieces = val.map(EfghVar::pieces); + let spread_pieces = val.map(EfghVar::::pieces); let spread_pieces = spread_pieces.transpose_vec(6); let a_lo = SpreadVar::without_lookup( @@ -341,12 +334,12 @@ impl CompressionConfig { }) } - pub(super) fn decompose_a( + pub(super) fn decompose_a( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: RoundIdx, a_val: Value, - ) -> Result { + ) -> Result, Error> { let row = get_decompose_a_row(round_idx); let (dense_halves, spread_halves) = self.assign_word_halves(region, row, a_val)?; @@ -354,12 +347,12 @@ impl CompressionConfig { Ok(RoundWordA::new(a_pieces, dense_halves, spread_halves)) } - pub(super) fn decompose_e( + pub(super) fn decompose_e( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: RoundIdx, e_val: Value, - ) -> Result { + ) -> Result, Error> { let row = get_decompose_e_row(round_idx); let (dense_halves, spread_halves) = self.assign_word_halves(region, row, e_val)?; @@ -367,12 +360,12 @@ impl CompressionConfig { Ok(RoundWordE::new(e_pieces, dense_halves, spread_halves)) } - pub(super) fn assign_upper_sigma_0( + pub(super) fn assign_upper_sigma_0( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: MainRoundIdx, - word: AbcdVar, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { + word: AbcdVar, + ) -> Result<(AssignedBits, AssignedBits), Error> { // Rename these here for ease of matching the gates to the specification. let a_3 = self.extras[0]; let a_4 = self.extras[1]; @@ -425,12 +418,12 @@ impl CompressionConfig { ) } - pub(super) fn assign_upper_sigma_1( + pub(super) fn assign_upper_sigma_1( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: MainRoundIdx, - word: EfghVar, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { + word: EfghVar, + ) -> Result<(AssignedBits, AssignedBits), Error> { // Rename these here for ease of matching the gates to the specification. let a_3 = self.extras[0]; let a_4 = self.extras[1]; @@ -484,15 +477,15 @@ impl CompressionConfig { ) } - fn assign_ch_outputs( + fn assign_ch_outputs( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, row: usize, r_0_even: Value<[bool; 16]>, r_0_odd: Value<[bool; 16]>, r_1_even: Value<[bool; 16]>, r_1_odd: Value<[bool; 16]>, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { + ) -> Result<(AssignedBits, AssignedBits), Error> { let a_3 = self.extras[0]; let (_even, odd) = self.assign_spread_outputs( @@ -509,13 +502,13 @@ impl CompressionConfig { Ok(odd) } - pub(super) fn assign_ch( + pub(super) fn assign_ch( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: MainRoundIdx, - spread_halves_e: RoundWordSpread, - spread_halves_f: RoundWordSpread, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { + spread_halves_e: RoundWordSpread, + spread_halves_f: RoundWordSpread, + ) -> Result<(AssignedBits, AssignedBits), Error> { let a_3 = self.extras[0]; let a_4 = self.extras[1]; @@ -555,13 +548,13 @@ impl CompressionConfig { self.assign_ch_outputs(region, row, p_0_even, p_0_odd, p_1_even, p_1_odd) } - pub(super) fn assign_ch_neg( + pub(super) fn assign_ch_neg( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: MainRoundIdx, - spread_halves_e: RoundWordSpread, - spread_halves_g: RoundWordSpread, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { + spread_halves_e: RoundWordSpread, + spread_halves_g: RoundWordSpread, + ) -> Result<(AssignedBits, AssignedBits), Error> { let row = get_ch_neg_row(round_idx); self.s_ch_neg.enable(region, row)?; @@ -592,7 +585,7 @@ impl CompressionConfig { .value() .map(|spread_e_lo| negate_spread(spread_e_lo.0)); // Assign spread_neg_e_lo - AssignedBits::<32>::assign_bits( + AssignedBits::::assign_bits( region, || "spread_neg_e_lo", a_3, @@ -606,7 +599,7 @@ impl CompressionConfig { .value() .map(|spread_e_hi| negate_spread(spread_e_hi.0)); // Assign spread_neg_e_hi - AssignedBits::<32>::assign_bits( + AssignedBits::::assign_bits( region, || "spread_neg_e_hi", a_4, @@ -634,15 +627,15 @@ impl CompressionConfig { self.assign_ch_outputs(region, row, p_0_even, p_0_odd, p_1_even, p_1_odd) } - fn assign_maj_outputs( + fn assign_maj_outputs( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, row: usize, r_0_even: Value<[bool; 16]>, r_0_odd: Value<[bool; 16]>, r_1_even: Value<[bool; 16]>, r_1_odd: Value<[bool; 16]>, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { + ) -> Result<(AssignedBits, AssignedBits), Error> { let a_3 = self.extras[0]; let (_even, odd) = self.assign_spread_outputs( region, @@ -658,14 +651,14 @@ impl CompressionConfig { Ok(odd) } - pub(super) fn assign_maj( + pub(super) fn assign_maj( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: MainRoundIdx, - spread_halves_a: RoundWordSpread, - spread_halves_b: RoundWordSpread, - spread_halves_c: RoundWordSpread, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { + spread_halves_a: RoundWordSpread, + spread_halves_b: RoundWordSpread, + spread_halves_c: RoundWordSpread, + ) -> Result<(AssignedBits, AssignedBits), Error> { let a_4 = self.extras[1]; let a_5 = self.message_schedule; @@ -716,17 +709,17 @@ impl CompressionConfig { // s_h_prime to get H' = H + Ch(E, F, G) + s_upper_sigma_1(E) + K + W #[allow(clippy::too_many_arguments)] - pub(super) fn assign_h_prime( + pub(super) fn assign_h_prime( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: MainRoundIdx, - h: RoundWordDense, - ch: (AssignedBits<16>, AssignedBits<16>), - ch_neg: (AssignedBits<16>, AssignedBits<16>), - sigma_1: (AssignedBits<16>, AssignedBits<16>), + h: RoundWordDense, + ch: (AssignedBits, AssignedBits), + ch_neg: (AssignedBits, AssignedBits), + sigma_1: (AssignedBits, AssignedBits), k: u32, - w: &(AssignedBits<16>, AssignedBits<16>), - ) -> Result { + w: &(AssignedBits, AssignedBits), + ) -> Result, Error> { let row = get_h_prime_row(round_idx); self.s_h_prime.enable(region, row)?; @@ -750,8 +743,14 @@ impl CompressionConfig { let k_lo: [bool; 16] = k[..16].try_into().unwrap(); let k_hi: [bool; 16] = k[16..].try_into().unwrap(); { - AssignedBits::<16>::assign_bits(region, || "k_lo", a_6, row - 1, Value::known(k_lo))?; - AssignedBits::<16>::assign_bits(region, || "k_hi", a_6, row, Value::known(k_hi))?; + AssignedBits::::assign_bits( + region, + || "k_lo", + a_6, + row - 1, + Value::known(k_lo), + )?; + AssignedBits::::assign_bits(region, || "k_hi", a_6, row, Value::known(k_hi))?; } // Assign and copy w @@ -783,30 +782,40 @@ impl CompressionConfig { || "h_prime_carry", a_9, row + 1, - || h_prime_carry.map(|value| pallas::Base::from(value as u64)), + || h_prime_carry.map(|value| F::from(value)), )?; let h_prime: Value<[bool; 32]> = h_prime.map(|w| i2lebsp(w.into())); let h_prime_lo: Value<[bool; 16]> = h_prime.map(|w| w[..16].try_into().unwrap()); let h_prime_hi: Value<[bool; 16]> = h_prime.map(|w| w[16..].try_into().unwrap()); - let h_prime_lo = - AssignedBits::<16>::assign_bits(region, || "h_prime_lo", a_7, row + 1, h_prime_lo)?; - let h_prime_hi = - AssignedBits::<16>::assign_bits(region, || "h_prime_hi", a_8, row + 1, h_prime_hi)?; + let h_prime_lo = AssignedBits::::assign_bits( + region, + || "h_prime_lo", + a_7, + row + 1, + h_prime_lo, + )?; + let h_prime_hi = AssignedBits::::assign_bits( + region, + || "h_prime_hi", + a_8, + row + 1, + h_prime_hi, + )?; Ok((h_prime_lo, h_prime_hi).into()) } } // s_e_new to get E_new = H' + D - pub(super) fn assign_e_new( + pub(super) fn assign_e_new( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: MainRoundIdx, - d: &RoundWordDense, - h_prime: &RoundWordDense, - ) -> Result { + d: &RoundWordDense, + h_prime: &RoundWordDense, + ) -> Result, Error> { let row = get_e_new_row(round_idx); self.s_e_new.enable(region, row)?; @@ -826,25 +835,20 @@ impl CompressionConfig { ]); let e_new_dense = self.assign_word_halves_dense(region, row, a_8, row + 1, a_8, e_new)?; - region.assign_advice( - || "e_new_carry", - a_9, - row + 1, - || e_new_carry.map(pallas::Base::from), - )?; + region.assign_advice(|| "e_new_carry", a_9, row + 1, || e_new_carry.map(F::from))?; Ok(e_new_dense) } // s_a_new to get A_new = H' + Maj(A, B, C) + s_upper_sigma_0(A) - pub(super) fn assign_a_new( + pub(super) fn assign_a_new( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: MainRoundIdx, - maj: (AssignedBits<16>, AssignedBits<16>), - sigma_0: (AssignedBits<16>, AssignedBits<16>), - h_prime: RoundWordDense, - ) -> Result { + maj: (AssignedBits, AssignedBits), + sigma_0: (AssignedBits, AssignedBits), + h_prime: RoundWordDense, + ) -> Result, Error> { let row = get_a_new_row(round_idx); self.s_a_new.enable(region, row)?; @@ -880,35 +884,30 @@ impl CompressionConfig { ]); let a_new_dense = self.assign_word_halves_dense(region, row, a_8, row + 1, a_8, a_new)?; - region.assign_advice( - || "a_new_carry", - a_9, - row, - || a_new_carry.map(pallas::Base::from), - )?; + region.assign_advice(|| "a_new_carry", a_9, row, || a_new_carry.map(F::from))?; Ok(a_new_dense) } - pub fn assign_word_halves_dense( + pub fn assign_word_halves_dense( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, lo_row: usize, lo_col: Column, hi_row: usize, hi_col: Column, word: Value, - ) -> Result { + ) -> Result, Error> { let word: Value<[bool; 32]> = word.map(|w| i2lebsp(w.into())); let lo = { let lo: Value<[bool; 16]> = word.map(|w| w[..16].try_into().unwrap()); - AssignedBits::<16>::assign_bits(region, || "lo", lo_col, lo_row, lo)? + AssignedBits::::assign_bits(region, || "lo", lo_col, lo_row, lo)? }; let hi = { let hi: Value<[bool; 16]> = word.map(|w| w[16..].try_into().unwrap()); - AssignedBits::<16>::assign_bits(region, || "hi", hi_col, hi_row, hi)? + AssignedBits::::assign_bits(region, || "hi", hi_col, hi_row, hi)? }; Ok((lo, hi).into()) @@ -916,12 +915,12 @@ impl CompressionConfig { // Assign hi and lo halves for both dense and spread versions of a word #[allow(clippy::type_complexity)] - pub fn assign_word_halves( + pub fn assign_word_halves( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, row: usize, word: Value, - ) -> Result<(RoundWordDense, RoundWordSpread), Error> { + ) -> Result<(RoundWordDense, RoundWordSpread), Error> { // Rename these here for ease of matching the gates to the specification. let a_7 = self.extras[3]; let a_8 = self.extras[4]; @@ -942,17 +941,18 @@ impl CompressionConfig { } #[allow(clippy::many_single_char_names)] -pub fn match_state( - state: State, +#[allow(clippy::type_complexity)] +pub fn match_state( + state: State, ) -> ( - RoundWordA, - RoundWord, - RoundWord, - RoundWordDense, - RoundWordE, - RoundWord, - RoundWord, - RoundWordDense, + RoundWordA, + RoundWord, + RoundWord, + RoundWordDense, + RoundWordE, + RoundWord, + RoundWord, + RoundWordDense, ) { let a = match state.a { Some(StateWord::A(a)) => a, diff --git a/halo2_gadgets/src/sha256/table16/compression/subregion_digest.rs b/halo2_gadgets/src/sha256/table16/compression/subregion_digest.rs index aa30f80af7..a22c8cd676 100644 --- a/halo2_gadgets/src/sha256/table16/compression/subregion_digest.rs +++ b/halo2_gadgets/src/sha256/table16/compression/subregion_digest.rs @@ -1,102 +1,180 @@ -use super::super::{super::DIGEST_SIZE, BlockWord, RoundWordDense}; -use super::{compression_util::*, CompressionConfig, State}; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::{Advice, Column, Error}, +use super::super::util::{i2lebsp, sum_with_carry}; +use super::{ + super::{AssignedBits, RoundWordDense, SpreadVar, SpreadWord, STATE}, + compression_util::*, + CompressionConfig, Field, State, }; -use halo2curves::pasta::pallas; +use halo2_proofs::{circuit::Region, plonk::Error}; impl CompressionConfig { + // #[allow(clippy::many_single_char_names)] + // pub fn assign_digest( + // &self, + // region: &mut Region<'_, F>, + // state: State, + // ) -> Result<[BlockWord; DIGEST_SIZE], Error> { + // let a_3 = self.extras[0]; + // let a_4 = self.extras[1]; + // let a_5 = self.message_schedule; + // let a_6 = self.extras[2]; + // let a_7 = self.extras[3]; + // let a_8 = self.extras[4]; + + // let (a, b, c, d, e, f, g, h) = match_state(state); + + // let abcd_row = 0; + // self.s_digest.enable(region, abcd_row)?; + // let efgh_row = abcd_row + 2; + // self.s_digest.enable(region, efgh_row)?; + + // // Assign digest for A, B, C, D + // a.dense_halves + // .0 + // .copy_advice(|| "a_lo", region, a_3, abcd_row)?; + // a.dense_halves + // .1 + // .copy_advice(|| "a_hi", region, a_4, abcd_row)?; + // let a = a.dense_halves.value(); + // region.assign_advice(|| "a", a_5, abcd_row, || a.map(|a| F::from(a as u64)))?; + + // let b = self.assign_digest_word(region, abcd_row, a_6, a_7, a_8, b.dense_halves)?; + // let c = self.assign_digest_word(region, abcd_row + 1, a_3, a_4, a_5, c.dense_halves)?; + // let d = self.assign_digest_word(region, abcd_row + 1, a_6, a_7, a_8, d)?; + + // // Assign digest for E, F, G, H + // e.dense_halves + // .0 + // .copy_advice(|| "e_lo", region, a_3, efgh_row)?; + // e.dense_halves + // .1 + // .copy_advice(|| "e_hi", region, a_4, efgh_row)?; + // let e = e.dense_halves.value(); + // region.assign_advice(|| "e", a_5, efgh_row, || e.map(|e| F::from(e as u64)))?; + + // let f = self.assign_digest_word(region, efgh_row, a_6, a_7, a_8, f.dense_halves)?; + // let g = self.assign_digest_word(region, efgh_row + 1, a_3, a_4, a_5, g.dense_halves)?; + // let h = self.assign_digest_word(region, efgh_row + 1, a_6, a_7, a_8, h)?; + + // Ok([ + // BlockWord(a), + // BlockWord(b), + // BlockWord(c), + // BlockWord(d), + // BlockWord(e), + // BlockWord(f), + // BlockWord(g), + // BlockWord(h), + // ]) + // } + + // fn assign_digest_word( + // &self, + // region: &mut Region<'_, F>, + // row: usize, + // lo_col: Column, + // hi_col: Column, + // word_col: Column, + // dense_halves: RoundWordDense, + // ) -> Result, Error> { + // dense_halves.0.copy_advice(|| "lo", region, lo_col, row)?; + // dense_halves.1.copy_advice(|| "hi", region, hi_col, row)?; + + // let val = dense_halves.value(); + // region.assign_advice( + // || "word", + // word_col, + // row, + // || val.map(|val| F::from(val as u64)), + // )?; + + // Ok(val) + // } + #[allow(clippy::many_single_char_names)] - pub fn assign_digest( + pub fn complete_digest( &self, - region: &mut Region<'_, pallas::Base>, - state: State, - ) -> Result<[BlockWord; DIGEST_SIZE], Error> { + region: &mut Region<'_, F>, + last_compress_state: State, + initial_state: State, + ) -> Result<[RoundWordDense; STATE], Error> { let a_3 = self.extras[0]; - let a_4 = self.extras[1]; let a_5 = self.message_schedule; let a_6 = self.extras[2]; - let a_7 = self.extras[3]; let a_8 = self.extras[4]; - let (a, b, c, d, e, f, g, h) = match_state(state); - - let abcd_row = 0; - self.s_digest.enable(region, abcd_row)?; - let efgh_row = abcd_row + 2; - self.s_digest.enable(region, efgh_row)?; - - // Assign digest for A, B, C, D - a.dense_halves - .0 - .copy_advice(|| "a_lo", region, a_3, abcd_row)?; - a.dense_halves - .1 - .copy_advice(|| "a_hi", region, a_4, abcd_row)?; - let a = a.dense_halves.value(); - region.assign_advice( - || "a", - a_5, - abcd_row, - || a.map(|a| pallas::Base::from(a as u64)), - )?; - - let b = self.assign_digest_word(region, abcd_row, a_6, a_7, a_8, b.dense_halves)?; - let c = self.assign_digest_word(region, abcd_row + 1, a_3, a_4, a_5, c.dense_halves)?; - let d = self.assign_digest_word(region, abcd_row + 1, a_6, a_7, a_8, d)?; - - // Assign digest for E, F, G, H - e.dense_halves - .0 - .copy_advice(|| "e_lo", region, a_3, efgh_row)?; - e.dense_halves - .1 - .copy_advice(|| "e_hi", region, a_4, efgh_row)?; - let e = e.dense_halves.value(); - region.assign_advice( - || "e", - a_5, - efgh_row, - || e.map(|e| pallas::Base::from(e as u64)), - )?; - - let f = self.assign_digest_word(region, efgh_row, a_6, a_7, a_8, f.dense_halves)?; - let g = self.assign_digest_word(region, efgh_row + 1, a_3, a_4, a_5, g.dense_halves)?; - let h = self.assign_digest_word(region, efgh_row + 1, a_6, a_7, a_8, h)?; - - Ok([ - BlockWord(a), - BlockWord(b), - BlockWord(c), - BlockWord(d), - BlockWord(e), - BlockWord(f), - BlockWord(g), - BlockWord(h), + let (a, b, c, d, e, f, g, h) = match_state(last_compress_state); + let (a_i, b_i, c_i, d_i, e_i, f_i, g_i, h_i) = match_state(initial_state); + + let mut digest_dense = Vec::new(); + for (i, (final_dense, init_dense)) in [ + a.dense_halves, + b.dense_halves, + c.dense_halves, + d, + e.dense_halves, + f.dense_halves, + g.dense_halves, + h, + ] + .into_iter() + .zip([ + a_i.dense_halves, + b_i.dense_halves, + c_i.dense_halves, + d_i, + e_i.dense_halves, + f_i.dense_halves, + g_i.dense_halves, + h_i, ]) - } + .enumerate() + { + let row = i * 2; + self.s_digest.enable(region, row)?; + let (final_lo, final_hi) = final_dense.decompose(); + let (init_lo, init_hi) = init_dense.decompose(); - fn assign_digest_word( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - lo_col: Column, - hi_col: Column, - word_col: Column, - dense_halves: RoundWordDense, - ) -> Result, Error> { - dense_halves.0.copy_advice(|| "lo", region, lo_col, row)?; - dense_halves.1.copy_advice(|| "hi", region, hi_col, row)?; - - let val = dense_halves.value(); - region.assign_advice( - || "word", - word_col, - row, - || val.map(|val| pallas::Base::from(val as u64)), - )?; - - Ok(val) + let (digest, carry) = sum_with_carry(vec![ + (final_lo.value_u16(), final_hi.value_u16()), + (init_lo.value_u16(), init_hi.value_u16()), + ]); + + region.assign_advice(|| "digest carry", a_8, row, || carry.map(F::from))?; + region.assign_advice( + || "digest word", + a_5, + row, + || digest.map(|v| F::from(v as u64)), + )?; + + final_lo.copy_advice(|| "final lo", region, a_3, row)?; + final_hi.copy_advice(|| "final hi", region, a_3, row + 1)?; + init_lo.copy_advice(|| "init lo", region, a_6, row)?; + init_hi.copy_advice(|| "init hi", region, a_6, row + 1)?; + + let word = digest.map(|w| i2lebsp(w.into())); + let digest_lo = word.map(|w: [bool; 32]| w[..16].try_into().unwrap()); + let digest_hi = word.map(|w| w[16..].try_into().unwrap()); + + let digest_lo = SpreadVar::with_lookup( + region, + &self.lookup, + row, + digest_lo.map(SpreadWord::<16, 32>::new), + )? + .dense; + let digest_hi = SpreadVar::with_lookup( + region, + &self.lookup, + row + 1, + digest_hi.map(SpreadWord::<16, 32>::new), + )? + .dense; + digest_dense.push((digest_lo, digest_hi)) + } + + let ret: [(AssignedBits, AssignedBits); STATE] = + digest_dense.try_into().unwrap(); + Ok(ret.map(RoundWordDense::from)) } } diff --git a/halo2_gadgets/src/sha256/table16/compression/subregion_initial.rs b/halo2_gadgets/src/sha256/table16/compression/subregion_initial.rs index a487dc0c87..9b0c4341bd 100644 --- a/halo2_gadgets/src/sha256/table16/compression/subregion_initial.rs +++ b/halo2_gadgets/src/sha256/table16/compression/subregion_initial.rs @@ -1,19 +1,21 @@ -use super::super::{RoundWord, StateWord, STATE}; -use super::{compression_util::*, CompressionConfig, State}; +use super::{ + super::{RoundWord, StateWord, STATE}, + compression_util::*, + CompressionConfig, Field, RoundWordDense, State, +}; use halo2_proofs::{ circuit::{Region, Value}, plonk::Error, }; -use halo2curves::pasta::pallas; impl CompressionConfig { #[allow(clippy::many_single_char_names)] - pub fn initialize_iv( + pub fn initialize_iv( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, iv: [u32; STATE], - ) -> Result { + ) -> Result, Error> { let a_7 = self.extras[3]; // Decompose E into (6, 5, 14, 7)-bit chunks @@ -53,43 +55,37 @@ impl CompressionConfig { } #[allow(clippy::many_single_char_names)] - pub fn initialize_state( + pub fn initialize_state( &self, - region: &mut Region<'_, pallas::Base>, - state: State, - ) -> Result { + region: &mut Region<'_, F>, + state_dense: [RoundWordDense; STATE], + ) -> Result, Error> { + // TODO: there is no constraint on the input state and the output decomposed state + let a_7 = self.extras[3]; - let (a, b, c, d, e, f, g, h) = match_state(state); + let [a, b, c, d, e, f, g, h] = state_dense; // Decompose E into (6, 5, 14, 7)-bit chunks - let e = e.dense_halves.value(); - let e = self.decompose_e(region, RoundIdx::Init, e)?; + let e = self.decompose_e(region, RoundIdx::Init, e.value())?; // Decompose F, G - let f = f.dense_halves.value(); - let f = self.decompose_f(region, InitialRound, f)?; - let g = g.dense_halves.value(); - let g = self.decompose_g(region, InitialRound, g)?; + let f = self.decompose_f(region, InitialRound, f.value())?; + let g = self.decompose_g(region, InitialRound, g.value())?; // Assign H - let h = h.value(); let h_row = get_h_row(RoundIdx::Init); - let h = self.assign_word_halves_dense(region, h_row, a_7, h_row + 1, a_7, h)?; + let h = self.assign_word_halves_dense(region, h_row, a_7, h_row + 1, a_7, h.value())?; // Decompose A into (2, 11, 9, 10)-bit chunks - let a = a.dense_halves.value(); - let a = self.decompose_a(region, RoundIdx::Init, a)?; + let a = self.decompose_a(region, RoundIdx::Init, a.value())?; // Decompose B, C - let b = b.dense_halves.value(); - let b = self.decompose_b(region, InitialRound, b)?; - let c = c.dense_halves.value(); - let c = self.decompose_c(region, InitialRound, c)?; + let b = self.decompose_b(region, InitialRound, b.value())?; + let c = self.decompose_c(region, InitialRound, c.value())?; // Assign D - let d = d.value(); let d_row = get_d_row(RoundIdx::Init); - let d = self.assign_word_halves_dense(region, d_row, a_7, d_row + 1, a_7, d)?; + let d = self.assign_word_halves_dense(region, d_row, a_7, d_row + 1, a_7, d.value())?; Ok(State::new( StateWord::A(a), @@ -103,12 +99,12 @@ impl CompressionConfig { )) } - fn decompose_b( + fn decompose_b( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: InitialRound, b_val: Value, - ) -> Result { + ) -> Result, Error> { let row = get_decompose_b_row(round_idx); let (dense_halves, spread_halves) = self.assign_word_halves(region, row, b_val)?; @@ -116,12 +112,12 @@ impl CompressionConfig { Ok(RoundWord::new(dense_halves, spread_halves)) } - fn decompose_c( + fn decompose_c( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: InitialRound, c_val: Value, - ) -> Result { + ) -> Result, Error> { let row = get_decompose_c_row(round_idx); let (dense_halves, spread_halves) = self.assign_word_halves(region, row, c_val)?; @@ -129,12 +125,12 @@ impl CompressionConfig { Ok(RoundWord::new(dense_halves, spread_halves)) } - fn decompose_f( + fn decompose_f( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: InitialRound, f_val: Value, - ) -> Result { + ) -> Result, Error> { let row = get_decompose_f_row(round_idx); let (dense_halves, spread_halves) = self.assign_word_halves(region, row, f_val)?; @@ -142,12 +138,12 @@ impl CompressionConfig { Ok(RoundWord::new(dense_halves, spread_halves)) } - fn decompose_g( + fn decompose_g( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: InitialRound, g_val: Value, - ) -> Result { + ) -> Result, Error> { let row = get_decompose_g_row(round_idx); let (dense_halves, spread_halves) = self.assign_word_halves(region, row, g_val)?; diff --git a/halo2_gadgets/src/sha256/table16/compression/subregion_main.rs b/halo2_gadgets/src/sha256/table16/compression/subregion_main.rs index bda188a866..ab79849790 100644 --- a/halo2_gadgets/src/sha256/table16/compression/subregion_main.rs +++ b/halo2_gadgets/src/sha256/table16/compression/subregion_main.rs @@ -1,19 +1,19 @@ -use super::super::{AssignedBits, RoundWord, RoundWordA, RoundWordE, StateWord, ROUND_CONSTANTS}; -use super::{compression_util::*, CompressionConfig, State}; +use super::{ + super::{AssignedBits, RoundWord, RoundWordA, RoundWordE, StateWord, ROUND_CONSTANTS}, + compression_util::*, + CompressionConfig, Field, State, +}; use halo2_proofs::{circuit::Region, plonk::Error}; -use halo2curves::pasta::pallas; impl CompressionConfig { #[allow(clippy::many_single_char_names)] - pub fn assign_round( + pub fn assign_round( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, round_idx: MainRoundIdx, - state: State, - schedule_word: &(AssignedBits<16>, AssignedBits<16>), - ) -> Result { - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; + state: State, + schedule_word: &(AssignedBits, AssignedBits), + ) -> Result, Error> { let a_7 = self.extras[3]; let (a, b, c, d, e, f, g, h) = match_state(state); @@ -103,21 +103,12 @@ impl CompressionConfig { StateWord::H(g.dense_halves), )) } else { - let abcd_row = get_digest_abcd_row(); - let efgh_row = get_digest_efgh_row(); - - let a_final = - self.assign_word_halves_dense(region, abcd_row, a_3, abcd_row, a_4, a_new_val)?; - - let e_final = - self.assign_word_halves_dense(region, efgh_row, a_3, efgh_row, a_4, e_new_val)?; - Ok(State::new( - StateWord::A(RoundWordA::new_dense(a_final)), + StateWord::A(RoundWordA::new_dense(a_new_dense)), StateWord::B(RoundWord::new(a.dense_halves, a.spread_halves.unwrap())), StateWord::C(b), StateWord::D(c.dense_halves), - StateWord::E(RoundWordE::new_dense(e_final)), + StateWord::E(RoundWordE::new_dense(e_new_dense)), StateWord::F(RoundWord::new(e.dense_halves, e.spread_halves.unwrap())), StateWord::G(f), StateWord::H(g.dense_halves), diff --git a/halo2_gadgets/src/sha256/table16/message_schedule.rs b/halo2_gadgets/src/sha256/table16/message_schedule.rs index 690e086c49..792e980ff8 100644 --- a/halo2_gadgets/src/sha256/table16/message_schedule.rs +++ b/halo2_gadgets/src/sha256/table16/message_schedule.rs @@ -1,12 +1,13 @@ use std::convert::TryInto; -use super::{super::BLOCK_SIZE, AssignedBits, BlockWord, SpreadInputs, Table16Assignment, ROUNDS}; +use super::{ + super::BLOCK_SIZE, AssignedBits, BlockWord, Field, SpreadInputs, Table16Assignment, ROUNDS, +}; use halo2_proofs::{ circuit::Layouter, plonk::{Advice, Column, ConstraintSystem, Error, Selector}, poly::Rotation, }; -use halo2curves::pasta::pallas; mod schedule_gates; mod schedule_util; @@ -21,10 +22,10 @@ use schedule_util::*; pub use schedule_util::msg_schedule_test_input; #[derive(Clone, Debug)] -pub(super) struct MessageWord(AssignedBits<32>); +pub(super) struct MessageWord(AssignedBits); -impl std::ops::Deref for MessageWord { - type Target = AssignedBits<32>; +impl std::ops::Deref for MessageWord { + type Target = AssignedBits; fn deref(&self) -> &Self::Target { &self.0 @@ -57,7 +58,7 @@ pub(super) struct MessageScheduleConfig { s_lower_sigma_1_v2: Selector, } -impl Table16Assignment for MessageScheduleConfig {} +impl Table16Assignment for MessageScheduleConfig {} impl MessageScheduleConfig { /// Configures the message schedule. @@ -70,8 +71,8 @@ impl MessageScheduleConfig { /// gates, and will not place any constraints on (such as lookup constraints) outside /// itself. #[allow(clippy::many_single_char_names)] - pub(super) fn configure( - meta: &mut ConstraintSystem, + pub(super) fn configure( + meta: &mut ConstraintSystem, lookup: SpreadInputs, message_schedule: Column, extras: [Column; 6], @@ -302,25 +303,25 @@ impl MessageScheduleConfig { } #[allow(clippy::type_complexity)] - pub(super) fn process( + pub(super) fn process( &self, - layouter: &mut impl Layouter, + layouter: &mut impl Layouter, input: [BlockWord; BLOCK_SIZE], ) -> Result< ( - [MessageWord; ROUNDS], - [(AssignedBits<16>, AssignedBits<16>); ROUNDS], + [MessageWord; ROUNDS], + [(AssignedBits, AssignedBits); ROUNDS], ), Error, > { - let mut w = Vec::::with_capacity(ROUNDS); - let mut w_halves = Vec::<(AssignedBits<16>, AssignedBits<16>)>::with_capacity(ROUNDS); + let mut w = Vec::>::with_capacity(ROUNDS); + let mut w_halves = Vec::<(AssignedBits<_, 16>, AssignedBits<_, 16>)>::with_capacity(ROUNDS); layouter.assign_region( || "process message block", |mut region| { - w = Vec::::with_capacity(ROUNDS); - w_halves = Vec::<(AssignedBits<16>, AssignedBits<16>)>::with_capacity(ROUNDS); + w = Vec::>::with_capacity(ROUNDS); + w_halves = Vec::<(AssignedBits<_, 16>, AssignedBits<_, 16>)>::with_capacity(ROUNDS); // Assign all fixed columns for index in 1..14 { @@ -393,10 +394,13 @@ impl MessageScheduleConfig { #[cfg(test)] mod tests { - use super::super::{ - super::BLOCK_SIZE, util::lebs2ip, BlockWord, SpreadTableChip, Table16Chip, Table16Config, + use super::{ + super::{ + super::BLOCK_SIZE, util::lebs2ip, BlockWord, SpreadTableChip, Table16Chip, + Table16Config, + }, + schedule_util::*, }; - use super::schedule_util::*; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, dev::MockProver, @@ -448,7 +452,7 @@ mod tests { let prover = match MockProver::::run(17, &circuit, vec![]) { Ok(prover) => prover, - Err(e) => panic!("{:?}", e), + Err(e) => panic!("{e:?}"), }; assert_eq!(prover.verify(), Ok(())); } diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/schedule_util.rs b/halo2_gadgets/src/sha256/table16/message_schedule/schedule_util.rs index 79a9fa2621..3aab76e6fa 100644 --- a/halo2_gadgets/src/sha256/table16/message_schedule/schedule_util.rs +++ b/halo2_gadgets/src/sha256/table16/message_schedule/schedule_util.rs @@ -1,10 +1,9 @@ -use super::super::AssignedBits; -use super::MessageScheduleConfig; +use super::super::Field; +use super::{super::AssignedBits, MessageScheduleConfig}; use halo2_proofs::{ circuit::{Region, Value}, plonk::Error, }; -use halo2curves::pasta::pallas; #[cfg(test)] use super::super::{super::BLOCK_SIZE, BlockWord, ROUNDS}; @@ -40,20 +39,17 @@ pub fn get_word_row(word_idx: usize) -> usize { if word_idx == 0 { 0 } else if (1..=13).contains(&word_idx) { - SUBREGION_0_ROWS + SUBREGION_1_WORD * (word_idx - 1) as usize + SUBREGION_0_ROWS + SUBREGION_1_WORD * (word_idx - 1) } else if (14..=48).contains(&word_idx) { SUBREGION_0_ROWS + SUBREGION_1_ROWS + SUBREGION_2_WORD * (word_idx - 14) + 1 } else if (49..=61).contains(&word_idx) { - SUBREGION_0_ROWS - + SUBREGION_1_ROWS - + SUBREGION_2_ROWS - + SUBREGION_3_WORD * (word_idx - 49) as usize + SUBREGION_0_ROWS + SUBREGION_1_ROWS + SUBREGION_2_ROWS + SUBREGION_3_WORD * (word_idx - 49) } else { SUBREGION_0_ROWS + SUBREGION_1_ROWS + SUBREGION_2_ROWS + SUBREGION_3_ROWS - + DECOMPOSE_0_ROWS * (word_idx - 62) as usize + + DECOMPOSE_0_ROWS * (word_idx - 62) } } @@ -150,12 +146,19 @@ pub const MSG_SCHEDULE_TEST_OUTPUT: [u32; ROUNDS] = [ impl MessageScheduleConfig { // Assign a word and its hi and lo halves - pub fn assign_word_and_halves( + #[allow(clippy::type_complexity)] + pub fn assign_word_and_halves( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, word: Value, word_idx: usize, - ) -> Result<(AssignedBits<32>, (AssignedBits<16>, AssignedBits<16>)), Error> { + ) -> Result< + ( + AssignedBits, + (AssignedBits, AssignedBits), + ), + Error, + > { // Rename these here for ease of matching the gates to the specification. let a_3 = self.extras[0]; let a_4 = self.extras[1]; @@ -164,16 +167,28 @@ impl MessageScheduleConfig { let w_lo = { let w_lo_val = word.map(|word| word as u16); - AssignedBits::<16>::assign(region, || format!("W_{}_lo", word_idx), a_3, row, w_lo_val)? + AssignedBits::<_, 16>::assign( + region, + || format!("W_{word_idx}_lo"), + a_3, + row, + w_lo_val, + )? }; let w_hi = { let w_hi_val = word.map(|word| (word >> 16) as u16); - AssignedBits::<16>::assign(region, || format!("W_{}_hi", word_idx), a_4, row, w_hi_val)? + AssignedBits::<_, 16>::assign( + region, + || format!("W_{word_idx}_hi"), + a_4, + row, + w_hi_val, + )? }; - let word = AssignedBits::<32>::assign( + let word = AssignedBits::<_, 32>::assign( region, - || format!("W_{}", word_idx), + || format!("W_{word_idx}"), self.message_schedule, row, word, diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/subregion1.rs b/halo2_gadgets/src/sha256/table16/message_schedule/subregion1.rs index 947c9dda2a..a5bed0b062 100644 --- a/halo2_gadgets/src/sha256/table16/message_schedule/subregion1.rs +++ b/halo2_gadgets/src/sha256/table16/message_schedule/subregion1.rs @@ -1,26 +1,29 @@ -use super::super::{util::*, AssignedBits, BlockWord, SpreadVar, SpreadWord, Table16Assignment}; -use super::{schedule_util::*, MessageScheduleConfig}; +use super::super::Field; +use super::{ + super::{util::*, AssignedBits, BlockWord, SpreadVar, SpreadWord, Table16Assignment}, + schedule_util::*, + MessageScheduleConfig, +}; use halo2_proofs::{ circuit::{Region, Value}, plonk::Error, }; -use halo2curves::pasta::pallas; use std::convert::TryInto; // A word in subregion 1 // (3, 4, 11, 14)-bit chunks #[derive(Debug)] -pub struct Subregion1Word { +pub struct Subregion1Word { index: usize, - a: AssignedBits<3>, - b: AssignedBits<4>, - c: AssignedBits<11>, - d: AssignedBits<14>, - spread_c: AssignedBits<22>, - spread_d: AssignedBits<28>, + a: AssignedBits, + b: AssignedBits, + c: AssignedBits, + d: AssignedBits, + spread_c: AssignedBits, + spread_d: AssignedBits, } -impl Subregion1Word { +impl Subregion1Word { fn spread_a(&self) -> Value<[bool; 6]> { self.a.value().map(|v| v.spread()) } @@ -75,11 +78,12 @@ impl Subregion1Word { } impl MessageScheduleConfig { - pub fn assign_subregion1( + #[allow(clippy::type_complexity)] + pub fn assign_subregion1( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, input: &[BlockWord], - ) -> Result, AssignedBits<16>)>, Error> { + ) -> Result, AssignedBits)>, Error> { assert_eq!(input.len(), SUBREGION_1_LEN); Ok(input .iter() @@ -101,12 +105,13 @@ impl MessageScheduleConfig { } /// Pieces of length [3, 4, 11, 14] - fn decompose_subregion1_word( + #[allow(clippy::type_complexity)] + fn decompose_subregion1_word( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, word: Value<[bool; 32]>, index: usize, - ) -> Result { + ) -> Result, Error> { let row = get_word_row(index); // Rename these here for ease of matching the gates to the specification. @@ -124,11 +129,21 @@ impl MessageScheduleConfig { let pieces = pieces.transpose_vec(4); // Assign `a` (3-bit piece) - let a = - AssignedBits::<3>::assign_bits(region, || "word_a", a_3, row + 1, pieces[0].clone())?; + let a = AssignedBits::<_, 3>::assign_bits( + region, + || "word_a", + a_3, + row + 1, + pieces[0].clone(), + )?; // Assign `b` (4-bit piece) - let b = - AssignedBits::<4>::assign_bits(region, || "word_b", a_4, row + 1, pieces[1].clone())?; + let b = AssignedBits::<_, 4>::assign_bits( + region, + || "word_b", + a_4, + row + 1, + pieces[1].clone(), + )?; // Assign `c` (11-bit piece) lookup let spread_c = pieces[2].clone().map(SpreadWord::try_new); @@ -151,11 +166,11 @@ impl MessageScheduleConfig { // sigma_0 v1 on a word in W_1 to W_13 // (3, 4, 11, 14)-bit chunks - fn lower_sigma_0( + fn lower_sigma_0( &self, - region: &mut Region<'_, pallas::Base>, - word: Subregion1Word, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { + region: &mut Region<'_, F>, + word: Subregion1Word, + ) -> Result<(AssignedBits, AssignedBits), Error> { let a_3 = self.extras[0]; let a_4 = self.extras[1]; let a_5 = self.message_schedule; @@ -168,16 +183,16 @@ impl MessageScheduleConfig { // Witness `spread_a` let spread_a = word.a.value().map(|bits| spread_bits(bits.0)); - AssignedBits::<6>::assign_bits(region, || "spread_a", a_6, row + 1, spread_a)?; + AssignedBits::<_, 6>::assign_bits(region, || "spread_a", a_6, row + 1, spread_a)?; // Split `b` (4-bit chunk) into `b_hi` and `b_lo` // Assign `b_lo`, `spread_b_lo` let b_lo: Value<[bool; 2]> = word.b.value().map(|b| b.0[..2].try_into().unwrap()); let spread_b_lo = b_lo.map(spread_bits); { - AssignedBits::<2>::assign_bits(region, || "b_lo", a_3, row - 1, b_lo)?; + AssignedBits::<_, 2>::assign_bits(region, || "b_lo", a_3, row - 1, b_lo)?; - AssignedBits::<4>::assign_bits(region, || "spread_b_lo", a_4, row - 1, spread_b_lo)?; + AssignedBits::<_, 4>::assign_bits(region, || "spread_b_lo", a_4, row - 1, spread_b_lo)?; }; // Split `b` (2-bit chunk) into `b_hi` and `b_lo` @@ -185,9 +200,9 @@ impl MessageScheduleConfig { let b_hi: Value<[bool; 2]> = word.b.value().map(|b| b.0[2..].try_into().unwrap()); let spread_b_hi = b_hi.map(spread_bits); { - AssignedBits::<2>::assign_bits(region, || "b_hi", a_5, row - 1, b_hi)?; + AssignedBits::<_, 2>::assign_bits(region, || "b_hi", a_5, row - 1, b_hi)?; - AssignedBits::<4>::assign_bits(region, || "spread_b_hi", a_6, row - 1, spread_b_hi)?; + AssignedBits::<_, 4>::assign_bits(region, || "spread_b_hi", a_6, row - 1, spread_b_hi)?; }; // Assign `b` and copy constraint diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/subregion2.rs b/halo2_gadgets/src/sha256/table16/message_schedule/subregion2.rs index 43e96c934f..e34c4bd3a2 100644 --- a/halo2_gadgets/src/sha256/table16/message_schedule/subregion2.rs +++ b/halo2_gadgets/src/sha256/table16/message_schedule/subregion2.rs @@ -1,29 +1,32 @@ -use super::super::{util::*, AssignedBits, Bits, SpreadVar, SpreadWord, Table16Assignment}; -use super::{schedule_util::*, MessageScheduleConfig, MessageWord}; +use super::super::Field; +use super::{ + super::{util::*, AssignedBits, Bits, SpreadVar, SpreadWord, Table16Assignment}, + schedule_util::*, + MessageScheduleConfig, MessageWord, +}; use halo2_proofs::{ circuit::{Region, Value}, plonk::Error, }; -use halo2curves::pasta::pallas; use std::convert::TryInto; /// A word in subregion 2 /// (3, 4, 3, 7, 1, 1, 13)-bit chunks #[derive(Clone, Debug)] -pub struct Subregion2Word { +pub struct Subregion2Word { index: usize, - a: AssignedBits<3>, - b: AssignedBits<4>, - c: AssignedBits<3>, - d: AssignedBits<7>, - e: AssignedBits<1>, - f: AssignedBits<1>, - g: AssignedBits<13>, - spread_d: AssignedBits<14>, - spread_g: AssignedBits<26>, + a: AssignedBits, + b: AssignedBits, + c: AssignedBits, + d: AssignedBits, + e: AssignedBits, + f: AssignedBits, + g: AssignedBits, + spread_d: AssignedBits, + spread_g: AssignedBits, } -impl Subregion2Word { +impl Subregion2Word { fn spread_a(&self) -> Value<[bool; 6]> { self.a.value().map(|v| v.spread()) } @@ -153,13 +156,14 @@ impl Subregion2Word { impl MessageScheduleConfig { // W_[14..49] - pub fn assign_subregion2( + #[allow(clippy::type_complexity)] + pub fn assign_subregion2( &self, - region: &mut Region<'_, pallas::Base>, - lower_sigma_0_output: Vec<(AssignedBits<16>, AssignedBits<16>)>, - w: &mut Vec, - w_halves: &mut Vec<(AssignedBits<16>, AssignedBits<16>)>, - ) -> Result, AssignedBits<16>)>, Error> { + region: &mut Region<'_, F>, + lower_sigma_0_output: Vec<(AssignedBits, AssignedBits)>, + w: &mut Vec>, + w_halves: &mut Vec<(AssignedBits, AssignedBits)>, + ) -> Result, AssignedBits)>, Error> { let a_5 = self.message_schedule; let a_6 = self.extras[2]; let a_7 = self.extras[3]; @@ -167,9 +171,9 @@ impl MessageScheduleConfig { let a_9 = self.extras[5]; let mut lower_sigma_0_v2_results = - Vec::<(AssignedBits<16>, AssignedBits<16>)>::with_capacity(SUBREGION_2_LEN); + Vec::<(AssignedBits<_, 16>, AssignedBits<_, 16>)>::with_capacity(SUBREGION_2_LEN); let mut lower_sigma_1_v2_results = - Vec::<(AssignedBits<16>, AssignedBits<16>)>::with_capacity(SUBREGION_2_LEN); + Vec::<(AssignedBits<_, 16>, AssignedBits<_, 16>)>::with_capacity(SUBREGION_2_LEN); // Closure to compose new word // W_i = sigma_1(W_{i - 2}) + W_{i - 7} + sigma_0(W_{i - 15}) + W_{i - 16} @@ -179,98 +183,99 @@ impl MessageScheduleConfig { // sigma_0_v2(W_[14..36]) will be used to get the new W_[29..51] // sigma_1_v2(W_[14..49]) will be used to get the W_[16..51] // The lowest-index words involved will be W_[0..13] - let mut new_word = |idx: usize, - sigma_0_output: &(AssignedBits<16>, AssignedBits<16>)| - -> Result, AssignedBits<16>)>, Error> { - // Decompose word into (3, 4, 3, 7, 1, 1, 13)-bit chunks - let word = self.decompose_word(region, w[idx].value(), idx)?; - - // sigma_0 v2 and sigma_1 v2 on word - lower_sigma_0_v2_results.push(self.lower_sigma_0_v2(region, word.clone())?); - lower_sigma_1_v2_results.push(self.lower_sigma_1_v2(region, word)?); - - let new_word_idx = idx + 2; - - // Copy sigma_0(W_{i - 15}) output from Subregion 1 - sigma_0_output.0.copy_advice( - || format!("sigma_0(W_{})_lo", new_word_idx - 15), - region, - a_6, - get_word_row(new_word_idx - 16), - )?; - sigma_0_output.1.copy_advice( - || format!("sigma_0(W_{})_hi", new_word_idx - 15), - region, - a_6, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Copy sigma_1(W_{i - 2}) - lower_sigma_1_v2_results[new_word_idx - 16].0.copy_advice( - || format!("sigma_1(W_{})_lo", new_word_idx - 2), - region, - a_7, - get_word_row(new_word_idx - 16), - )?; - lower_sigma_1_v2_results[new_word_idx - 16].1.copy_advice( - || format!("sigma_1(W_{})_hi", new_word_idx - 2), - region, - a_7, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Copy W_{i - 7} - w_halves[new_word_idx - 7].0.copy_advice( - || format!("W_{}_lo", new_word_idx - 7), - region, - a_8, - get_word_row(new_word_idx - 16), - )?; - w_halves[new_word_idx - 7].1.copy_advice( - || format!("W_{}_hi", new_word_idx - 7), - region, - a_8, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Calculate W_i, carry_i - let (word, carry) = sum_with_carry(vec![ - ( - lower_sigma_1_v2_results[new_word_idx - 16].0.value_u16(), - lower_sigma_1_v2_results[new_word_idx - 16].1.value_u16(), - ), - ( - w_halves[new_word_idx - 7].0.value_u16(), - w_halves[new_word_idx - 7].1.value_u16(), - ), - (sigma_0_output.0.value_u16(), sigma_0_output.1.value_u16()), - ( - w_halves[new_word_idx - 16].0.value_u16(), - w_halves[new_word_idx - 16].1.value_u16(), - ), - ]); - - // Assign W_i, carry_i - region.assign_advice( - || format!("W_{}", new_word_idx), - a_5, - get_word_row(new_word_idx - 16) + 1, - || word.map(|word| pallas::Base::from(word as u64)), - )?; - region.assign_advice( - || format!("carry_{}", new_word_idx), - a_9, - get_word_row(new_word_idx - 16) + 1, - || carry.map(|carry| pallas::Base::from(carry as u64)), - )?; - let (word, halves) = self.assign_word_and_halves(region, word, new_word_idx)?; - w.push(MessageWord(word)); - w_halves.push(halves); - - Ok(lower_sigma_0_v2_results.clone()) - }; - - let mut tmp_lower_sigma_0_v2_results: Vec<(AssignedBits<16>, AssignedBits<16>)> = + let mut new_word = + |idx: usize, + sigma_0_output: &(AssignedBits<_, 16>, AssignedBits<_, 16>)| + -> Result, AssignedBits<_, 16>)>, Error> { + // Decompose word into (3, 4, 3, 7, 1, 1, 13)-bit chunks + let word = self.decompose_word(region, w[idx].value(), idx)?; + + // sigma_0 v2 and sigma_1 v2 on word + lower_sigma_0_v2_results.push(self.lower_sigma_0_v2(region, word.clone())?); + lower_sigma_1_v2_results.push(self.lower_sigma_1_v2(region, word)?); + + let new_word_idx = idx + 2; + + // Copy sigma_0(W_{i - 15}) output from Subregion 1 + sigma_0_output.0.copy_advice( + || format!("sigma_0(W_{})_lo", new_word_idx - 15), + region, + a_6, + get_word_row(new_word_idx - 16), + )?; + sigma_0_output.1.copy_advice( + || format!("sigma_0(W_{})_hi", new_word_idx - 15), + region, + a_6, + get_word_row(new_word_idx - 16) + 1, + )?; + + // Copy sigma_1(W_{i - 2}) + lower_sigma_1_v2_results[new_word_idx - 16].0.copy_advice( + || format!("sigma_1(W_{})_lo", new_word_idx - 2), + region, + a_7, + get_word_row(new_word_idx - 16), + )?; + lower_sigma_1_v2_results[new_word_idx - 16].1.copy_advice( + || format!("sigma_1(W_{})_hi", new_word_idx - 2), + region, + a_7, + get_word_row(new_word_idx - 16) + 1, + )?; + + // Copy W_{i - 7} + w_halves[new_word_idx - 7].0.copy_advice( + || format!("W_{}_lo", new_word_idx - 7), + region, + a_8, + get_word_row(new_word_idx - 16), + )?; + w_halves[new_word_idx - 7].1.copy_advice( + || format!("W_{}_hi", new_word_idx - 7), + region, + a_8, + get_word_row(new_word_idx - 16) + 1, + )?; + + // Calculate W_i, carry_i + let (word, carry) = sum_with_carry(vec![ + ( + lower_sigma_1_v2_results[new_word_idx - 16].0.value_u16(), + lower_sigma_1_v2_results[new_word_idx - 16].1.value_u16(), + ), + ( + w_halves[new_word_idx - 7].0.value_u16(), + w_halves[new_word_idx - 7].1.value_u16(), + ), + (sigma_0_output.0.value_u16(), sigma_0_output.1.value_u16()), + ( + w_halves[new_word_idx - 16].0.value_u16(), + w_halves[new_word_idx - 16].1.value_u16(), + ), + ]); + + // Assign W_i, carry_i + region.assign_advice( + || format!("W_{new_word_idx}"), + a_5, + get_word_row(new_word_idx - 16) + 1, + || word.map(|word| F::from(word as u64)), + )?; + region.assign_advice( + || format!("carry_{new_word_idx}"), + a_9, + get_word_row(new_word_idx - 16) + 1, + || carry.map(|carry| F::from(carry)), + )?; + let (word, halves) = self.assign_word_and_halves(region, word, new_word_idx)?; + w.push(MessageWord(word)); + w_halves.push(halves); + + Ok(lower_sigma_0_v2_results.clone()) + }; + + let mut tmp_lower_sigma_0_v2_results: Vec<(AssignedBits<_, 16>, AssignedBits<_, 16>)> = Vec::with_capacity(SUBREGION_2_LEN); // Use up all the output from Subregion 1 lower_sigma_0 @@ -288,12 +293,12 @@ impl MessageScheduleConfig { } /// Pieces of length [3, 4, 3, 7, 1, 1, 13] - fn decompose_word( + fn decompose_word( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, word: Value<&Bits<32>>, index: usize, - ) -> Result { + ) -> Result, Error> { let row = get_word_row(index); let pieces = word.map(|word| { @@ -314,24 +319,24 @@ impl MessageScheduleConfig { let a_4 = self.extras[1]; // Assign `a` (3-bit piece) - let a = AssignedBits::<3>::assign_bits(region, || "a", a_3, row - 1, pieces[0].clone())?; + let a = AssignedBits::<_, 3>::assign_bits(region, || "a", a_3, row - 1, pieces[0].clone())?; // Assign `b` (4-bit piece) lookup let spread_b: Value> = pieces[1].clone().map(SpreadWord::try_new); let spread_b = SpreadVar::with_lookup(region, &self.lookup, row + 1, spread_b)?; // Assign `c` (3-bit piece) - let c = AssignedBits::<3>::assign_bits(region, || "c", a_4, row - 1, pieces[2].clone())?; + let c = AssignedBits::<_, 3>::assign_bits(region, || "c", a_4, row - 1, pieces[2].clone())?; // Assign `d` (7-bit piece) lookup let spread_d: Value> = pieces[3].clone().map(SpreadWord::try_new); let spread_d = SpreadVar::with_lookup(region, &self.lookup, row, spread_d)?; // Assign `e` (1-bit piece) - let e = AssignedBits::<1>::assign_bits(region, || "e", a_3, row + 1, pieces[4].clone())?; + let e = AssignedBits::<_, 1>::assign_bits(region, || "e", a_3, row + 1, pieces[4].clone())?; // Assign `f` (1-bit piece) - let f = AssignedBits::<1>::assign_bits(region, || "f", a_4, row + 1, pieces[5].clone())?; + let f = AssignedBits::<_, 1>::assign_bits(region, || "f", a_4, row + 1, pieces[5].clone())?; // Assign `g` (13-bit piece) lookup let spread_g = pieces[6].clone().map(SpreadWord::try_new); @@ -354,11 +359,11 @@ impl MessageScheduleConfig { /// A word in subregion 2 /// (3, 4, 3, 7, 1, 1, 13)-bit chunks #[allow(clippy::type_complexity)] - fn assign_lower_sigma_v2_pieces( + fn assign_lower_sigma_v2_pieces( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, row: usize, - word: &Subregion2Word, + word: &Subregion2Word, ) -> Result<(), Error> { let a_3 = self.extras[0]; let a_4 = self.extras[1]; @@ -370,7 +375,7 @@ impl MessageScheduleConfig { word.a.copy_advice(|| "a", region, a_3, row + 1)?; // Witness `spread_a` - AssignedBits::<6>::assign_bits(region, || "spread_a", a_4, row + 1, word.spread_a())?; + AssignedBits::<_, 6>::assign_bits(region, || "spread_a", a_4, row + 1, word.spread_a())?; // Split `b` (4-bit chunk) into `b_hi` and `b_lo` // Assign `b_lo`, `spread_b_lo` @@ -378,9 +383,9 @@ impl MessageScheduleConfig { let b_lo: Value<[bool; 2]> = word.b.value().map(|b| b.0[..2].try_into().unwrap()); let spread_b_lo = b_lo.map(spread_bits); { - AssignedBits::<2>::assign_bits(region, || "b_lo", a_3, row - 1, b_lo)?; + AssignedBits::<_, 2>::assign_bits(region, || "b_lo", a_3, row - 1, b_lo)?; - AssignedBits::<4>::assign_bits(region, || "spread_b_lo", a_4, row - 1, spread_b_lo)?; + AssignedBits::<_, 4>::assign_bits(region, || "spread_b_lo", a_4, row - 1, spread_b_lo)?; }; // Split `b` (2-bit chunk) into `b_hi` and `b_lo` @@ -388,9 +393,9 @@ impl MessageScheduleConfig { let b_hi: Value<[bool; 2]> = word.b.value().map(|b| b.0[2..].try_into().unwrap()); let spread_b_hi = b_hi.map(spread_bits); { - AssignedBits::<2>::assign_bits(region, || "b_hi", a_5, row - 1, b_hi)?; + AssignedBits::<_, 2>::assign_bits(region, || "b_hi", a_5, row - 1, b_hi)?; - AssignedBits::<4>::assign_bits(region, || "spread_b_hi", a_6, row - 1, spread_b_hi)?; + AssignedBits::<_, 4>::assign_bits(region, || "spread_b_hi", a_6, row - 1, spread_b_hi)?; }; // Assign `b` and copy constraint @@ -400,7 +405,7 @@ impl MessageScheduleConfig { word.c.copy_advice(|| "c", region, a_5, row + 1)?; // Witness `spread_c` - AssignedBits::<6>::assign_bits(region, || "spread_c", a_6, row + 1, word.spread_c())?; + AssignedBits::<_, 6>::assign_bits(region, || "spread_c", a_6, row + 1, word.spread_c())?; // Assign `spread_d` and copy constraint word.spread_d.copy_advice(|| "spread_d", region, a_4, row)?; @@ -417,11 +422,11 @@ impl MessageScheduleConfig { Ok(()) } - fn lower_sigma_0_v2( + fn lower_sigma_0_v2( &self, - region: &mut Region<'_, pallas::Base>, - word: Subregion2Word, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { + region: &mut Region<'_, F>, + word: Subregion2Word, + ) -> Result<(AssignedBits, AssignedBits), Error> { let a_3 = self.extras[0]; let row = get_word_row(word.index) + 3; @@ -450,11 +455,11 @@ impl MessageScheduleConfig { ) } - fn lower_sigma_1_v2( + fn lower_sigma_1_v2( &self, - region: &mut Region<'_, pallas::Base>, - word: Subregion2Word, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { + region: &mut Region<'_, F>, + word: Subregion2Word, + ) -> Result<(AssignedBits, AssignedBits), Error> { let a_3 = self.extras[0]; let row = get_word_row(word.index) + SIGMA_0_V2_ROWS + 3; diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/subregion3.rs b/halo2_gadgets/src/sha256/table16/message_schedule/subregion3.rs index b23046e42e..9f2217c7c1 100644 --- a/halo2_gadgets/src/sha256/table16/message_schedule/subregion3.rs +++ b/halo2_gadgets/src/sha256/table16/message_schedule/subregion3.rs @@ -1,27 +1,30 @@ -use super::super::{util::*, AssignedBits, Bits, SpreadVar, SpreadWord, Table16Assignment}; -use super::{schedule_util::*, MessageScheduleConfig, MessageWord}; +use super::super::Field; +use super::{ + super::{util::*, AssignedBits, Bits, SpreadVar, SpreadWord, Table16Assignment}, + schedule_util::*, + MessageScheduleConfig, MessageWord, +}; use halo2_proofs::{ circuit::{Region, Value}, plonk::Error, }; -use halo2curves::pasta::pallas; use std::convert::TryInto; // A word in subregion 3 // (10, 7, 2, 13)-bit chunks -pub struct Subregion3Word { +pub struct Subregion3Word { index: usize, #[allow(dead_code)] - a: AssignedBits<10>, - b: AssignedBits<7>, - c: AssignedBits<2>, + a: AssignedBits, + b: AssignedBits, + c: AssignedBits, #[allow(dead_code)] - d: AssignedBits<13>, - spread_a: AssignedBits<20>, - spread_d: AssignedBits<26>, + d: AssignedBits, + spread_a: AssignedBits, + spread_d: AssignedBits, } -impl Subregion3Word { +impl Subregion3Word { fn spread_a(&self) -> Value<[bool; 20]> { self.spread_a.value().map(|v| v.0) } @@ -78,12 +81,12 @@ impl Subregion3Word { impl MessageScheduleConfig { // W_[49..62] - pub fn assign_subregion3( + pub fn assign_subregion3( &self, - region: &mut Region<'_, pallas::Base>, - lower_sigma_0_v2_output: Vec<(AssignedBits<16>, AssignedBits<16>)>, - w: &mut Vec, - w_halves: &mut Vec<(AssignedBits<16>, AssignedBits<16>)>, + region: &mut Region<'_, F>, + lower_sigma_0_v2_output: Vec<(AssignedBits, AssignedBits)>, + w: &mut Vec>, + w_halves: &mut Vec<(AssignedBits, AssignedBits)>, ) -> Result<(), Error> { let a_5 = self.message_schedule; let a_6 = self.extras[2]; @@ -168,16 +171,16 @@ impl MessageScheduleConfig { // Assign W_i, carry_i region.assign_advice( - || format!("W_{}", new_word_idx), + || format!("W_{new_word_idx}"), a_5, get_word_row(new_word_idx - 16) + 1, - || word.map(|word| pallas::Base::from(word as u64)), + || word.map(|word| F::from(word as u64)), )?; region.assign_advice( - || format!("carry_{}", new_word_idx), + || format!("carry_{new_word_idx}"), a_9, get_word_row(new_word_idx - 16) + 1, - || carry.map(|carry| pallas::Base::from(carry as u64)), + || carry.map(|carry| F::from(carry)), )?; let (word, halves) = self.assign_word_and_halves(region, word, new_word_idx)?; w.push(MessageWord(word)); @@ -194,12 +197,12 @@ impl MessageScheduleConfig { } /// Pieces of length [10, 7, 2, 13] - fn decompose_subregion3_word( + fn decompose_subregion3_word( &self, - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, word: Value<&Bits<32>>, index: usize, - ) -> Result { + ) -> Result, Error> { let row = get_word_row(index); // Rename these here for ease of matching the gates to the specification. @@ -221,10 +224,10 @@ impl MessageScheduleConfig { let spread_a = SpreadVar::with_lookup(region, &self.lookup, row + 1, spread_a)?; // Assign `b` (7-bit piece) - let b = AssignedBits::<7>::assign_bits(region, || "b", a_4, row + 1, pieces[1].clone())?; + let b = AssignedBits::::assign_bits(region, || "b", a_4, row + 1, pieces[1].clone())?; // Assign `c` (2-bit piece) - let c = AssignedBits::<2>::assign_bits(region, || "c", a_3, row + 1, pieces[2].clone())?; + let c = AssignedBits::::assign_bits(region, || "c", a_3, row + 1, pieces[2].clone())?; // Assign `d` (13-bit piece) lookup let spread_d = pieces[3].clone().map(SpreadWord::try_new); @@ -241,11 +244,11 @@ impl MessageScheduleConfig { }) } - fn lower_sigma_1( + fn lower_sigma_1( &self, - region: &mut Region<'_, pallas::Base>, - word: Subregion3Word, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { + region: &mut Region<'_, F>, + word: Subregion3Word, + ) -> Result<(AssignedBits, AssignedBits), Error> { let a_3 = self.extras[0]; let a_4 = self.extras[1]; let a_5 = self.message_schedule; @@ -289,7 +292,7 @@ impl MessageScheduleConfig { // Witness `spread_c` { let spread_c = word.c.value().map(spread_bits); - AssignedBits::<4>::assign_bits(region, || "spread_c", a_4, row + 1, spread_c)?; + AssignedBits::::assign_bits(region, || "spread_c", a_4, row + 1, spread_c)?; } // Assign `spread_d` and copy constraint diff --git a/halo2_gadgets/src/sha256/table16/spread_table.rs b/halo2_gadgets/src/sha256/table16/spread_table.rs index 3e1488e9ac..471a844f59 100644 --- a/halo2_gadgets/src/sha256/table16/spread_table.rs +++ b/halo2_gadgets/src/sha256/table16/spread_table.rs @@ -1,13 +1,10 @@ -use super::{util::*, AssignedBits}; +use super::{util::*, AssignedBits, Field}; use halo2_proofs::{ arithmetic::FieldExt, circuit::{Chip, Layouter, Region, Value}, plonk::{Advice, Column, ConstraintSystem, Error, TableColumn}, - poly::Rotation, }; -use halo2curves::pasta::pallas; -use std::convert::TryInto; -use std::marker::PhantomData; +use std::{convert::TryInto, marker::PhantomData}; const BITS_7: usize = 1 << 7; const BITS_10: usize = 1 << 10; @@ -67,15 +64,15 @@ impl SpreadWord { /// A variable stored in advice columns corresponding to a row of [`SpreadTableConfig`]. #[derive(Clone, Debug)] -pub(super) struct SpreadVar { +pub(super) struct SpreadVar { pub tag: Value, - pub dense: AssignedBits, - pub spread: AssignedBits, + pub dense: AssignedBits, + pub spread: AssignedBits, } -impl SpreadVar { +impl SpreadVar { pub(super) fn with_lookup( - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, cols: &SpreadInputs, row: usize, word: Value>, @@ -88,20 +85,25 @@ impl SpreadVar { || "tag", cols.tag, row, - || tag.map(|tag| pallas::Base::from(tag as u64)), + || tag.map(|tag| F::from(tag as u64)), )?; let dense = - AssignedBits::::assign_bits(region, || "dense", cols.dense, row, dense_val)?; + AssignedBits::<_, DENSE>::assign_bits(region, || "dense", cols.dense, row, dense_val)?; - let spread = - AssignedBits::::assign_bits(region, || "spread", cols.spread, row, spread_val)?; + let spread = AssignedBits::<_, SPREAD>::assign_bits( + region, + || "spread", + cols.spread, + row, + spread_val, + )?; Ok(SpreadVar { tag, dense, spread }) } pub(super) fn without_lookup( - region: &mut Region<'_, pallas::Base>, + region: &mut Region<'_, F>, dense_col: Column, dense_row: usize, spread_col: Column, @@ -112,7 +114,7 @@ impl SpreadVar { let dense_val = word.map(|word| word.dense); let spread_val = word.map(|word| word.spread); - let dense = AssignedBits::::assign_bits( + let dense = AssignedBits::<_, DENSE>::assign_bits( region, || "dense", dense_col, @@ -120,7 +122,7 @@ impl SpreadVar { dense_val, )?; - let spread = AssignedBits::::assign_bits( + let spread = AssignedBits::<_, SPREAD>::assign_bits( region, || "spread", spread_col, @@ -183,6 +185,7 @@ impl SpreadTableChip { let table_spread = meta.lookup_table_column(); meta.lookup("lookup", |meta| { + use halo2_proofs::poly::Rotation; let tag_cur = meta.query_advice(input_tag, Rotation::cur()); let dense_cur = meta.query_advice(input_dense, Rotation::cur()); let spread_cur = meta.query_advice(input_spread, Rotation::cur()); @@ -441,7 +444,7 @@ mod tests { let prover = match MockProver::::run(17, &circuit, vec![]) { Ok(prover) => prover, - Err(e) => panic!("{:?}", e), + Err(e) => panic!("{e:?}"), }; assert_eq!(prover.verify(), Ok(())); } diff --git a/halo2_gadgets/src/sha256/table16/util.rs b/halo2_gadgets/src/sha256/table16/util.rs index 6a790d3797..d3da5317ca 100644 --- a/halo2_gadgets/src/sha256/table16/util.rs +++ b/halo2_gadgets/src/sha256/table16/util.rs @@ -110,7 +110,7 @@ pub fn sum_with_carry(words: Vec<(Value, Value)>) -> (Value, Valu sum_lo.zip(sum_hi).map(|(lo, hi)| lo + (1 << 16) * hi) }; - let carry = sum.map(|sum| (sum >> 32) as u64); + let carry = sum.map(|sum| (sum >> 32)); let sum = sum.map(|sum| sum as u32); (sum, carry) From cf9765a485d2ed76424ffb04b7c801deb2ef9136 Mon Sep 17 00:00:00 2001 From: naure Date: Thu, 30 Nov 2023 06:41:28 +0100 Subject: [PATCH 47/54] Bus auto (#72) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * bus: expose global offset of regions * bus-auto: add query_advice and query_fixed function in witness generation * bus-auto: fix clippy --------- Co-authored-by: Aurélien Nicolas --- halo2_proofs/src/circuit.rs | 15 ++++++ .../src/circuit/floor_planner/single_pass.rs | 16 ++++++ halo2_proofs/src/circuit/floor_planner/v1.rs | 16 ++++++ halo2_proofs/src/circuit/layouter.rs | 21 ++++++++ halo2_proofs/src/dev.rs | 50 +++++++++++++++++++ halo2_proofs/src/dev/cost.rs | 8 +++ halo2_proofs/src/dev/graph.rs | 8 +++ halo2_proofs/src/dev/graph/layout.rs | 8 +++ halo2_proofs/src/plonk/circuit.rs | 15 +++++- halo2_proofs/src/plonk/keygen.rs | 20 ++++++++ halo2_proofs/src/plonk/prover.rs | 27 ++++++++++ 11 files changed, 203 insertions(+), 1 deletion(-) diff --git a/halo2_proofs/src/circuit.rs b/halo2_proofs/src/circuit.rs index 52db772c94..3874cbced8 100644 --- a/halo2_proofs/src/circuit.rs +++ b/halo2_proofs/src/circuit.rs @@ -221,6 +221,16 @@ impl<'r, F: Field> Region<'r, F> { .name_column(&|| annotation().into(), column.into()); } + /// Get the last assigned value of an advice cell. + pub fn query_advice(&self, column: Column, offset: usize) -> Result { + self.region.query_advice(column, offset) + } + + /// Get the last assigned value of a fixed cell. + pub fn query_fixed(&self, column: Column, offset: usize) -> Result { + self.region.query_fixed(column, offset) + } + /// Assign an advice column value (witness). /// /// Even though `to` has `FnMut` bounds, it is guaranteed to be called at most once. @@ -367,6 +377,11 @@ impl<'r, F: Field> Region<'r, F> { pub fn constrain_equal(&mut self, left: Cell, right: Cell) -> Result<(), Error> { self.region.constrain_equal(left, right) } + + /// Return the offset of a row within the overall circuit. + pub fn global_offset(&self, row_offset: usize) -> usize { + self.region.global_offset(row_offset) + } } /// A lookup table in the circuit. diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index 3c445230d3..a76cab9f4d 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -480,6 +480,18 @@ impl<'r, 'a, F: Field, CS: Assignment + 'a> RegionLayouter self.layouter.cs.annotate_column(annotation, column); } + fn query_advice(&self, column: Column, offset: usize) -> Result { + self.layouter + .cs + .query_advice(column, *self.layouter.regions[*self.region_index] + offset) + } + + fn query_fixed(&self, column: Column, offset: usize) -> Result { + self.layouter + .cs + .query_fixed(column, *self.layouter.regions[*self.region_index] + offset) + } + fn assign_advice<'v>( &'v mut self, annotation: &'v (dyn Fn() -> String + 'v), @@ -573,6 +585,10 @@ impl<'r, 'a, F: Field, CS: Assignment + 'a> RegionLayouter Ok(()) } + + fn global_offset(&self, row_offset: usize) -> usize { + *self.layouter.regions[*self.region_index] + row_offset + } } /// The default value to fill a table column with. diff --git a/halo2_proofs/src/circuit/floor_planner/v1.rs b/halo2_proofs/src/circuit/floor_planner/v1.rs index 0fd28c196f..8a366d84cf 100644 --- a/halo2_proofs/src/circuit/floor_planner/v1.rs +++ b/halo2_proofs/src/circuit/floor_planner/v1.rs @@ -427,6 +427,18 @@ impl<'r, 'a, F: Field, CS: Assignment + 'a> RegionLayouter for V1Region<'r ) } + fn query_advice(&self, column: Column, offset: usize) -> Result { + self.plan + .cs + .query_advice(column, *self.plan.regions[*self.region_index] + offset) + } + + fn query_fixed(&self, column: Column, offset: usize) -> Result { + self.plan + .cs + .query_fixed(column, *self.plan.regions[*self.region_index] + offset) + } + fn assign_advice<'v>( &'v mut self, annotation: &'v (dyn Fn() -> String + 'v), @@ -528,6 +540,10 @@ impl<'r, 'a, F: Field, CS: Assignment + 'a> RegionLayouter for V1Region<'r Ok(()) } + + fn global_offset(&self, row_offset: usize) -> usize { + *self.plan.regions[*self.region_index] + row_offset + } } #[cfg(test)] diff --git a/halo2_proofs/src/circuit/layouter.rs b/halo2_proofs/src/circuit/layouter.rs index f73d7d7d73..8f36c3f171 100644 --- a/halo2_proofs/src/circuit/layouter.rs +++ b/halo2_proofs/src/circuit/layouter.rs @@ -58,6 +58,12 @@ pub trait RegionLayouter: fmt::Debug { column: Column, ); + /// Get the last assigned value of an advice cell. + fn query_advice(&self, column: Column, offset: usize) -> Result; + + /// Get the last assigned value of a fixed cell. + fn query_fixed(&self, column: Column, offset: usize) -> Result; + /// Assign an advice column value (witness) fn assign_advice<'v>( &'v mut self, @@ -112,6 +118,9 @@ pub trait RegionLayouter: fmt::Debug { /// /// Returns an error if either of the cells is not within the given permutation. fn constrain_equal(&mut self, left: Cell, right: Cell) -> Result<(), Error>; + + /// Return the offset of a row within the overall circuit. + fn global_offset(&self, row_offset: usize) -> usize; } /// Helper trait for implementing a custom [`Layouter`]. @@ -219,6 +228,14 @@ impl RegionLayouter for RegionShape { Ok(()) } + fn query_advice(&self, _column: Column, _offset: usize) -> Result { + Ok(F::zero()) + } + + fn query_fixed(&self, _column: Column, _offset: usize) -> Result { + Ok(F::zero()) + } + fn assign_advice<'v>( &'v mut self, _: &'v (dyn Fn() -> String + 'v), @@ -302,4 +319,8 @@ impl RegionLayouter for RegionShape { // Equality constraints don't affect the region shape. Ok(()) } + + fn global_offset(&self, _row_offset: usize) -> usize { + 0 + } } diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 94d7da90a1..ddee47b169 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -651,6 +651,56 @@ impl<'a, F: Field + Group> Assignment for MockProver<'a, F> { Ok(()) } + fn query_advice(&self, column: Column, row: usize) -> Result { + if !self.usable_rows.contains(&row) { + return Err(Error::not_enough_rows_available(self.k)); + } + if !self.rw_rows.contains(&row) { + return Err(Error::InvalidRange( + row, + self.current_region + .as_ref() + .map(|region| region.name.clone()) + .unwrap(), + )); + } + self.advice + .get(column.index()) + .and_then(|v| v.get(row - self.rw_rows.start)) + .map(|v| match v { + CellValue::Assigned(f) => *f, + #[cfg(feature = "mock-batch-inv")] + CellValue::Rational(n, d) => *n * d.invert().unwrap_or(F::zero()), + _ => F::zero(), + }) + .ok_or(Error::BoundsFailure) + } + + fn query_fixed(&self, column: Column, row: usize) -> Result { + if !self.usable_rows.contains(&row) { + return Err(Error::not_enough_rows_available(self.k)); + } + if !self.rw_rows.contains(&row) { + return Err(Error::InvalidRange( + row, + self.current_region + .as_ref() + .map(|region| region.name.clone()) + .unwrap(), + )); + } + self.fixed + .get(column.index()) + .and_then(|v| v.get(row - self.rw_rows.start)) + .map(|v| match v { + CellValue::Assigned(f) => *f, + #[cfg(feature = "mock-batch-inv")] + CellValue::Rational(n, d) => *n * d.invert().unwrap_or(F::zero()), + _ => F::zero(), + }) + .ok_or(Error::BoundsFailure) + } + fn query_instance( &self, column: Column, diff --git a/halo2_proofs/src/dev/cost.rs b/halo2_proofs/src/dev/cost.rs index 2a39cc5182..bc7d18fab1 100644 --- a/halo2_proofs/src/dev/cost.rs +++ b/halo2_proofs/src/dev/cost.rs @@ -78,6 +78,14 @@ impl Assignment for Assembly { todo!() } + fn query_advice(&self, _column: Column, _row: usize) -> Result { + Ok(F::zero()) + } + + fn query_fixed(&self, _column: Column, _row: usize) -> Result { + Ok(F::zero()) + } + fn query_instance(&self, _: Column, _: usize) -> Result, Error> { Ok(Value::unknown()) } diff --git a/halo2_proofs/src/dev/graph.rs b/halo2_proofs/src/dev/graph.rs index 8482879913..c43016b86d 100644 --- a/halo2_proofs/src/dev/graph.rs +++ b/halo2_proofs/src/dev/graph.rs @@ -116,6 +116,14 @@ impl Assignment for Graph { // Do nothing } + fn query_advice(&self, _column: Column, _row: usize) -> Result { + Ok(F::zero()) + } + + fn query_fixed(&self, _column: Column, _row: usize) -> Result { + Ok(F::zero()) + } + fn query_instance(&self, _: Column, _: usize) -> Result, Error> { Ok(Value::unknown()) } diff --git a/halo2_proofs/src/dev/graph/layout.rs b/halo2_proofs/src/dev/graph/layout.rs index ad989eab10..6812a24ede 100644 --- a/halo2_proofs/src/dev/graph/layout.rs +++ b/halo2_proofs/src/dev/graph/layout.rs @@ -440,6 +440,14 @@ impl Assignment for Layout { todo!() } + fn query_advice(&self, _column: Column, _row: usize) -> Result { + Ok(F::zero()) + } + + fn query_fixed(&self, _column: Column, _row: usize) -> Result { + Ok(F::zero()) + } + fn query_instance(&self, _: Column, _: usize) -> Result, Error> { Ok(Value::unknown()) } diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 8f1ec3da8c..500c8185f7 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -32,7 +32,6 @@ pub struct Column { } impl Column { - #[cfg(test)] pub(crate) fn new(index: usize, column_type: C) -> Self { Column { index, column_type } } @@ -409,6 +408,10 @@ impl FixedQuery { pub fn column_index(&self) -> usize { self.column_index } + /// Column + pub fn column(&self) -> Column { + Column::new(self.column_index, Fixed) + } /// Rotation of this query pub fn rotation(&self) -> Rotation { @@ -438,6 +441,10 @@ impl AdviceQuery { pub fn column_index(&self) -> usize { self.column_index } + /// Column + pub fn column(&self) -> Column { + Column::new(self.column_index, Advice { phase: self.phase }) + } /// Rotation of this query pub fn rotation(&self) -> Rotation { @@ -577,6 +584,12 @@ pub trait Assignment: Sized + Send { unimplemented!("merge is not implemented by default") } + /// Get the last assigned value of an advice cell. + fn query_advice(&self, column: Column, row: usize) -> Result; + + /// Get the last assigned value of a fixed cell. + fn query_fixed(&self, column: Column, row: usize) -> Result; + /// Queries the cell of an instance column at a particular absolute row. /// /// Returns the cell's value, if known. diff --git a/halo2_proofs/src/plonk/keygen.rs b/halo2_proofs/src/plonk/keygen.rs index 2f461491f6..5a08ca2ec3 100644 --- a/halo2_proofs/src/plonk/keygen.rs +++ b/halo2_proofs/src/plonk/keygen.rs @@ -186,6 +186,26 @@ impl<'a, F: Field> Assignment for Assembly<'a, F> { Ok(()) } + fn query_advice(&self, _column: Column, _row: usize) -> Result { + // We only care about fixed columns here + Ok(F::zero()) + } + + fn query_fixed(&self, column: Column, row: usize) -> Result { + if !self.usable_rows.contains(&row) { + return Err(Error::not_enough_rows_available(self.k)); + } + if !self.rw_rows.contains(&row) { + log::error!("query_fixed: {:?}, row: {}", column, row); + return Err(Error::Synthesis); + } + self.fixed + .get(column.index()) + .and_then(|v| v.get(row - self.rw_rows.start)) + .map(|v| v.evaluate()) + .ok_or(Error::BoundsFailure) + } + fn query_instance(&self, _: Column, row: usize) -> Result, Error> { if !self.usable_rows.contains(&row) { return Err(Error::not_enough_rows_available(self.k)); diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index 7c176e576a..7f28f22480 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -146,6 +146,7 @@ pub fn create_proof< advice: Vec<&'a mut [Assigned]>, challenges: &'a HashMap, instances: &'a [&'a [F]], + fixed_values: &'a [Polynomial], rw_rows: Range, usable_rows: RangeTo, _marker: std::marker::PhantomData, @@ -229,6 +230,7 @@ pub fn create_proof< advice, challenges: self.challenges, instances: self.instances, + fixed_values: self.fixed_values, rw_rows: sub_range.clone(), usable_rows: self.usable_rows, _marker: Default::default(), @@ -250,6 +252,30 @@ pub fn create_proof< // Do nothing } + /// Get the last assigned value of a cell. + fn query_advice(&self, column: Column, row: usize) -> Result { + if !self.usable_rows.contains(&row) { + return Err(Error::not_enough_rows_available(self.k)); + } + if !self.rw_rows.contains(&row) { + log::error!("query_advice: {:?}, row: {}", column, row); + return Err(Error::Synthesis); + } + self.advice + .get(column.index()) + .and_then(|v| v.get(row - self.rw_rows.start)) + .map(|v| v.evaluate()) + .ok_or(Error::BoundsFailure) + } + + fn query_fixed(&self, column: Column, row: usize) -> Result { + self.fixed_values + .get(column.index()) + .and_then(|v| v.get(row)) + .copied() + .ok_or(Error::BoundsFailure) + } + fn query_instance(&self, column: Column, row: usize) -> Result, Error> { if !self.usable_rows.contains(&row) { return Err(Error::not_enough_rows_available(self.k)); @@ -403,6 +429,7 @@ pub fn create_proof< advice_vec, advice: advice_slice, instances, + fixed_values: &pk.fixed_values, challenges: &challenges, // The prover will not be allowed to assign values to advice // cells that exist within inactive rows, which include some From 5f758e0bf22157f1f64e93056e8f5aea35ea6f19 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Thu, 30 Nov 2023 13:42:23 +0800 Subject: [PATCH 48/54] fix-tob-scroll-21 (#59) * fix-tob-scroll-21 * expose param field for re-randomization --- halo2_proofs/src/helpers.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/halo2_proofs/src/helpers.rs b/halo2_proofs/src/helpers.rs index f58ec9b100..e8521aa7ff 100644 --- a/halo2_proofs/src/helpers.rs +++ b/halo2_proofs/src/helpers.rs @@ -48,6 +48,10 @@ pub fn field_to_bn(f: &F) -> BigUint { /// Input a big integer `bn`, compute a field element `f` /// such that `f == bn % F::MODULUS`. +/// Require: +/// - bn is less than 512 bits. +/// Return: +/// - bn mod F::MODULUS when bn > F::MODULUS pub fn bn_to_field(bn: &BigUint) -> F { let mut buf = bn.to_bytes_le(); buf.resize(64, 0u8); From 5b9a3d71a325a9ecbad164aba90a7f6a8550a015 Mon Sep 17 00:00:00 2001 From: Ho Date: Thu, 30 Nov 2023 19:44:35 +0800 Subject: [PATCH 49/54] enable accessing for table16 (#75) --- halo2_gadgets/benches/sha256.rs | 5 ++++- halo2_gadgets/src/lib.rs | 4 ++-- halo2_gadgets/src/sha256.rs | 5 ++--- halo2_gadgets/src/sha256/table16.rs | 12 ++++++++---- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/halo2_gadgets/benches/sha256.rs b/halo2_gadgets/benches/sha256.rs index a702e84ebe..cb5b5c3194 100644 --- a/halo2_gadgets/benches/sha256.rs +++ b/halo2_gadgets/benches/sha256.rs @@ -15,7 +15,10 @@ use std::{ use criterion::{criterion_group, criterion_main, Criterion}; -use halo2_gadgets::sha256::{BlockWord, Sha256, Table16Chip, Table16Config, BLOCK_SIZE}; +use halo2_gadgets::sha256::{ + table16::{BlockWord, Table16Chip, Table16Config}, + Sha256, BLOCK_SIZE, +}; use halo2_proofs::{ poly::{ diff --git a/halo2_gadgets/src/lib.rs b/halo2_gadgets/src/lib.rs index 446b16c5f6..8d4d4292b0 100644 --- a/halo2_gadgets/src/lib.rs +++ b/halo2_gadgets/src/lib.rs @@ -25,8 +25,8 @@ pub mod ecc; pub mod poseidon; -//#[cfg(feature = "unstable")] -//#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] +#[cfg(feature = "unstable")] +#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] pub mod sha256; pub mod sinsemilla; pub mod utilities; diff --git a/halo2_gadgets/src/sha256.rs b/halo2_gadgets/src/sha256.rs index 19a658df3a..499613ad18 100644 --- a/halo2_gadgets/src/sha256.rs +++ b/halo2_gadgets/src/sha256.rs @@ -12,9 +12,8 @@ use halo2_proofs::{ plonk::Error, }; -mod table16; - -pub use table16::{BlockWord, Table16Chip, Table16Config}; +/// The core circuit for SHA256 +pub mod table16; /// The size of a SHA-256 block, in 32-bit words. pub const BLOCK_SIZE: usize = 16; diff --git a/halo2_gadgets/src/sha256/table16.rs b/halo2_gadgets/src/sha256/table16.rs index 33fb54f1a3..48a38ea5fb 100644 --- a/halo2_gadgets/src/sha256/table16.rs +++ b/halo2_gadgets/src/sha256/table16.rs @@ -234,7 +234,8 @@ pub struct Table16Config { } impl Table16Config { - pub(crate) fn initialize( + /// export initialize of compression module + pub fn initialize( &self, layouter: &mut impl Layouter, init_state_assigned: [RoundWordDense; STATE], @@ -242,7 +243,8 @@ impl Table16Config { self.compression.initialize(layouter, init_state_assigned) } - pub(crate) fn compress( + /// export compress of compression module + pub fn compress( &self, layouter: &mut impl Layouter, initialized_state: State, @@ -252,7 +254,8 @@ impl Table16Config { .compress(layouter, initialized_state, w_halves) } - pub(crate) fn digest( + /// export digest of compression module + pub fn digest( &self, layouter: &mut impl Layouter, final_state: State, @@ -262,8 +265,9 @@ impl Table16Config { .digest(layouter, final_state, initialized_state) } + /// export message_process module #[allow(clippy::type_complexity)] - pub(crate) fn message_process( + pub fn message_process( &self, layouter: &mut impl Layouter, input: [BlockWord; super::BLOCK_SIZE], From 44dbed4515984bbc14cb8283e273794b03c28afa Mon Sep 17 00:00:00 2001 From: zhenfei Date: Thu, 30 Nov 2023 22:37:09 -0500 Subject: [PATCH 50/54] chore: update poseidon link --- Cargo.lock | 2 +- halo2_proofs/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9a6ee62d9a..bac52822ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1412,7 +1412,7 @@ dependencies = [ [[package]] name = "poseidon" version = "0.2.0" -source = "git+https://github.com/scroll-tech/poseidon.git?branch=sync-ff-0.13#5787dd3d2ce7a9e9601a035c396ac0c03449b54d" +source = "git+https://github.com/scroll-tech/poseidon.git?branch=main#5787dd3d2ce7a9e9601a035c396ac0c03449b54d" dependencies = [ "halo2curves 0.1.0", "subtle", diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index 5eabdd43bc..b7eb49477d 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -55,7 +55,7 @@ blake2b_simd = "1" sha3 = "0.9.1" subtle = "2.3" cfg-if = "0.1" -poseidon = { git = "https://github.com/scroll-tech/poseidon.git", branch = "sync-ff-0.13" } +poseidon = { git = "https://github.com/scroll-tech/poseidon.git", branch = "main" } num-integer = "0.1" num-bigint = { version = "0.4", features = ["rand"] } From 45c4539dd935cda5a9e836a8880346e3521d2cbe Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Tue, 5 Dec 2023 15:40:15 +0800 Subject: [PATCH 51/54] merge sha256 gadget changes --- halo2_proofs/src/circuit/layouter.rs | 4 ++-- halo2_proofs/src/dev.rs | 8 ++++---- halo2_proofs/src/dev/cost.rs | 4 ++-- halo2_proofs/src/dev/graph.rs | 4 ++-- halo2_proofs/src/dev/graph/layout.rs | 4 ++-- halo2_proofs/src/plonk/keygen.rs | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/halo2_proofs/src/circuit/layouter.rs b/halo2_proofs/src/circuit/layouter.rs index c5a740a71c..4c9572e16b 100644 --- a/halo2_proofs/src/circuit/layouter.rs +++ b/halo2_proofs/src/circuit/layouter.rs @@ -229,11 +229,11 @@ impl RegionLayouter for RegionShape { } fn query_advice(&self, _column: Column, _offset: usize) -> Result { - Ok(F::zero()) + Ok(F::ZERO) } fn query_fixed(&self, _column: Column, _offset: usize) -> Result { - Ok(F::zero()) + Ok(F::ZERO) } fn assign_advice<'v>( diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index d156b6f294..585987cc9d 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -668,8 +668,8 @@ impl<'a, F: Field> Assignment for MockProver<'a, F> { .map(|v| match v { CellValue::Assigned(f) => *f, #[cfg(feature = "mock-batch-inv")] - CellValue::Rational(n, d) => *n * d.invert().unwrap_or(F::zero()), - _ => F::zero(), + CellValue::Rational(n, d) => *n * d.invert().unwrap_or(F::ZERO), + _ => F::ZERO, }) .ok_or(Error::BoundsFailure) } @@ -693,8 +693,8 @@ impl<'a, F: Field> Assignment for MockProver<'a, F> { .map(|v| match v { CellValue::Assigned(f) => *f, #[cfg(feature = "mock-batch-inv")] - CellValue::Rational(n, d) => *n * d.invert().unwrap_or(F::zero()), - _ => F::zero(), + CellValue::Rational(n, d) => *n * d.invert().unwrap_or(F::ZERO), + _ => F::ZERO, }) .ok_or(Error::BoundsFailure) } diff --git a/halo2_proofs/src/dev/cost.rs b/halo2_proofs/src/dev/cost.rs index bc7d18fab1..effbd97976 100644 --- a/halo2_proofs/src/dev/cost.rs +++ b/halo2_proofs/src/dev/cost.rs @@ -79,11 +79,11 @@ impl Assignment for Assembly { } fn query_advice(&self, _column: Column, _row: usize) -> Result { - Ok(F::zero()) + Ok(F::ZERO) } fn query_fixed(&self, _column: Column, _row: usize) -> Result { - Ok(F::zero()) + Ok(F::ZERO) } fn query_instance(&self, _: Column, _: usize) -> Result, Error> { diff --git a/halo2_proofs/src/dev/graph.rs b/halo2_proofs/src/dev/graph.rs index c43016b86d..ec9d3d3bfa 100644 --- a/halo2_proofs/src/dev/graph.rs +++ b/halo2_proofs/src/dev/graph.rs @@ -117,11 +117,11 @@ impl Assignment for Graph { } fn query_advice(&self, _column: Column, _row: usize) -> Result { - Ok(F::zero()) + Ok(F::ZERO) } fn query_fixed(&self, _column: Column, _row: usize) -> Result { - Ok(F::zero()) + Ok(F::ZERO) } fn query_instance(&self, _: Column, _: usize) -> Result, Error> { diff --git a/halo2_proofs/src/dev/graph/layout.rs b/halo2_proofs/src/dev/graph/layout.rs index 6812a24ede..fb7e83e74b 100644 --- a/halo2_proofs/src/dev/graph/layout.rs +++ b/halo2_proofs/src/dev/graph/layout.rs @@ -441,11 +441,11 @@ impl Assignment for Layout { } fn query_advice(&self, _column: Column, _row: usize) -> Result { - Ok(F::zero()) + Ok(F::ZERO) } fn query_fixed(&self, _column: Column, _row: usize) -> Result { - Ok(F::zero()) + Ok(F::ZERO) } fn query_instance(&self, _: Column, _: usize) -> Result, Error> { diff --git a/halo2_proofs/src/plonk/keygen.rs b/halo2_proofs/src/plonk/keygen.rs index 8b404151c9..e5459969f5 100644 --- a/halo2_proofs/src/plonk/keygen.rs +++ b/halo2_proofs/src/plonk/keygen.rs @@ -188,7 +188,7 @@ impl<'a, F: Field> Assignment for Assembly<'a, F> { fn query_advice(&self, _column: Column, _row: usize) -> Result { // We only care about fixed columns here - Ok(F::zero()) + Ok(F::ZERO) } fn query_fixed(&self, column: Column, row: usize) -> Result { From f427acac46f97c133043a75a2da150348818edc8 Mon Sep 17 00:00:00 2001 From: xkx Date: Thu, 7 Dec 2023 22:29:40 +0800 Subject: [PATCH 52/54] Fix the CI errors (#78) * cargo fmt * fix clippy error --- halo2_gadgets/src/sha256/table16.rs | 2 +- .../src/sha256/table16/compression/compression_gates.rs | 2 +- halo2_gadgets/src/sha256/table16/spread_table.rs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/halo2_gadgets/src/sha256/table16.rs b/halo2_gadgets/src/sha256/table16.rs index 48a38ea5fb..41798978de 100644 --- a/halo2_gadgets/src/sha256/table16.rs +++ b/halo2_gadgets/src/sha256/table16.rs @@ -1,4 +1,4 @@ -use halo2_proofs::arithmetic::FieldExt as Field; +use ff::PrimeField as Field; use halo2_proofs::{ circuit::{AssignedCell, Chip, Layouter, Region, Value}, plonk::{Advice, Any, Assigned, Column, ConstraintSystem, Error}, diff --git a/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs b/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs index b7a23735d3..2828a49182 100644 --- a/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs +++ b/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs @@ -1,6 +1,6 @@ use super::super::{util::*, Gate}; -use ff::PrimeField; use crate::utilities::range_check; +use ff::PrimeField; use halo2_proofs::plonk::{Constraint, Constraints, Expression}; use std::marker::PhantomData; diff --git a/halo2_gadgets/src/sha256/table16/spread_table.rs b/halo2_gadgets/src/sha256/table16/spread_table.rs index 0d016656c9..87a71efd52 100644 --- a/halo2_gadgets/src/sha256/table16/spread_table.rs +++ b/halo2_gadgets/src/sha256/table16/spread_table.rs @@ -1,7 +1,6 @@ use super::{util::*, AssignedBits, Field}; use ff::PrimeField; use halo2_proofs::{ - arithmetic::Field, circuit::{Chip, Layouter, Region, Value}, plonk::{Advice, Column, ConstraintSystem, Error, TableColumn}, }; From 84003a202d6b9185c952ec91ea793dbbd6c5b200 Mon Sep 17 00:00:00 2001 From: xkx Date: Fri, 8 Dec 2023 17:22:49 +0800 Subject: [PATCH 53/54] Feat: switch to logup scheme for lookup argument (#71) * Multi-input mv-lookup. (#49) * Add mv_lookup.rs * mv_lookup::prover, mv_lookup::verifier * Replace lookup with mv_lookup * replace halo2 with mv lookup Co-authored-by: ying tong * cleanups Co-authored-by: ying tong * ConstraintSystem: setup lookup_tracker Co-authored-by: Andrija * mv_lookup::hybrid_prover Co-authored-by: Andrija * WIP * mv_multi_lookup: enable lookup caching Co-authored-by: therealyingtong * Rename hybrid_lookup -> lookup * Chunk lookups using user-provided minimum degree Co-authored-by: Andrija * mv_lookup bench Co-authored-by: Andrija * Introduce counter feature for FFTs and MSMs Co-authored-by: Andrija * Fix off-by-one errors in chunk_lookup Co-authored-by: Andrija * bench wip * time evaluate_h * KZG * more efficient batch inversion * extended lookup example * Finalize mv lookup Author: therealyingtong * Remove main/ * Fix according to the comments * replace scan with parallel grand sum computation * Revert Cargo.lock * mv lookup Argument name * parallel batch invert --------- Co-authored-by: Andrija Co-authored-by: ying tong Co-authored-by: therealyingtong * fmt * fix unit test * fix clippy errors * add todo in mv_lookup's prover * fmt and clippy * fix clippy * add detailed running time of steps in logup's prover * fmt * add more log hooks * more running time logs * use par invert * use sorted-vector to store how many times a table element occurs in input * par the process to get inputs_inv_sum * use par * fix par * add feature to skip inv sums * add new feature flag * fix clippy error --------- Co-authored-by: Sphere L Co-authored-by: Andrija Co-authored-by: ying tong Co-authored-by: therealyingtong --- Cargo.lock | 1 + halo2_proofs/Cargo.toml | 10 +- halo2_proofs/benches/lookups.rs | 239 +++++ halo2_proofs/src/arithmetic.rs | 22 +- halo2_proofs/src/dev.rs | 172 ++-- halo2_proofs/src/dev/failure.rs | 151 +-- halo2_proofs/src/lib.rs | 19 + halo2_proofs/src/plonk.rs | 2 + halo2_proofs/src/plonk/circuit.rs | 176 +++- .../src/plonk/circuit/compress_selectors.rs | 2 +- halo2_proofs/src/plonk/evaluation.rs | 266 ++++-- halo2_proofs/src/plonk/keygen.rs | 2 + halo2_proofs/src/plonk/mv_lookup.rs | 96 ++ .../src/plonk/mv_lookup/exec_info.json | 46 + halo2_proofs/src/plonk/mv_lookup/prover.rs | 529 +++++++++++ halo2_proofs/src/plonk/mv_lookup/verifier.rs | 191 ++++ halo2_proofs/src/plonk/prover.rs | 28 +- halo2_proofs/src/plonk/verifier.rs | 50 +- halo2_proofs/src/poly.rs | 2 +- halo2_proofs/tests/plonk_api.rs | 857 ++++++++++++------ 20 files changed, 2293 insertions(+), 568 deletions(-) create mode 100644 halo2_proofs/benches/lookups.rs create mode 100644 halo2_proofs/src/plonk/mv_lookup.rs create mode 100644 halo2_proofs/src/plonk/mv_lookup/exec_info.json create mode 100644 halo2_proofs/src/plonk/mv_lookup/prover.rs create mode 100644 halo2_proofs/src/plonk/mv_lookup/verifier.rs diff --git a/Cargo.lock b/Cargo.lock index bac52822ae..3a36d84c12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -886,6 +886,7 @@ dependencies = [ "group", "gumdrop", "halo2curves 0.1.0", + "lazy_static", "log", "num-bigint", "num-integer", diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index b7eb49477d..94d7df91ab 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -39,6 +39,10 @@ harness = false name = "dev_lookup" harness = false +[[bench]] +name = "lookups" +harness = false + [[bench]] name = "fft" harness = false @@ -63,11 +67,13 @@ crossbeam = "0.8.0" # Developer tooling dependencies plotters = { version = "0.3.0", optional = true } tabbycat = { version = "0.1", features = ["attributes"], optional = true } +lazy_static = { version = "1", optional = true } log = "0.4.17" # timer ark-std = { version = "0.3.0" } + [dev-dependencies] assert_matches = "1.5" criterion = "0.3" @@ -80,7 +86,7 @@ rand_core = { version = "0.6", default-features = false, features = ["getrandom" getrandom = { version = "0.2", features = ["js"] } [features] -default = ["batch", "gwc"] +default = ["batch", "gwc", "logup_skip_inv"] dev-graph = ["plotters", "tabbycat"] gadget-traces = ["backtrace"] sanity-checks = [] @@ -90,7 +96,9 @@ gwc = [] parallel_syn = [] phase-check = [] profile = ["ark-std/print-trace"] +counter = ["lazy_static"] mock-batch-inv = [] +logup_skip_inv = [] [lib] bench = false diff --git a/halo2_proofs/benches/lookups.rs b/halo2_proofs/benches/lookups.rs new file mode 100644 index 0000000000..601b1a4285 --- /dev/null +++ b/halo2_proofs/benches/lookups.rs @@ -0,0 +1,239 @@ +#[macro_use] +extern crate criterion; + +use halo2_proofs::circuit::{Layouter, SimpleFloorPlanner, Value}; +use halo2_proofs::plonk::*; +use halo2_proofs::poly::kzg::multiopen::VerifierGWC; +use halo2_proofs::poly::{commitment::ParamsProver, Rotation}; +use halo2_proofs::transcript::{Blake2bRead, Blake2bWrite, Challenge255}; +use halo2curves::bn256::{Bn256, G1Affine}; +use halo2curves::pairing::Engine; +use rand_core::OsRng; + +use halo2_proofs::{ + poly::kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG}, + multiopen::ProverGWC, + strategy::SingleStrategy, + }, + transcript::{TranscriptReadBuffer, TranscriptWriterBuffer}, +}; + +use std::marker::PhantomData; + +use criterion::{BenchmarkId, Criterion}; +use ff::PrimeField as Field; + +fn criterion_benchmark(c: &mut Criterion) { + #[derive(Clone, Default)] + struct MyCircuit { + _marker: PhantomData, + } + + #[derive(Clone)] + struct MyConfig { + selector: Selector, + table: TableColumn, + advice: Column, + other_advice: Column, + } + + impl Circuit for MyCircuit { + type Config = MyConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> MyConfig { + let config = MyConfig { + selector: meta.complex_selector(), + table: meta.lookup_table_column(), + advice: meta.advice_column(), + other_advice: meta.advice_column(), + }; + + let dummy_selector = meta.complex_selector(); + + meta.create_gate("degree 6 gate", |meta| { + let dummy_selector = meta.query_selector(dummy_selector); + let constraints = vec![dummy_selector.clone(); 4] + .iter() + .fold(dummy_selector.clone(), |acc, val| acc * val.clone()); + Constraints::with_selector(dummy_selector, Some(constraints)) + }); + + meta.lookup("lookup", |meta| { + let advice = meta.query_advice(config.advice, Rotation::cur()); + vec![(advice, config.table)] + }); + + meta.lookup("lookup", |meta| { + let advice = meta.query_advice(config.advice, Rotation::cur()); + vec![(advice, config.table)] + }); + + meta.lookup("lookup", |meta| { + let advice = meta.query_advice(config.advice, Rotation::cur()); + vec![(advice, config.table)] + }); + + meta.lookup("lookup", |meta| { + let advice = meta.query_advice(config.advice, Rotation::cur()); + vec![(advice, config.table)] + }); + + meta.lookup("lookup", |meta| { + let advice = meta.query_advice(config.advice, Rotation::cur()); + vec![(advice, config.table)] + }); + + /* + - We need degree at least 6 because 6 - 1 = 5 and we need to go to extended domain of 8n + - Our goal is to get to max degree of 9 because now 9 - 1 = 8 and that will fit into domain + + - base degree = table_deg + 2 + - if we put input_expression_degree = 1 + => degree = base + 1 = 3 + 1 = 4 + - we can batch one more with 5 more lookups + */ + + config + } + + fn synthesize( + &self, + config: MyConfig, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + layouter.assign_table( + || "8-bit table", + |mut table| { + for row in 0u64..(1 << 8) { + table.assign_cell( + || format!("row {}", row), + config.table, + row as usize, + || Value::known(F::from(row)), + )?; + } + + Ok(()) + }, + )?; + + layouter.assign_region( + || "assign values", + |mut region| { + for offset in 0u64..(1 << 10) { + config.selector.enable(&mut region, offset as usize)?; + region.assign_advice( + || format!("offset {}", offset), + config.advice, + offset as usize, + || Value::known(F::from(offset % 256)), + )?; + } + for offset in 1u64..(1 << 10) { + config.selector.enable(&mut region, offset as usize)?; + region.assign_advice( + || format!("offset {}", offset), + config.other_advice, + offset as usize - 1, + || Value::known(F::from(offset % 256)), + )?; + } + Ok(()) + }, + ) + } + } + + fn keygen(k: u32) -> (ParamsKZG, ProvingKey) { + let params: ParamsKZG = ParamsKZG::new(k); + let empty_circuit: MyCircuit<::Scalar> = MyCircuit { + _marker: PhantomData, + }; + let vk = keygen_vk(¶ms, &empty_circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(¶ms, vk, &empty_circuit).expect("keygen_pk should not fail"); + (params, pk) + } + + fn prover(_k: u32, params: &ParamsKZG, pk: &ProvingKey) -> Vec { + let rng = OsRng; + + let circuit: MyCircuit<::Scalar> = MyCircuit { + _marker: PhantomData, + }; + + let mut transcript = Blake2bWrite::<_, _, Challenge255>::init(vec![]); + create_proof::, ProverGWC<'_, Bn256>, _, _, _, _>( + params, + pk, + &[circuit], + &[&[]], + rng, + &mut transcript, + ) + .expect("proof generation should not fail"); + transcript.finalize() + } + + fn verifier(params: &ParamsKZG, vk: &VerifyingKey, proof: &[u8]) { + let strategy = SingleStrategy::new(params); + let mut transcript = Blake2bRead::<_, _, Challenge255>::init(proof); + assert!(verify_proof::< + KZGCommitmentScheme, + VerifierGWC<'_, Bn256>, + Challenge255, + Blake2bRead<&[u8], G1Affine, Challenge255>, + SingleStrategy<'_, Bn256>, + >(params, vk, strategy, &[&[]], &mut transcript) + .is_ok()); + } + + let k_range = 16..=16; + + let mut keygen_group = c.benchmark_group("plonk-keygen"); + keygen_group.sample_size(10); + for k in k_range.clone() { + keygen_group.bench_with_input(BenchmarkId::from_parameter(k), &k, |b, &k| { + b.iter(|| keygen(k)); + }); + } + keygen_group.finish(); + + let mut prover_group = c.benchmark_group("plonk-prover"); + prover_group.sample_size(10); + for k in k_range.clone() { + let (params, pk) = keygen(k); + + prover_group.bench_with_input( + BenchmarkId::from_parameter(k), + &(k, ¶ms, &pk), + |b, &(k, params, pk)| { + b.iter(|| prover(k, params, pk)); + }, + ); + } + prover_group.finish(); + + let mut verifier_group = c.benchmark_group("plonk-verifier"); + for k in k_range { + let (params, pk) = keygen(k); + let proof = prover(k, ¶ms, &pk); + + verifier_group.bench_with_input( + BenchmarkId::from_parameter(k), + &(¶ms, pk.get_vk(), &proof[..]), + |b, &(params, vk, proof)| { + b.iter(|| verifier(params, vk, proof)); + }, + ); + } + verifier_group.finish(); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/halo2_proofs/src/arithmetic.rs b/halo2_proofs/src/arithmetic.rs index 56ca5fd90c..849a7022cc 100644 --- a/halo2_proofs/src/arithmetic.rs +++ b/halo2_proofs/src/arithmetic.rs @@ -535,9 +535,18 @@ where q } +pub fn par_invert(values: &mut [F]) { + parallelize(values, |values, _start| { + values.batch_invert(); + }); +} + /// This simple utility function will parallelize an operation that is to be /// performed over a mutable slice. -pub fn parallelize(v: &mut [T], f: F) { +pub(crate) fn parallelize_internal( + v: &mut [T], + f: F, +) -> Vec { let n = v.len(); let num_threads = multicore::current_num_threads(); let mut chunk = (n as usize) / num_threads; @@ -546,14 +555,23 @@ pub fn parallelize(v: &mu } multicore::scope(|scope| { + let mut chunk_starts = vec![]; for (chunk_num, v) in v.chunks_mut(chunk).enumerate() { let f = f.clone(); scope.spawn(move |_| { let start = chunk_num * chunk; f(v, start); }); + let start = chunk_num * chunk; + chunk_starts.push(start); } - }); + + chunk_starts + }) +} + +pub fn parallelize(v: &mut [T], f: F) { + parallelize_internal(v, f); } fn log2_floor(num: usize) -> u32 { diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index 585987cc9d..a83478366c 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -940,6 +940,7 @@ impl<'a, F: FromUniformBytes<64> + Ord> MockProver<'a, F> { let mut cs = ConstraintSystem::default(); let config = ConcreteCircuit::configure(&mut cs); + let cs = cs.chunk_lookups(); let cs = cs; if n < cs.minimum_rows() { @@ -1340,7 +1341,9 @@ impl<'a, F: FromUniformBytes<64> + Ord> MockProver<'a, F> { ) }; - assert!(lookup.table_expressions.len() == lookup.input_expressions.len()); + for input_expressions in lookup.inputs_expressions.iter() { + assert!(lookup.table_expressions.len() == input_expressions.len()); + } assert!(self.usable_rows.end > 0); // We optimize on the basis that the table might have been filled so that the last @@ -1386,49 +1389,53 @@ impl<'a, F: FromUniformBytes<64> + Ord> MockProver<'a, F> { } let table = &cached_table; - let mut inputs: Vec<(Vec<_>, usize)> = lookup_input_row_ids - .clone() - .into_iter() - .filter_map(|input_row| { - let t = lookup - .input_expressions - .iter() - .map(move |c| load(c, input_row)) - .collect(); - - if t != fill_row { - // Also keep track of the original input row, since we're going to sort. - Some((t, input_row)) - } else { - None - } - }) - .collect(); - inputs.sort_unstable(); - - let mut i = 0; - inputs + lookup + .inputs_expressions .iter() - .filter_map(move |(input, input_row)| { - while i < table.len() && &table[i] < input { - i += 1; - } - if i == table.len() || &table[i] > input { - assert!(table.binary_search(input).is_err()); + .map(|input_expressions| { + let mut inputs: Vec<(Vec<_>, usize)> = lookup_input_row_ids + .clone() + .filter_map(|input_row| { + let t = input_expressions + .iter() + .map(move |c| load(c, input_row)) + .collect(); + + if t != fill_row { + // Also keep track of the original input row, since we're going to sort. + Some((t, input_row)) + } else { + None + } + }) + .collect(); + inputs.sort_unstable(); - Some(VerifyFailure::Lookup { - name: lookup.name, - lookup_index, - location: FailureLocation::find_expressions( - &self.cs, - &self.regions, - *input_row, - lookup.input_expressions.iter(), - ), + let mut i = 0; + inputs + .iter() + .filter_map(move |(input, input_row)| { + while i < table.len() && &table[i] < input { + i += 1; + } + if i == table.len() || &table[i] > input { + assert!(table.binary_search(input).is_err()); + + Some(VerifyFailure::Lookup { + name: lookup.name, + lookup_index, + location: FailureLocation::find_expressions( + &self.cs, + &self.regions, + *input_row, + input_expressions.iter(), + ), + }) + } else { + None + } }) - } else { - None - } + .collect::>() }) .collect::>() }); @@ -1483,7 +1490,7 @@ impl<'a, F: FromUniformBytes<64> + Ord> MockProver<'a, F> { let mut errors: Vec<_> = iter::empty() .chain(selector_errors) .chain(gate_errors) - .chain(lookup_errors) + .chain(lookup_errors.flatten()) .chain(perm_errors) .collect(); if errors.is_empty() { @@ -1719,7 +1726,9 @@ impl<'a, F: FromUniformBytes<64> + Ord> MockProver<'a, F> { ) }; - assert!(lookup.table_expressions.len() == lookup.input_expressions.len()); + for input_expressions in lookup.inputs_expressions.iter() { + assert!(lookup.table_expressions.len() == input_expressions.len()); + } assert!(self.usable_rows.end > 0); // We optimize on the basis that the table might have been filled so that the last @@ -1766,43 +1775,48 @@ impl<'a, F: FromUniformBytes<64> + Ord> MockProver<'a, F> { } let table = &cached_table; - let mut inputs: Vec<(Vec<_>, usize)> = lookup_input_row_ids - .clone() - .into_par_iter() - .filter_map(|input_row| { - let t = lookup - .input_expressions - .iter() - .map(move |c| load(c, input_row)) + lookup + .inputs_expressions + .iter() + .map(|input_expressions| { + let mut inputs: Vec<(Vec<_>, usize)> = lookup_input_row_ids + .clone() + .into_par_iter() + .filter_map(|input_row| { + let t = input_expressions + .iter() + .map(move |c| load(c, input_row)) + .collect(); + + if t != fill_row { + // Also keep track of the original input row, since we're going to sort. + Some((t, input_row)) + } else { + None + } + }) .collect(); - - if t != fill_row { - // Also keep track of the original input row, since we're going to sort. - Some((t, input_row)) - } else { - None - } - }) - .collect(); - inputs.par_sort_unstable(); - - inputs - .par_iter() - .filter_map(move |(input, input_row)| { - if table.binary_search(input).is_err() { - Some(VerifyFailure::Lookup { - name: lookup.name, - lookup_index, - location: FailureLocation::find_expressions( - &self.cs, - &self.regions, - *input_row, - lookup.input_expressions.iter(), - ), + inputs.par_sort_unstable(); + + inputs + .par_iter() + .filter_map(move |(input, input_row)| { + if table.binary_search(input).is_err() { + Some(VerifyFailure::Lookup { + name: lookup.name, + lookup_index, + location: FailureLocation::find_expressions( + &self.cs, + &self.regions, + *input_row, + input_expressions.iter(), + ), + }) + } else { + None + } }) - } else { - None - } + .collect::>() }) .collect::>() }); @@ -1861,7 +1875,7 @@ impl<'a, F: FromUniformBytes<64> + Ord> MockProver<'a, F> { let mut errors: Vec<_> = iter::empty() .chain(selector_errors) .chain(gate_errors) - .chain(lookup_errors) + .chain(lookup_errors.flatten()) .chain(perm_errors) .collect(); if errors.is_empty() { diff --git a/halo2_proofs/src/dev/failure.rs b/halo2_proofs/src/dev/failure.rs index 54b7a473db..06aaafe201 100644 --- a/halo2_proofs/src/dev/failure.rs +++ b/halo2_proofs/src/dev/failure.rs @@ -158,7 +158,6 @@ pub enum VerifyFailure { }, /// A lookup input did not exist in its corresponding table. Lookup { - /// The name of the lookup that is not satisfied. name: &'static str, /// The index of the lookup that is not satisfied. These indices are assigned in /// the order in which `ConstraintSystem::lookup` is called during @@ -445,7 +444,7 @@ fn render_constraint_not_satisfied( /// ``` fn render_lookup( prover: &MockProver, - name: &str, + _name: &str, lookup_index: usize, location: &FailureLocation, ) { @@ -533,8 +532,10 @@ fn render_lookup( eprintln!("error: lookup input does not exist in table"); eprint!(" ("); - for i in 0..lookup.input_expressions.len() { - eprint!("{}L{}", if i == 0 { "" } else { ", " }, i); + for input_expressions in lookup.inputs_expressions.iter() { + for i in 0..input_expressions.len() { + eprint!("{}L{}", if i == 0 { "" } else { ", " }, i); + } } eprint!(") ∉ ("); @@ -544,79 +545,81 @@ fn render_lookup( eprintln!(")"); eprintln!(); - eprintln!(" Lookup '{}' inputs:", name); - for (i, input) in lookup.input_expressions.iter().enumerate() { - // Fetch the cell values (since we don't store them in VerifyFailure::Lookup). - let cell_values = input.evaluate( - &|_| BTreeMap::default(), - &|_| panic!("virtual selectors are removed during optimization"), - &cell_value(&util::load_slice( - n, - row, - &cs.fixed_queries, - prover.fixed.as_slice(), - )), - &cell_value(&util::load_slice( - n, - row, - &cs.advice_queries, - &prover.advice, - )), - &cell_value(&util::load_instance( - n, - row, - &cs.instance_queries, - &prover.instance, - )), - &|_| BTreeMap::default(), - &|a| a, - &|mut a, mut b| { - a.append(&mut b); - a - }, - &|mut a, mut b| { - a.append(&mut b); - a - }, - &|a, _| a, - ); - - // Collect the necessary rendering information: - // - The columns involved in this constraint. - // - How many cells are in each column. - // - The grid of cell values, indexed by rotation. - let mut columns = BTreeMap::::default(); - let mut layout = BTreeMap::>::default(); - for (i, (cell, _)) in cell_values.iter().enumerate() { - *columns.entry(cell.column).or_default() += 1; - layout - .entry(cell.rotation) - .or_default() - .entry(cell.column) - .or_insert(format!("x{}", i)); - } + eprintln!(" Lookup inputs:"); + for input_expressions in lookup.inputs_expressions.iter() { + for (i, input) in input_expressions.iter().enumerate() { + // Fetch the cell values (since we don't store them in VerifyFailure::Lookup). + let cell_values = input.evaluate( + &|_| BTreeMap::default(), + &|_| panic!("virtual selectors are removed during optimization"), + &cell_value(&util::load_slice( + n, + row, + &cs.fixed_queries, + prover.fixed.as_slice(), + )), + &cell_value(&util::load_slice( + n, + row, + &cs.advice_queries, + &prover.advice, + )), + &cell_value(&util::load_instance( + n, + row, + &cs.instance_queries, + &prover.instance, + )), + &|_| BTreeMap::default(), + &|a| a, + &|mut a, mut b| { + a.append(&mut b); + a + }, + &|mut a, mut b| { + a.append(&mut b); + a + }, + &|a, _| a, + ); + + // Collect the necessary rendering information: + // - The columns involved in this constraint. + // - How many cells are in each column. + // - The grid of cell values, indexed by rotation. + let mut columns = BTreeMap::::default(); + let mut layout = BTreeMap::>::default(); + for (i, (cell, _)) in cell_values.iter().enumerate() { + *columns.entry(cell.column).or_default() += 1; + layout + .entry(cell.rotation) + .or_default() + .entry(cell.column) + .or_insert(format!("x{}", i)); + } - if i != 0 { - eprintln!(); - } - eprintln!( - " L{} = {}", - i, - emitter::expression_to_string(input, &layout) - ); - eprintln!(" ^"); - - emitter::render_cell_layout(" | ", location, &columns, &layout, |_, rotation| { - if rotation == 0 { - eprint!(" <--{{ Lookup '{}' inputs queried here", name); + if i != 0 { + eprintln!(); } - }); + eprintln!( + " L{} = {}", + i, + emitter::expression_to_string(input, &layout) + ); + eprintln!(" ^"); + + emitter::render_cell_layout(" | ", location, &columns, &layout, |_, rotation| { + if rotation == 0 { + eprint!(" <--{{ Lookup inputs queried here"); + } + }); - // Print the map from local variables to assigned values. - eprintln!(" |"); - eprintln!(" | Assigned cell values:"); - for (i, (_, value)) in cell_values.iter().enumerate() { - eprintln!(" | x{} = {}", i, value); + // Print the map from local variables to assigned values. + eprintln!(" |"); + eprintln!(" | Assigned cell values:"); + for (i, (_, value)) in cell_values.iter().enumerate() { + eprintln!(" | x{} = {}", i, value); + } } } } diff --git a/halo2_proofs/src/lib.rs b/halo2_proofs/src/lib.rs index 6192272fc2..39fd43d4e5 100644 --- a/halo2_proofs/src/lib.rs +++ b/halo2_proofs/src/lib.rs @@ -25,6 +25,25 @@ #![allow(unused_imports)] #![allow(clippy::derive_partial_eq_without_eq)] +#[cfg(feature = "counter")] +#[macro_use] +extern crate lazy_static; + +#[cfg(feature = "counter")] +use lazy_static::lazy_static; + +#[cfg(feature = "counter")] +use std::sync::Mutex; + +#[cfg(feature = "counter")] +use std::collections::BTreeMap; + +#[cfg(feature = "counter")] +lazy_static! { + static ref FFT_COUNTER: Mutex> = Mutex::new(BTreeMap::new()); + static ref MSM_COUNTER: Mutex> = Mutex::new(BTreeMap::new()); +} + pub mod arithmetic; pub mod circuit; pub use halo2curves; diff --git a/halo2_proofs/src/plonk.rs b/halo2_proofs/src/plonk.rs index dc80092f7b..96d34992e1 100644 --- a/halo2_proofs/src/plonk.rs +++ b/halo2_proofs/src/plonk.rs @@ -26,7 +26,9 @@ mod circuit; mod error; mod evaluation; mod keygen; +#[allow(dead_code)] mod lookup; +mod mv_lookup; pub(crate) mod permutation; mod vanishing; diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 85e48022f8..251c146aeb 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -1,14 +1,17 @@ use core::cmp::max; use core::ops::{Add, Mul}; use ff::Field; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; +use std::fmt::Debug; +use std::hash::Hasher; +use std::marker::PhantomData; use std::ops::Range; use std::{ convert::TryFrom, ops::{Neg, Sub}, }; -use super::{lookup, permutation, Assigned, Error}; +use super::{mv_lookup, permutation, Assigned, Error}; use crate::dev::metadata; use crate::{ circuit::{Layouter, Region, Value}, @@ -388,7 +391,7 @@ impl Selector { } /// Query of fixed column at a certain relative location -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct FixedQuery { /// Query index pub(crate) index: usize, @@ -419,7 +422,7 @@ impl FixedQuery { } /// Query of advice column at a certain relative location -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct AdviceQuery { /// Query index pub(crate) index: usize, @@ -457,7 +460,7 @@ impl AdviceQuery { } /// Query of instance column at a certain relative location -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct InstanceQuery { /// Query index pub(crate) index: usize, @@ -1382,9 +1385,16 @@ impl Gate { } } +/// TODO doc +#[derive(Debug, Clone)] +pub struct LookupTracker { + pub(crate) table: Vec>, + pub(crate) inputs: Vec>>, +} + /// This is a description of the circuit environment, such as the gate, column and /// permutation arrangements. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub struct ConstraintSystem { pub num_fixed_columns: usize, pub num_advice_columns: usize, @@ -1414,9 +1424,12 @@ pub struct ConstraintSystem { // Permutation argument for performing equality constraints pub permutation: permutation::Argument, + /// Map from table expression to vec of vec of input expressions + pub lookups_map: BTreeMap>, + // Vector of lookup arguments, where each corresponds to a sequence of // input expressions and a sequence of table expressions involved in the lookup. - pub lookups: Vec>, + pub 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: BTreeMap, @@ -1443,7 +1456,7 @@ pub struct PinnedConstraintSystem<'a, F: Field> { instance_queries: &'a Vec<(Column, Rotation)>, fixed_queries: &'a Vec<(Column, Rotation)>, permutation: &'a permutation::Argument, - lookups: &'a Vec>, + lookups_map: &'a BTreeMap>, constants: &'a Vec>, minimum_degree: &'a Option, } @@ -1469,7 +1482,7 @@ impl<'a, F: Field> std::fmt::Debug for PinnedConstraintSystem<'a, F> { .field("instance_queries", self.instance_queries) .field("fixed_queries", self.fixed_queries) .field("permutation", self.permutation) - .field("lookups", self.lookups) + .field("lookups_map", self.lookups_map) .field("constants", self.constants) .field("minimum_degree", self.minimum_degree); debug_struct.finish() @@ -1504,6 +1517,7 @@ impl Default for ConstraintSystem { num_advice_queries: Vec::new(), instance_queries: Vec::new(), permutation: permutation::Argument::new(), + lookups_map: BTreeMap::default(), lookups: Vec::new(), general_column_annotations: BTreeMap::new(), constants: vec![], @@ -1530,7 +1544,7 @@ impl ConstraintSystem { advice_queries: &self.advice_queries, instance_queries: &self.instance_queries, permutation: &self.permutation, - lookups: &self.lookups, + lookups_map: &self.lookups_map, constants: &self.constants, minimum_degree: &self.minimum_degree, } @@ -1561,11 +1575,12 @@ impl ConstraintSystem { /// they need to match. pub fn lookup( &mut self, - name: &'static str, + // FIXME use name in debug messages + _name: &'static str, table_map: impl FnOnce(&mut VirtualCells<'_, F>) -> Vec<(Expression, TableColumn)>, - ) -> usize { + ) { let mut cells = VirtualCells::new(self); - let table_map = table_map(&mut cells) + let (input_expressions, table_expressions): (Vec<_>, Vec<_>) = table_map(&mut cells) .into_iter() .map(|(input, table)| { if input.contains_simple_selector() { @@ -1576,13 +1591,90 @@ impl ConstraintSystem { (input, table) }) - .collect(); + .unzip(); - let index = self.lookups.len(); + let table_expressions_identifier = table_expressions + .iter() + .fold(String::new(), |string, expr| string + &expr.identifier()); + + self.lookups_map + .entry(table_expressions_identifier) + .and_modify(|table_tracker| table_tracker.inputs.push(input_expressions.clone())) + .or_insert(LookupTracker { + table: table_expressions, + inputs: vec![input_expressions], + }); + } - self.lookups.push(lookup::Argument::new(name, table_map)); + /// Chunk lookup arguments into pieces below a given degree bound + pub fn chunk_lookups(mut self) -> Self { + if self.lookups_map.is_empty() { + return self; + } - index + let max_gate_degree = self.max_gate_degree(); + let max_single_lookup_degree: usize = self + .lookups_map + .values() + .map(|v| { + let table_degree = v.table.iter().map(|expr| expr.degree()).max().unwrap(); + let base_lookup_degree = super::mv_lookup::base_degree(table_degree); + + let max_inputs_degree: usize = v + .inputs + .iter() + .map(|input| input.iter().map(|expr| expr.degree()).max().unwrap()) + .max() + .unwrap(); + + mv_lookup::degree_with_input(base_lookup_degree, max_inputs_degree) + }) + .max() + .unwrap(); + + let required_degree = std::cmp::max(max_gate_degree, max_single_lookup_degree); + let required_degree = (required_degree as u64 - 1).next_power_of_two() as usize; + + self.set_minimum_degree(required_degree + 1); + + // safe to unwrap here + let minimum_degree = self.minimum_degree.unwrap(); + + let mut lookups: Vec<_> = vec![]; + for v in self.lookups_map.values() { + let LookupTracker { table, inputs } = v; + let mut args = vec![super::mv_lookup::Argument::new( + "lookup", + table, + &[inputs[0].clone()], + )]; + + for input in inputs.iter().skip(1) { + let cur_input_degree = input.iter().map(|expr| expr.degree()).max().unwrap(); + let mut indicator = false; + for arg in args.iter_mut() { + // try to fit input in one of the args + let cur_argument_degree = arg.required_degree(); + let new_potential_degree = cur_argument_degree + cur_input_degree; + if new_potential_degree <= minimum_degree { + arg.inputs_expressions.push(input.clone()); + indicator = true; + break; + } + } + + if !indicator { + args.push(super::mv_lookup::Argument::new( + "dummy", + table, + &[input.clone()], + )) + } + } + lookups.append(&mut args); + } + self.lookups = lookups; + self } /// Add a lookup argument for some input expressions and table expressions. @@ -1591,17 +1683,26 @@ impl ConstraintSystem { /// they need to match. pub fn lookup_any( &mut self, - name: &'static str, + // FIXME use name in debug messages + _name: &'static str, 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 index = self.lookups.len(); - - self.lookups.push(lookup::Argument::new(name, table_map)); - - index + let (input_expressions, table_expressions): (Vec<_>, Vec<_>) = + table_map.into_iter().unzip(); + let table_expressions_identifier = table_expressions + .iter() + .fold(String::new(), |string, expr| string + &expr.identifier()); + + self.lookups_map + .entry(table_expressions_identifier) + .and_modify(|table_tracker| table_tracker.inputs.push(input_expressions.clone())) + .or_insert(LookupTracker { + table: table_expressions, + inputs: vec![input_expressions], + }); } fn query_fixed_index(&mut self, column: Column, at: Rotation) -> usize { @@ -1710,7 +1811,9 @@ impl ConstraintSystem { /// larger amount than actually needed. This can be used, for example, to /// force the permutation argument to involve more columns in the same set. pub fn set_minimum_degree(&mut self, degree: usize) { - self.minimum_degree = Some(degree); + self.minimum_degree = self + .minimum_degree + .map_or(Some(degree), |min_degree| Some(max(min_degree, degree))); } /// Creates a new gate. @@ -1855,8 +1958,9 @@ impl ConstraintSystem { // lookup expressions for expr in self.lookups.iter_mut().flat_map(|lookup| { lookup - .input_expressions + .inputs_expressions .iter_mut() + .flatten() .chain(lookup.table_expressions.iter_mut()) }) { replace_selectors(expr, &selector_replacements, true); @@ -2015,6 +2119,15 @@ impl ConstraintSystem { (0..=max_phase).map(sealed::Phase) } + /// Compute the maximum degree of gates in the constraint system + pub fn max_gate_degree(&self) -> usize { + self.gates + .iter() + .flat_map(|gate| gate.polynomials().iter().map(|poly| poly.degree())) + .max() + .unwrap_or(0) + } + /// Compute the degree of the constraint system (the maximum degree of all /// constraints). pub fn degree(&self) -> usize { @@ -2035,13 +2148,16 @@ impl ConstraintSystem { // Account for each gate to ensure our quotient polynomial is the // correct degree and that our extended domain is the right size. + degree = std::cmp::max(degree, self.max_gate_degree()); + + // Lookup degree degree = std::cmp::max( degree, - self.gates + self.lookups .iter() - .flat_map(|gate| gate.polynomials().iter().map(|poly| poly.degree())) + .map(|hl| hl.required_degree()) .max() - .unwrap_or(0), + .unwrap_or(1), ); std::cmp::max(degree, self.minimum_degree.unwrap_or(1)) @@ -2147,7 +2263,7 @@ impl ConstraintSystem { } /// Returns lookup arguments - pub fn lookups(&self) -> &Vec> { + pub fn lookups(&self) -> &Vec> { &self.lookups } diff --git a/halo2_proofs/src/plonk/circuit/compress_selectors.rs b/halo2_proofs/src/plonk/circuit/compress_selectors.rs index 60898d3950..f52a0e7c9a 100644 --- a/halo2_proofs/src/plonk/circuit/compress_selectors.rs +++ b/halo2_proofs/src/plonk/circuit/compress_selectors.rs @@ -20,7 +20,7 @@ pub struct SelectorDescription { /// This describes the assigned combination of a particular selector as well as /// the expression it should be substituted with. #[derive(Debug, Clone)] -pub struct SelectorAssignment { +pub struct SelectorAssignment { /// The selector that this structure references, by index. pub selector: usize, diff --git a/halo2_proofs/src/plonk/evaluation.rs b/halo2_proofs/src/plonk/evaluation.rs index 2f08a43e01..f626bcbb54 100644 --- a/halo2_proofs/src/plonk/evaluation.rs +++ b/halo2_proofs/src/plonk/evaluation.rs @@ -1,7 +1,9 @@ use crate::multicore; use crate::plonk::lookup::prover::Committed; use crate::plonk::permutation::Argument; -use crate::plonk::{lookup, permutation, AdviceQuery, Any, FixedQuery, InstanceQuery, ProvingKey}; +use crate::plonk::{ + mv_lookup, permutation, AdviceQuery, Any, FixedQuery, InstanceQuery, ProvingKey, +}; use crate::poly::Basis; use crate::{ arithmetic::{eval_polynomial, parallelize, CurveAffine}, @@ -16,10 +18,14 @@ use group::{ ff::{BatchInvert, Field, PrimeField, WithSmallOrderMulGroup}, Curve, }; +use rayon::prelude::IntoParallelIterator; +use rayon::prelude::ParallelIterator; use std::any::TypeId; use std::convert::TryInto; use std::num::ParseIntError; +use std::process::exit; use std::slice; +use std::sync::atomic::fence; use std::{ collections::BTreeMap, iter, @@ -51,7 +57,8 @@ pub enum ValueSource { /// beta Beta(), /// gamma - Gamma(), + // only used by the old halo2 lookup scheme + // Gamma(), /// theta Theta(), /// y @@ -78,7 +85,7 @@ impl ValueSource { instance_values: &[Polynomial], challenges: &[F], beta: &F, - gamma: &F, + _gamma: &F, theta: &F, y: &F, previous_value: &F, @@ -97,7 +104,7 @@ impl ValueSource { } ValueSource::Challenge(index) => challenges[*index], ValueSource::Beta() => *beta, - ValueSource::Gamma() => *gamma, + // ValueSource::Gamma() => *gamma, ValueSource::Theta() => *theta, ValueSource::Y() => *y, ValueSource::PreviousValue() => *previous_value, @@ -185,7 +192,7 @@ pub struct Evaluator { /// Custom gates evalution pub custom_gates: GraphEvaluator, /// Lookups evalution - pub lookups: Vec>, + pub lookups: Vec<(Vec>, GraphEvaluator)>, } /// GraphEvaluator @@ -241,9 +248,12 @@ impl Evaluator { // Lookups for lookup in cs.lookups.iter() { - let mut graph = GraphEvaluator::default(); + let mut graph_table = GraphEvaluator::default(); + let mut graph_inputs: Vec<_> = (0..lookup.inputs_expressions.len()) + .map(|_| GraphEvaluator::default()) + .collect(); - let mut evaluate_lc = |expressions: &Vec>| { + let evaluate_lc = |graph: &mut GraphEvaluator, expressions: &Vec>| { let parts = expressions .iter() .map(|expr| graph.add_expression(expr)) @@ -255,22 +265,33 @@ impl Evaluator { )) }; - // Input coset - let compressed_input_coset = evaluate_lc(&lookup.input_expressions); + // Inputs cosets + for (input_expressions, graph_input) in lookup + .inputs_expressions + .iter() + .zip(graph_inputs.iter_mut()) + { + let compressed_input_coset = evaluate_lc(graph_input, input_expressions); + + graph_input.add_calculation(Calculation::Add( + compressed_input_coset, + ValueSource::Beta(), + )); + } + // table coset - let compressed_table_coset = evaluate_lc(&lookup.table_expressions); - // z(\omega X) (a'(X) + \beta) (s'(X) + \gamma) - let right_gamma = graph.add_calculation(Calculation::Add( + let compressed_table_coset = evaluate_lc(&mut graph_table, &lookup.table_expressions); + + graph_table.add_calculation(Calculation::Add( compressed_table_coset, - ValueSource::Gamma(), - )); - let lc = graph.add_calculation(Calculation::Add( - compressed_input_coset, ValueSource::Beta(), )); - graph.add_calculation(Calculation::Mul(lc, right_gamma)); - ev.lookups.push(graph); + /* + a) f_i + beta + b) t + beta + */ + ev.lookups.push((graph_inputs.to_vec(), graph_table)); } ev @@ -287,7 +308,7 @@ impl Evaluator { beta: C::ScalarExt, gamma: C::ScalarExt, theta: C::ScalarExt, - lookups: &[Vec>], + lookups: &[Vec>], permutations: &[permutation::prover::Committed], ) -> Polynomial { let domain = &pk.vk.domain; @@ -492,33 +513,140 @@ impl Evaluator { }); } + // For lookups, compute inputs_inv_sum = ∑ 1 / (f_i(X) + beta) + // The outer vector has capacity self.lookups.len() + #[cfg(not(feature = "logup_skip_inv"))] + let inputs_inv_sum: Vec> = self + .lookups + .iter() + .map(|lookup| { + let (inputs_lookup_evaluator, _) = lookup; + + let inputs_values_for_extended_domain: Vec> = (0..size) + .into_par_iter() + .map(|idx| { + let mut inputs_eval_data: Vec<_> = inputs_lookup_evaluator + .iter() + .map(|input_lookup_evaluator| { + input_lookup_evaluator.instance() + }) + .collect(); + + inputs_lookup_evaluator + .iter() + .zip(inputs_eval_data.iter_mut()) + .map(|(input_lookup_evaluator, input_eval_data)| { + input_lookup_evaluator.evaluate( + input_eval_data, + fixed, + advice, + instance, + challenges, + &beta, + &gamma, + &theta, + &y, + &C::ScalarExt::zero(), + idx, + rot_scale, + isize, + ) + }) + .collect() + }) + .collect(); + let mut inputs_values_for_extended_domain: Vec = + inputs_values_for_extended_domain + .into_iter() + .flatten() + .collect(); + + parallelize(&mut inputs_values_for_extended_domain, |values, _| { + values.batch_invert(); + }); + + let inputs_len = inputs_lookup_evaluator.len(); + + (0..size) + .into_par_iter() + .map(|i| { + inputs_values_for_extended_domain + [i * inputs_len..(i + 1) * inputs_len] + .iter() + .fold(C::Scalar::zero(), |acc, x| acc + x) + }) + .collect::>() + }) + .collect(); + // Lookups for (n, lookup) in lookups.iter().enumerate() { // Polynomials required for this lookup. // Calculated here so these only have to be kept in memory for the short time // they are actually needed. - let product_coset = pk.vk.domain.coeff_to_extended_part( - lookup.product_poly.clone(), - current_extended_omega, - ); - let permuted_input_coset = pk.vk.domain.coeff_to_extended_part( - lookup.permuted_input_poly.clone(), - current_extended_omega, - ); - let permuted_table_coset = pk.vk.domain.coeff_to_extended_part( - lookup.permuted_table_poly.clone(), + let phi_coset = pk.vk.domain.coeff_to_extended_part( + lookup.phi_poly.clone(), current_extended_omega, ); + let m_coset = pk + .vk + .domain + .coeff_to_extended_part(lookup.m_poly.clone(), current_extended_omega); // Lookup constraints + /* + φ_i(X) = f_i(X) + beta + τ(X) = t(X) + beta + LHS = τ(X) * Π(φ_i(X)) * (ϕ(gX) - ϕ(X)) + RHS = τ(X) * Π(φ_i(X)) * (∑ 1/(φ_i(X)) - m(X) / τ(X)))) (1) + = (τ(X) * Π(φ_i(X)) * ∑ 1/(φ_i(X))) - Π(φ_i(X)) * m(X) + = Π(φ_i(X)) * (τ(X) * ∑ 1/(φ_i(X)) - m(X)) + + = ∑_i τ(X) * Π_{j != i} φ_j(X) - m(X) * Π(φ_i(X)) (2) + */ parallelize(&mut values, |values, start| { - let lookup_evaluator = &self.lookups[n]; - let mut eval_data = lookup_evaluator.instance(); + let (inputs_lookup_evaluator, table_lookup_evaluator) = + &self.lookups[n]; + let mut inputs_eval_data: Vec<_> = inputs_lookup_evaluator + .iter() + .map(|input_lookup_evaluator| input_lookup_evaluator.instance()) + .collect(); + let mut table_eval_data = table_lookup_evaluator.instance(); + for (i, value) in values.iter_mut().enumerate() { let idx = start + i; - let table_value = lookup_evaluator.evaluate( - &mut eval_data, + // f_i(X) + beta for i in expressions + let inputs_value: Vec = inputs_lookup_evaluator + .iter() + .zip(inputs_eval_data.iter_mut()) + .map(|(input_lookup_evaluator, input_eval_data)| { + input_lookup_evaluator.evaluate( + input_eval_data, + fixed, + advice, + instance, + challenges, + &beta, + &gamma, + &theta, + &y, + &C::ScalarExt::ZERO, + idx, + rot_scale, + isize, + ) + }) + .collect(); + + // Π(φ_i(X)) + let inputs_prod: C::Scalar = inputs_value + .iter() + .fold(C::Scalar::ZERO, |acc, input| acc * input); + + // t(X) + beta + let table_value = table_lookup_evaluator.evaluate( + &mut table_eval_data, fixed, advice, instance, @@ -534,41 +662,45 @@ impl Evaluator { ); let r_next = get_rotation_idx(idx, 1, rot_scale, isize); - let r_prev = get_rotation_idx(idx, -1, rot_scale, isize); - let a_minus_s = - permuted_input_coset[idx] - permuted_table_coset[idx]; - // l_0(X) * (1 - z(X)) = 0 - *value = *value * y + ((one - product_coset[idx]) * l0[idx]); - // l_last(X) * (z(X)^2 - z(X)) = 0 - *value = *value * y - + ((product_coset[idx] * product_coset[idx] - - product_coset[idx]) - * l_last[idx]); - // (1 - (l_last(X) + l_blind(X))) * ( - // z(\omega X) (a'(X) + \beta) (s'(X) + \gamma) - // - z(X) (\theta^{m-1} a_0(X) + ... + a_{m-1}(X) + \beta) - // (\theta^{m-1} s_0(X) + ... + s_{m-1}(X) + \gamma) - // ) = 0 - *value = *value * y - + ((product_coset[r_next] - * (permuted_input_coset[idx] + beta) - * (permuted_table_coset[idx] + gamma) - - product_coset[idx] * table_value) - * l_active_row[idx]); - // Check that the first values in the permuted input expression and permuted - // fixed expression are the same. - // l_0(X) * (a'(X) - s'(X)) = 0 - *value = *value * y + (a_minus_s * l0[idx]); - // Check that each value in the permuted lookup input expression is either - // equal to the value above it, or the value at the same index in the - // permuted table expression. - // (1 - (l_last + l_blind)) * (a′(X) − s′(X))⋅(a′(X) − a′(\omega^{-1} X)) = 0 - *value = *value * y - + (a_minus_s - * (permuted_input_coset[idx] - - permuted_input_coset[r_prev]) - * l_active_row[idx]); + let lhs = { + // τ(X) * Π(φ_i(X)) * (ϕ(gX) - ϕ(X)) + table_value * inputs_prod * (phi_coset[r_next] - phi_coset[idx]) + }; + + #[cfg(feature = "logup_skip_inv")] + let rhs = { + // τ(X) * Π(φ_i(X)) * (∑ 1/(φ_i(X)) - m(X) / τ(X)))) + // = ∑_i τ(X) * Π_{j != i} φ_j(X) - m(X) * Π(φ_i(X)) + let inputs = (0..inputs_value.len()) + .map(|i| { + inputs_value + .iter() + .enumerate() + .filter(|(j, _)| *j != i) + .fold(C::Scalar::ZERO, |acc, (_, x)| acc * *x) + }) + .fold(C::Scalar::ZERO, |acc, x| acc + x); + inputs * table_value - inputs_prod * m_coset[idx] + }; + #[cfg(not(feature = "logup_skip_inv"))] + let rhs = { + // ∑ 1 / (f_i(X) + beta) at ω^idx + let inv_sum: C::Scalar = inputs_inv_sum[n][idx]; + // τ(X) * Π(φ_i(X)) * (∑ 1/(φ_i(X)) - m(X) / τ(X)))) + // = (τ(X) * Π(φ_i(X)) * ∑ 1/(φ_i(X))) - Π(φ_i(X)) * m(X) + // = Π(φ_i(X)) * (τ(X) * ∑ 1/(φ_i(X)) - m(X)) + inputs_prod * (table_value * inv_sum - m_coset[idx]) + }; + + // phi[0] = 0 + *value = *value * y + l0[idx] * phi_coset[idx]; + + // phi[u] = 0 + *value = *value * y + l_last[idx] * phi_coset[idx]; + + // q(X) = (1 - (l_last(X) + l_blind(X))) * (LHS - RHS) + *value = *value * y + (lhs - rhs) * l_active_row[idx]; } }); } diff --git a/halo2_proofs/src/plonk/keygen.rs b/halo2_proofs/src/plonk/keygen.rs index e5459969f5..92ef096f32 100644 --- a/halo2_proofs/src/plonk/keygen.rs +++ b/halo2_proofs/src/plonk/keygen.rs @@ -41,6 +41,8 @@ where let mut cs = ConstraintSystem::default(); let config = ConcreteCircuit::configure(&mut cs); + let cs = cs.chunk_lookups(); + let degree = cs.degree(); let domain = EvaluationDomain::new(degree as u32, k); diff --git a/halo2_proofs/src/plonk/mv_lookup.rs b/halo2_proofs/src/plonk/mv_lookup.rs new file mode 100644 index 0000000000..b4fd2d825f --- /dev/null +++ b/halo2_proofs/src/plonk/mv_lookup.rs @@ -0,0 +1,96 @@ +use super::circuit::Expression; +use ff::Field; +use std::fmt::{self, Debug}; + +pub(crate) mod prover; +pub(crate) mod verifier; + +/// Degree of lookup without inputs +pub fn base_degree(table_degree: usize) -> usize { + // let lhs_degree = table_degree + inputs_expressions_degree + 1 + // let degree = lhs_degree + 1 + std::cmp::max(3, table_degree + 2) +} + +pub fn degree_with_input(base_degree: usize, input_expression_degree: usize) -> usize { + base_degree + input_expression_degree +} + +#[derive(Clone)] +pub struct Argument { + pub name: &'static str, + pub(crate) table_expressions: Vec>, + pub(crate) inputs_expressions: Vec>>, +} + +impl Debug for Argument { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Argument") + .field("table_expressions", &self.table_expressions) + .field("inputs_expressions", &self.inputs_expressions) + .finish() + } +} + +impl Argument { + /// Constructs a new lookup argument. + pub fn new(name: &'static str, table: &[Expression], input: &[Vec>]) -> Self { + Self { + name, + table_expressions: table.to_owned(), + inputs_expressions: input.to_owned(), + } + } + + pub(crate) fn required_degree(&self) -> usize { + assert!(self + .inputs_expressions + .iter() + .all(|input| input.len() == self.table_expressions.len())); + + let expr_degree = |input_expressions: &Vec>| { + let mut input_degree = 0; + for expr in input_expressions.iter() { + input_degree = std::cmp::max(input_degree, expr.degree()); + } + + input_degree + }; + + let inputs_expressions_degree: usize = self + .inputs_expressions + .iter() + .map(|input_expressions| expr_degree(input_expressions)) + .sum(); + + let table_degree = expr_degree(&self.table_expressions); + + /* + φ_i(X) = f_i(X) + α + τ(X) = t(X) + α + LHS = τ(X) * Π(φ_i(X)) * (ϕ(gX) - ϕ(X)) + = table_degree + sum(input_degree) + 1 + RHS = τ(X) * Π(φ_i(X)) * (∑ 1/(φ_i(X)) - m(X) / τ(X)))) + + deg(q(X)) = (1 - (q_last + q_blind)) * (LHS - RHS) + = 1 + LHS + */ + + let lhs_degree = table_degree + inputs_expressions_degree + 1; + let degree = lhs_degree + 1; + + // 3 = phi + q_blind + table (where table is = 1) + // + 1 for each of inputs expressions + std::cmp::max(3 + self.inputs_expressions.len(), degree) + } + + /// Returns input of this argument + pub fn input_expressions(&self) -> &Vec>> { + &self.inputs_expressions + } + + /// Returns table of this argument + pub fn table_expressions(&self) -> &Vec> { + &self.table_expressions + } +} diff --git a/halo2_proofs/src/plonk/mv_lookup/exec_info.json b/halo2_proofs/src/plonk/mv_lookup/exec_info.json new file mode 100644 index 0000000000..f7a7042c0f --- /dev/null +++ b/halo2_proofs/src/plonk/mv_lookup/exec_info.json @@ -0,0 +1,46 @@ +{ + "unit": "ms", + "non_batched": { + "k": 14, + "halo2": { + "protocol": "halo2", + "methods": { + "commit_permuted": { + "compress_expressions": 1, + "permute_expressions": 4.5, + "commit_permuted_input": 5, + "commit_permuted_table": 5 + }, + "grand_product": { + "lookup_product_denom": 2, + "lookup_product": 0.2, + "grand_prod_evals": 0.5, + "grand_prod_commit": 7.5 + }, + "h_evaluation": { + + } + } + }, + "mv": { + "protocol": "mv", + "methods": { + "compute_multiplicity": { + "compress_expressions": 1, + "compute_multiplicities": 2, + "commit_m": 1 + }, + "grand_sum": { + "inputs_log_derivatives": 2, + "table_log_derivatives": 1.8, + "log_derivatives_diff": 0.2, + "grand_sum_evals": 0.2, + "grand_sum_commit": 33 + }, + "h_evaluation": { + + } + } + } + } +} \ No newline at end of file diff --git a/halo2_proofs/src/plonk/mv_lookup/prover.rs b/halo2_proofs/src/plonk/mv_lookup/prover.rs new file mode 100644 index 0000000000..52d434289b --- /dev/null +++ b/halo2_proofs/src/plonk/mv_lookup/prover.rs @@ -0,0 +1,529 @@ +use super::super::{ + circuit::Expression, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, Error, + ProvingKey, +}; +use super::Argument; +use crate::plonk::evaluation::evaluate; +use crate::{ + arithmetic::{eval_polynomial, parallelize, CurveAffine}, + poly::{ + commitment::{Blind, Params}, + Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, ProverQuery, + Rotation, + }, + transcript::{EncodedChallenge, TranscriptWrite}, +}; +use ark_std::{end_timer, start_timer}; +use blake2b_simd::Hash; +use ff::{BitViewSized, PrimeField, PrimeFieldBits, WithSmallOrderMulGroup}; +use group::{ + ff::{BatchInvert, Field}, + Curve, +}; +use rand_core::RngCore; +use rayon::current_num_threads; +use std::collections::{BTreeSet, HashSet}; +use std::time::Instant; +use std::{any::TypeId, convert::TryInto, num::ParseIntError, ops::Index}; +use std::{ + collections::BTreeMap, + iter, + ops::{Mul, MulAssign}, +}; + +use crate::arithmetic::{par_invert, parallelize_internal}; +use rayon::prelude::{ + IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator, ParallelSliceMut, +}; + +#[derive(Debug)] +pub(in crate::plonk) struct Prepared { + compressed_inputs_expressions: Vec>, + compressed_table_expression: Polynomial, + m_values: Polynomial, +} + +#[derive(Debug)] +pub(in crate::plonk) struct Committed { + pub(in crate::plonk) m_poly: Polynomial, + pub(in crate::plonk) phi_poly: Polynomial, +} + +pub(in crate::plonk) struct Evaluated { + constructed: Committed, +} + +impl + Ord> Argument { + pub(in crate::plonk) fn prepare< + 'a, + 'params: 'a, + C, + P: Params<'params, C>, + E: EncodedChallenge, + R: RngCore, + T: TranscriptWrite, + >( + &self, + pk: &ProvingKey, + params: &P, + domain: &EvaluationDomain, + theta: ChallengeTheta, + advice_values: &'a [Polynomial], + fixed_values: &'a [Polynomial], + instance_values: &'a [Polynomial], + challenges: &'a [C::Scalar], + mut rng: R, // in case we want to blind (do we actually need zk?) + transcript: &mut T, + ) -> Result, Error> + where + C: CurveAffine, + C::Curve: Mul + MulAssign, + { + let prepare_time = start_timer!(|| format!( + "prepare m(X) (inputs={:?}, table={})", + self.inputs_expressions + .iter() + .map(|e| e.len()) + .collect::>(), + self.table_expressions.len() + )); + // Closure to get values of expressions and compress them + let compress_expressions = |expressions: &[Expression]| { + let compressed_expression = expressions + .iter() + .map(|expression| { + pk.vk.domain.lagrange_from_vec(evaluate( + expression, + params.n() as usize, + 1, + fixed_values, + advice_values, + instance_values, + challenges, + )) + }) + .fold(domain.empty_lagrange(), |acc, expression| { + acc * *theta + &expression + }); + compressed_expression + }; + + // Get values of input expressions involved in the lookup and compress them + let compressed_inputs_expressions: Vec<_> = self + .inputs_expressions + .iter() + .map(|input_expressions| compress_expressions(input_expressions)) + .collect(); + + // Get values of table expressions involved in the lookup and compress them + let compressed_table_expression = compress_expressions(&self.table_expressions); + + let blinding_factors = pk.vk.cs.blinding_factors(); + + // compute m(X) + let tivm_time = start_timer!(|| "table index value mapping"); + let mut sorted_table_with_indices = compressed_table_expression + .iter() + .take(params.n() as usize - blinding_factors - 1) + .enumerate() + .map(|(i, t)| (t, i)) + .collect::>(); + sorted_table_with_indices.par_sort_by_key(|(&t, _)| t); + end_timer!(tivm_time); + + let m_time = start_timer!(|| "m(X) values"); + let m_values: Vec = { + use std::sync::atomic::{AtomicU64, Ordering}; + use std::sync::RwLock; + let m_values: Vec = (0..params.n()).map(|_| AtomicU64::new(0)).collect(); + + for compressed_input_expression in compressed_inputs_expressions.iter() { + let _ = compressed_input_expression + .par_iter() + .take(params.n() as usize - blinding_factors - 1) + .try_for_each(|fi| -> Result<(), Error> { + let index = sorted_table_with_indices + .binary_search_by_key(&fi, |&(t, _)| t) + .map_err(|_| Error::ConstraintSystemFailure)?; + let index = sorted_table_with_indices[index].1; + + m_values[index].fetch_add(1, Ordering::Relaxed); + Ok(()) + }); + } + + m_values + .par_iter() + .map(|mi| F::from(mi.load(Ordering::Relaxed) as u64)) + .collect() + }; + end_timer!(m_time); + let m_values = pk.vk.domain.lagrange_from_vec(m_values); + + #[cfg(feature = "sanity-checks")] + { + // check that m is zero after blinders + let invalid_ms = m_values + .iter() + .skip(params.n() as usize - blinding_factors) + .collect::>(); + assert_eq!(invalid_ms.len(), blinding_factors); + for mi in invalid_ms { + assert_eq!(*mi, C::Scalar::ZERO); + } + + // check sums + let alpha = C::Scalar::random(&mut rng); + let cs_input_sum = + |compressed_input_expression: &Polynomial| { + let mut lhs_sum = C::Scalar::ZERO; + for &fi in compressed_input_expression + .iter() + .take(params.n() as usize - blinding_factors - 1) + { + lhs_sum += (fi + alpha).invert().unwrap(); + } + + lhs_sum + }; + + let mut lhs_sum = C::Scalar::ZERO; + + for compressed_input_expression in compressed_inputs_expressions.iter() { + lhs_sum += cs_input_sum(compressed_input_expression); + } + + let mut rhs_sum = C::Scalar::ZERO; + for (&ti, &mi) in compressed_table_expression.iter().zip(m_values.iter()) { + rhs_sum += mi * (ti + alpha).invert().unwrap(); + } + + assert_eq!(lhs_sum, rhs_sum); + } + + // commit to m(X) + // TODO: should we use zero instead? + let blind = Blind(C::Scalar::random(rng)); + let m_commitment = params.commit_lagrange(&m_values, blind).to_affine(); + + // write commitment of m(X) to transcript + transcript.write_point(m_commitment)?; + + end_timer!(prepare_time); + + Ok(Prepared { + compressed_inputs_expressions, + compressed_table_expression, + m_values, + }) + } +} + +impl Prepared { + pub(in crate::plonk) fn commit_grand_sum< + 'params, + P: Params<'params, C>, + E: EncodedChallenge, + R: RngCore, + T: TranscriptWrite, + >( + self, + pk: &ProvingKey, + params: &P, + beta: ChallengeBeta, + mut rng: R, + transcript: &mut T, + ) -> Result, Error> { + /* + φ_i(X) = f_i(X) + beta + τ(X) = t(X) + beta + LHS = τ(X) * Π(φ_i(X)) * (ϕ(gX) - ϕ(X)) + RHS = τ(X) * Π(φ_i(X)) * (∑ 1/(φ_i(X)) - m(X) / τ(X)))) + */ + let lookup_commit_time = start_timer!(|| "commit_grand_sum"); + + // ∑ 1/(φ_i(X)) + let inputs_log_drv_time = start_timer!(|| "inputs_log_derivative"); + let mut inputs_log_derivatives = vec![C::Scalar::ZERO; params.n() as usize]; + for compressed_input_expression in self.compressed_inputs_expressions.iter() { + let mut input_log_derivatives = vec![C::Scalar::ZERO; params.n() as usize]; + + parallelize( + &mut input_log_derivatives, + |input_log_derivatives, start| { + for (input_log_derivative, fi) in input_log_derivatives + .iter_mut() + .zip(compressed_input_expression[start..].iter()) + { + *input_log_derivative = *beta + fi; + } + }, + ); + let inputs_inv_time = start_timer!(|| "batch invert"); + par_invert(input_log_derivatives.as_mut_slice()); + end_timer!(inputs_inv_time); + + // TODO: remove last blinders from this + for i in 0..params.n() as usize { + inputs_log_derivatives[i] += input_log_derivatives[i]; + } + } + end_timer!(inputs_log_drv_time); + + // 1 / τ(X) + let table_log_drv_time = start_timer!(|| "table log derivative"); + let mut table_log_derivatives = vec![C::Scalar::ZERO; params.n() as usize]; + parallelize( + &mut table_log_derivatives, + |table_log_derivatives, start| { + for (table_log_derivative, ti) in table_log_derivatives + .iter_mut() + .zip(self.compressed_table_expression[start..].iter()) + { + *table_log_derivative = *beta + ti; + } + }, + ); + + let table_inv_time = start_timer!(|| "table batch invert"); + par_invert(table_log_derivatives.as_mut_slice()); + end_timer!(table_inv_time); + end_timer!(table_log_drv_time); + + let log_drv_diff_time = start_timer!(|| "log derivatives diff"); + // (Σ 1/(φ_i(X)) - m(X) / τ(X)) + let mut log_derivatives_diff = vec![C::Scalar::ZERO; params.n() as usize]; + parallelize(&mut log_derivatives_diff, |log_derivatives_diff, start| { + for (((log_derivative_diff, fi), ti), mi) in log_derivatives_diff + .iter_mut() + .zip(inputs_log_derivatives[start..].iter()) + .zip(table_log_derivatives[start..].iter()) + .zip(self.m_values[start..].iter()) + { + // (Σ 1/(φ_i(X)) - m(X) / τ(X)) + *log_derivative_diff = *fi - *mi * *ti; + } + }); + end_timer!(log_drv_diff_time); + + // Compute the evaluations of the lookup grand sum polynomial + // over our domain, starting with phi[0] = 0 + let blinding_factors = pk.vk.cs.blinding_factors(); + let phi_time = start_timer!(|| "par_scan(log_derivatives_diff)"); + let phi = { + // parallelized version of log_derivatives_diff.scan() + let active_size = params.n() as usize - blinding_factors; + let chunk = { + let num_threads = crate::multicore::current_num_threads(); + let mut chunk = (active_size as usize) / num_threads; + if chunk < num_threads { + chunk = 1; + } + chunk + }; + let num_chunks = (active_size as usize + chunk - 1) / chunk; + let mut segment_sum = vec![C::Scalar::ZERO; num_chunks]; + let mut grand_sum = iter::once(C::Scalar::ZERO) + .chain(log_derivatives_diff) + .take(active_size) + .collect::>(); + // TODO: remove the implicit assumption that parallelize() split the grand_sum + // into segments that each has `chunk` elements except the last. + parallelize(&mut grand_sum, |segment_grand_sum, _| { + for i in 1..segment_grand_sum.len() { + segment_grand_sum[i] += segment_grand_sum[i - 1]; + } + }); + for i in 1..segment_sum.len() { + segment_sum[i] = segment_sum[i - 1] + grand_sum[i * chunk - 1]; + } + parallelize(&mut grand_sum, |grand_sum, start| { + let prefix_sum = segment_sum[start / chunk]; + for v in grand_sum.iter_mut() { + *v += prefix_sum; + } + }); + grand_sum + .into_iter() + .chain((0..blinding_factors).map(|_| C::Scalar::random(&mut rng))) + .collect::>() + }; + end_timer!(phi_time); + assert_eq!(phi.len(), params.n() as usize); + let phi = pk.vk.domain.lagrange_from_vec(phi); + + #[cfg(feature = "sanity-checks")] + // This test works only with intermediate representations in this method. + // It can be used for debugging purposes. + { + // While in Lagrange basis, check that product is correctly constructed + let u = (params.n() as usize) - (blinding_factors + 1); + + /* + φ_i(X) = f_i(X) + α + τ(X) = t(X) + α + LHS = τ(X) * Π(φ_i(X)) * (ϕ(gX) - ϕ(X)) + RHS = τ(X) * Π(φ_i(X)) * (∑ 1/(φ_i(X)) - m(X) / τ(X)))) + */ + + // q(X) = LHS - RHS mod zH(X) + for i in 0..u { + // Π(φ_i(X)) + let fi_prod = || { + let mut prod = C::Scalar::ONE; + for compressed_input_expression in self.compressed_inputs_expressions.iter() { + prod *= *beta + compressed_input_expression[i]; + } + + prod + }; + + let fi_log_derivative = || { + let mut sum = C::Scalar::ZERO; + for compressed_input_expression in self.compressed_inputs_expressions.iter() { + sum += (*beta + compressed_input_expression[i]).invert().unwrap(); + } + + sum + }; + + // LHS = τ(X) * Π(φ_i(X)) * (ϕ(gX) - ϕ(X)) + let lhs = { + (*beta + self.compressed_table_expression[i]) + * fi_prod() + * (phi[i + 1] - phi[i]) + }; + + // RHS = τ(X) * Π(φ_i(X)) * (∑ 1/(φ_i(X)) - m(X) / τ(X)))) + let rhs = { + (*beta + self.compressed_table_expression[i]) + * fi_prod() + * (fi_log_derivative() + - self.m_values[i] + * (*beta + self.compressed_table_expression[i]) + .invert() + .unwrap()) + }; + + assert_eq!(lhs - rhs, C::Scalar::ZERO); + } + + assert_eq!(phi[u], C::Scalar::ZERO); + } + + let grand_sum_blind = Blind(C::Scalar::random(rng)); + let phi_commitment = params.commit_lagrange(&phi, grand_sum_blind).to_affine(); + + // Hash grand sum commitment + transcript.write_point(phi_commitment)?; + + end_timer!(lookup_commit_time); + Ok(Committed { + m_poly: pk.vk.domain.lagrange_to_coeff(self.m_values), + phi_poly: pk.vk.domain.lagrange_to_coeff(phi), + }) + } +} + +impl Committed { + pub(in crate::plonk) fn evaluate, T: TranscriptWrite>( + self, + pk: &ProvingKey, + x: ChallengeX, + transcript: &mut T, + ) -> Result, Error> { + let domain = &pk.vk.domain; + let x_next = domain.rotate_omega(*x, Rotation::next()); + + let phi_eval = eval_polynomial(&self.phi_poly, *x); + let phi_next_eval = eval_polynomial(&self.phi_poly, x_next); + let m_eval = eval_polynomial(&self.m_poly, *x); + + // Hash each advice evaluation + for eval in iter::empty() + .chain(Some(phi_eval)) + .chain(Some(phi_next_eval)) + .chain(Some(m_eval)) + { + transcript.write_scalar(eval)?; + } + + Ok(Evaluated { constructed: self }) + } +} + +impl Evaluated { + pub(in crate::plonk) fn open<'a>( + &'a self, + pk: &'a ProvingKey, + x: ChallengeX, + ) -> impl Iterator> + Clone { + let x_next = pk.vk.domain.rotate_omega(*x, Rotation::next()); + + iter::empty() + .chain(Some(ProverQuery { + point: *x, + poly: &self.constructed.phi_poly, + blind: Blind(C::Scalar::ZERO), + })) + .chain(Some(ProverQuery { + point: x_next, + poly: &self.constructed.phi_poly, + blind: Blind(C::Scalar::ZERO), + })) + .chain(Some(ProverQuery { + point: *x, + poly: &self.constructed.m_poly, + blind: Blind(C::Scalar::ZERO), + })) + } +} + +mod benches { + use ark_std::rand::thread_rng; + use ff::Field; + use halo2curves::bn256::Fr; + use std::collections::BTreeMap; + use std::time::Instant; + + // bench the time to construct a BTreeMap out of a large table + // tivm is short for table_index_value_mapping + #[ignore] + #[test] + fn bench_tivm_btree_map() { + env_logger::init(); + let mut rng = thread_rng(); + + for log_n in 20..26 { + let n = 1 << log_n; + let dur = Instant::now(); + let _table: BTreeMap = (0..n) + .into_iter() + .map(|_| Fr::random(&mut rng)) + .enumerate() + .map(|(i, x)| (x, i)) + .collect(); + log::info!( + "construct btreemap from random vec (len = {}) took {:?}", + n, + dur.elapsed() + ); + } + + for log_n in 20..26 { + let n = 1 << log_n; + let dur = Instant::now(); + let _table: BTreeMap = (0..n) + .into_iter() + .map(Fr::from) + .enumerate() + .map(|(i, x)| (x, i)) + .collect(); + log::info!( + "construct btreemap from increasing vec (len = {}) took {:?}", + n, + dur.elapsed() + ); + } + } +} diff --git a/halo2_proofs/src/plonk/mv_lookup/verifier.rs b/halo2_proofs/src/plonk/mv_lookup/verifier.rs new file mode 100644 index 0000000000..361bb5f972 --- /dev/null +++ b/halo2_proofs/src/plonk/mv_lookup/verifier.rs @@ -0,0 +1,191 @@ +use std::iter; + +use super::super::{ + circuit::Expression, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, +}; +use super::Argument; +use crate::{ + arithmetic::CurveAffine, + plonk::{Error, VerifyingKey}, + poly::{commitment::MSM, Rotation, VerifierQuery}, + transcript::{EncodedChallenge, TranscriptRead}, +}; +use ff::{BatchInvert, Field, PrimeField, WithSmallOrderMulGroup}; + +pub struct PreparedCommitments { + m_commitment: C, +} + +pub struct Committed { + prepared: PreparedCommitments, + phi_commitment: C, +} + +pub struct Evaluated { + committed: Committed, + phi_eval: C::Scalar, + phi_next_eval: C::Scalar, + m_eval: C::Scalar, +} + +impl> Argument { + pub(in crate::plonk) fn read_prepared_commitments< + C: CurveAffine, + E: EncodedChallenge, + T: TranscriptRead, + >( + &self, + transcript: &mut T, + ) -> Result, Error> { + let m_commitment = transcript.read_point()?; + + Ok(PreparedCommitments { m_commitment }) + } +} + +impl PreparedCommitments { + pub(in crate::plonk) fn read_grand_sum_commitment< + E: EncodedChallenge, + T: TranscriptRead, + >( + self, + transcript: &mut T, + ) -> Result, Error> { + let phi_commitment = transcript.read_point()?; + + Ok(Committed { + prepared: self, + phi_commitment, + }) + } +} + +impl Committed { + pub(crate) fn evaluate, T: TranscriptRead>( + self, + transcript: &mut T, + ) -> Result, Error> { + let phi_eval = transcript.read_scalar()?; + let phi_next_eval = transcript.read_scalar()?; + let m_eval = transcript.read_scalar()?; + + Ok(Evaluated { + committed: self, + phi_eval, + phi_next_eval, + m_eval, + }) + } +} + +impl Evaluated { + pub(in crate::plonk) fn expressions<'a>( + &'a self, + l_0: C::Scalar, + l_last: C::Scalar, + l_blind: C::Scalar, + argument: &'a Argument, + theta: ChallengeTheta, + beta: ChallengeBeta, + advice_evals: &[C::Scalar], + fixed_evals: &[C::Scalar], + instance_evals: &[C::Scalar], + challenges: &[C::Scalar], + ) -> impl Iterator + 'a { + let active_rows = C::Scalar::ZERO - (l_last + l_blind); + + /* + φ_i(X) = f_i(X) + beta + τ(X) = t(X) + beta + LHS = τ(X) * Π(φ_i(X)) * (ϕ(gX) - ϕ(X)) + RHS = τ(X) * Π(φ_i(X)) * (∑ 1/(φ_i(X)) - m(X) / τ(X)))) + */ + + let grand_sum_expression = || { + let compress_expressions = |expressions: &[Expression]| { + expressions + .iter() + .map(|expression| { + 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], + &|challenge| challenges[challenge.index()], + &|a| -a, + &|a, b| a + &b, + &|a, b| a * &b, + &|a, scalar| a * &scalar, + ) + }) + .fold(C::Scalar::ZERO, |acc, eval| acc * &*theta + &eval) + }; + + // φ_i(X) = f_i(X) + beta + let mut f_evals: Vec<_> = argument + .inputs_expressions + .iter() + .map(|input_expressions| compress_expressions(input_expressions) + *beta) + .collect(); + + let t_eval = compress_expressions(&argument.table_expressions); + + let tau = t_eval + *beta; + // Π(φ_i(X)) + let prod_fi = f_evals.iter().fold(C::Scalar::ZERO, |acc, eval| acc * eval); + // ∑ 1/(φ_i(X)) + let sum_inv_fi = { + f_evals.batch_invert(); + f_evals.iter().fold(C::Scalar::ZERO, |acc, eval| acc + eval) + }; + + // LHS = τ(X) * Π(φ_i(X)) * (ϕ(gX) - ϕ(X)) + let lhs = tau * prod_fi * (self.phi_next_eval - self.phi_eval); + + // RHS = τ(X) * Π(φ_i(X)) * (∑ 1/(φ_i(X)) - m(X) / τ(X)))) + let rhs = { tau * prod_fi * (sum_inv_fi - self.m_eval * tau.invert().unwrap()) }; + + (lhs - rhs) * active_rows + }; + + std::iter::empty() + .chain( + // phi[0] = 0 + Some(l_0 * self.phi_eval), + ) + .chain( + // phi[u] = 0 + Some(l_last * self.phi_eval), + ) + .chain( + // (1 - l_last - l_blind) * (lhs - rhs) = 0 + Some(grand_sum_expression()), + ) + } + + pub(in crate::plonk) fn queries<'r, M: MSM + 'r>( + &'r self, + vk: &'r VerifyingKey, + x: ChallengeX, + ) -> impl Iterator> + Clone { + let x_next = vk.domain.rotate_omega(*x, Rotation::next()); + + iter::empty() + .chain(Some(VerifierQuery::new_commitment( + &self.committed.phi_commitment, + *x, + self.phi_eval, + ))) + .chain(Some(VerifierQuery::new_commitment( + &self.committed.phi_commitment, + x_next, + self.phi_next_eval, + ))) + .chain(Some(VerifierQuery::new_commitment( + &self.committed.prepared.m_commitment, + *x, + self.m_eval, + ))) + } +} diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index 15f0438470..768216e4c5 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -16,7 +16,7 @@ use super::{ Advice, Any, Assignment, Challenge, Circuit, Column, ConstraintSystem, FirstPhase, Fixed, FloorPlanner, Instance, Selector, }, - lookup, permutation, vanishing, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, + mv_lookup, permutation, vanishing, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, ChallengeY, Error, Expression, ProvingKey, }; use crate::{ @@ -34,6 +34,7 @@ use crate::{ poly::batch_invert_assigned, transcript::{EncodedChallenge, TranscriptWrite}, }; +use ark_std::{end_timer, start_timer}; use group::prime::PrimeCurveAffine; /// This creates a proof for the provided `circuit` when given the public @@ -57,7 +58,7 @@ pub fn create_proof< transcript: &mut T, ) -> Result<(), Error> where - Scheme::Scalar: WithSmallOrderMulGroup<3> + FromUniformBytes<64>, + Scheme::Scalar: WithSmallOrderMulGroup<3> + FromUniformBytes<64> + Ord, { for instance in instances.iter() { if instance.len() != pk.vk.cs.num_instance_columns { @@ -546,17 +547,20 @@ where // Sample theta challenge for keeping lookup columns linearly independent let theta: ChallengeTheta<_> = transcript.squeeze_challenge_scalar(); - let lookups: Vec>> = instance + let lookups: Vec>> = instance .iter() .zip(advice.iter()) .map(|(instance, advice)| -> Result, Error> { + let lookup_get_mx_time = + start_timer!(|| format!("get m(X) in {} lookups", pk.vk.cs.lookups.len())); // Construct and commit to permuted values for each lookup - pk.vk + let mx = pk + .vk .cs .lookups .iter() .map(|lookup| { - lookup.commit_permuted( + lookup.prepare( pk, params, domain, @@ -569,7 +573,10 @@ where transcript, ) }) - .collect() + .collect(); + end_timer!(lookup_get_mx_time); + + mx }) .collect::, _>>()?; @@ -599,16 +606,18 @@ where }) .collect::, _>>()?; - let lookups: Vec>> = lookups + let lookup_commit_time = start_timer!(|| "lookup commit grand sum"); + let lookups: Vec>> = lookups .into_iter() .map(|lookups| -> Result, _> { // Construct and commit to products for each lookup lookups .into_iter() - .map(|lookup| lookup.commit_product(pk, params, beta, gamma, &mut rng, transcript)) + .map(|lookup| lookup.commit_grand_sum(pk, params, beta, &mut rng, transcript)) .collect::, _>>() }) .collect::, _>>()?; + end_timer!(lookup_commit_time); // Commit to the vanishing argument's random polynomial for blinding h(x_3) let vanishing = vanishing::Argument::commit(params, domain, &mut rng, transcript)?; @@ -728,8 +737,7 @@ where .map(|permutation| -> Result<_, _> { permutation.construct().evaluate(pk, x, transcript) }) .collect::, _>>()?; - // Evaluate the lookups, if any, at omega^i x. - let lookups: Vec>> = lookups + let lookups: Vec>> = lookups .into_iter() .map(|lookups| -> Result, _> { lookups diff --git a/halo2_proofs/src/plonk/verifier.rs b/halo2_proofs/src/plonk/verifier.rs index f5984d2c79..315a3b6ca1 100644 --- a/halo2_proofs/src/plonk/verifier.rs +++ b/halo2_proofs/src/plonk/verifier.rs @@ -131,7 +131,7 @@ where vk.cs .lookups .iter() - .map(|argument| argument.read_permuted_commitments(transcript)) + .map(|argument| argument.read_prepared_commitments(transcript)) .collect::, _>>() }) .collect::, _>>()?; @@ -152,10 +152,10 @@ where let lookups_committed = lookups_permuted .into_iter() .map(|lookups| { - // Hash each lookup product commitment + // Hash each lookup sum commitment lookups .into_iter() - .map(|lookup| lookup.read_product_commitment(transcript)) + .map(|lookup| lookup.read_grand_sum_commitment(transcript)) .collect::, _>>() }) .collect::, _>>()?; @@ -300,27 +300,22 @@ where gamma, x, )) - .chain( - lookups - .iter() - .zip(vk.cs.lookups.iter()) - .flat_map(move |(p, argument)| { - p.expressions( - l_0, - l_last, - l_blind, - argument, - theta, - beta, - gamma, - advice_evals, - fixed_evals, - instance_evals, - challenges, - ) - }) - .into_iter(), - ) + .chain(lookups.iter().zip(vk.cs.lookups.iter()).flat_map( + move |(p, argument)| { + p.expressions( + l_0, + l_last, + l_blind, + argument, + theta, + beta, + advice_evals, + fixed_evals, + instance_evals, + challenges, + ) + }, + )) }); vanishing.verify(params, expressions, y, xn) @@ -366,12 +361,7 @@ where }, )) .chain(permutation.queries(vk, x)) - .chain( - lookups - .iter() - .flat_map(move |p| p.queries(vk, x)) - .into_iter(), - ) + .chain(lookups.iter().flat_map(move |p| p.queries(vk, x))) }, ) .chain( diff --git a/halo2_proofs/src/poly.rs b/halo2_proofs/src/poly.rs index 42e43b2e29..31f6d1f71d 100644 --- a/halo2_proofs/src/poly.rs +++ b/halo2_proofs/src/poly.rs @@ -304,7 +304,7 @@ impl<'a, F: Field, B: Basis> Sub for &'a Polynomial { /// Describes the relative rotation of a vector. Negative numbers represent /// reverse (leftmost) rotations and positive numbers represent forward (rightmost) /// rotations. Zero represents no rotation. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct Rotation(pub i32); impl Rotation { diff --git a/halo2_proofs/tests/plonk_api.rs b/halo2_proofs/tests/plonk_api.rs index 187280b034..1f1f0a2aa7 100644 --- a/halo2_proofs/tests/plonk_api.rs +++ b/halo2_proofs/tests/plonk_api.rs @@ -17,252 +17,390 @@ use halo2_proofs::transcript::{ Blake2bRead, Blake2bWrite, Challenge255, EncodedChallenge, TranscriptReadBuffer, TranscriptWriterBuffer, }; +use halo2curves::bn256::Bn256; use rand_core::{OsRng, RngCore}; use std::marker::PhantomData; use std::time::Instant; #[cfg(feature = "parallel_syn")] use halo2_proofs::circuit::Region; +use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; +use halo2_proofs::poly::kzg::multiopen::{ProverGWC, VerifierGWC}; +use halo2_proofs::poly::kzg::strategy::AccumulatorStrategy; + +/// This represents an advice column at a certain row in the ConstraintSystem +#[derive(Copy, Clone, Debug)] +pub struct Variable(Column, usize); + +#[derive(Clone)] +struct PlonkConfig { + a: Column, + b: Column, + c: Column, + d: Column, + e: Column, + + sa: Column, + sb: Column, + sc: Column, + sm: Column, + sp: Column, + sl: TableColumn, +} -#[test] -fn plonk_api() { - const K: u32 = 17; - - /// This represents an advice column at a certain row in the ConstraintSystem - #[derive(Copy, Clone, Debug)] - pub struct Variable(Column, usize); - - #[derive(Clone)] - struct PlonkConfig { - a: Column, - b: Column, - c: Column, - d: Column, - e: Column, - - sa: Column, - sb: Column, - sc: Column, - sm: Column, - sp: Column, - sl: TableColumn, - } +impl PlonkConfig { + pub fn construct(meta: &mut ConstraintSystem) -> Self { + let e = meta.advice_column(); + let a = meta.advice_column(); + let b = meta.advice_column(); + let sf = meta.fixed_column(); + let c = meta.advice_column(); + let d = meta.advice_column(); + let p = meta.instance_column(); + + meta.enable_equality(a); + meta.enable_equality(b); + meta.enable_equality(c); + + let sm = meta.fixed_column(); + let sa = meta.fixed_column(); + let sb = meta.fixed_column(); + let sc = meta.fixed_column(); + let sp = meta.fixed_column(); + let sl = meta.lookup_table_column(); + + // Add to test mvlookup + let dummy = meta.complex_selector(); + let dummy_2 = meta.complex_selector(); + let dummy_3 = meta.complex_selector(); + + let dummy_table = meta.lookup_table_column(); - #[allow(clippy::type_complexity)] - trait StandardCs { - fn raw_multiply( - &self, - layouter: &mut impl Layouter, - f: F, - ) -> Result<(Cell, Cell, Cell), Error> - where - F: FnMut() -> Value<(Assigned, Assigned, Assigned)>; - fn raw_add( - &self, - layouter: &mut impl Layouter, - f: F, - ) -> Result<(Cell, Cell, Cell), Error> - where - F: FnMut() -> Value<(Assigned, Assigned, Assigned)>; - fn copy(&self, layouter: &mut impl Layouter, a: Cell, b: Cell) -> Result<(), Error>; - fn public_input(&self, layouter: &mut impl Layouter, f: F) -> Result - where - F: FnMut() -> Value; - fn lookup_table( - &self, - layouter: &mut impl Layouter, - values: &[FF], - ) -> Result<(), Error>; + /* + * A B ... sl + * [ + * instance 0 ... 0 + * a a ... 0 + * a a^2 ... 0 + * a a ... 0 + * a a^2 ... 0 + * ... ... ... ... + * ... ... ... instance + * ... ... ... a + * ... ... ... a + * ... ... ... 0 + * ] + */ + + meta.lookup("lookup", |meta| { + let a_ = meta.query_any(a, Rotation::cur()); + vec![(a_, sl)] + }); + + // Add to test mvlookup + meta.lookup("lookup_same", |meta| { + let a_ = meta.query_any(a, Rotation::cur()); + vec![(a_, sl)] + }); + + meta.lookup("lookup_same", |meta| { + let b_ = meta.query_any(b, Rotation::cur()); + let dummy = meta.query_selector(dummy); + let dummy_2 = meta.query_selector(dummy_2); + let dummy_3 = meta.query_selector(dummy_3); + + vec![(dummy * dummy_2 * dummy_3 * b_, dummy_table)] + }); + + meta.create_gate("Combined add-mult", |meta| { + let d = meta.query_advice(d, Rotation::next()); + let a = meta.query_advice(a, Rotation::cur()); + let sf = meta.query_fixed(sf, Rotation::cur()); + let e = meta.query_advice(e, Rotation::prev()); + let b = meta.query_advice(b, Rotation::cur()); + let c = meta.query_advice(c, Rotation::cur()); + + let sa = meta.query_fixed(sa, Rotation::cur()); + let sb = meta.query_fixed(sb, Rotation::cur()); + let sc = meta.query_fixed(sc, Rotation::cur()); + let sm = meta.query_fixed(sm, Rotation::cur()); + + vec![a.clone() * sa + b.clone() * sb + a * b * sm - (c * sc) + sf * (d * e)] + }); + + meta.create_gate("Public input", |meta| { + let a = meta.query_advice(a, Rotation::cur()); + let p = meta.query_instance(p, Rotation::cur()); + let sp = meta.query_fixed(sp, Rotation::cur()); + + vec![sp * (a - p)] + }); + + meta.enable_equality(sf); + meta.enable_equality(e); + meta.enable_equality(d); + meta.enable_equality(p); + meta.enable_equality(sm); + meta.enable_equality(sa); + meta.enable_equality(sb); + meta.enable_equality(sc); + meta.enable_equality(sp); + + PlonkConfig { + a, + b, + c, + d, + e, + sa, + sb, + sc, + sm, + sp, + sl, + } } +} - #[derive(Clone)] - struct MyCircuit { - a: Value, - lookup_table: Vec, - } +#[allow(clippy::type_complexity)] +trait StandardCs { + fn raw_multiply( + &self, + layouter: &mut impl Layouter, + f: F, + ) -> Result<(Cell, Cell, Cell), Error> + where + F: FnMut() -> Value<(Assigned, Assigned, Assigned)>; + fn raw_add( + &self, + layouter: &mut impl Layouter, + f: F, + ) -> Result<(Cell, Cell, Cell), Error> + where + F: FnMut() -> Value<(Assigned, Assigned, Assigned)>; + fn copy(&self, layouter: &mut impl Layouter, a: Cell, b: Cell) -> Result<(), Error>; + fn public_input(&self, layouter: &mut impl Layouter, f: F) -> Result + where + F: FnMut() -> Value; + fn lookup_table(&self, layouter: &mut impl Layouter, values: &[FF]) -> Result<(), Error>; +} - struct StandardPlonk { - config: PlonkConfig, - _marker: PhantomData, - } +struct StandardPlonk { + config: PlonkConfig, + _marker: PhantomData, +} - impl StandardPlonk { - fn new(config: PlonkConfig) -> Self { - StandardPlonk { - config, - _marker: PhantomData, - } +impl StandardPlonk { + fn new(config: PlonkConfig) -> Self { + StandardPlonk { + config, + _marker: PhantomData, } } +} +impl StandardCs for StandardPlonk { + fn raw_multiply( + &self, + layouter: &mut impl Layouter, + mut f: F, + ) -> Result<(Cell, Cell, Cell), Error> + where + F: FnMut() -> Value<(Assigned, Assigned, Assigned)>, + { + layouter.assign_region( + || "raw_multiply", + |mut region| { + let mut value = None; + let lhs = region.assign_advice( + || "lhs", + self.config.a, + 0, + || { + value = Some(f()); + value.unwrap().map(|v| v.0) + }, + )?; + region.assign_advice( + || "lhs^4", + self.config.d, + 0, + || value.unwrap().map(|v| v.0).square().square(), + )?; + let rhs = region.assign_advice( + || "rhs", + self.config.b, + 0, + || value.unwrap().map(|v| v.1), + )?; + region.assign_advice( + || "rhs^4", + self.config.e, + 0, + || value.unwrap().map(|v| v.1).square().square(), + )?; + let out = region.assign_advice( + || "out", + self.config.c, + 0, + || value.unwrap().map(|v| v.2), + )?; + + region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::ZERO))?; + region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::ZERO))?; + region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "a * b", self.config.sm, 0, || Value::known(FF::ONE))?; + Ok((lhs.cell(), rhs.cell(), out.cell())) + }, + ) + } + fn raw_add( + &self, + layouter: &mut impl Layouter, + mut f: F, + ) -> Result<(Cell, Cell, Cell), Error> + where + F: FnMut() -> Value<(Assigned, Assigned, Assigned)>, + { + layouter.assign_region( + || "raw_add", + |mut region| { + let mut value = None; + let lhs = region.assign_advice( + || "lhs", + self.config.a, + 0, + || { + value = Some(f()); + value.unwrap().map(|v| v.0) + }, + )?; + region.assign_advice( + || "lhs^4", + self.config.d, + 0, + || value.unwrap().map(|v| v.0).square().square(), + )?; + let rhs = region.assign_advice( + || "rhs", + self.config.b, + 0, + || value.unwrap().map(|v| v.1), + )?; + region.assign_advice( + || "rhs^4", + self.config.e, + 0, + || value.unwrap().map(|v| v.1).square().square(), + )?; + let out = region.assign_advice( + || "out", + self.config.c, + 0, + || value.unwrap().map(|v| v.2), + )?; + + region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::ONE))?; + region.assign_fixed(|| "a * b", self.config.sm, 0, || Value::known(FF::ZERO))?; + Ok((lhs.cell(), rhs.cell(), out.cell())) + }, + ) + } + fn copy(&self, layouter: &mut impl Layouter, left: Cell, right: Cell) -> Result<(), Error> { + layouter.assign_region( + || "copy", + |mut region| { + region.constrain_equal(left, right)?; + region.constrain_equal(left, right) + }, + ) + } + fn public_input(&self, layouter: &mut impl Layouter, mut f: F) -> Result + where + F: FnMut() -> Value, + { + layouter.assign_region( + || "public_input", + |mut region| { + let value = region.assign_advice(|| "value", self.config.a, 0, &mut f)?; + region.assign_fixed(|| "public", self.config.sp, 0, || Value::known(FF::ONE))?; - impl StandardCs for StandardPlonk { - fn raw_multiply( - &self, - layouter: &mut impl Layouter, - mut f: F, - ) -> Result<(Cell, Cell, Cell), Error> - where - F: FnMut() -> Value<(Assigned, Assigned, Assigned)>, - { - layouter.assign_region( - || "raw_multiply", - |mut region| { - let mut value = None; - let lhs = region.assign_advice( - || "lhs", - self.config.a, - 0, - || { - value = Some(f()); - value.unwrap().map(|v| v.0) - }, - )?; - region.assign_advice( - || "lhs^4", - self.config.d, - 0, - || value.unwrap().map(|v| v.0).square().square(), - )?; - let rhs = region.assign_advice( - || "rhs", - self.config.b, - 0, - || value.unwrap().map(|v| v.1), - )?; - region.assign_advice( - || "rhs^4", - self.config.e, - 0, - || value.unwrap().map(|v| v.1).square().square(), - )?; - let out = region.assign_advice( - || "out", - self.config.c, - 0, - || value.unwrap().map(|v| v.2), + Ok(value.cell()) + }, + ) + } + fn lookup_table(&self, layouter: &mut impl Layouter, values: &[FF]) -> Result<(), Error> { + layouter.assign_table( + || "", + |mut table| { + for (index, &value) in values.iter().enumerate() { + table.assign_cell( + || "table col", + self.config.sl, + index, + || Value::known(value), )?; + } + Ok(()) + }, + )?; + Ok(()) + } +} - region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::ZERO))?; - region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::ZERO))?; - region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::ONE))?; - region.assign_fixed(|| "a * b", self.config.sm, 0, || Value::known(FF::ONE))?; - Ok((lhs.cell(), rhs.cell(), out.cell())) - }, - ) - } - fn raw_add( - &self, - layouter: &mut impl Layouter, - mut f: F, - ) -> Result<(Cell, Cell, Cell), Error> - where - F: FnMut() -> Value<(Assigned, Assigned, Assigned)>, - { - layouter.assign_region( - || "raw_add", - |mut region| { - let mut value = None; - let lhs = region.assign_advice( - || "lhs", - self.config.a, - 0, - || { - value = Some(f()); - value.unwrap().map(|v| v.0) - }, - )?; - region.assign_advice( - || "lhs^4", - self.config.d, - 0, - || value.unwrap().map(|v| v.0).square().square(), - )?; - let rhs = region.assign_advice( - || "rhs", - self.config.b, - 0, - || value.unwrap().map(|v| v.1), - )?; - region.assign_advice( - || "rhs^4", - self.config.e, - 0, - || value.unwrap().map(|v| v.1).square().square(), - )?; - let out = region.assign_advice( - || "out", - self.config.c, - 0, - || value.unwrap().map(|v| v.2), - )?; +macro_rules! common { + ($scheme:ident) => {{ + let a = <$scheme as CommitmentScheme>::Scalar::from(2834758237) + * <$scheme as CommitmentScheme>::Scalar::ZETA; + let instance = + <$scheme as CommitmentScheme>::Scalar::ONE + <$scheme as CommitmentScheme>::Scalar::ONE; + let lookup_table = vec![instance, a, a, <$scheme as CommitmentScheme>::Scalar::ZERO]; + (a, instance, lookup_table) + }}; +} - region.assign_fixed(|| "a", self.config.sa, 0, || Value::known(FF::ONE))?; - region.assign_fixed(|| "b", self.config.sb, 0, || Value::known(FF::ONE))?; - region.assign_fixed(|| "c", self.config.sc, 0, || Value::known(FF::ONE))?; - region.assign_fixed( - || "a * b", - self.config.sm, - 0, - || Value::known(FF::ZERO), - )?; - Ok((lhs.cell(), rhs.cell(), out.cell())) - }, - ) - } - fn copy( - &self, - layouter: &mut impl Layouter, - left: Cell, - right: Cell, - ) -> Result<(), Error> { - layouter.assign_region( - || "copy", - |mut region| { - region.constrain_equal(left, right)?; - region.constrain_equal(left, right) - }, - ) - } - fn public_input(&self, layouter: &mut impl Layouter, mut f: F) -> Result - where - F: FnMut() -> Value, - { - layouter.assign_region( - || "public_input", - |mut region| { - let value = region.assign_advice(|| "value", self.config.a, 0, &mut f)?; - region.assign_fixed( - || "public", - self.config.sp, - 0, - || Value::known(FF::ONE), - )?; +fn verify_proof< + 'a, + 'params, + Scheme: CommitmentScheme, + V: Verifier<'params, Scheme>, + E: EncodedChallenge, + T: TranscriptReadBuffer<&'a [u8], Scheme::Curve, E>, + Strategy: VerificationStrategy<'params, Scheme, V, Output = Strategy>, +>( + params_verifier: &'params Scheme::ParamsVerifier, + vk: &VerifyingKey, + proof: &'a [u8], +) where + Scheme::Scalar: Ord + WithSmallOrderMulGroup<3> + FromUniformBytes<64>, +{ + let (_, instance, _) = common!(Scheme); + let pubinputs = [instance]; + + let mut transcript = T::init(proof); + + let strategy = Strategy::new(params_verifier); + let strategy = verify_plonk_proof( + params_verifier, + vk, + strategy, + &[&[&pubinputs[..]], &[&pubinputs[..]]], + &mut transcript, + ) + .unwrap(); + + assert!(strategy.finalize()); +} - Ok(value.cell()) - }, - ) - } - fn lookup_table( - &self, - layouter: &mut impl Layouter, - values: &[FF], - ) -> Result<(), Error> { - layouter.assign_table( - || "", - |mut table| { - for (index, &value) in values.iter().enumerate() { - table.assign_cell( - || "table col", - self.config.sl, - index, - || Value::known(value), - )?; - } - Ok(()) - }, - )?; - Ok(()) - } +#[test] +fn plonk_api() { + const K: u32 = 17; + + #[derive(Clone)] + struct MyCircuit { + a: Value, + lookup_table: Vec, } impl Circuit for MyCircuit { @@ -469,17 +607,6 @@ fn plonk_api() { } } - macro_rules! common { - ($scheme:ident) => {{ - let a = <$scheme as CommitmentScheme>::Scalar::from(2834758237) - * <$scheme as CommitmentScheme>::Scalar::ZETA; - let instance = <$scheme as CommitmentScheme>::Scalar::ONE - + <$scheme as CommitmentScheme>::Scalar::ONE; - let lookup_table = vec![instance, a, a, <$scheme as CommitmentScheme>::Scalar::ZERO]; - (a, instance, lookup_table) - }}; - } - /* macro_rules! bad_keys { ($scheme:ident) => {{ @@ -569,39 +696,6 @@ fn plonk_api() { transcript.finalize() } - fn verify_proof< - 'a, - 'params, - Scheme: CommitmentScheme, - V: Verifier<'params, Scheme>, - E: EncodedChallenge, - T: TranscriptReadBuffer<&'a [u8], Scheme::Curve, E>, - Strategy: VerificationStrategy<'params, Scheme, V, Output = Strategy>, - >( - params_verifier: &'params Scheme::ParamsVerifier, - vk: &VerifyingKey, - proof: &'a [u8], - ) where - Scheme::Scalar: Ord + WithSmallOrderMulGroup<3> + FromUniformBytes<64>, - { - let (_, instance, _) = common!(Scheme); - let pubinputs = [instance]; - - let mut transcript = T::init(proof); - - let strategy = Strategy::new(params_verifier); - let strategy = verify_plonk_proof( - params_verifier, - vk, - strategy, - &[&[&pubinputs[..]], &[&pubinputs[..]]], - &mut transcript, - ) - .unwrap(); - - assert!(strategy.finalize()); - } - fn test_plonk_api_gwc() { use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use halo2_proofs::poly::kzg::multiopen::{ProverGWC, VerifierGWC}; @@ -675,6 +769,7 @@ fn plonk_api() { >(verifier_params, pk.get_vk(), &proof[..]); } + #[allow(unused)] fn test_plonk_api_ipa() { use halo2_proofs::poly::ipa::commitment::{IPACommitmentScheme, ParamsIPA}; use halo2_proofs::poly::ipa::multiopen::{ProverIPA, VerifierIPA}; @@ -1109,8 +1204,224 @@ fn plonk_api() { */ } - env_logger::init(); - test_plonk_api_ipa(); + let _logger_err = env_logger::try_init(); + // TODO: fix the ipa test + // test_plonk_api_ipa(); test_plonk_api_gwc(); test_plonk_api_shplonk(); } + +#[test] +fn plonk_api_with_many_subregions() { + #[derive(Clone)] + struct MyCircuit { + a: Value, + lookup_table: Vec, + } + + impl Circuit for MyCircuit { + type Config = PlonkConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self { + a: Value::unknown(), + lookup_table: self.lookup_table.clone(), + } + } + + fn configure(meta: &mut ConstraintSystem) -> PlonkConfig { + PlonkConfig::construct(meta) + } + + fn synthesize( + &self, + config: PlonkConfig, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let cs = StandardPlonk::new(config); + + let _ = cs.public_input(&mut layouter, || Value::known(F::ONE + F::ONE))?; + + let a: Value> = self.a.into(); + let parallel_regions_time = Instant::now(); + #[cfg(feature = "parallel_syn")] + layouter.assign_regions( + || "regions", + (0..(1 << 14)) + .into_iter() + .map(|_| { + let mut is_first_pass = true; + move |mut region: Region<'_, F>| -> Result<(), Error> { + let n = 1 << 1; + for i in 0..n { + // skip the assign of rows except the last row in the first pass + if is_first_pass && i < n - 1 { + is_first_pass = false; + continue; + } + let a0 = + region.assign_advice(|| "config.a", cs.config.a, i, || a)?; + let a1 = + region.assign_advice(|| "config.b", cs.config.b, i, || a)?; + region.assign_advice( + || "config.c", + cs.config.c, + i, + || a.double(), + )?; + + region.assign_fixed( + || "a", + cs.config.sa, + i, + || Value::known(F::ONE), + )?; + region.assign_fixed( + || "b", + cs.config.sb, + i, + || Value::known(F::ONE), + )?; + region.assign_fixed( + || "c", + cs.config.sc, + i, + || Value::known(F::ONE), + )?; + region.assign_fixed( + || "a * b", + cs.config.sm, + i, + || Value::known(F::ZERO), + )?; + + region.constrain_equal(a0.cell(), a1.cell())?; + } + is_first_pass = false; + Ok(()) + } + }) + .collect(), + )?; + log::info!( + "parallel_regions assign took {:?}", + parallel_regions_time.elapsed() + ); + + for _ in 0..10 { + let a: Value> = self.a.into(); + let mut a_squared = Value::unknown(); + let (a0, _, c0) = cs.raw_multiply(&mut layouter, || { + a_squared = a.square(); + a.zip(a_squared).map(|(a, a_squared)| (a, a, a_squared)) + })?; + let (a1, b1, _) = cs.raw_add(&mut layouter, || { + let fin = a_squared + a; + a.zip(a_squared) + .zip(fin) + .map(|((a, a_squared), fin)| (a, a_squared, fin)) + })?; + cs.copy(&mut layouter, a0, a1)?; + cs.copy(&mut layouter, b1, c0)?; + } + + cs.lookup_table(&mut layouter, &self.lookup_table)?; + + Ok(()) + } + } + fn keygen(params: &Scheme::ParamsProver) -> ProvingKey + where + Scheme::Scalar: Ord + WithSmallOrderMulGroup<3> + FromUniformBytes<64>, + { + let (_, _, lookup_table) = common!(Scheme); + let empty_circuit: MyCircuit = MyCircuit { + a: Value::unknown(), + lookup_table, + }; + + // Initialize the proving key + let vk = keygen_vk(params, &empty_circuit).expect("keygen_vk should not fail"); + log::info!("keygen vk succeed"); + + let pk = keygen_pk(params, vk, &empty_circuit).expect("keygen_pk should not fail"); + log::info!("keygen pk succeed"); + + pk + } + + fn create_proof< + 'params, + Scheme: CommitmentScheme, + P: Prover<'params, Scheme>, + E: EncodedChallenge, + R: RngCore, + T: TranscriptWriterBuffer, Scheme::Curve, E>, + >( + rng: R, + params: &'params Scheme::ParamsProver, + pk: &ProvingKey, + ) -> Vec + where + Scheme::Scalar: Ord + WithSmallOrderMulGroup<3> + FromUniformBytes<64>, + { + let (a, instance, lookup_table) = common!(Scheme); + + let circuit: MyCircuit = MyCircuit { + a: Value::known(a), + lookup_table, + }; + + let mut transcript = T::init(vec![]); + + create_plonk_proof::( + params, + pk, + &[circuit.clone(), circuit], + &[&[&[instance]], &[&[instance]]], + rng, + &mut transcript, + ) + .expect("proof generation should not fail"); + + transcript.finalize() + } + + const K: u32 = 17; + type Scheme = KZGCommitmentScheme; + // bad_keys!(Scheme); + + let _logger_err = env_logger::try_init(); + let (a, instance, lookup_table) = common!(Scheme); + + let circuit: MyCircuit<::Scalar> = MyCircuit { + a: Value::known(a), + lookup_table, + }; + + // Check this circuit is satisfied. + let prover = match MockProver::run(K, &circuit, vec![vec![instance]]) { + Ok(prover) => prover, + Err(e) => panic!("{:?}", e), + }; + assert_eq!(prover.verify_par(), Ok(())); + log::info!("mock proving succeed!"); + + let params = ParamsKZG::::new(K); + let rng = OsRng; + + let pk = keygen::>(¶ms); + + let proof = create_proof::<_, ProverGWC<_>, _, _, Blake2bWrite<_, _, Challenge255<_>>>( + rng, ¶ms, &pk, + ); + + let verifier_params = params.verifier_params(); + + verify_proof::<_, VerifierGWC<_>, _, Blake2bRead<_, _, Challenge255<_>>, AccumulatorStrategy<_>>( + verifier_params, + pk.get_vk(), + &proof[..], + ); +} From 1070391642dd64b2d68b47ec246cba9e35bd3c15 Mon Sep 17 00:00:00 2001 From: Zhang Zhuo Date: Wed, 13 Dec 2023 14:13:50 +0800 Subject: [PATCH 54/54] unify halo2curves version --- Cargo.lock | 24 +++--------------------- Cargo.toml | 1 + halo2_gadgets/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3a36d84c12..7a0fd1b201 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -859,7 +859,7 @@ dependencies = [ "ff", "group", "halo2_proofs", - "halo2curves 0.3.2", + "halo2curves", "lazy_static", "plotters", "pprof", @@ -885,7 +885,7 @@ dependencies = [ "getrandom", "group", "gumdrop", - "halo2curves 0.1.0", + "halo2curves", "lazy_static", "log", "num-bigint", @@ -923,24 +923,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "halo2curves" -version = "0.3.2" -source = "git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.3.2#9f5c50810bbefe779ee5cf1d852b2fe85dc35d5e" -dependencies = [ - "ff", - "group", - "lazy_static", - "num-bigint", - "num-traits", - "pasta_curves", - "paste", - "rand", - "rand_core", - "static_assertions", - "subtle", -] - [[package]] name = "hashbrown" version = "0.11.2" @@ -1415,7 +1397,7 @@ name = "poseidon" version = "0.2.0" source = "git+https://github.com/scroll-tech/poseidon.git?branch=main#5787dd3d2ce7a9e9601a035c396ac0c03449b54d" dependencies = [ - "halo2curves 0.1.0", + "halo2curves", "subtle", ] diff --git a/Cargo.toml b/Cargo.toml index b7878ae843..68165eaf41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "halo2", "halo2_gadgets", diff --git a/halo2_gadgets/Cargo.toml b/halo2_gadgets/Cargo.toml index 136ef63a16..b495dc7350 100644 --- a/halo2_gadgets/Cargo.toml +++ b/halo2_gadgets/Cargo.toml @@ -28,7 +28,7 @@ ff = { version = "0.13", features = ["bits"] } group = "0.13" halo2_proofs = { version = "0.2", path = "../halo2_proofs" } lazy_static = "1" -halo2curves = { git = 'https://github.com/privacy-scaling-explorations/halo2curves', tag = "0.3.2" } +halo2curves = { version = "0.1.0"} proptest = { version = "1.0.0", optional = true } rand = "0.8" subtle = "2.3"