diff --git a/Cargo.toml b/Cargo.toml index 9d8d2d5c..1887b081 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "halo2-ecc", "hashes/zkevm-keccak", ] +resolver = "2" [profile.dev] opt-level = 3 @@ -37,9 +38,4 @@ incremental = false # For performance profiling [profile.flamegraph] inherits = "release" -debug = true - -# patch so snark-verifier uses this crate's halo2-base -[patch."https://github.com/axiom-crypto/halo2-lib.git"] -halo2-base = { path = "./halo2-base" } -halo2-ecc = { path = "./halo2-ecc" } +debug = true \ No newline at end of file diff --git a/halo2-base/Cargo.toml b/halo2-base/Cargo.toml index 3c568313..93f0f21b 100644 --- a/halo2-base/Cargo.toml +++ b/halo2-base/Cargo.toml @@ -1,25 +1,24 @@ [package] name = "halo2-base" -version = "0.3.1" +version = "0.3.2" edition = "2021" [dependencies] -itertools = "0.10" +itertools = "0.11" num-bigint = { version = "0.4", features = ["rand"] } num-integer = "0.1" num-traits = "0.2" rand_chacha = "0.3" rustc-hash = "1.1" -ff = "0.12" -rayon = "1.6.1" +rayon = "1.7" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" log = "0.4" # Use Axiom's custom halo2 monorepo for faster proving when feature = "halo2-axiom" is on -halo2_proofs_axiom = { git = "https://github.com/axiom-crypto/halo2.git", branch = "main", package = "halo2_proofs", optional = true } +halo2_proofs_axiom = { git = "https://github.com/axiom-crypto/halo2.git", package = "halo2_proofs", optional = true } # Use PSE halo2 and halo2curves for compatibility when feature = "halo2-pse" is on -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02", optional = true } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", rev = "f348757", optional = true } # plotting circuit layout plotters = { version = "0.3.0", optional = true } @@ -34,7 +33,6 @@ rand = "0.8" pprof = { version = "0.11", features = ["criterion", "flamegraph"] } criterion = "0.4" criterion-macro = "0.4" -rayon = "1.6.1" test-case = "3.1.0" proptest = "1.1.0" @@ -46,8 +44,9 @@ mimalloc = { version = "0.1", default-features = false, optional = true } [features] default = ["halo2-axiom", "display"] +asm = ["halo2_proofs_axiom?/asm"] dev-graph = ["halo2_proofs?/dev-graph", "halo2_proofs_axiom?/dev-graph", "plotters"] -halo2-pse = ["halo2_proofs"] +halo2-pse = ["halo2_proofs/circuit-params"] halo2-axiom = ["halo2_proofs_axiom"] display = [] profile = ["halo2_proofs_axiom?/profile"] diff --git a/halo2-base/benches/inner_product.rs b/halo2-base/benches/inner_product.rs index 71702bc0..e348459e 100644 --- a/halo2-base/benches/inner_product.rs +++ b/halo2-base/benches/inner_product.rs @@ -1,10 +1,7 @@ -#![allow(unused_imports)] -#![allow(unused_variables)] -use halo2_base::gates::builder::{GateCircuitBuilder, GateThreadBuilder, RangeCircuitBuilder}; -use halo2_base::gates::flex_gate::{FlexGateConfig, GateChip, GateInstructions, GateStrategy}; +use halo2_base::gates::builder::{GateThreadBuilder, RangeCircuitBuilder}; +use halo2_base::gates::flex_gate::{GateChip, GateInstructions}; use halo2_base::halo2_proofs::{ arithmetic::Field, - circuit::*, dev::MockProver, halo2curves::bn256::{Bn256, Fr, G1Affine}, plonk::*, @@ -15,14 +12,9 @@ use halo2_base::halo2_proofs::{ transcript::{Blake2bWrite, Challenge255, TranscriptWriterBuffer}, }; use halo2_base::utils::ScalarField; -use halo2_base::{ - Context, - QuantumCell::{Existing, Witness}, - SKIP_FIRST_PASS, -}; +use halo2_base::{Context, QuantumCell::Existing}; use itertools::Itertools; use rand::rngs::OsRng; -use std::marker::PhantomData; use criterion::{criterion_group, criterion_main}; use criterion::{BenchmarkId, Criterion}; @@ -49,8 +41,8 @@ fn bench(c: &mut Criterion) { // create circuit for keygen let mut builder = GateThreadBuilder::new(false); inner_prod_bench(builder.main(0), vec![Fr::zero(); 5], vec![Fr::zero(); 5]); - builder.config(k as usize, Some(20)); - let circuit = RangeCircuitBuilder::mock(builder); + let config_params = builder.config(k as usize, Some(20)); + let circuit = RangeCircuitBuilder::mock(builder, config_params.clone()); // check the circuit is correct just in case MockProver::run(k, &circuit, vec![]).unwrap().assert_satisfied(); @@ -73,7 +65,11 @@ fn bench(c: &mut Criterion) { let a = (0..5).map(|_| Fr::random(OsRng)).collect_vec(); let b = (0..5).map(|_| Fr::random(OsRng)).collect_vec(); inner_prod_bench(builder.main(0), a, b); - let circuit = RangeCircuitBuilder::prover(builder, break_points.clone()); + let circuit = RangeCircuitBuilder::prover( + builder, + config_params.clone(), + break_points.clone(), + ); let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); create_proof::< diff --git a/halo2-base/benches/mul.rs b/halo2-base/benches/mul.rs index 1099db67..f1cae5b9 100644 --- a/halo2-base/benches/mul.rs +++ b/halo2-base/benches/mul.rs @@ -1,8 +1,8 @@ -use ff::Field; use halo2_base::gates::builder::{GateThreadBuilder, RangeCircuitBuilder}; use halo2_base::gates::flex_gate::{GateChip, GateInstructions}; use halo2_base::halo2_proofs::{ halo2curves::bn256::{Bn256, Fr, G1Affine}, + halo2curves::ff::Field, plonk::*, poly::kzg::{ commitment::{KZGCommitmentScheme, ParamsKZG}, @@ -36,8 +36,8 @@ fn bench(c: &mut Criterion) { // create circuit for keygen let mut builder = GateThreadBuilder::new(false); mul_bench(builder.main(0), [Fr::zero(); 2]); - builder.config(K as usize, Some(9)); - let circuit = RangeCircuitBuilder::keygen(builder); + let config_params = builder.config(K as usize, Some(9)); + let circuit = RangeCircuitBuilder::keygen(builder, config_params.clone()); let params = ParamsKZG::::setup(K, OsRng); let vk = keygen_vk(¶ms, &circuit).expect("vk should not fail"); @@ -56,7 +56,11 @@ fn bench(c: &mut Criterion) { let mut builder = GateThreadBuilder::new(true); // do the computation mul_bench(builder.main(0), inputs); - let circuit = RangeCircuitBuilder::prover(builder, break_points.clone()); + let circuit = RangeCircuitBuilder::prover( + builder, + config_params.clone(), + break_points.clone(), + ); let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); create_proof::< diff --git a/halo2-base/examples/inner_product.rs b/halo2-base/examples/inner_product.rs index 585a8b78..9be3014b 100644 --- a/halo2-base/examples/inner_product.rs +++ b/halo2-base/examples/inner_product.rs @@ -1,10 +1,7 @@ -#![allow(unused_imports)] -#![allow(unused_variables)] use halo2_base::gates::builder::{GateThreadBuilder, RangeCircuitBuilder}; -use halo2_base::gates::flex_gate::{FlexGateConfig, GateChip, GateInstructions, GateStrategy}; +use halo2_base::gates::flex_gate::{GateChip, GateInstructions}; use halo2_base::halo2_proofs::{ arithmetic::Field, - circuit::*, dev::MockProver, halo2curves::bn256::{Bn256, Fr, G1Affine}, plonk::*, @@ -18,21 +15,9 @@ use halo2_base::halo2_proofs::{ transcript::{Blake2bWrite, Challenge255, TranscriptWriterBuffer}, }; use halo2_base::utils::ScalarField; -use halo2_base::{ - Context, - QuantumCell::{Existing, Witness}, - SKIP_FIRST_PASS, -}; +use halo2_base::{Context, QuantumCell::Existing}; use itertools::Itertools; use rand::rngs::OsRng; -use std::marker::PhantomData; - -use criterion::{criterion_group, criterion_main}; -use criterion::{BenchmarkId, Criterion}; - -use pprof::criterion::{Output, PProfProfiler}; -// Thanks to the example provided by @jebbow in his article -// https://www.jibbow.com/posts/criterion-flamegraphs/ const K: u32 = 19; @@ -52,8 +37,8 @@ fn main() { // create circuit for keygen let mut builder = GateThreadBuilder::new(false); inner_prod_bench(builder.main(0), vec![Fr::zero(); 5], vec![Fr::zero(); 5]); - builder.config(k as usize, Some(20)); - let circuit = RangeCircuitBuilder::mock(builder); + let config_params = builder.config(k as usize, Some(20)); + let circuit = RangeCircuitBuilder::mock(builder, config_params.clone()); // check the circuit is correct just in case MockProver::run(k, &circuit, vec![]).unwrap().assert_satisfied(); @@ -68,7 +53,7 @@ fn main() { let a = (0..5).map(|_| Fr::random(OsRng)).collect_vec(); let b = (0..5).map(|_| Fr::random(OsRng)).collect_vec(); inner_prod_bench(builder.main(0), a, b); - let circuit = RangeCircuitBuilder::prover(builder, break_points); + let circuit = RangeCircuitBuilder::prover(builder, config_params, break_points); let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); create_proof::< diff --git a/halo2-base/src/gates/builder/mod.rs b/halo2-base/src/gates/builder/mod.rs index ed20fa47..7280967a 100644 --- a/halo2-base/src/gates/builder/mod.rs +++ b/halo2-base/src/gates/builder/mod.rs @@ -24,16 +24,6 @@ pub type ThreadBreakPoints = Vec; /// Vector of vectors tracking the thread break points across different halo2 phases pub type MultiPhaseThreadBreakPoints = Vec; -thread_local! { - /// This is used as a thread-safe way to auto-configure a circuit's shape and then pass the configuration to `Circuit::configure`. - pub static BASE_CONFIG_PARAMS: RefCell = RefCell::new(Default::default()); -} - -/// Sets the thread-local number of bits to be range checkable via a lookup table with entries [0, 2lookup_bits) -pub fn set_lookup_bits(lookup_bits: usize) { - BASE_CONFIG_PARAMS.with(|conf| conf.borrow_mut().lookup_bits = Some(lookup_bits)); -} - /// Stores the cell values loaded during the Keygen phase of a halo2 proof and breakpoints for multi-threading #[derive(Clone, Debug, Default)] pub struct KeygenAssignments { @@ -71,6 +61,11 @@ impl GateThreadBuilder { Self { threads, thread_count: 1, witness_gen_only, use_unknown: false } } + /// Creates a new [GateThreadBuilder] depending on the stage of circuit building. If the stage is [CircuitBuilderStage::Prover], the [GateThreadBuilder] is used for witness generation only. + pub fn from_stage(stage: CircuitBuilderStage) -> Self { + Self::new(stage == CircuitBuilderStage::Prover) + } + /// Creates a new [GateThreadBuilder] with `witness_gen_only` set to false. /// /// Performs the witness assignment computations and then checks using normal programming logic whether the gate constraints are all satisfied. @@ -173,7 +168,7 @@ impl GateThreadBuilder { .len(); let num_fixed = (total_fixed + (1 << k) - 1) >> k; - let mut params = BaseConfigParams { + let params = BaseConfigParams { strategy: GateStrategy::Vertical, num_advice_per_phase, num_lookup_advice_per_phase, @@ -181,10 +176,6 @@ impl GateThreadBuilder { k, lookup_bits: None, }; - BASE_CONFIG_PARAMS.with(|conf| { - params.lookup_bits = conf.borrow().lookup_bits; - *conf.borrow_mut() = params.clone(); - }); #[cfg(feature = "display")] { for phase in 0..MAX_PHASE { @@ -492,25 +483,40 @@ pub struct GateCircuitBuilder { pub builder: RefCell>, // `RefCell` is just to trick circuit `synthesize` to take ownership of the inner builder /// Break points for threads within the circuit pub break_points: RefCell, // `RefCell` allows the circuit to record break points in a keygen call of `synthesize` for use in later witness gen + /// Configuration parameters for the circuit shape + pub config_params: BaseConfigParams, } impl GateCircuitBuilder { /// Creates a new [GateCircuitBuilder] with `use_unknown` of [GateThreadBuilder] set to true. - pub fn keygen(builder: GateThreadBuilder) -> Self { - Self { builder: RefCell::new(builder.unknown(true)), break_points: RefCell::new(vec![]) } + pub fn keygen(builder: GateThreadBuilder, config_params: BaseConfigParams) -> Self { + Self { + builder: RefCell::new(builder.unknown(true)), + config_params, + break_points: Default::default(), + } } /// Creates a new [GateCircuitBuilder] with `use_unknown` of [GateThreadBuilder] set to false. - pub fn mock(builder: GateThreadBuilder) -> Self { - Self { builder: RefCell::new(builder.unknown(false)), break_points: RefCell::new(vec![]) } + pub fn mock(builder: GateThreadBuilder, config_params: BaseConfigParams) -> Self { + Self { + builder: RefCell::new(builder.unknown(false)), + config_params, + break_points: Default::default(), + } } - /// Creates a new [GateCircuitBuilder]. + /// Creates a new [GateCircuitBuilder] with a pinned circuit configuration given by `config_params` and `break_points`. pub fn prover( builder: GateThreadBuilder, + config_params: BaseConfigParams, break_points: MultiPhaseThreadBreakPoints, ) -> Self { - Self { builder: RefCell::new(builder), break_points: RefCell::new(break_points) } + Self { + builder: RefCell::new(builder), + config_params, + break_points: RefCell::new(break_points), + } } /// Synthesizes from the [GateCircuitBuilder] by populating the advice column and assigning new threads if witness generation is performed. @@ -555,12 +561,8 @@ impl GateCircuitBuilder { // If we are only generating witness, we can skip the first pass and assign threads directly let builder = self.builder.take(); let break_points = self.break_points.take(); - for (phase, (threads, break_points)) in builder - .threads - .into_iter() - .zip(break_points.into_iter()) - .enumerate() - .take(1) + for (phase, (threads, break_points)) in + builder.threads.into_iter().zip(break_points).enumerate().take(1) { assign_threads_in( phase, @@ -585,28 +587,52 @@ impl GateCircuitBuilder { pub struct RangeCircuitBuilder(pub GateCircuitBuilder); impl RangeCircuitBuilder { + /// Convenience function to create a new [RangeCircuitBuilder] with a given [CircuitBuilderStage]. + pub fn from_stage( + stage: CircuitBuilderStage, + builder: GateThreadBuilder, + config_params: BaseConfigParams, + break_points: Option, + ) -> Self { + match stage { + CircuitBuilderStage::Keygen => Self::keygen(builder, config_params), + CircuitBuilderStage::Mock => Self::mock(builder, config_params), + CircuitBuilderStage::Prover => Self::prover( + builder, + config_params, + break_points.expect("break points must be pre-calculated for prover"), + ), + } + } + /// Creates an instance of the [RangeCircuitBuilder] and executes in keygen mode. - pub fn keygen(builder: GateThreadBuilder) -> Self { - Self(GateCircuitBuilder::keygen(builder)) + pub fn keygen(builder: GateThreadBuilder, config_params: BaseConfigParams) -> Self { + Self(GateCircuitBuilder::keygen(builder, config_params)) } /// Creates a mock instance of the [RangeCircuitBuilder]. - pub fn mock(builder: GateThreadBuilder) -> Self { - Self(GateCircuitBuilder::mock(builder)) + pub fn mock(builder: GateThreadBuilder, config_params: BaseConfigParams) -> Self { + Self(GateCircuitBuilder::mock(builder, config_params)) } /// Creates an instance of the [RangeCircuitBuilder] and executes in prover mode. pub fn prover( builder: GateThreadBuilder, + config_params: BaseConfigParams, break_points: MultiPhaseThreadBreakPoints, ) -> Self { - Self(GateCircuitBuilder::prover(builder, break_points)) + Self(GateCircuitBuilder::prover(builder, config_params, break_points)) } } impl Circuit for RangeCircuitBuilder { type Config = BaseConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = BaseConfigParams; + + fn params(&self) -> Self::Params { + self.0.config_params.clone() + } /// Creates a new instance of the [RangeCircuitBuilder] without witnesses by setting the witness_gen_only flag to false fn without_witnesses(&self) -> Self { @@ -614,13 +640,14 @@ impl Circuit for RangeCircuitBuilder { } /// Configures a new circuit using [`BaseConfigParams`] - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let params = BASE_CONFIG_PARAMS - .try_with(|config| config.borrow().clone()) - .expect("You need to call config() to configure the halo2-base circuit shape first"); + fn configure_with_params(meta: &mut ConstraintSystem, params: Self::Params) -> Self::Config { BaseConfig::configure(meta, params) } + fn configure(_: &mut ConstraintSystem) -> Self::Config { + unreachable!("You must use configure_with_params"); + } + /// Performs the actual computation on the circuit (e.g., witness generation), populating the lookup table and filling in all the advice values for a particular proof. fn synthesize( &self, @@ -663,26 +690,49 @@ pub struct RangeWithInstanceCircuitBuilder { } impl RangeWithInstanceCircuitBuilder { + /// Convenience function to create a new [RangeWithInstanceCircuitBuilder] with a given [CircuitBuilderStage]. + pub fn from_stage( + stage: CircuitBuilderStage, + builder: GateThreadBuilder, + config_params: BaseConfigParams, + break_points: Option, + assigned_instances: Vec>, + ) -> Self { + Self { + circuit: RangeCircuitBuilder::from_stage(stage, builder, config_params, break_points), + assigned_instances, + } + } + /// See [`RangeCircuitBuilder::keygen`] pub fn keygen( builder: GateThreadBuilder, + config_params: BaseConfigParams, assigned_instances: Vec>, ) -> Self { - Self { circuit: RangeCircuitBuilder::keygen(builder), assigned_instances } + Self { circuit: RangeCircuitBuilder::keygen(builder, config_params), assigned_instances } } /// See [`RangeCircuitBuilder::mock`] - pub fn mock(builder: GateThreadBuilder, assigned_instances: Vec>) -> Self { - Self { circuit: RangeCircuitBuilder::mock(builder), assigned_instances } + pub fn mock( + builder: GateThreadBuilder, + config_params: BaseConfigParams, + assigned_instances: Vec>, + ) -> Self { + Self { circuit: RangeCircuitBuilder::mock(builder, config_params), assigned_instances } } /// See [`RangeCircuitBuilder::prover`] pub fn prover( builder: GateThreadBuilder, - assigned_instances: Vec>, + config_params: BaseConfigParams, break_points: MultiPhaseThreadBreakPoints, + assigned_instances: Vec>, ) -> Self { - Self { circuit: RangeCircuitBuilder::prover(builder, break_points), assigned_instances } + Self { + circuit: RangeCircuitBuilder::prover(builder, config_params, break_points), + assigned_instances, + } } /// Creates a new instance of the [RangeWithInstanceCircuitBuilder]. @@ -690,11 +740,6 @@ impl RangeWithInstanceCircuitBuilder { Self { circuit, assigned_instances } } - /// Calls [`GateThreadBuilder::config`] - pub fn config(&self, k: u32, minimum_rows: Option) -> BaseConfigParams { - self.circuit.0.builder.borrow().config(k as usize, minimum_rows) - } - /// Gets the break points of the circuit. pub fn break_points(&self) -> MultiPhaseThreadBreakPoints { self.circuit.0.break_points.borrow().clone() @@ -714,18 +759,27 @@ impl RangeWithInstanceCircuitBuilder { impl Circuit for RangeWithInstanceCircuitBuilder { type Config = PublicBaseConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = BaseConfigParams; + + fn params(&self) -> Self::Params { + self.circuit.0.config_params.clone() + } fn without_witnesses(&self) -> Self { unimplemented!() } - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let base = RangeCircuitBuilder::configure(meta); + fn configure_with_params(meta: &mut ConstraintSystem, params: Self::Params) -> Self::Config { + let base = BaseConfig::configure(meta, params); let instance = meta.instance_column(); meta.enable_equality(instance); PublicBaseConfig { base, instance } } + fn configure(_: &mut ConstraintSystem) -> Self::Config { + unreachable!("You must use configure_with_params") + } + fn synthesize( &self, config: Self::Config, diff --git a/halo2-base/src/gates/flex_gate.rs b/halo2-base/src/gates/flex_gate.rs index 999cfd77..ea8a7739 100644 --- a/halo2-base/src/gates/flex_gate.rs +++ b/halo2-base/src/gates/flex_gate.rs @@ -162,9 +162,6 @@ pub trait GateInstructions { /// Returns a slice of the [ScalarField] field elements 2^i for i in 0..F::NUM_BITS. fn pow_of_two(&self) -> &[F]; - /// Converts a [u64] into a scalar field element [ScalarField]. - fn get_field_element(&self, n: u64) -> F; - /// Constrains and returns `a + b * 1 = out`. /// /// Defines a vertical gate of form | a | b | 1 | a + b | where (a + b) = out. @@ -180,7 +177,7 @@ pub trait GateInstructions { let a = a.into(); let b = b.into(); let out_val = *a.value() + b.value(); - ctx.assign_region_last([a, b, Constant(F::one()), Witness(out_val)], [0]) + ctx.assign_region_last([a, b, Constant(F::ONE), Witness(out_val)], [0]) } /// Constrains and returns `a + b * (-1) = out`. @@ -198,8 +195,8 @@ pub trait GateInstructions { let a = a.into(); let b = b.into(); let out_val = *a.value() - b.value(); - // slightly better to not have to compute -F::one() since F::one() is cached - ctx.assign_region([Witness(out_val), b, Constant(F::one()), a], [0]); + // slightly better to not have to compute -F::ONE since F::ONE is cached + ctx.assign_region([Witness(out_val), b, Constant(F::ONE), a], [0]); ctx.get(-4) } @@ -211,7 +208,7 @@ pub trait GateInstructions { fn neg(&self, ctx: &mut Context, a: impl Into>) -> AssignedValue { let a = a.into(); let out_val = -*a.value(); - ctx.assign_region([a, Witness(out_val), Constant(F::one()), Constant(F::zero())], [0]); + ctx.assign_region([a, Witness(out_val), Constant(F::ONE), Constant(F::ZERO)], [0]); ctx.get(-3) } @@ -230,7 +227,7 @@ pub trait GateInstructions { let a = a.into(); let b = b.into(); let out_val = *a.value() * b.value(); - ctx.assign_region_last([Constant(F::zero()), a, b, Witness(out_val)], [0]) + ctx.assign_region_last([Constant(F::ZERO), a, b, Witness(out_val)], [0]) } /// Constrains and returns `a * b + c = out`. @@ -268,7 +265,7 @@ pub trait GateInstructions { ) -> AssignedValue { let a = a.into(); let b = b.into(); - let out_val = (F::one() - a.value()) * b.value(); + let out_val = (F::ONE - a.value()) * b.value(); ctx.assign_region_smart([Witness(out_val), a, b, b], [0], [(2, 3)], []); ctx.get(-4) } @@ -279,7 +276,7 @@ pub trait GateInstructions { /// * `ctx`: [Context] to add the constraints to /// * `x`: [QuantumCell] value to constrain fn assert_bit(&self, ctx: &mut Context, x: AssignedValue) { - ctx.assign_region([Constant(F::zero()), Existing(x), Existing(x), Existing(x)], [0]); + ctx.assign_region([Constant(F::ZERO), Existing(x), Existing(x), Existing(x)], [0]); } /// Constrains and returns a / b = 0. @@ -301,7 +298,7 @@ pub trait GateInstructions { // TODO: if really necessary, make `c` of type `Assigned` // this would require the API using `Assigned` instead of `F` everywhere, so leave as last resort let c = b.value().invert().unwrap() * a.value(); - ctx.assign_region([Constant(F::zero()), Witness(c), b, a], [0]); + ctx.assign_region([Constant(F::ZERO), Witness(c), b, a], [0]); ctx.get(-3) } @@ -385,7 +382,7 @@ pub trait GateInstructions { let cells = iter::once(start).chain(a.flat_map(|a| { let a = a.into(); sum += a.value(); - [a, Constant(F::one()), Witness(sum)] + [a, Constant(F::ONE), Witness(sum)] })); ctx.assign_region_last(cells, (0..len).map(|i| 3 * i as isize)) } @@ -419,7 +416,7 @@ pub trait GateInstructions { let cells = iter::once(start).chain(a.flat_map(|a| { let a = a.into(); sum += a.value(); - [a, Constant(F::one()), Witness(sum)] + [a, Constant(F::ONE), Witness(sum)] })); ctx.assign_region(cells, (0..len).map(|i| 3 * i as isize)); Box::new((0..=len).rev().map(|i| ctx.get(-1 - 3 * (i as isize)))) @@ -486,13 +483,13 @@ pub trait GateInstructions { ) -> AssignedValue { let a = a.into(); let b = b.into(); - let not_b_val = F::one() - b.value(); + let not_b_val = F::ONE - b.value(); let out_val = *a.value() + b.value() - *a.value() * b.value(); let cells = [ Witness(not_b_val), - Constant(F::one()), + Constant(F::ONE), b, - Constant(F::one()), + Constant(F::ONE), b, a, Witness(not_b_val), @@ -523,7 +520,7 @@ pub trait GateInstructions { /// * `ctx`: [Context] to add the constraints to. /// * `a`: [QuantumCell] that contains a boolean value. fn not(&self, ctx: &mut Context, a: impl Into>) -> AssignedValue { - self.sub(ctx, Constant(F::one()), a) + self.sub(ctx, Constant(F::ONE), a) } /// Constrains and returns `sel ? a : b` assuming `sel` is boolean. @@ -574,10 +571,10 @@ pub trait GateInstructions { let (inv_last_bit, last_bit) = { ctx.assign_region( [ - Witness(F::one() - bits[k - 1].value()), + Witness(F::ONE - bits[k - 1].value()), Existing(bits[k - 1]), - Constant(F::one()), - Constant(F::one()), + Constant(F::ONE), + Constant(F::ONE), ], [0], ); @@ -590,7 +587,7 @@ pub trait GateInstructions { for (idx, bit) in bits.iter().rev().enumerate().skip(1) { for old_idx in 0..(1 << idx) { // inv_prod_val = (1 - bit) * indicator[offset + old_idx] - let inv_prod_val = (F::one() - bit.value()) * indicator[offset + old_idx].value(); + let inv_prod_val = (F::ONE - bit.value()) * indicator[offset + old_idx].value(); ctx.assign_region( [ Witness(inv_prod_val), @@ -631,25 +628,25 @@ pub trait GateInstructions { // unroll `is_zero` to make sure if `idx == Witness(_)` it is replaced by `Existing(_)` in later iterations let x = idx.value(); let (is_zero, inv) = if x.is_zero_vartime() { - (F::one(), Assigned::Trivial(F::one())) + (F::ONE, Assigned::Trivial(F::ONE)) } else { - (F::zero(), Assigned::Rational(F::one(), *x)) + (F::ZERO, Assigned::Rational(F::ONE, *x)) }; let cells = [ Witness(is_zero), idx, WitnessFraction(inv), - Constant(F::one()), - Constant(F::zero()), + Constant(F::ONE), + Constant(F::ZERO), idx, Witness(is_zero), - Constant(F::zero()), + Constant(F::ZERO), ]; ctx.assign_region_smart(cells, [0, 4], [(0, 6), (1, 5)], []); // note the two `idx` need to be constrained equal: (1, 5) idx = Existing(ctx.get(-3)); // replacing `idx` with Existing cell so future loop iterations constrain equality of all `idx`s ctx.get(-2) } else { - self.is_equal(ctx, idx, Constant(self.get_field_element(i as u64))) + self.is_equal(ctx, idx, Constant(F::from(i as u64))) } }) .collect() @@ -671,18 +668,17 @@ pub trait GateInstructions { where Q: Into>, { - let mut sum = F::zero(); + let mut sum = F::ZERO; let a = a.into_iter(); let (len, hi) = a.size_hint(); assert_eq!(Some(len), hi); - let cells = std::iter::once(Constant(F::zero())).chain( - a.zip(indicator.into_iter()).flat_map(|(a, ind)| { + let cells = + std::iter::once(Constant(F::ZERO)).chain(a.zip(indicator).flat_map(|(a, ind)| { let a = a.into(); sum = if ind.value().is_zero_vartime() { sum } else { *a.value() }; [a, Existing(ind), Witness(sum)] - }), - ); + })); ctx.assign_region_last(cells, (0..len).map(|i| 3 * i as isize)) } @@ -717,20 +713,20 @@ pub trait GateInstructions { fn is_zero(&self, ctx: &mut Context, a: AssignedValue) -> AssignedValue { let x = a.value(); let (is_zero, inv) = if x.is_zero_vartime() { - (F::one(), Assigned::Trivial(F::one())) + (F::ONE, Assigned::Trivial(F::ONE)) } else { - (F::zero(), Assigned::Rational(F::one(), *x)) + (F::ZERO, Assigned::Rational(F::ONE, *x)) }; let cells = [ Witness(is_zero), Existing(a), WitnessFraction(inv), - Constant(F::one()), - Constant(F::zero()), + Constant(F::ONE), + Constant(F::ZERO), Existing(a), Witness(is_zero), - Constant(F::zero()), + Constant(F::ZERO), ]; ctx.assign_region_smart(cells, [0, 4], [(0, 6)], []); ctx.get(-2) @@ -810,7 +806,7 @@ pub trait GateInstructions { } // TODO: batch inversion let is_zero = self.is_zero(ctx, denom); - self.assert_is_const(ctx, &is_zero, &F::zero()); + self.assert_is_const(ctx, &is_zero, &F::ZERO); // y_i / denom let quot = self.div_unsafe(ctx, coords[i].1, denom); @@ -848,7 +844,7 @@ impl GateChip { pub fn new(strategy: GateStrategy) -> Self { let mut pow_of_two = Vec::with_capacity(F::NUM_BITS as usize); let two = F::from(2); - pow_of_two.push(F::one()); + pow_of_two.push(F::ONE); pow_of_two.push(two); for _ in 2..F::NUM_BITS { pow_of_two.push(two * pow_of_two.last().unwrap()); @@ -860,7 +856,7 @@ impl GateChip { /// Calculates and constrains the inner product of ``. /// - /// Returns `true` if `b` start with `Constant(F::one())`, and `false` otherwise. + /// Returns `true` if `b` start with `Constant(F::ONE)`, and `false` otherwise. /// /// Assumes `a` and `b` are the same length. /// * `ctx`: [Context] of the circuit @@ -879,15 +875,15 @@ impl GateChip { let mut a = a.into_iter(); let mut b = b.into_iter().peekable(); - let b_starts_with_one = matches!(b.peek(), Some(Constant(c)) if c == &F::one()); + let b_starts_with_one = matches!(b.peek(), Some(Constant(c)) if c == &F::ONE); let cells = if b_starts_with_one { b.next(); let start_a = a.next().unwrap().into(); sum = *start_a.value(); iter::once(start_a) } else { - sum = F::zero(); - iter::once(Constant(F::zero())) + sum = F::ZERO; + iter::once(Constant(F::ZERO)) } .chain(a.zip(b).flat_map(|(a, b)| { let a = a.into(); @@ -918,17 +914,6 @@ impl GateInstructions for GateChip { &self.pow_of_two } - /// Returns the the value of `n` as a [ScalarField] element. - /// * `n`: the [u64] value to convert - fn get_field_element(&self, n: u64) -> F { - let get = self.field_element_cache.get(n as usize); - if let Some(fe) = get { - *fe - } else { - F::from(n) - } - } - /// Constrains and returns the inner product of ``. /// /// Assumes 'a' and 'b' are the same length. @@ -1022,11 +1007,11 @@ impl GateInstructions for GateChip { match self.strategy { GateStrategy::Vertical => { // Create an iterator starting with `var` and - let (a, b): (Vec<_>, Vec<_>) = std::iter::once((var, Constant(F::one()))) + let (a, b): (Vec<_>, Vec<_>) = std::iter::once((var, Constant(F::ONE))) .chain(values.into_iter().filter_map(|(c, va, vb)| { - if c == F::one() { + if c == F::ONE { Some((va, vb)) - } else if c != F::zero() { + } else if c != F::ZERO { let prod = self.mul(ctx, va, vb); Some((QuantumCell::Existing(prod), Constant(c))) } else { @@ -1064,7 +1049,7 @@ impl GateInstructions for GateChip { GateStrategy::Vertical => { let cells = [ Witness(diff_val), - Constant(F::one()), + Constant(F::ONE), b, a, b, @@ -1096,20 +1081,20 @@ impl GateInstructions for GateChip { let b = b.into(); let c = c.into(); let bc_val = *b.value() * c.value(); - let not_bc_val = F::one() - bc_val; - let not_a_val = *a.value() - F::one(); + let not_bc_val = F::ONE - bc_val; + let not_a_val = *a.value() - F::ONE; let out_val = bc_val + a.value() - bc_val * a.value(); let cells = [ Witness(not_bc_val), b, c, - Constant(F::one()), + Constant(F::ONE), Witness(not_a_val), Witness(not_bc_val), Witness(out_val), Witness(not_a_val), - Constant(F::one()), - Constant(F::one()), + Constant(F::ONE), + Constant(F::ONE), a, ]; ctx.assign_region_smart(cells, [0, 3, 7], [(4, 7), (0, 5)], []); @@ -1161,7 +1146,7 @@ impl GateInstructions for GateChip { ) -> AssignedValue { let exp_bits = self.num_to_bits(ctx, exp, max_bits); // standard square-and-mul approach - let mut acc = ctx.load_constant(F::one()); + let mut acc = ctx.load_constant(F::ONE); for (i, bit) in exp_bits.into_iter().rev().enumerate() { if i > 0 { // square diff --git a/halo2-base/src/gates/range.rs b/halo2-base/src/gates/range.rs index 4221feb6..83714e75 100644 --- a/halo2-base/src/gates/range.rs +++ b/halo2-base/src/gates/range.rs @@ -293,7 +293,7 @@ pub trait RangeInstructions { (bit_length(b) + self.lookup_bits() - 1) / self.lookup_bits() * self.lookup_bits(); self.range_check(ctx, a, range_bits); - self.check_less_than(ctx, a, Constant(self.gate().get_field_element(b)), range_bits) + self.check_less_than(ctx, a, Constant(F::from(b)), range_bits) } /// Performs a range check that `a` has at most `bit_length(b)` bits and then constrains that `a` is less than `b`. @@ -341,7 +341,7 @@ pub trait RangeInstructions { (bit_length(b) + self.lookup_bits() - 1) / self.lookup_bits() * self.lookup_bits(); self.range_check(ctx, a, range_bits); - self.is_less_than(ctx, a, Constant(self.gate().get_field_element(b)), range_bits) + self.is_less_than(ctx, a, Constant(F::from(b)), range_bits) } /// Performs a range check that `a` has at most `ceil(b.bits() / lookup_bits) * lookup_bits` bits and then constrains that `a` is in `[0,b)`. @@ -448,7 +448,7 @@ pub trait RangeInstructions { let [div_lo, div_hi, div, rem] = [-5, -4, -2, -1].map(|i| ctx.get(i)); self.range_check(ctx, div_lo, b_num_bits); if a_num_bits <= b_num_bits { - self.gate().assert_is_const(ctx, &div_hi, &F::zero()); + self.gate().assert_is_const(ctx, &div_hi, &F::ZERO); } else { self.range_check(ctx, div_hi, a_num_bits - b_num_bits); } @@ -481,7 +481,7 @@ pub trait RangeInstructions { ) -> AssignedValue { let a_big = fe_to_biguint(a.value()); let bit_v = F::from(a_big.bit(0)); - let two = self.gate().get_field_element(2u64); + let two = F::from(2u64); let h_v = F::from_bytes_le(&(a_big >> 1usize).to_bytes_le()); ctx.assign_region([Witness(bit_v), Witness(h_v), Constant(two), Existing(a)], [0]); @@ -519,7 +519,7 @@ impl RangeChip { let mut running_base = limb_base; let num_bases = F::CAPACITY as usize / lookup_bits; let mut limb_bases = Vec::with_capacity(num_bases + 1); - limb_bases.extend([Constant(F::one()), Constant(running_base)]); + limb_bases.extend([Constant(F::ONE), Constant(running_base)]); for _ in 2..=num_bases { running_base *= &limb_base; limb_bases.push(Constant(running_base)); @@ -570,7 +570,7 @@ impl RangeInstructions for RangeChip { /// * `ceil(range_bits / lookup_bits) * lookup_bits <= F::CAPACITY` fn range_check(&self, ctx: &mut Context, a: AssignedValue, range_bits: usize) { if range_bits == 0 { - self.gate.assert_is_const(ctx, &a, &F::zero()); + self.gate.assert_is_const(ctx, &a, &F::ZERO); return; } // the number of limbs @@ -640,10 +640,10 @@ impl RangeInstructions for RangeChip { let cells = [ Witness(shift_a_val - b.value()), b, - Constant(F::one()), + Constant(F::ONE), Witness(shift_a_val), Constant(-pow_of_two), - Constant(F::one()), + Constant(F::ONE), a, ]; ctx.assign_region(cells, [0, 3]); @@ -689,10 +689,10 @@ impl RangeInstructions for RangeChip { [ Witness(shifted_val), b, - Constant(F::one()), + Constant(F::ONE), Witness(shift_a_val), Constant(-pow_padded), - Constant(F::one()), + Constant(F::ONE), a, ], [0, 3], diff --git a/halo2-base/src/gates/tests/general.rs b/halo2-base/src/gates/tests/general.rs index 2569096a..a212fb77 100644 --- a/halo2-base/src/gates/tests/general.rs +++ b/halo2-base/src/gates/tests/general.rs @@ -1,3 +1,4 @@ +use crate::ff::Field; use crate::halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; use crate::utils::{BigPrimeField, ScalarField}; use crate::{ @@ -9,7 +10,6 @@ use crate::{ utils::testing::base_test, }; use crate::{Context, QuantumCell::Constant}; -use ff::Field; use rand::rngs::OsRng; use rayon::prelude::*; @@ -29,7 +29,7 @@ fn gate_tests(ctx: &mut Context, inputs: [F; 3]) { // test idx_to_indicator chip.idx_to_indicator(ctx, Constant(F::from(3u64)), 4); - let bits = ctx.assign_witnesses([F::zero(), F::one()]); + let bits = ctx.assign_witnesses([F::ZERO, F::ONE]); chip.bits_to_indicator(ctx, &bits); chip.is_equal(ctx, b, a); @@ -56,9 +56,9 @@ fn test_multithread_gates() { builder.threads[0].extend(new_threads); // auto-tune circuit - builder.config(k, Some(9)); + let config_params = builder.config(k, Some(9)); // create circuit - let circuit = RangeCircuitBuilder::mock(builder); + let circuit = RangeCircuitBuilder::mock(builder, config_params); MockProver::run(k as u32, &circuit, vec![]).unwrap().assert_satisfied(); } diff --git a/halo2-base/src/gates/tests/idx_to_indicator.rs b/halo2-base/src/gates/tests/idx_to_indicator.rs index 4b34e80c..dff29eed 100644 --- a/halo2-base/src/gates/tests/idx_to_indicator.rs +++ b/halo2-base/src/gates/tests/idx_to_indicator.rs @@ -1,3 +1,4 @@ +use crate::ff::Field; use crate::{ gates::{ builder::{GateThreadBuilder, RangeCircuitBuilder}, @@ -12,7 +13,6 @@ use crate::{ utils::testing::{check_proof, gen_proof}, QuantumCell::Witness, }; -use ff::Field; use itertools::Itertools; use rand::{rngs::OsRng, thread_rng, Rng}; @@ -25,9 +25,8 @@ fn test_idx_to_indicator_gen(k: u32, len: usize) { let indicator = gate.idx_to_indicator(builder.main(0), dummy_idx, len); // get the offsets of the indicator cells for later 'pranking' let ind_offsets = indicator.iter().map(|ind| ind.cell.unwrap().offset).collect::>(); - // set env vars - builder.config(k as usize, Some(9)); - let circuit = RangeCircuitBuilder::keygen(builder); + let config_params = builder.config(k as usize, Some(9)); + let circuit = RangeCircuitBuilder::keygen(builder, config_params.clone()); let params = ParamsKZG::setup(k, OsRng); // generate proving key @@ -46,7 +45,7 @@ fn test_idx_to_indicator_gen(k: u32, len: usize) { for (offset, witness) in ind_offsets.iter().zip_eq(ind_witnesses) { builder.main(0).advice[*offset] = Assigned::Trivial(*witness); } - let circuit = RangeCircuitBuilder::prover(builder, vec![vec![]]); // no break points + let circuit = RangeCircuitBuilder::prover(builder, config_params.clone(), vec![vec![]]); // no break points gen_proof(¶ms, &pk, circuit) }; diff --git a/halo2-base/src/gates/tests/neg_prop.rs b/halo2-base/src/gates/tests/neg_prop.rs index d9548a60..27994ac0 100644 --- a/halo2-base/src/gates/tests/neg_prop.rs +++ b/halo2-base/src/gates/tests/neg_prop.rs @@ -1,32 +1,19 @@ -use ff::Field; -use itertools::Itertools; -use num_bigint::BigUint; -use proptest::{collection::vec, prelude::*}; -use rand::rngs::OsRng; - -use crate::{ - gates::builder::set_lookup_bits, - halo2_proofs::{ - dev::MockProver, - halo2curves::{bn256::Fr, FieldExt}, - plonk::Assigned, - }, -}; use crate::{ + ff::Field, gates::{ - builder::{GateThreadBuilder, RangeCircuitBuilder}, - range::{RangeChip, RangeInstructions}, - tests::{ - pos_prop::{rand_bin_witness, rand_fr, rand_witness}, - utils, - }, - GateChip, GateInstructions, + range::RangeInstructions, + tests::{pos_prop::rand_fr, utils}, + GateInstructions, }, - utils::{biguint_to_fe, bit_length, fe_to_biguint, ScalarField}, - QuantumCell, + halo2_proofs::halo2curves::bn256::Fr, + utils::{biguint_to_fe, bit_length, fe_to_biguint, testing::base_test, ScalarField}, QuantumCell::Witness, }; +use num_bigint::BigUint; +use proptest::{collection::vec, prelude::*}; +use rand::rngs::OsRng; + // Strategies for generating random witnesses prop_compose! { // length == 1 is just selecting [0] which should be covered in unit test @@ -41,8 +28,8 @@ prop_compose! { prop_compose! { fn select_strat(k_bounds: (usize, usize)) - (k in k_bounds.0..=k_bounds.1, a in rand_witness(), b in rand_witness(), sel in rand_bin_witness(), rand_output in rand_fr()) - -> (usize, QuantumCell, QuantumCell, QuantumCell, Fr) { + (k in k_bounds.0..=k_bounds.1, a in rand_fr(), b in rand_fr(), sel in any::(), rand_output in rand_fr()) + -> (usize, Fr, Fr, bool, Fr) { (k, a, b, sel, rand_output) } } @@ -50,8 +37,8 @@ prop_compose! { prop_compose! { fn select_by_indicator_strat(k_bounds: (usize, usize), max_size: usize) (k in k_bounds.0..=k_bounds.1, len in 2usize..=max_size) - (k in Just(k), a in vec(rand_witness(), len), idx in 0..len, rand_output in rand_fr()) - -> (usize, Vec>, usize, Fr) { + (k in Just(k), a in vec(rand_fr(), len), idx in 0..len, rand_output in rand_fr()) + -> (usize, Vec, usize, Fr) { (k, a, idx, rand_output) } } @@ -59,8 +46,8 @@ prop_compose! { prop_compose! { fn select_from_idx_strat(k_bounds: (usize, usize), max_size: usize) (k in k_bounds.0..=k_bounds.1, len in 2usize..=max_size) - (k in Just(k), cells in vec(rand_witness(), len), idx in 0..len, rand_output in rand_fr()) - -> (usize, Vec>, usize, Fr) { + (k in Just(k), cells in vec(rand_fr(), len), idx in 0..len, rand_output in rand_fr()) + -> (usize, Vec, usize, Fr) { (k, cells, idx, rand_output) } } @@ -68,8 +55,8 @@ prop_compose! { prop_compose! { fn inner_product_strat(k_bounds: (usize, usize), max_size: usize) (k in k_bounds.0..=k_bounds.1, len in 2usize..=max_size) - (k in Just(k), a in vec(rand_witness(), len), b in vec(rand_witness(), len), rand_output in rand_fr()) - -> (usize, Vec>, Vec>, Fr) { + (k in Just(k), a in vec(rand_fr(), len), b in vec(rand_fr(), len), rand_output in rand_fr()) + -> (usize, Vec, Vec, Fr) { (k, a, b, rand_output) } } @@ -77,8 +64,8 @@ prop_compose! { prop_compose! { fn inner_product_left_last_strat(k_bounds: (usize, usize), max_size: usize) (k in k_bounds.0..=k_bounds.1, len in 2usize..=max_size) - (k in Just(k), a in vec(rand_witness(), len), b in vec(rand_witness(), len), rand_output in (rand_fr(), rand_fr())) - -> (usize, Vec>, Vec>, (Fr, Fr)) { + (k in Just(k), a in vec(rand_fr(), len), b in vec(rand_fr(), len), rand_output in (rand_fr(), rand_fr())) + -> (usize, Vec, Vec, (Fr, Fr)) { (k, a, b, rand_output) } } @@ -122,7 +109,7 @@ fn check_idx_to_indicator(idx: Fr, len: usize, ind_witnesses: &[Fr]) -> bool { return false; } - let idx_val = idx.get_lower_128() as usize; + let idx_val = idx.get_lower_64() as usize; // Check that all indexes are zero except for the one at idx for (i, v) in ind_witnesses.iter().enumerate() { @@ -134,265 +121,146 @@ fn check_idx_to_indicator(idx: Fr, len: usize, ind_witnesses: &[Fr]) -> bool { } // verify rand_output == a if sel == 1, rand_output == b if sel == 0 -fn check_select(a: Fr, b: Fr, sel: Fr, rand_output: Fr) -> bool { - if (sel == Fr::zero() && rand_output != b) || (sel == Fr::one() && rand_output != a) { +fn check_select(a: Fr, b: Fr, sel: bool, rand_output: Fr) -> bool { + if (!sel && rand_output != b) || (sel && rand_output != a) { return false; } true } -fn neg_test_idx_to_indicator(k: usize, len: usize, idx: usize, ind_witnesses: &[Fr]) -> bool { - let mut builder = GateThreadBuilder::mock(); - let gate = GateChip::default(); - // assign value to advice column before by assigning `idx` via ctx.load() -> use same method as ind_offsets to get offset - let dummy_idx = Witness(Fr::from(idx as u64)); - let indicator = gate.idx_to_indicator(builder.main(0), dummy_idx, len); - // get the offsets of the indicator cells for later 'pranking' - builder.config(k, Some(9)); - let ind_offsets = indicator.iter().map(|ind| ind.cell.unwrap().offset).collect::>(); - // prank the indicator cells - // TODO: prank the entire advice column with random values - for (offset, witness) in ind_offsets.iter().zip_eq(ind_witnesses) { - builder.main(0).advice[*offset] = Assigned::Trivial(*witness); - } - // Get idx and indicator from advice column - // Apply check instance function to `idx` and `ind_witnesses` - let circuit = RangeCircuitBuilder::mock(builder); // no break points - // Check soundness of witness values +fn neg_test_idx_to_indicator(k: usize, len: usize, idx: usize, ind_witnesses: &[Fr]) { + // Check soundness of witness values let is_valid_witness = check_idx_to_indicator(Fr::from(idx as u64), len, ind_witnesses); - match MockProver::run(k as u32, &circuit, vec![]).unwrap().verify() { - // if the proof is valid, then the instance should be valid -> return true - Ok(_) => is_valid_witness, - // if the proof is invalid, ignore - Err(_) => !is_valid_witness, - } + base_test().k(k as u32).expect_satisfied(is_valid_witness).run_gate(|ctx, gate| { + // assign value to advice column before by assigning `idx` via ctx.load() -> use same method as ind_offsets to get offset + let dummy_idx = Witness(Fr::from(idx as u64)); + let mut indicator = gate.idx_to_indicator(ctx, dummy_idx, len); + for (advice, prank_val) in indicator.iter_mut().zip(ind_witnesses) { + advice.debug_prank(ctx, *prank_val); + } + }); } -fn neg_test_select( - k: usize, - a: QuantumCell, - b: QuantumCell, - sel: QuantumCell, - rand_output: Fr, -) -> bool { - let mut builder = GateThreadBuilder::mock(); - let gate = GateChip::default(); - // add select gate - let select = gate.select(builder.main(0), a, b, sel); - - // Get the offset of `select`s output for later 'pranking' - builder.config(k, Some(9)); - let select_offset = select.cell.unwrap().offset; - // Prank the output - builder.main(0).advice[select_offset] = Assigned::Trivial(rand_output); - - let circuit = RangeCircuitBuilder::mock(builder); // no break points - // Check soundness of output - let is_valid_instance = check_select(*a.value(), *b.value(), *sel.value(), rand_output); - match MockProver::run(k as u32, &circuit, vec![]).unwrap().verify() { - // if the proof is valid, then the instance should be valid -> return true - Ok(_) => is_valid_instance, - // if the proof is invalid, ignore - Err(_) => !is_valid_instance, - } +fn neg_test_select(k: usize, a: Fr, b: Fr, sel: bool, prank_output: Fr) { + // Check soundness of output + let is_valid_instance = check_select(a, b, sel, prank_output); + base_test().k(k as u32).expect_satisfied(is_valid_instance).run_gate(|ctx, gate| { + let [a, b, sel] = [a, b, Fr::from(sel)].map(|x| ctx.load_witness(x)); + let select = gate.select(ctx, a, b, sel); + select.debug_prank(ctx, prank_output); + }) } -fn neg_test_select_by_indicator( - k: usize, - a: Vec>, - idx: usize, - rand_output: Fr, -) -> bool { - let mut builder = GateThreadBuilder::mock(); - let gate = GateChip::default(); - - let indicator = gate.idx_to_indicator(builder.main(0), Witness(Fr::from(idx as u64)), a.len()); - let a_idx = gate.select_by_indicator(builder.main(0), a.clone(), indicator); - builder.config(k, Some(9)); - - let a_idx_offset = a_idx.cell.unwrap().offset; - builder.main(0).advice[a_idx_offset] = Assigned::Trivial(rand_output); - let circuit = RangeCircuitBuilder::mock(builder); // no break points - // Check soundness of witness values - // retrieve the value of a[idx] and check that it is equal to rand_output - let is_valid_witness = rand_output == *a[idx].value(); - match MockProver::run(k as u32, &circuit, vec![]).unwrap().verify() { - // if the proof is valid, then the instance should be valid -> return true - Ok(_) => is_valid_witness, - // if the proof is invalid, ignore - Err(_) => !is_valid_witness, - } +fn neg_test_select_by_indicator(k: usize, a: Vec, idx: usize, prank_output: Fr) { + // retrieve the value of a[idx] and check that it is equal to rand_output + let is_valid_witness = prank_output == a[idx]; + base_test().k(k as u32).expect_satisfied(is_valid_witness).run_gate(|ctx, gate| { + let indicator = gate.idx_to_indicator(ctx, Witness(Fr::from(idx as u64)), a.len()); + let a = ctx.assign_witnesses(a); + let a_idx = gate.select_by_indicator(ctx, a, indicator); + a_idx.debug_prank(ctx, prank_output); + }); } -fn neg_test_select_from_idx( - k: usize, - cells: Vec>, - idx: usize, - rand_output: Fr, -) -> bool { - let mut builder = GateThreadBuilder::mock(); - let gate = GateChip::default(); - - let idx_val = - gate.select_from_idx(builder.main(0), cells.clone(), Witness(Fr::from(idx as u64))); - builder.config(k, Some(9)); - - let idx_offset = idx_val.cell.unwrap().offset; - builder.main(0).advice[idx_offset] = Assigned::Trivial(rand_output); - let circuit = RangeCircuitBuilder::mock(builder); // no break points - // Check soundness of witness values - let is_valid_witness = rand_output == *cells[idx].value(); - match MockProver::run(k as u32, &circuit, vec![]).unwrap().verify() { - // if the proof is valid, then the instance should be valid -> return true - Ok(_) => is_valid_witness, - // if the proof is invalid, ignore - Err(_) => !is_valid_witness, - } +fn neg_test_select_from_idx(k: usize, cells: Vec, idx: usize, prank_output: Fr) { + // Check soundness of witness values + let is_valid_witness = prank_output == cells[idx]; + base_test().k(k as u32).expect_satisfied(is_valid_witness).run_gate(|ctx, gate| { + let cells = ctx.assign_witnesses(cells); + let idx_val = gate.select_from_idx(ctx, cells, Witness(Fr::from(idx as u64))); + idx_val.debug_prank(ctx, prank_output); + }); } -fn neg_test_inner_product( - k: usize, - a: Vec>, - b: Vec>, - rand_output: Fr, -) -> bool { - let mut builder = GateThreadBuilder::mock(); - let gate = GateChip::default(); - - let inner_product = gate.inner_product(builder.main(0), a.clone(), b.clone()); - builder.config(k, Some(9)); - - let inner_product_offset = inner_product.cell.unwrap().offset; - builder.main(0).advice[inner_product_offset] = Assigned::Trivial(rand_output); - let circuit = RangeCircuitBuilder::mock(builder); // no break points - // Check soundness of witness values - let is_valid_witness = rand_output == utils::inner_product_ground_truth(&(a, b)); - match MockProver::run(k as u32, &circuit, vec![]).unwrap().verify() { - // if the proof is valid, then the instance should be valid -> return true - Ok(_) => is_valid_witness, - // if the proof is invalid, ignore - Err(_) => !is_valid_witness, - } +fn neg_test_inner_product(k: usize, a: Vec, b: Vec, prank_output: Fr) { + let is_valid_witness = prank_output == utils::inner_product_ground_truth(&a, &b); + base_test().k(k as u32).expect_satisfied(is_valid_witness).run_gate(|ctx, gate| { + let a = ctx.assign_witnesses(a); + let inner_product = gate.inner_product(ctx, a, b.into_iter().map(Witness)); + inner_product.debug_prank(ctx, prank_output); + }); } fn neg_test_inner_product_left_last( k: usize, - a: Vec>, - b: Vec>, - rand_output: (Fr, Fr), -) -> bool { - let mut builder = GateThreadBuilder::mock(); - let gate = GateChip::default(); - - let inner_product = gate.inner_product_left_last(builder.main(0), a.clone(), b.clone()); - builder.config(k, Some(9)); - - let inner_product_offset = - (inner_product.0.cell.unwrap().offset, inner_product.1.cell.unwrap().offset); - // prank the output cells - builder.main(0).advice[inner_product_offset.0] = Assigned::Trivial(rand_output.0); - builder.main(0).advice[inner_product_offset.1] = Assigned::Trivial(rand_output.1); - let circuit = RangeCircuitBuilder::mock(builder); // no break points - // Check soundness of witness values - // (inner_product_ground_truth, a[a.len()-1]) - let inner_product_ground_truth = utils::inner_product_ground_truth(&(a.clone(), b)); - let is_valid_witness = - rand_output.0 == inner_product_ground_truth && rand_output.1 == *a[a.len() - 1].value(); - match MockProver::run(k as u32, &circuit, vec![]).unwrap().verify() { - // if the proof is valid, then the instance should be valid -> return true - Ok(_) => is_valid_witness, - // if the proof is invalid, ignore - Err(_) => !is_valid_witness, - } + a: Vec, + b: Vec, + (prank_output, prank_a_last): (Fr, Fr), +) { + let is_valid_witness = prank_output == utils::inner_product_ground_truth(&a, &b) + && prank_a_last == *a.last().unwrap(); + base_test().k(k as u32).expect_satisfied(is_valid_witness).run_gate(|ctx, gate| { + let a = ctx.assign_witnesses(a); + let (inner_product, a_last) = + gate.inner_product_left_last(ctx, a, b.into_iter().map(Witness)); + inner_product.debug_prank(ctx, prank_output); + a_last.debug_prank(ctx, prank_a_last); + }); } // Range Check -fn neg_test_range_check(k: usize, range_bits: usize, lookup_bits: usize, rand_a: Fr) -> bool { - let mut builder = GateThreadBuilder::mock(); - let gate = RangeChip::default(lookup_bits); - - let a_witness = builder.main(0).load_witness(rand_a); - gate.range_check(builder.main(0), a_witness, range_bits); - - builder.config(k, Some(9)); - set_lookup_bits(lookup_bits); - let circuit = RangeCircuitBuilder::mock(builder); // no break points - // Check soundness of witness values +fn neg_test_range_check(k: usize, range_bits: usize, lookup_bits: usize, rand_a: Fr) { let correct = fe_to_biguint(&rand_a).bits() <= range_bits as u64; - - MockProver::run(k as u32, &circuit, vec![]).unwrap().verify().is_ok() == correct + base_test().k(k as u32).lookup_bits(lookup_bits).expect_satisfied(correct).run(|ctx, range| { + let a_witness = ctx.load_witness(rand_a); + range.range_check(ctx, a_witness, range_bits); + }) } // TODO: expand to prank output of is_less_than_safe() -fn neg_test_is_less_than_safe( - k: usize, - b: u64, - lookup_bits: usize, - rand_a: Fr, - prank_out: bool, -) -> bool { - let mut builder = GateThreadBuilder::mock(); - let gate = RangeChip::default(lookup_bits); - let ctx = builder.main(0); - - let a_witness = ctx.load_witness(rand_a); // cannot prank this later because this witness will be copy-constrained - let out = gate.is_less_than_safe(ctx, a_witness, b); - - let out_idx = out.cell.unwrap().offset; - ctx.advice[out_idx] = Assigned::Trivial(Fr::from(prank_out)); - - builder.config(k, Some(9)); - set_lookup_bits(lookup_bits); - let circuit = RangeCircuitBuilder::mock(builder); // no break points - // Check soundness of witness values - // println!("rand_a: {rand_a:?}, b: {b:?}"); +fn neg_test_is_less_than_safe(k: usize, b: u64, lookup_bits: usize, rand_a: Fr, prank_out: bool) { let a_big = fe_to_biguint(&rand_a); let is_lt = a_big < BigUint::from(b); let correct = (is_lt == prank_out) && (a_big.bits() as usize <= (bit_length(b) + lookup_bits - 1) / lookup_bits * lookup_bits); // circuit should always fail if `a` doesn't pass range check - MockProver::run(k as u32, &circuit, vec![]).unwrap().verify().is_ok() == correct + + base_test().k(k as u32).lookup_bits(lookup_bits).expect_satisfied(correct).run(|ctx, range| { + let a_witness = ctx.load_witness(rand_a); + let out = range.is_less_than_safe(ctx, a_witness, b); + out.debug_prank(ctx, Fr::from(prank_out)); + }); } proptest! { // Note setting the minimum value of k to 8 is intentional as it is the smallest value that will not cause an `out of columns` error. Should be noted that filtering by len * (number cells per iteration) < 2^k leads to the filtering of to many cases and the failure of the tests w/o any runs. #[test] fn prop_test_neg_idx_to_indicator((k, len, idx, witness_vals) in idx_to_indicator_strat((10,20),100)) { - prop_assert!(neg_test_idx_to_indicator(k, len, idx, witness_vals.as_slice())); + neg_test_idx_to_indicator(k, len, idx, witness_vals.as_slice()); } #[test] fn prop_test_neg_select((k, a, b, sel, rand_output) in select_strat((10,20))) { - prop_assert!(neg_test_select(k, a, b, sel, rand_output)); + neg_test_select(k, a, b, sel, rand_output); } #[test] fn prop_test_neg_select_by_indicator((k, a, idx, rand_output) in select_by_indicator_strat((12,20),100)) { - prop_assert!(neg_test_select_by_indicator(k, a, idx, rand_output)); + neg_test_select_by_indicator(k, a, idx, rand_output); } #[test] fn prop_test_neg_select_from_idx((k, cells, idx, rand_output) in select_from_idx_strat((10,20),100)) { - prop_assert!(neg_test_select_from_idx(k, cells, idx, rand_output)); + neg_test_select_from_idx(k, cells, idx, rand_output); } #[test] fn prop_test_neg_inner_product((k, a, b, rand_output) in inner_product_strat((10,20),100)) { - prop_assert!(neg_test_inner_product(k, a, b, rand_output)); + neg_test_inner_product(k, a, b, rand_output); } #[test] fn prop_test_neg_inner_product_left_last((k, a, b, rand_output) in inner_product_left_last_strat((10,20),100)) { - prop_assert!(neg_test_inner_product_left_last(k, a, b, rand_output)); + neg_test_inner_product_left_last(k, a, b, rand_output); } #[test] fn prop_test_neg_range_check((k, range_bits, lookup_bits, rand_a) in range_check_strat((10,23),90)) { - prop_assert!(neg_test_range_check(k, range_bits, lookup_bits, rand_a)); + neg_test_range_check(k, range_bits, lookup_bits, rand_a); } #[test] fn prop_test_neg_is_less_than_safe((k, b, lookup_bits, rand_a, out) in is_less_than_safe_strat((10,20))) { - prop_assert!(neg_test_is_less_than_safe(k, b, lookup_bits, rand_a, out)); + neg_test_is_less_than_safe(k, b, lookup_bits, rand_a, out); } } diff --git a/halo2-base/src/gates/tests/pos_prop.rs b/halo2-base/src/gates/tests/pos_prop.rs index dc4e3702..270bb015 100644 --- a/halo2-base/src/gates/tests/pos_prop.rs +++ b/halo2-base/src/gates/tests/pos_prop.rs @@ -1,17 +1,15 @@ use std::cmp::max; +use crate::ff::{Field, PrimeField}; use crate::gates::tests::{flex_gate, range, utils::*, Fr}; use crate::utils::{biguint_to_fe, bit_length, fe_to_biguint}; use crate::{QuantumCell, QuantumCell::Witness}; -use ff::{Field, PrimeField}; use num_bigint::{BigUint, RandBigInt, RandomBits}; use proptest::{collection::vec, prelude::*}; use rand::rngs::StdRng; use rand::SeedableRng; -//TODO: implement Copy for rand witness and rand fr to allow for array creation -// create vec and convert to array??? -//TODO: implement arbitrary for fr using looks like you'd probably need to implement your own TestFr struct to implement Arbitrary: https://docs.rs/quickcheck/latest/quickcheck/trait.Arbitrary.html , can probably just hack it from Fr = [u64; 4] + prop_compose! { pub fn rand_fr()(seed in any::()) -> Fr { let rng = StdRng::seed_from_u64(seed); @@ -161,14 +159,18 @@ proptest! { #[test] fn prop_test_inner_product(inputs in (vec(rand_witness(), 0..=100), vec(rand_witness(), 0..=100)).prop_filter("Input vectors must have equal length", |(a, b)| a.len() == b.len())) { - let ground_truth = inner_product_ground_truth(&inputs); + let a = inputs.0.iter().map(|x| *x.value()).collect::>(); + let b = inputs.1.iter().map(|x| *x.value()).collect::>(); + let ground_truth = inner_product_ground_truth(&a, &b); let result = flex_gate::test_inner_product(inputs); prop_assert_eq!(result, ground_truth); } #[test] fn prop_test_inner_product_left_last(inputs in (vec(rand_witness(), 1..=100), vec(rand_witness(), 1..=100)).prop_filter("Input vectors must have equal length", |(a, b)| a.len() == b.len())) { - let ground_truth = inner_product_left_last_ground_truth(&inputs); + let a = inputs.0.iter().map(|x| *x.value()).collect::>(); + let b = inputs.1.iter().map(|x| *x.value()).collect::>(); + let ground_truth = inner_product_left_last_ground_truth(&a, &b); let result = flex_gate::test_inner_product_left_last(inputs); prop_assert_eq!(result, ground_truth); } diff --git a/halo2-base/src/gates/tests/utils.rs b/halo2-base/src/gates/tests/utils.rs index 59942637..8ae095da 100644 --- a/halo2-base/src/gates/tests/utils.rs +++ b/halo2-base/src/gates/tests/utils.rs @@ -32,28 +32,20 @@ pub fn mul_add_ground_truth(inputs: &[QuantumCell]) -> F { } pub fn mul_not_ground_truth(inputs: &[QuantumCell]) -> F { - (F::one() - *inputs[0].value()) * *inputs[1].value() + (F::ONE - *inputs[0].value()) * *inputs[1].value() } pub fn div_unsafe_ground_truth(inputs: &[QuantumCell]) -> F { inputs[1].value().invert().unwrap() * *inputs[0].value() } -pub fn inner_product_ground_truth( - inputs: &(Vec>, Vec>), -) -> F { - inputs - .0 - .iter() - .zip(inputs.1.iter()) - .fold(F::zero(), |acc, (a, b)| acc + (*a.value() * *b.value())) -} - -pub fn inner_product_left_last_ground_truth( - inputs: &(Vec>, Vec>), -) -> (F, F) { - let product = inner_product_ground_truth(inputs); - let last = *inputs.0.last().unwrap().value(); +pub fn inner_product_ground_truth(a: &[F], b: &[F]) -> F { + a.iter().zip(b.iter()).fold(F::ZERO, |acc, (&a, &b)| acc + a * b) +} + +pub fn inner_product_left_last_ground_truth(a: &[F], b: &[F]) -> (F, F) { + let product = inner_product_ground_truth(a, b); + let last = *a.last().unwrap(); (product, last) } @@ -62,7 +54,7 @@ pub fn inner_product_with_sums_ground_truth( ) -> Vec { let (a, b) = &input; let mut result = Vec::new(); - let mut sum = F::zero(); + let mut sum = F::ZERO; // TODO: convert to fold for (ai, bi) in a.iter().zip(b) { let product = *ai.value() * *bi.value(); @@ -75,9 +67,10 @@ pub fn inner_product_with_sums_ground_truth( pub fn sum_products_with_coeff_and_var_ground_truth( input: &(Vec<(F, QuantumCell, QuantumCell)>, QuantumCell), ) -> F { - let expected = input.0.iter().fold(F::zero(), |acc, (coeff, cell1, cell2)| { - acc + *coeff * *cell1.value() * *cell2.value() - }) + *input.1.value(); + let expected = + input.0.iter().fold(F::ZERO, |acc, (coeff, cell1, cell2)| { + acc + *coeff * *cell1.value() * *cell2.value() + }) + *input.1.value(); expected } @@ -86,7 +79,7 @@ pub fn and_ground_truth(inputs: &[QuantumCell]) -> F { } pub fn not_ground_truth(a: &QuantumCell) -> F { - F::one() - *a.value() + F::ONE - *a.value() } pub fn select_ground_truth(inputs: &[QuantumCell]) -> F { @@ -100,7 +93,7 @@ pub fn or_and_ground_truth(inputs: &[QuantumCell]) -> F { pub fn idx_to_indicator_ground_truth(inputs: (QuantumCell, usize)) -> Vec { let (idx, size) = inputs; - let mut indicator = vec![F::zero(); size]; + let mut indicator = vec![F::ZERO; size]; let mut idx_value = size + 1; for i in 0..size as u64 { if F::from(i) == *idx.value() { @@ -109,7 +102,7 @@ pub fn idx_to_indicator_ground_truth(inputs: (QuantumCell, us } } if idx_value < size { - indicator[idx_value] = F::one(); + indicator[idx_value] = F::ONE; } indicator } @@ -118,7 +111,7 @@ pub fn select_by_indicator_ground_truth( inputs: &(Vec>, QuantumCell), ) -> F { let mut idx_value = inputs.0.len() + 1; - let mut indicator = vec![F::zero(); inputs.0.len()]; + let mut indicator = vec![F::ZERO; inputs.0.len()]; for i in 0..inputs.0.len() as u64 { if F::from(i) == *inputs.1.value() { idx_value = i as usize; @@ -126,10 +119,10 @@ pub fn select_by_indicator_ground_truth( } } if idx_value < inputs.0.len() { - indicator[idx_value] = F::one(); + indicator[idx_value] = F::ONE; } // take cross product of indicator and inputs.0 - inputs.0.iter().zip(indicator.iter()).fold(F::zero(), |acc, (a, b)| acc + (*a.value() * *b)) + inputs.0.iter().zip(indicator.iter()).fold(F::ZERO, |acc, (a, b)| acc + (*a.value() * *b)) } pub fn select_from_idx_ground_truth( @@ -142,22 +135,22 @@ pub fn select_from_idx_ground_truth( return *inputs.0[i as usize].value(); } } - F::zero() + F::ZERO } pub fn is_zero_ground_truth(x: F) -> F { if x.is_zero().into() { - F::one() + F::ONE } else { - F::zero() + F::ZERO } } pub fn is_equal_ground_truth(inputs: &[QuantumCell]) -> F { if inputs[0].value() == inputs[1].value() { - F::one() + F::ONE } else { - F::zero() + F::ZERO } } @@ -170,9 +163,9 @@ pub fn lagrange_eval_ground_truth(inputs: &[F]) -> (F, F) { pub fn is_less_than_ground_truth(inputs: (F, F)) -> F { if inputs.0 < inputs.1 { - F::one() + F::ONE } else { - F::zero() + F::ZERO } } diff --git a/halo2-base/src/lib.rs b/halo2-base/src/lib.rs index 358f8b4a..9f20386e 100644 --- a/halo2-base/src/lib.rs +++ b/halo2-base/src/lib.rs @@ -1,6 +1,5 @@ //! Base library to build Halo2 circuits. #![feature(generic_const_exprs)] -#![feature(const_cmp)] #![allow(incomplete_features)] #![feature(stmt_expr_attributes)] #![feature(trait_alias)] @@ -36,6 +35,7 @@ pub use halo2_proofs; #[cfg(feature = "halo2-axiom")] pub use halo2_proofs_axiom as halo2_proofs; +use halo2_proofs::halo2curves::ff; use halo2_proofs::plonk::Assigned; use utils::ScalarField; @@ -126,10 +126,10 @@ impl AssignedValue { } } - /// Debug helper function for writing negative tests. This will change the **witness** value of the assigned cell - /// to `prank_value`. It does not change any constraints. - pub fn debug_prank(&mut self, prank_value: F) { - self.value = Assigned::Trivial(prank_value); + /// Debug helper function for writing negative tests. This will change the **witness** value in `ctx` corresponding to `self.offset`. + /// This assumes that `ctx` is the context that `self` lies in. + pub fn debug_prank(&self, ctx: &mut Context, prank_value: F) { + ctx.advice[self.cell.unwrap().offset] = Assigned::Trivial(prank_value); } } @@ -415,7 +415,7 @@ impl Context { if let Some(zcell) = &self.zero_cell { return *zcell; } - let zero_cell = self.load_constant(F::zero()); + let zero_cell = self.load_constant(F::ZERO); self.zero_cell = Some(zero_cell); zero_cell } @@ -424,8 +424,8 @@ impl Context { /// The `MockProver` will print out the row, column where it fails, so it serves as a debugging "break point" /// so you can add to your code to search for where the actual constraint failure occurs. pub fn debug_assert_false(&mut self) { - let one = self.load_constant(F::one()); - let zero = self.load_zero(); - self.constrain_equal(&one, &zero); + let three = self.load_witness(F::from(3)); + let four = self.load_witness(F::from(4)); + self.constrain_equal(&three, &four); } } diff --git a/halo2-base/src/safe_types/mod.rs b/halo2-base/src/safe_types/mod.rs index fe1ea375..5a18c158 100644 --- a/halo2-base/src/safe_types/mod.rs +++ b/halo2-base/src/safe_types/mod.rs @@ -39,12 +39,15 @@ impl pub const BYTES_PER_ELE: usize = BYTES_PER_ELE; /// Total bits of this type. pub const TOTAL_BITS: usize = TOTAL_BITS; - /// Number of bits of each element. - pub const BITS_PER_ELE: usize = min(TOTAL_BITS, BYTES_PER_ELE * BITS_PER_BYTE); /// Number of elements of this type. pub const VALUE_LENGTH: usize = (TOTAL_BITS + BYTES_PER_ELE * BITS_PER_BYTE - 1) / (BYTES_PER_ELE * BITS_PER_BYTE); + /// Number of bits of each element. + pub fn bits_per_ele() -> usize { + min(TOTAL_BITS, BYTES_PER_ELE * BITS_PER_BYTE) + } + // new is private so Safetype can only be constructed by this crate. fn new(raw_values: RawAssignedValues) -> Self { assert!(raw_values.len() == Self::VALUE_LENGTH, "Invalid raw values length"); @@ -103,7 +106,7 @@ impl<'a, F: ScalarField> SafeTypeChip<'a, F> { ctx: &mut Context, inputs: RawAssignedValues, ) -> SafeType { - let element_bits = SafeType::::BITS_PER_ELE; + let element_bits = SafeType::::bits_per_ele(); let bits = TOTAL_BITS; assert!( inputs.len() * BITS_PER_BYTE == max(bits, BITS_PER_BYTE), diff --git a/halo2-base/src/safe_types/tests.rs b/halo2-base/src/safe_types/tests.rs index ccf49930..e71f3159 100644 --- a/halo2-base/src/safe_types/tests.rs +++ b/halo2-base/src/safe_types/tests.rs @@ -1,5 +1,4 @@ use crate::{ - gates::builder::set_lookup_bits, halo2_proofs::{halo2curves::bn256::Fr, poly::kzg::commitment::ParamsKZG}, utils::testing::{check_proof, gen_proof}, }; @@ -28,7 +27,6 @@ fn test_raw_bytes_to_gen( // first create proving and verifying key let mut builder = GateThreadBuilder::::keygen(); let lookup_bits = 3; - set_lookup_bits(lookup_bits); let range_chip = RangeChip::::default(lookup_bits); let safe_type_chip = SafeTypeChip::new(&range_chip); @@ -41,9 +39,10 @@ fn test_raw_bytes_to_gen( // get the offsets of the safe value cells for later 'pranking' let safe_value_offsets = safe_value.value().iter().map(|v| v.cell.unwrap().offset).collect::>(); - // set env vars - builder.config(k as usize, Some(9)); - let circuit = RangeCircuitBuilder::keygen(builder); + + let mut config_params = builder.config(k as usize, Some(9)); + config_params.lookup_bits = Some(lookup_bits); + let circuit = RangeCircuitBuilder::keygen(builder, config_params.clone()); let params = ParamsKZG::setup(k, OsRng); // generate proving key @@ -64,7 +63,7 @@ fn test_raw_bytes_to_gen( for (offset, witness) in safe_value_offsets.iter().zip_eq(outputs) { builder.main(0).advice[*offset] = Assigned::::Trivial(*witness); } - let circuit = RangeCircuitBuilder::prover(builder, vec![vec![]]); // no break points + let circuit = RangeCircuitBuilder::prover(builder, config_params, vec![vec![]]); // no break points gen_proof(¶ms, &pk, circuit) }; let pf = gen_pf(raw_bytes, outputs); diff --git a/halo2-base/src/utils/mod.rs b/halo2-base/src/utils/mod.rs index 0000a408..7c91448f 100644 --- a/halo2-base/src/utils/mod.rs +++ b/halo2-base/src/utils/mod.rs @@ -1,7 +1,12 @@ -#[cfg(feature = "halo2-pse")] -use crate::halo2_proofs::arithmetic::CurveAffine; -use crate::halo2_proofs::{arithmetic::FieldExt, circuit::Value}; use core::hash::Hash; + +use crate::ff::PrimeField; +#[cfg(not(feature = "halo2-axiom"))] +use crate::halo2_proofs::arithmetic::CurveAffine; +use crate::halo2_proofs::circuit::Value; +#[cfg(feature = "halo2-axiom")] +pub use crate::halo2_proofs::halo2curves::CurveAffineExt; + use num_bigint::BigInt; use num_bigint::BigUint; use num_bigint::Sign; @@ -39,7 +44,7 @@ where /// Helper trait to represent a field element that can be converted into [u64] limbs. /// /// Note: Since the number of bits necessary to represent a field element is larger than the number of bits in a u64, we decompose the integer representation of the field element into multiple [u64] values e.g. `limbs`. -pub trait ScalarField: FieldExt + Hash { +pub trait ScalarField: PrimeField + From + Hash + PartialEq + PartialOrd { /// Returns the base `2bit_len` little endian representation of the [ScalarField] element up to `num_limbs` number of limbs (truncates any extra limbs). /// /// Assumes `bit_len < 64`. @@ -59,13 +64,34 @@ pub trait ScalarField: FieldExt + Hash { repr.as_mut()[..bytes.len()].copy_from_slice(bytes); Self::from_repr(repr).unwrap() } + + /// Gets the least significant 32 bits of the field element. + fn get_lower_32(&self) -> u32 { + let bytes = self.to_bytes_le(); + let mut lower_32 = 0u32; + for (i, byte) in bytes.into_iter().enumerate().take(4) { + lower_32 |= (byte as u32) << (i * 8); + } + lower_32 + } + + /// Gets the least significant 64 bits of the field element. + fn get_lower_64(&self) -> u64 { + let bytes = self.to_bytes_le(); + let mut lower_64 = 0u64; + for (i, byte) in bytes.into_iter().enumerate().take(8) { + lower_64 |= (byte as u64) << (i * 8); + } + lower_64 + } } // See below for implementations // Later: will need to separate BigPrimeField from ScalarField when Goldilocks is introduced +/// [ScalarField] that is ~256 bits long #[cfg(feature = "halo2-pse")] -pub trait BigPrimeField = FieldExt + ScalarField; +pub trait BigPrimeField = PrimeField + ScalarField; /// Converts an [Iterator] of u64 digits into `number_of_limbs` limbs of `bit_len` bits returned as a [Vec]. /// @@ -134,7 +160,7 @@ pub fn log2_ceil(x: u64) -> usize { /// Returns the modulus of [BigPrimeField]. pub fn modulus() -> BigUint { - fe_to_biguint(&-F::one()) + 1u64 + fe_to_biguint(&-F::ONE) + 1u64 } /// Returns the [BigPrimeField] element of 2n. @@ -340,13 +366,10 @@ pub fn compose(input: Vec, bit_len: usize) -> BigUint { input.iter().rev().fold(BigUint::zero(), |acc, val| (acc << bit_len) + val) } -#[cfg(feature = "halo2-axiom")] -pub use halo2_proofs_axiom::halo2curves::CurveAffineExt; - /// Helper trait #[cfg(feature = "halo2-pse")] pub trait CurveAffineExt: CurveAffine { - /// Unlike the `Coordinates` trait, this just returns the raw affine (X, Y) coordinantes without checking `is_on_curve` + /// Returns the raw affine (X, Y) coordinantes fn into_coordinates(self) -> (Self::Base, Self::Base) { let coordinates = self.coordinates().unwrap(); (*coordinates.x(), *coordinates.y()) @@ -357,12 +380,12 @@ impl CurveAffineExt for C {} mod scalar_field_impls { use super::{decompose_u64_digits_to_limbs, ScalarField}; + #[cfg(feature = "halo2-pse")] + use crate::ff::PrimeField; use crate::halo2_proofs::halo2curves::{ bn256::{Fq as bn254Fq, Fr as bn254Fr}, secp256k1::{Fp as secpFp, Fq as secpFq}, }; - #[cfg(feature = "halo2-pse")] - use ff::PrimeField; /// To ensure `ScalarField` is only implemented for `ff:Field` where `Repr` is little endian, we use the following macro /// to implement the trait for each field. @@ -383,6 +406,18 @@ mod scalar_field_impls { let tmp: [u64; 4] = (*self).into(); tmp.iter().flat_map(|x| x.to_le_bytes()).collect() } + + #[inline(always)] + fn get_lower_32(&self) -> u32 { + let tmp: [u64; 4] = (*self).into(); + tmp[0] as u32 + } + + #[inline(always)] + fn get_lower_64(&self) -> u64 { + let tmp: [u64; 4] = (*self).into(); + tmp[0] + } } }; } @@ -487,7 +522,10 @@ pub mod fs { mod tests { use crate::halo2_proofs::halo2curves::bn256::Fr; use num_bigint::RandomBits; - use rand::{rngs::OsRng, Rng}; + use rand::{ + rngs::{OsRng, StdRng}, + Rng, SeedableRng, + }; use std::ops::Shl; use super::*; @@ -559,4 +597,23 @@ mod tests { fn test_log2_ceil_zero() { assert_eq!(log2_ceil(0), 0); } + + #[test] + fn test_get_lower_32() { + let mut rng = StdRng::seed_from_u64(0); + for _ in 0..10_000usize { + let e: u32 = rng.gen_range(0..u32::MAX); + assert_eq!(Fr::from(e as u64).get_lower_32(), e); + } + assert_eq!(Fr::from((1u64 << 32_i32) + 1).get_lower_32(), 1); + } + + #[test] + fn test_get_lower_64() { + let mut rng = StdRng::seed_from_u64(0); + for _ in 0..10_000usize { + let e: u64 = rng.gen_range(0..u64::MAX); + assert_eq!(Fr::from(e).get_lower_64(), e); + } + } } diff --git a/halo2-base/src/utils/testing.rs b/halo2-base/src/utils/testing.rs index e51b4eef..6c92df31 100644 --- a/halo2-base/src/utils/testing.rs +++ b/halo2-base/src/utils/testing.rs @@ -1,10 +1,11 @@ //! Utilities for testing use crate::{ gates::{ - builder::{GateThreadBuilder, RangeCircuitBuilder, BASE_CONFIG_PARAMS}, + builder::{GateThreadBuilder, RangeCircuitBuilder}, GateChip, }, halo2_proofs::{ + dev::MockProver, halo2curves::bn256::{Bn256, Fr, G1Affine}, plonk::{create_proof, verify_proof, Circuit, ProvingKey, VerifyingKey}, poly::commitment::ParamsProver, @@ -19,7 +20,6 @@ use crate::{ safe_types::RangeChip, Context, }; -use halo2_proofs_axiom::dev::MockProver; use rand::{rngs::StdRng, SeedableRng}; /// helper function to generate a proof with real prover @@ -130,10 +130,6 @@ impl BaseTester { ) -> R { let mut builder = GateThreadBuilder::mock(); let range = RangeChip::default(self.lookup_bits.unwrap_or(0)); - BASE_CONFIG_PARAMS.with(|conf| { - conf.borrow_mut().k = self.k as usize; - conf.borrow_mut().lookup_bits = self.lookup_bits; - }); // run the function, mutating `builder` let res = f(&mut builder, &range); @@ -143,16 +139,13 @@ impl BaseTester { .iter() .map(|t| t.iter().map(|ctx| ctx.cells_to_lookup.len()).sum::()) .sum::(); - if t_cells_lookup == 0 { - BASE_CONFIG_PARAMS.with(|conf| { - conf.borrow_mut().lookup_bits = None; - }) - } + let lookup_bits = if t_cells_lookup == 0 { None } else { self.lookup_bits }; // configure the circuit shape, 9 blinding rows seems enough - builder.config(self.k as usize, Some(9)); + let mut config_params = builder.config(self.k as usize, Some(9)); + config_params.lookup_bits = lookup_bits; // create circuit - let circuit = RangeCircuitBuilder::mock(builder); + let circuit = RangeCircuitBuilder::mock(builder, config_params); if self.expect_satisfied { MockProver::run(self.k, &circuit, vec![]).unwrap().assert_satisfied(); } else { diff --git a/halo2-ecc/Cargo.toml b/halo2-ecc/Cargo.toml index 2b03e1cb..01992ed8 100644 --- a/halo2-ecc/Cargo.toml +++ b/halo2-ecc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "halo2-ecc" -version = "0.3.0" +version = "0.3.1" edition = "2021" [dependencies] @@ -16,10 +16,6 @@ serde_json = "1.0" rayon = "1.6.1" test-case = "3.1.0" -# arithmetic -ff = "0.12" -group = "0.12" - halo2-base = { path = "../halo2-base", default-features = false } [dev-dependencies] @@ -33,6 +29,7 @@ halo2-base = { path = "../halo2-base", default-features = false, features = ["te default = ["jemallocator", "halo2-axiom", "display"] dev-graph = ["halo2-base/dev-graph"] display = ["halo2-base/display"] +asm = ["halo2-base/asm"] halo2-pse = ["halo2-base/halo2-pse"] halo2-axiom = ["halo2-base/halo2-axiom"] jemallocator = ["halo2-base/jemallocator"] diff --git a/halo2-ecc/benches/fixed_base_msm.rs b/halo2-ecc/benches/fixed_base_msm.rs index 581835b1..660b7c6c 100644 --- a/halo2-ecc/benches/fixed_base_msm.rs +++ b/halo2-ecc/benches/fixed_base_msm.rs @@ -1,11 +1,12 @@ use ark_std::{end_timer, start_timer}; use halo2_base::gates::{ builder::{ - set_lookup_bits, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, + BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder, }, RangeChip, }; +use halo2_base::halo2_proofs::halo2curves::ff::PrimeField as _; use halo2_base::halo2_proofs::{ arithmetic::Field, halo2curves::bn256::{Bn256, Fr, G1Affine}, @@ -16,7 +17,7 @@ use halo2_base::halo2_proofs::{ }, transcript::{Blake2bWrite, Challenge255, TranscriptWriterBuffer}, }; -use halo2_ecc::{bn254::FpChip, ecc::EccChip, fields::PrimeField}; +use halo2_ecc::{bn254::FpChip, ecc::EccChip}; use rand::rngs::OsRng; use criterion::{criterion_group, criterion_main}; @@ -46,7 +47,6 @@ fn fixed_base_msm_bench( bases: Vec, scalars: Vec, ) { - set_lookup_bits(params.lookup_bits); let range = RangeChip::::default(params.lookup_bits); let fp_chip = FpChip::::new(&range, params.limb_bits, params.num_limbs); let ecc_chip = EccChip::new(&fp_chip); @@ -64,28 +64,23 @@ fn fixed_base_msm_circuit( stage: CircuitBuilderStage, bases: Vec, scalars: Vec, + config_params: Option, break_points: Option, ) -> RangeCircuitBuilder { let k = params.degree as usize; - let mut builder = match stage { - CircuitBuilderStage::Mock => GateThreadBuilder::mock(), - CircuitBuilderStage::Prover => GateThreadBuilder::prover(), - CircuitBuilderStage::Keygen => GateThreadBuilder::keygen(), - }; + let mut builder = GateThreadBuilder::new(stage == CircuitBuilderStage::Prover); let start0 = start_timer!(|| format!("Witness generation for circuit in {stage:?} stage")); fixed_base_msm_bench(&mut builder, params, bases, scalars); + let mut config_params = config_params.unwrap_or_else(|| builder.config(k, Some(20))); + config_params.lookup_bits = Some(params.lookup_bits); let circuit = match stage { - CircuitBuilderStage::Mock => { - builder.config(k, Some(20)); - RangeCircuitBuilder::mock(builder) - } - CircuitBuilderStage::Keygen => { - builder.config(k, Some(20)); - RangeCircuitBuilder::keygen(builder) + CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder, config_params), + CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder, config_params), + CircuitBuilderStage::Prover => { + RangeCircuitBuilder::prover(builder, config_params, break_points.unwrap()) } - CircuitBuilderStage::Prover => RangeCircuitBuilder::prover(builder, break_points.unwrap()), }; end_timer!(start0); circuit @@ -102,7 +97,9 @@ fn bench(c: &mut Criterion) { vec![G1Affine::generator(); config.batch_size], vec![Fr::zero(); config.batch_size], None, + None, ); + let config_params = circuit.0.config_params.clone(); let params = ParamsKZG::::setup(k, &mut rng); let vk = keygen_vk(¶ms, &circuit).expect("vk should not fail"); @@ -124,6 +121,7 @@ fn bench(c: &mut Criterion) { CircuitBuilderStage::Prover, bases.clone(), scalars.clone(), + Some(config_params.clone()), Some(break_points.clone()), ); diff --git a/halo2-ecc/benches/fp_mul.rs b/halo2-ecc/benches/fp_mul.rs index 10ef5f20..05ae449b 100644 --- a/halo2-ecc/benches/fp_mul.rs +++ b/halo2-ecc/benches/fp_mul.rs @@ -2,7 +2,7 @@ use ark_std::{end_timer, start_timer}; use halo2_base::{ gates::{ builder::{ - set_lookup_bits, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, + BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder, }, RangeChip, @@ -17,10 +17,11 @@ use halo2_base::{ }, transcript::{Blake2bWrite, Challenge255, TranscriptWriterBuffer}, }, + utils::BigPrimeField, Context, }; use halo2_ecc::fields::fp::FpChip; -use halo2_ecc::fields::{FieldChip, PrimeField}; +use halo2_ecc::fields::FieldChip; use rand::rngs::OsRng; use criterion::{criterion_group, criterion_main}; @@ -32,7 +33,7 @@ use pprof::criterion::{Output, PProfProfiler}; const K: u32 = 19; -fn fp_mul_bench( +fn fp_mul_bench( ctx: &mut Context, lookup_bits: usize, limb_bits: usize, @@ -40,7 +41,6 @@ fn fp_mul_bench( _a: Fq, _b: Fq, ) { - set_lookup_bits(lookup_bits); let range = RangeChip::::default(lookup_bits); let chip = FpChip::::new(&range, limb_bits, num_limbs); @@ -54,9 +54,11 @@ fn fp_mul_circuit( stage: CircuitBuilderStage, a: Fq, b: Fq, + config_params: Option, break_points: Option, ) -> RangeCircuitBuilder { let k = K as usize; + let lookup_bits = k - 1; let mut builder = match stage { CircuitBuilderStage::Mock => GateThreadBuilder::mock(), CircuitBuilderStage::Prover => GateThreadBuilder::prover(), @@ -64,25 +66,24 @@ fn fp_mul_circuit( }; let start0 = start_timer!(|| format!("Witness generation for circuit in {stage:?} stage")); - fp_mul_bench(builder.main(0), k - 1, 88, 3, a, b); + fp_mul_bench(builder.main(0), lookup_bits, 88, 3, a, b); + let mut config_params = config_params.unwrap_or_else(|| builder.config(k, Some(20))); + config_params.lookup_bits = Some(lookup_bits); let circuit = match stage { - CircuitBuilderStage::Mock => { - builder.config(k, Some(20)); - RangeCircuitBuilder::mock(builder) + CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder, config_params), + CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder, config_params), + CircuitBuilderStage::Prover => { + RangeCircuitBuilder::prover(builder, config_params, break_points.unwrap()) } - CircuitBuilderStage::Keygen => { - builder.config(k, Some(20)); - RangeCircuitBuilder::keygen(builder) - } - CircuitBuilderStage::Prover => RangeCircuitBuilder::prover(builder, break_points.unwrap()), }; end_timer!(start0); circuit } fn bench(c: &mut Criterion) { - let circuit = fp_mul_circuit(CircuitBuilderStage::Keygen, Fq::zero(), Fq::zero(), None); + let circuit = fp_mul_circuit(CircuitBuilderStage::Keygen, Fq::zero(), Fq::zero(), None, None); + let config_params = circuit.0.config_params.clone(); let params = ParamsKZG::::setup(K, OsRng); let vk = keygen_vk(¶ms, &circuit).expect("vk should not fail"); @@ -98,8 +99,13 @@ fn bench(c: &mut Criterion) { &(¶ms, &pk, a, b), |bencher, &(params, pk, a, b)| { bencher.iter(|| { - let circuit = - fp_mul_circuit(CircuitBuilderStage::Prover, a, b, Some(break_points.clone())); + let circuit = fp_mul_circuit( + CircuitBuilderStage::Prover, + a, + b, + Some(config_params.clone()), + Some(break_points.clone()), + ); let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); create_proof::< diff --git a/halo2-ecc/benches/msm.rs b/halo2-ecc/benches/msm.rs index 3d97e361..27667157 100644 --- a/halo2-ecc/benches/msm.rs +++ b/halo2-ecc/benches/msm.rs @@ -1,11 +1,12 @@ use ark_std::{end_timer, start_timer}; use halo2_base::gates::{ builder::{ - set_lookup_bits, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, + BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder, }, RangeChip, }; +use halo2_base::halo2_proofs::halo2curves::ff::PrimeField as _; use halo2_base::halo2_proofs::{ arithmetic::Field, halo2curves::bn256::{Bn256, Fr, G1Affine}, @@ -16,7 +17,7 @@ use halo2_base::halo2_proofs::{ }, transcript::{Blake2bWrite, Challenge255, TranscriptWriterBuffer}, }; -use halo2_ecc::{bn254::FpChip, ecc::EccChip, fields::PrimeField}; +use halo2_ecc::{bn254::FpChip, ecc::EccChip}; use rand::rngs::OsRng; use criterion::{criterion_group, criterion_main}; @@ -52,7 +53,6 @@ fn msm_bench( bases: Vec, scalars: Vec, ) { - set_lookup_bits(params.lookup_bits); let range = RangeChip::::default(params.lookup_bits); let fp_chip = FpChip::::new(&range, params.limb_bits, params.num_limbs); let ecc_chip = EccChip::new(&fp_chip); @@ -80,6 +80,7 @@ fn msm_circuit( stage: CircuitBuilderStage, bases: Vec, scalars: Vec, + config_params: Option, break_points: Option, ) -> RangeCircuitBuilder { let start0 = start_timer!(|| format!("Witness generation for circuit in {stage:?} stage")); @@ -92,16 +93,14 @@ fn msm_circuit( msm_bench(&mut builder, params, bases, scalars); + let mut config_params = config_params.unwrap_or_else(|| builder.config(k, Some(20))); + config_params.lookup_bits = Some(params.lookup_bits); let circuit = match stage { - CircuitBuilderStage::Mock => { - builder.config(k, Some(20)); - RangeCircuitBuilder::mock(builder) + CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder, config_params), + CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder, config_params), + CircuitBuilderStage::Prover => { + RangeCircuitBuilder::prover(builder, config_params, break_points.unwrap()) } - CircuitBuilderStage::Keygen => { - builder.config(k, Some(20)); - RangeCircuitBuilder::keygen(builder) - } - CircuitBuilderStage::Prover => RangeCircuitBuilder::prover(builder, break_points.unwrap()), }; end_timer!(start0); circuit @@ -118,7 +117,9 @@ fn bench(c: &mut Criterion) { vec![G1Affine::generator(); config.batch_size], vec![Fr::one(); config.batch_size], None, + None, ); + let config_params = circuit.0.config_params.clone(); let params = ParamsKZG::::setup(k, &mut rng); let vk = keygen_vk(¶ms, &circuit).expect("vk should not fail"); @@ -140,6 +141,7 @@ fn bench(c: &mut Criterion) { CircuitBuilderStage::Prover, bases.clone(), scalars.clone(), + Some(config_params.clone()), Some(break_points.clone()), ); diff --git a/halo2-ecc/src/bigint/carry_mod.rs b/halo2-ecc/src/bigint/carry_mod.rs index a78fd32b..f242ad8f 100644 --- a/halo2-ecc/src/bigint/carry_mod.rs +++ b/halo2-ecc/src/bigint/carry_mod.rs @@ -121,10 +121,10 @@ pub fn crt( // where prod is at relative row `offset` ctx.assign_region( [ - Constant(-F::one()), + Constant(-F::ONE), Existing(a_limb), Witness(temp1), - Constant(F::one()), + Constant(F::ONE), Witness(out_v), Witness(check_val), ], diff --git a/halo2-ecc/src/bigint/check_carry_mod_to_zero.rs b/halo2-ecc/src/bigint/check_carry_mod_to_zero.rs index 6232cbdf..13523ba5 100644 --- a/halo2-ecc/src/bigint/check_carry_mod_to_zero.rs +++ b/halo2-ecc/src/bigint/check_carry_mod_to_zero.rs @@ -79,8 +79,8 @@ pub fn crt( // transpose of: // | prod | -1 | a | prod - a | let check_val = *prod.value() - a_limb.value(); - let check_cell = ctx - .assign_region_last([Constant(-F::one()), Existing(a_limb), Witness(check_val)], [-1]); + let check_cell = + ctx.assign_region_last([Constant(-F::ONE), Existing(a_limb), Witness(check_val)], [-1]); quot_assigned.push(new_quot_cell); check_assigned.push(check_cell); @@ -119,7 +119,7 @@ pub fn crt( // Check `0 + modulus * quotient - a = 0` in native field // | 0 | modulus | quotient | a | ctx.assign_region( - [Constant(F::zero()), Constant(mod_native), Existing(quot_native), Existing(a.native)], + [Constant(F::ZERO), Constant(mod_native), Existing(quot_native), Existing(a.native)], [0], ); } diff --git a/halo2-ecc/src/bigint/check_carry_to_zero.rs b/halo2-ecc/src/bigint/check_carry_to_zero.rs index fa2f5648..d445f7e5 100644 --- a/halo2-ecc/src/bigint/check_carry_to_zero.rs +++ b/halo2-ecc/src/bigint/check_carry_to_zero.rs @@ -62,14 +62,14 @@ pub fn truncate( // let num_windows = (k - 1) / window + 1; // = ((k - 1) - (window - 1) + window - 1) / window + 1; let mut previous = None; - for (a_limb, carry) in a.limbs.into_iter().zip(carries.into_iter()) { + for (a_limb, carry) in a.limbs.into_iter().zip(carries) { let neg_carry_val = bigint_to_fe(&-carry); ctx.assign_region( [ Existing(a_limb), Witness(neg_carry_val), Constant(limb_base), - previous.map(Existing).unwrap_or_else(|| Constant(F::zero())), + previous.map(Existing).unwrap_or_else(|| Constant(F::ZERO)), ], [0], ); diff --git a/halo2-ecc/src/bigint/sub.rs b/halo2-ecc/src/bigint/sub.rs index 8b2263f9..c8a18433 100644 --- a/halo2-ecc/src/bigint/sub.rs +++ b/halo2-ecc/src/bigint/sub.rs @@ -46,7 +46,7 @@ pub fn assign( Existing(lt), Constant(limb_base), Witness(a_with_borrow_val), - Constant(-F::one()), + Constant(-F::ONE), Existing(bottom), Witness(out_val), ], diff --git a/halo2-ecc/src/bn254/final_exp.rs b/halo2-ecc/src/bn254/final_exp.rs index 7959142e..ae2ecac9 100644 --- a/halo2-ecc/src/bn254/final_exp.rs +++ b/halo2-ecc/src/bn254/final_exp.rs @@ -5,14 +5,19 @@ use crate::halo2_proofs::{ }; use crate::{ ecc::get_naf, - fields::{fp12::mul_no_carry_w6, vector::FieldVector, FieldChip, PrimeField}, + fields::{fp12::mul_no_carry_w6, vector::FieldVector, FieldChip}, +}; +use halo2_base::{ + gates::GateInstructions, + utils::{modulus, BigPrimeField}, + Context, + QuantumCell::Constant, }; -use halo2_base::{gates::GateInstructions, utils::modulus, Context, QuantumCell::Constant}; use num_bigint::BigUint; const XI_0: i64 = 9; -impl<'chip, F: PrimeField> Fp12Chip<'chip, F> { +impl<'chip, F: BigPrimeField> Fp12Chip<'chip, F> { // computes a ** (p ** power) // only works for p = 3 (mod 4) and p = 1 (mod 6) pub fn frobenius_map( @@ -172,8 +177,8 @@ impl<'chip, F: PrimeField> Fp12Chip<'chip, F> { // compute `g0 + 1` g0[0].truncation.limbs[0] = - fp2_chip.gate().add(ctx, g0[0].truncation.limbs[0], Constant(F::one())); - g0[0].native = fp2_chip.gate().add(ctx, g0[0].native, Constant(F::one())); + fp2_chip.gate().add(ctx, g0[0].truncation.limbs[0], Constant(F::ONE)); + g0[0].native = fp2_chip.gate().add(ctx, g0[0].native, Constant(F::ONE)); g0[0].truncation.max_limb_bits += 1; g0[0].value += 1usize; diff --git a/halo2-ecc/src/bn254/pairing.rs b/halo2-ecc/src/bn254/pairing.rs index e25f066a..1a201f55 100644 --- a/halo2-ecc/src/bn254/pairing.rs +++ b/halo2-ecc/src/bn254/pairing.rs @@ -7,8 +7,9 @@ use crate::halo2_proofs::halo2curves::bn256::{ use crate::{ ecc::{EcPoint, EccChip}, fields::fp12::mul_no_carry_w6, - fields::{FieldChip, PrimeField}, + fields::FieldChip, }; +use halo2_base::utils::BigPrimeField; use halo2_base::Context; const XI_0: i64 = 9; @@ -21,7 +22,7 @@ const XI_0: i64 = 9; // line_{Psi(Q0), Psi(Q1)}(P) where Psi(x,y) = (w^2 x, w^3 y) // - equals w^3 (y_1 - y_2) X + w^2 (x_2 - x_1) Y + w^5 (x_1 y_2 - x_2 y_1) =: out3 * w^3 + out2 * w^2 + out5 * w^5 where out2, out3, out5 are Fp2 points // Output is [None, None, out2, out3, None, out5] as vector of `Option`s -pub fn sparse_line_function_unequal( +pub fn sparse_line_function_unequal( fp2_chip: &Fp2Chip, ctx: &mut Context, Q: (&EcPoint>, &EcPoint>), @@ -60,7 +61,7 @@ pub fn sparse_line_function_unequal( // line_{Psi(Q), Psi(Q)}(P) where Psi(x,y) = (w^2 x, w^3 y) // - equals (3x^3 - 2y^2)(XI_0 + u) + w^4 (-3 x^2 * Q.x) + w^3 (2 y * Q.y) =: out0 + out4 * w^4 + out3 * w^3 where out0, out3, out4 are Fp2 points // Output is [out0, None, None, out3, out4, None] as vector of `Option`s -pub fn sparse_line_function_equal( +pub fn sparse_line_function_equal( fp2_chip: &Fp2Chip, ctx: &mut Context, Q: &EcPoint>, @@ -95,7 +96,7 @@ pub fn sparse_line_function_equal( // multiply Fp12 point `a` with Fp12 point `b` where `b` is len 6 vector of Fp2 points, where some are `None` to represent zero. // Assumes `b` is not vector of all `None`s -pub fn sparse_fp12_multiply( +pub fn sparse_fp12_multiply( fp2_chip: &Fp2Chip, ctx: &mut Context, a: &FqPoint, @@ -162,7 +163,7 @@ pub fn sparse_fp12_multiply( // - P is point in E(Fp) // Output: // - out = g * l_{Psi(Q0), Psi(Q1)}(P) as Fp12 point -pub fn fp12_multiply_with_line_unequal( +pub fn fp12_multiply_with_line_unequal( fp2_chip: &Fp2Chip, ctx: &mut Context, g: &FqPoint, @@ -179,7 +180,7 @@ pub fn fp12_multiply_with_line_unequal( // - P is point in E(Fp) // Output: // - out = g * l_{Psi(Q), Psi(Q)}(P) as Fp12 point -pub fn fp12_multiply_with_line_equal( +pub fn fp12_multiply_with_line_equal( fp2_chip: &Fp2Chip, ctx: &mut Context, g: &FqPoint, @@ -208,7 +209,7 @@ pub fn fp12_multiply_with_line_equal( // - `0 <= loop_count < r` and `loop_count < p` (to avoid [loop_count]Q' = Frob_p(Q')) // - x^3 + b = 0 has no solution in Fp2, i.e., the y-coordinate of Q cannot be 0. -pub fn miller_loop_BN( +pub fn miller_loop_BN( ecc_chip: &EccChip>, ctx: &mut Context, Q: &EcPoint>, @@ -294,7 +295,7 @@ pub fn miller_loop_BN( // let pairs = [(a_i, b_i)], a_i in G_1, b_i in G_2 // output is Prod_i e'(a_i, b_i), where e'(a_i, b_i) is the output of `miller_loop_BN(b_i, a_i)` -pub fn multi_miller_loop_BN( +pub fn multi_miller_loop_BN( ecc_chip: &EccChip>, ctx: &mut Context, pairs: Vec<(&EcPoint>, &EcPoint>)>, @@ -397,7 +398,7 @@ pub fn multi_miller_loop_BN( // - coeff[1][2], coeff[1][3] as assigned cells: this is an optimization to avoid loading new constants // Output: // - (coeff[1][2] * x^p, coeff[1][3] * y^p) point in E(Fp2) -pub fn twisted_frobenius( +pub fn twisted_frobenius( ecc_chip: &EccChip>, ctx: &mut Context, Q: impl Into>>, @@ -423,7 +424,7 @@ pub fn twisted_frobenius( // - Q = (x, y) point in E(Fp2) // Output: // - (coeff[1][2] * x^p, coeff[1][3] * -y^p) point in E(Fp2) -pub fn neg_twisted_frobenius( +pub fn neg_twisted_frobenius( ecc_chip: &EccChip>, ctx: &mut Context, Q: impl Into>>, @@ -444,11 +445,11 @@ pub fn neg_twisted_frobenius( } // To avoid issues with mutably borrowing twice (not allowed in Rust), we only store fp_chip and construct g2_chip and fp12_chip in scope when needed for temporary mutable borrows -pub struct PairingChip<'chip, F: PrimeField> { +pub struct PairingChip<'chip, F: BigPrimeField> { pub fp_chip: &'chip FpChip<'chip, F>, } -impl<'chip, F: PrimeField> PairingChip<'chip, F> { +impl<'chip, F: BigPrimeField> PairingChip<'chip, F> { pub fn new(fp_chip: &'chip FpChip) -> Self { Self { fp_chip } } diff --git a/halo2-ecc/src/bn254/tests/ec_add.rs b/halo2-ecc/src/bn254/tests/ec_add.rs index a2136c9e..c128b308 100644 --- a/halo2-ecc/src/bn254/tests/ec_add.rs +++ b/halo2-ecc/src/bn254/tests/ec_add.rs @@ -4,11 +4,12 @@ use std::io::{BufRead, BufReader}; use super::*; use crate::fields::{FieldChip, FpStrategy}; +use crate::group::cofactor::CofactorCurveAffine; use crate::halo2_proofs::halo2curves::bn256::G2Affine; -use group::cofactor::CofactorCurveAffine; -use halo2_base::gates::builder::{set_lookup_bits, GateThreadBuilder, RangeCircuitBuilder}; +use halo2_base::gates::builder::{GateThreadBuilder, RangeCircuitBuilder}; use halo2_base::gates::RangeChip; use halo2_base::utils::fs::gen_srs; +use halo2_base::utils::BigPrimeField; use halo2_base::Context; use itertools::Itertools; use rand_core::OsRng; @@ -26,8 +27,11 @@ struct CircuitParams { batch_size: usize, } -fn g2_add_test(ctx: &mut Context, params: CircuitParams, _points: Vec) { - set_lookup_bits(params.lookup_bits); +fn g2_add_test( + ctx: &mut Context, + params: CircuitParams, + _points: Vec, +) { let range = RangeChip::::default(params.lookup_bits); let fp_chip = FpChip::::new(&range, params.limb_bits, params.num_limbs); let fp2_chip = Fp2Chip::::new(&fp_chip); @@ -59,8 +63,9 @@ fn test_ec_add() { let mut builder = GateThreadBuilder::::mock(); g2_add_test(builder.main(0), params, points); - builder.config(k as usize, Some(20)); - let circuit = RangeCircuitBuilder::mock(builder); + let mut config_params = builder.config(k as usize, Some(20)); + config_params.lookup_bits = Some(params.lookup_bits); + let circuit = RangeCircuitBuilder::mock(builder, config_params); MockProver::run(k, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -92,8 +97,9 @@ fn bench_ec_add() -> Result<(), Box> { let points = vec![G2Affine::generator(); bench_params.batch_size]; let mut builder = GateThreadBuilder::::keygen(); g2_add_test(builder.main(0), bench_params, points); - builder.config(k as usize, Some(20)); - RangeCircuitBuilder::keygen(builder) + let mut cp = builder.config(k as usize, Some(20)); + cp.lookup_bits = Some(bench_params.lookup_bits); + RangeCircuitBuilder::keygen(builder, cp) }; end_timer!(start0); @@ -104,6 +110,7 @@ fn bench_ec_add() -> Result<(), Box> { let pk = keygen_pk(¶ms, vk, &circuit)?; end_timer!(pk_time); + let cp = circuit.0.config_params.clone(); let break_points = circuit.0.break_points.take(); drop(circuit); @@ -113,8 +120,7 @@ fn bench_ec_add() -> Result<(), Box> { let proof_circuit = { let mut builder = GateThreadBuilder::::prover(); g2_add_test(builder.main(0), bench_params, points); - builder.config(k as usize, Some(20)); - RangeCircuitBuilder::prover(builder, break_points) + RangeCircuitBuilder::prover(builder, cp, break_points) }; let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); create_proof::< diff --git a/halo2-ecc/src/bn254/tests/fixed_base_msm.rs b/halo2-ecc/src/bn254/tests/fixed_base_msm.rs index d839049c..6f9c2027 100644 --- a/halo2-ecc/src/bn254/tests/fixed_base_msm.rs +++ b/halo2-ecc/src/bn254/tests/fixed_base_msm.rs @@ -3,15 +3,14 @@ use std::{ io::{BufRead, BufReader}, }; -use crate::fields::{FpStrategy, PrimeField}; +use crate::ff::{Field, PrimeField}; +use crate::fields::FpStrategy; use super::*; -#[allow(unused_imports)] -use ff::PrimeField as _; use halo2_base::{ gates::{ builder::{ - set_lookup_bits, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, + BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder, }, RangeChip, @@ -43,7 +42,6 @@ fn fixed_base_msm_test( bases: Vec, scalars: Vec, ) { - set_lookup_bits(params.lookup_bits); let range = RangeChip::::default(params.lookup_bits); let fp_chip = FpChip::::new(&range, params.limb_bits, params.num_limbs); let ecc_chip = EccChip::new(&fp_chip); @@ -71,6 +69,7 @@ fn random_fixed_base_msm_circuit( params: FixedMSMCircuitParams, bases: Vec, // bases are fixed in vkey so don't randomly generate stage: CircuitBuilderStage, + config_params: Option, break_points: Option, ) -> RangeCircuitBuilder { let k = params.degree as usize; @@ -84,16 +83,14 @@ fn random_fixed_base_msm_circuit( let start0 = start_timer!(|| format!("Witness generation for circuit in {stage:?} stage")); fixed_base_msm_test(&mut builder, params, bases, scalars); + let mut config_params = config_params.unwrap_or_else(|| builder.config(k, Some(20))); + config_params.lookup_bits = Some(params.lookup_bits); let circuit = match stage { - CircuitBuilderStage::Mock => { - builder.config(k, Some(20)); - RangeCircuitBuilder::mock(builder) + CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder, config_params), + CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder, config_params), + CircuitBuilderStage::Prover => { + RangeCircuitBuilder::prover(builder, config_params, break_points.unwrap()) } - CircuitBuilderStage::Keygen => { - builder.config(k, Some(20)); - RangeCircuitBuilder::keygen(builder) - } - CircuitBuilderStage::Prover => RangeCircuitBuilder::prover(builder, break_points.unwrap()), }; end_timer!(start0); circuit @@ -108,7 +105,8 @@ fn test_fixed_base_msm() { .unwrap(); let bases = (0..params.batch_size).map(|_| G1Affine::random(OsRng)).collect_vec(); - let circuit = random_fixed_base_msm_circuit(params, bases, CircuitBuilderStage::Mock, None); + let circuit = + random_fixed_base_msm_circuit(params, bases, CircuitBuilderStage::Mock, None, None); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -124,8 +122,9 @@ fn test_fixed_msm_minus_1() { let mut builder = GateThreadBuilder::mock(); fixed_base_msm_test(&mut builder, params, vec![base], vec![-Fr::one()]); - builder.config(k, Some(20)); - let circuit = RangeCircuitBuilder::mock(builder); + let mut config_params = builder.config(k, Some(20)); + config_params.lookup_bits = Some(params.lookup_bits); + let circuit = RangeCircuitBuilder::mock(builder, config_params); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -158,7 +157,9 @@ fn bench_fixed_base_msm() -> Result<(), Box> { bases.clone(), CircuitBuilderStage::Keygen, None, + None, ); + let cp = circuit.0.config_params.clone(); let vk_time = start_timer!(|| "Generating vkey"); let vk = keygen_vk(¶ms, &circuit)?; @@ -176,6 +177,7 @@ fn bench_fixed_base_msm() -> Result<(), Box> { bench_params, bases, CircuitBuilderStage::Prover, + Some(cp), Some(break_points), ); let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); diff --git a/halo2-ecc/src/bn254/tests/mod.rs b/halo2-ecc/src/bn254/tests/mod.rs index 172300a1..8776d73f 100644 --- a/halo2-ecc/src/bn254/tests/mod.rs +++ b/halo2-ecc/src/bn254/tests/mod.rs @@ -1,7 +1,8 @@ #![allow(non_snake_case)] use super::pairing::PairingChip; use super::*; -use crate::{ecc::EccChip, fields::PrimeField}; +use crate::ecc::EccChip; +use crate::group::Curve; use crate::{ fields::FpStrategy, halo2_proofs::{ @@ -19,7 +20,6 @@ use crate::{ }, }; use ark_std::{end_timer, start_timer}; -use group::Curve; use halo2_base::utils::fe_to_biguint; use serde::{Deserialize, Serialize}; use std::io::Write; diff --git a/halo2-ecc/src/bn254/tests/msm.rs b/halo2-ecc/src/bn254/tests/msm.rs index 804638b2..845a4283 100644 --- a/halo2-ecc/src/bn254/tests/msm.rs +++ b/halo2-ecc/src/bn254/tests/msm.rs @@ -1,9 +1,10 @@ +use crate::ff::{Field, PrimeField}; use crate::fields::FpStrategy; -use ff::{Field, PrimeField}; +use halo2_base::gates::builder::BaseConfigParams; use halo2_base::{ gates::{ builder::{ - set_lookup_bits, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, + CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder, }, RangeChip, @@ -39,7 +40,6 @@ fn msm_test( scalars: Vec, window_bits: usize, ) { - set_lookup_bits(params.lookup_bits); let range = RangeChip::::default(params.lookup_bits); let fp_chip = FpChip::::new(&range, params.limb_bits, params.num_limbs); let ecc_chip = EccChip::new(&fp_chip); @@ -78,6 +78,7 @@ fn msm_test( fn random_msm_circuit( params: MSMCircuitParams, stage: CircuitBuilderStage, + config_params: Option, break_points: Option, ) -> RangeCircuitBuilder { let k = params.degree as usize; @@ -92,16 +93,14 @@ fn random_msm_circuit( let start0 = start_timer!(|| format!("Witness generation for circuit in {stage:?} stage")); msm_test(&mut builder, params, bases, scalars, params.window_bits); + let mut config_params = config_params.unwrap_or_else(|| builder.config(k, Some(20))); + config_params.lookup_bits = Some(params.lookup_bits); let circuit = match stage { - CircuitBuilderStage::Mock => { - builder.config(k, Some(20)); - RangeCircuitBuilder::mock(builder) + CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder, config_params), + CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder, config_params), + CircuitBuilderStage::Prover => { + RangeCircuitBuilder::prover(builder, config_params, break_points.unwrap()) } - CircuitBuilderStage::Keygen => { - builder.config(k, Some(20)); - RangeCircuitBuilder::keygen(builder) - } - CircuitBuilderStage::Prover => RangeCircuitBuilder::prover(builder, break_points.unwrap()), }; end_timer!(start0); circuit @@ -115,7 +114,7 @@ fn test_msm() { ) .unwrap(); - let circuit = random_msm_circuit(params, CircuitBuilderStage::Mock, None); + let circuit = random_msm_circuit(params, CircuitBuilderStage::Mock, None, None); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -141,7 +140,7 @@ fn bench_msm() -> Result<(), Box> { let params = gen_srs(k); println!("{bench_params:?}"); - let circuit = random_msm_circuit(bench_params, CircuitBuilderStage::Keygen, None); + let circuit = random_msm_circuit(bench_params, CircuitBuilderStage::Keygen, None, None); let vk_time = start_timer!(|| "Generating vkey"); let vk = keygen_vk(¶ms, &circuit)?; @@ -151,12 +150,17 @@ fn bench_msm() -> Result<(), Box> { let pk = keygen_pk(¶ms, vk, &circuit)?; end_timer!(pk_time); + let config_params = circuit.0.config_params.clone(); let break_points = circuit.0.break_points.take(); drop(circuit); // create a proof let proof_time = start_timer!(|| "Proving time"); - let circuit = - random_msm_circuit(bench_params, CircuitBuilderStage::Prover, Some(break_points)); + let circuit = random_msm_circuit( + bench_params, + CircuitBuilderStage::Prover, + Some(config_params), + Some(break_points), + ); let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); create_proof::< KZGCommitmentScheme, diff --git a/halo2-ecc/src/bn254/tests/msm_sum_infinity.rs b/halo2-ecc/src/bn254/tests/msm_sum_infinity.rs index 45940c64..d35bb2eb 100644 --- a/halo2-ecc/src/bn254/tests/msm_sum_infinity.rs +++ b/halo2-ecc/src/bn254/tests/msm_sum_infinity.rs @@ -1,7 +1,7 @@ -use ff::PrimeField; +use crate::ff::PrimeField; use halo2_base::gates::{ builder::{ - set_lookup_bits, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, + BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder, }, RangeChip, @@ -18,7 +18,6 @@ fn msm_test( scalars: Vec, window_bits: usize, ) { - set_lookup_bits(params.lookup_bits); let range = RangeChip::::default(params.lookup_bits); let fp_chip = FpChip::::new(&range, params.limb_bits, params.num_limbs); let ecc_chip = EccChip::new(&fp_chip); @@ -57,6 +56,7 @@ fn msm_test( fn custom_msm_circuit( params: MSMCircuitParams, stage: CircuitBuilderStage, + config_params: Option, break_points: Option, bases: Vec, scalars: Vec, @@ -71,16 +71,14 @@ fn custom_msm_circuit( let start0 = start_timer!(|| format!("Witness generation for circuit in {stage:?} stage")); msm_test(&mut builder, params, bases, scalars, params.window_bits); + let mut config_params = config_params.unwrap_or_else(|| builder.config(k, Some(20))); + config_params.lookup_bits = Some(params.lookup_bits); let circuit = match stage { - CircuitBuilderStage::Mock => { - builder.config(k, Some(20)); - RangeCircuitBuilder::mock(builder) + CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder, config_params), + CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder, config_params), + CircuitBuilderStage::Prover => { + RangeCircuitBuilder::prover(builder, config_params, break_points.unwrap()) } - CircuitBuilderStage::Keygen => { - builder.config(k, Some(20)); - RangeCircuitBuilder::keygen(builder) - } - CircuitBuilderStage::Prover => RangeCircuitBuilder::prover(builder, break_points.unwrap()), }; end_timer!(start0); circuit @@ -99,7 +97,7 @@ fn test_msm1() { let bases = vec![random_point, random_point, random_point]; let scalars = vec![Fr::one(), Fr::one(), -Fr::one() - Fr::one()]; - let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars); + let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, None, bases, scalars); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -116,7 +114,7 @@ fn test_msm2() { let bases = vec![random_point, random_point, (random_point + random_point).to_affine()]; let scalars = vec![Fr::one(), Fr::one(), -Fr::one()]; - let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars); + let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, None, bases, scalars); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -138,7 +136,7 @@ fn test_msm3() { ]; let scalars = vec![Fr::one(), Fr::one(), Fr::one(), -Fr::one()]; - let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars); + let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, None, bases, scalars); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -160,7 +158,7 @@ fn test_msm4() { ]; let scalars = vec![Fr::one(), Fr::one(), Fr::one(), -Fr::one()]; - let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars); + let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, None, bases, scalars); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -179,6 +177,6 @@ fn test_msm5() { vec![random_point, random_point, random_point, (random_point + random_point).to_affine()]; let scalars = vec![-Fr::one(), -Fr::one(), Fr::one(), Fr::one()]; - let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars); + let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, None, bases, scalars); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } diff --git a/halo2-ecc/src/bn254/tests/msm_sum_infinity_fixed_base.rs b/halo2-ecc/src/bn254/tests/msm_sum_infinity_fixed_base.rs index b2eb1518..2f06b8fc 100644 --- a/halo2-ecc/src/bn254/tests/msm_sum_infinity_fixed_base.rs +++ b/halo2-ecc/src/bn254/tests/msm_sum_infinity_fixed_base.rs @@ -1,7 +1,7 @@ -use ff::PrimeField; +use crate::ff::PrimeField; use halo2_base::gates::{ builder::{ - set_lookup_bits, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, + BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder, }, RangeChip, @@ -18,7 +18,6 @@ fn msm_test( scalars: Vec, window_bits: usize, ) { - set_lookup_bits(params.lookup_bits); let range = RangeChip::::default(params.lookup_bits); let fp_chip = FpChip::::new(&range, params.limb_bits, params.num_limbs); let ecc_chip = EccChip::new(&fp_chip); @@ -57,6 +56,7 @@ fn msm_test( fn custom_msm_circuit( params: MSMCircuitParams, stage: CircuitBuilderStage, + config_params: Option, break_points: Option, bases: Vec, scalars: Vec, @@ -70,17 +70,14 @@ fn custom_msm_circuit( let start0 = start_timer!(|| format!("Witness generation for circuit in {stage:?} stage")); msm_test(&mut builder, params, bases, scalars, params.window_bits); - + let mut config_params = config_params.unwrap_or_else(|| builder.config(k, Some(20))); + config_params.lookup_bits = Some(params.lookup_bits); let circuit = match stage { - CircuitBuilderStage::Mock => { - builder.config(k, Some(20)); - RangeCircuitBuilder::mock(builder) - } - CircuitBuilderStage::Keygen => { - builder.config(k, Some(20)); - RangeCircuitBuilder::keygen(builder) + CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder, config_params), + CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder, config_params), + CircuitBuilderStage::Prover => { + RangeCircuitBuilder::prover(builder, config_params, break_points.unwrap()) } - CircuitBuilderStage::Prover => RangeCircuitBuilder::prover(builder, break_points.unwrap()), }; end_timer!(start0); circuit @@ -99,7 +96,7 @@ fn test_fb_msm1() { let bases = vec![random_point, random_point, random_point]; let scalars = vec![Fr::one(), Fr::one(), -Fr::one() - Fr::one()]; - let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars); + let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, None, bases, scalars); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -116,7 +113,7 @@ fn test_fb_msm2() { let bases = vec![random_point, random_point, (random_point + random_point).to_affine()]; let scalars = vec![Fr::one(), Fr::one(), -Fr::one()]; - let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars); + let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, None, bases, scalars); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -138,7 +135,7 @@ fn test_fb_msm3() { ]; let scalars = vec![Fr::one(), Fr::one(), Fr::one(), -Fr::one()]; - let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars); + let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, None, bases, scalars); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -160,7 +157,7 @@ fn test_fb_msm4() { ]; let scalars = vec![Fr::one(), Fr::one(), Fr::one(), -Fr::one()]; - let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars); + let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, None, bases, scalars); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -179,6 +176,6 @@ fn test_fb_msm5() { vec![random_point, random_point, random_point, (random_point + random_point).to_affine()]; let scalars = vec![-Fr::one(), -Fr::one(), Fr::one(), Fr::one()]; - let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, bases, scalars); + let circuit = custom_msm_circuit(params, CircuitBuilderStage::Mock, None, None, bases, scalars); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } diff --git a/halo2-ecc/src/bn254/tests/pairing.rs b/halo2-ecc/src/bn254/tests/pairing.rs index e5f3da48..b52b02de 100644 --- a/halo2-ecc/src/bn254/tests/pairing.rs +++ b/halo2-ecc/src/bn254/tests/pairing.rs @@ -9,13 +9,13 @@ use crate::{fields::FpStrategy, halo2_proofs::halo2curves::bn256::G2Affine}; use halo2_base::{ gates::{ builder::{ - set_lookup_bits, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, + BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder, }, RangeChip, }, halo2_proofs::poly::kzg::multiopen::{ProverGWC, VerifierGWC}, - utils::fs::gen_srs, + utils::{fs::gen_srs, BigPrimeField}, Context, }; use rand_core::OsRng; @@ -32,13 +32,12 @@ struct PairingCircuitParams { num_limbs: usize, } -fn pairing_test( +fn pairing_test( ctx: &mut Context, params: PairingCircuitParams, P: G1Affine, Q: G2Affine, ) { - set_lookup_bits(params.lookup_bits); let range = RangeChip::::default(params.lookup_bits); let fp_chip = FpChip::::new(&range, params.limb_bits, params.num_limbs); let chip = PairingChip::new(&fp_chip); @@ -61,6 +60,7 @@ fn pairing_test( fn random_pairing_circuit( params: PairingCircuitParams, stage: CircuitBuilderStage, + config_params: Option, break_points: Option, ) -> RangeCircuitBuilder { let k = params.degree as usize; @@ -76,16 +76,14 @@ fn random_pairing_circuit( let start0 = start_timer!(|| format!("Witness generation for circuit in {stage:?} stage")); pairing_test::(builder.main(0), params, P, Q); + let mut config_params = config_params.unwrap_or_else(|| builder.config(k, Some(20))); + config_params.lookup_bits = Some(params.lookup_bits); let circuit = match stage { - CircuitBuilderStage::Mock => { - builder.config(k, Some(20)); - RangeCircuitBuilder::mock(builder) + CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder, config_params), + CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder, config_params), + CircuitBuilderStage::Prover => { + RangeCircuitBuilder::prover(builder, config_params, break_points.unwrap()) } - CircuitBuilderStage::Keygen => { - builder.config(k, Some(20)); - RangeCircuitBuilder::keygen(builder) - } - CircuitBuilderStage::Prover => RangeCircuitBuilder::prover(builder, break_points.unwrap()), }; end_timer!(start0); circuit @@ -99,7 +97,7 @@ fn test_pairing() { ) .unwrap(); - let circuit = random_pairing_circuit(params, CircuitBuilderStage::Mock, None); + let circuit = random_pairing_circuit(params, CircuitBuilderStage::Mock, None, None); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -124,7 +122,7 @@ fn bench_pairing() -> Result<(), Box> { println!("---------------------- degree = {k} ------------------------------",); let params = gen_srs(k); - let circuit = random_pairing_circuit(bench_params, CircuitBuilderStage::Keygen, None); + let circuit = random_pairing_circuit(bench_params, CircuitBuilderStage::Keygen, None, None); let vk_time = start_timer!(|| "Generating vkey"); let vk = keygen_vk(¶ms, &circuit)?; @@ -135,11 +133,16 @@ fn bench_pairing() -> Result<(), Box> { end_timer!(pk_time); let break_points = circuit.0.break_points.take(); + let config_params = circuit.0.config_params.clone(); drop(circuit); // create a proof let proof_time = start_timer!(|| "Proving time"); - let circuit = - random_pairing_circuit(bench_params, CircuitBuilderStage::Prover, Some(break_points)); + let circuit = random_pairing_circuit( + bench_params, + CircuitBuilderStage::Prover, + Some(config_params), + Some(break_points), + ); let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); create_proof::< KZGCommitmentScheme, diff --git a/halo2-ecc/src/ecc/ecdsa.rs b/halo2-ecc/src/ecc/ecdsa.rs index ca0b111b..c72b3974 100644 --- a/halo2-ecc/src/ecc/ecdsa.rs +++ b/halo2-ecc/src/ecc/ecdsa.rs @@ -1,7 +1,8 @@ +use halo2_base::utils::BigPrimeField; use halo2_base::{gates::GateInstructions, utils::CurveAffineExt, AssignedValue, Context}; use crate::bigint::{big_is_equal, big_less_than, FixedOverflowInteger, ProperCrtUint}; -use crate::fields::{fp::FpChip, FieldChip, PrimeField}; +use crate::fields::{fp::FpChip, FieldChip}; use super::{fixed_base, scalar_multiply, EcPoint, EccChip}; // CF is the coordinate field of GA @@ -12,7 +13,7 @@ use super::{fixed_base, scalar_multiply, EcPoint, EccChip}; // Assumes `r, s` are proper CRT integers /// **WARNING**: Only use this function if `1 / (p - n)` is very small (e.g., < 2-100) /// `pubkey` should not be the identity point -pub fn ecdsa_verify_no_pubkey_check( +pub fn ecdsa_verify_no_pubkey_check( chip: &EccChip>, ctx: &mut Context, pubkey: EcPoint as FieldChip>::FieldPoint>, diff --git a/halo2-ecc/src/ecc/fixed_base.rs b/halo2-ecc/src/ecc/fixed_base.rs index 5dfba754..0c34bcbf 100644 --- a/halo2-ecc/src/ecc/fixed_base.rs +++ b/halo2-ecc/src/ecc/fixed_base.rs @@ -1,9 +1,11 @@ #![allow(non_snake_case)] use super::{ec_add_unequal, ec_select, ec_select_from_bits, EcPoint, EccChip}; use crate::ecc::{ec_sub_strict, load_random_point}; -use crate::fields::{FieldChip, PrimeField, Selectable}; -use group::Curve; +use crate::ff::Field; +use crate::fields::{FieldChip, Selectable}; +use crate::group::Curve; use halo2_base::gates::builder::{parallelize_in, GateThreadBuilder}; +use halo2_base::utils::BigPrimeField; use halo2_base::{gates::GateInstructions, utils::CurveAffineExt, AssignedValue, Context}; use itertools::Itertools; use rayon::prelude::*; @@ -27,12 +29,12 @@ pub fn scalar_multiply( window_bits: usize, ) -> EcPoint where - F: PrimeField, + F: BigPrimeField, C: CurveAffineExt, FC: FieldChip + Selectable, { if point.is_identity().into() { - let zero = chip.load_constant(ctx, C::Base::zero()); + let zero = chip.load_constant(ctx, C::Base::ZERO); return EcPoint::new(zero.clone(), zero); } assert!(!scalar.is_empty()); @@ -119,7 +121,7 @@ pub fn msm_par( phase: usize, ) -> EcPoint where - F: PrimeField, + F: BigPrimeField, C: CurveAffineExt, FC: FieldChip + Selectable, { diff --git a/halo2-ecc/src/ecc/mod.rs b/halo2-ecc/src/ecc/mod.rs index a196e039..a3901e39 100644 --- a/halo2-ecc/src/ecc/mod.rs +++ b/halo2-ecc/src/ecc/mod.rs @@ -1,9 +1,10 @@ #![allow(non_snake_case)] -use crate::fields::{fp::FpChip, FieldChip, PrimeField, Selectable}; +use crate::ff::Field; +use crate::fields::{fp::FpChip, FieldChip, Selectable}; +use crate::group::{Curve, Group}; use crate::halo2_proofs::arithmetic::CurveAffine; -use group::{Curve, Group}; use halo2_base::gates::builder::GateThreadBuilder; -use halo2_base::utils::modulus; +use halo2_base::utils::{modulus, BigPrimeField}; use halo2_base::{ gates::{GateInstructions, RangeInstructions}, utils::CurveAffineExt, @@ -21,20 +22,20 @@ pub mod pippenger; // EcPoint and EccChip take in a generic `FieldChip` to implement generic elliptic curve operations on arbitrary field extensions (provided chip exists) for short Weierstrass curves (currently further assuming a4 = 0 for optimization purposes) #[derive(Debug)] -pub struct EcPoint { +pub struct EcPoint { pub x: FieldPoint, pub y: FieldPoint, _marker: PhantomData, } -impl Clone for EcPoint { +impl Clone for EcPoint { fn clone(&self) -> Self { Self { x: self.x.clone(), y: self.y.clone(), _marker: PhantomData } } } // Improve readability by allowing `&EcPoint` to be converted to `EcPoint` via cloning -impl<'a, F: PrimeField, FieldPoint: Clone> From<&'a EcPoint> +impl<'a, F: BigPrimeField, FieldPoint: Clone> From<&'a EcPoint> for EcPoint { fn from(value: &'a EcPoint) -> Self { @@ -42,7 +43,7 @@ impl<'a, F: PrimeField, FieldPoint: Clone> From<&'a EcPoint> } } -impl EcPoint { +impl EcPoint { pub fn new(x: FieldPoint, y: FieldPoint) -> Self { Self { x, y, _marker: PhantomData } } @@ -58,25 +59,25 @@ impl EcPoint { /// An elliptic curve point where it is easy to compare the x-coordinate of two points #[derive(Clone, Debug)] -pub struct StrictEcPoint> { +pub struct StrictEcPoint> { pub x: FC::ReducedFieldPoint, pub y: FC::FieldPoint, _marker: PhantomData, } -impl> StrictEcPoint { +impl> StrictEcPoint { pub fn new(x: FC::ReducedFieldPoint, y: FC::FieldPoint) -> Self { Self { x, y, _marker: PhantomData } } } -impl> From> for EcPoint { +impl> From> for EcPoint { fn from(value: StrictEcPoint) -> Self { Self::new(value.x.into(), value.y) } } -impl<'a, F: PrimeField, FC: FieldChip> From<&'a StrictEcPoint> +impl<'a, F: BigPrimeField, FC: FieldChip> From<&'a StrictEcPoint> for EcPoint { fn from(value: &'a StrictEcPoint) -> Self { @@ -87,18 +88,18 @@ impl<'a, F: PrimeField, FC: FieldChip> From<&'a StrictEcPoint> /// An elliptic curve point where the x-coordinate has already been constrained to be reduced or not. /// In the reduced case one can more optimally compare equality of x-coordinates. #[derive(Clone, Debug)] -pub enum ComparableEcPoint> { +pub enum ComparableEcPoint> { Strict(StrictEcPoint), NonStrict(EcPoint), } -impl> From> for ComparableEcPoint { +impl> From> for ComparableEcPoint { fn from(pt: StrictEcPoint) -> Self { Self::Strict(pt) } } -impl> From> +impl> From> for ComparableEcPoint { fn from(pt: EcPoint) -> Self { @@ -106,7 +107,7 @@ impl> From> } } -impl<'a, F: PrimeField, FC: FieldChip> From<&'a StrictEcPoint> +impl<'a, F: BigPrimeField, FC: FieldChip> From<&'a StrictEcPoint> for ComparableEcPoint { fn from(pt: &'a StrictEcPoint) -> Self { @@ -114,7 +115,7 @@ impl<'a, F: PrimeField, FC: FieldChip> From<&'a StrictEcPoint> } } -impl<'a, F: PrimeField, FC: FieldChip> From<&'a EcPoint> +impl<'a, F: BigPrimeField, FC: FieldChip> From<&'a EcPoint> for ComparableEcPoint { fn from(pt: &'a EcPoint) -> Self { @@ -122,7 +123,7 @@ impl<'a, F: PrimeField, FC: FieldChip> From<&'a EcPoint> } } -impl> From> +impl> From> for EcPoint { fn from(pt: ComparableEcPoint) -> Self { @@ -149,7 +150,7 @@ impl> From> /// /// # Assumptions /// * Neither `P` nor `Q` is the point at infinity (undefined behavior otherwise) -pub fn ec_add_unequal>( +pub fn ec_add_unequal>( chip: &FC, ctx: &mut Context, P: impl Into>, @@ -179,7 +180,7 @@ pub fn ec_add_unequal>( /// If `do_check = true`, then this function constrains that `P.x != Q.x`. /// Otherwise does nothing. -fn check_points_are_unequal>( +fn check_points_are_unequal>( chip: &FC, ctx: &mut Context, P: impl Into>, @@ -195,7 +196,7 @@ fn check_points_are_unequal>( ComparableEcPoint::NonStrict(pt) => chip.enforce_less_than(ctx, pt.x.clone()), }); let x_is_equal = chip.is_equal_unenforced(ctx, x1, x2); - chip.gate().assert_is_const(ctx, &x_is_equal, &F::zero()); + chip.gate().assert_is_const(ctx, &x_is_equal, &F::ZERO); } (EcPoint::from(P), EcPoint::from(Q)) } @@ -215,7 +216,7 @@ fn check_points_are_unequal>( /// /// # Assumptions /// * Neither `P` nor `Q` is the point at infinity (undefined behavior otherwise) -pub fn ec_sub_unequal>( +pub fn ec_sub_unequal>( chip: &FC, ctx: &mut Context, P: impl Into>, @@ -249,7 +250,7 @@ pub fn ec_sub_unequal>( /// /// Assumptions /// # Neither P or Q is the point at infinity -pub fn ec_sub_strict>( +pub fn ec_sub_strict>( chip: &FC, ctx: &mut Context, P: impl Into>, @@ -279,7 +280,7 @@ where P = ec_select(chip, ctx, rand_pt, P, is_identity); let out = ec_sub_unequal(chip, ctx, P, Q, false); - let zero = chip.load_constant(ctx, FC::FieldType::zero()); + let zero = chip.load_constant(ctx, FC::FieldType::ZERO); ec_select(chip, ctx, EcPoint::new(zero.clone(), zero), out, is_identity) } @@ -298,7 +299,7 @@ where /// # Assumptions /// * `P.y != 0` /// * `P` is not the point at infinity (undefined behavior otherwise) -pub fn ec_double>( +pub fn ec_double>( chip: &FC, ctx: &mut Context, P: impl Into>, @@ -337,7 +338,7 @@ pub fn ec_double>( /// /// # Assumptions /// * Neither `P` nor `Q` is the point at infinity (undefined behavior otherwise) -pub fn ec_double_and_add_unequal>( +pub fn ec_double_and_add_unequal>( chip: &FC, ctx: &mut Context, P: impl Into>, @@ -354,7 +355,7 @@ pub fn ec_double_and_add_unequal>( ComparableEcPoint::NonStrict(pt) => chip.enforce_less_than(ctx, pt.x.clone()), }); let x_is_equal = chip.is_equal_unenforced(ctx, x0.clone(), x1); - chip.gate().assert_is_const(ctx, &x_is_equal, &F::zero()); + chip.gate().assert_is_const(ctx, &x_is_equal, &F::ZERO); x_0 = Some(x0); } let P = EcPoint::from(P); @@ -375,7 +376,7 @@ pub fn ec_double_and_add_unequal>( // TODO: when can we remove this check? // constrains that x_2 != x_0 let x_is_equal = chip.is_equal_unenforced(ctx, x_0.unwrap(), x_2); - chip.range().gate().assert_is_const(ctx, &x_is_equal, &F::zero()); + chip.range().gate().assert_is_const(ctx, &x_is_equal, &F::ZERO); } // lambda_1 = lambda_0 + 2 * y_0 / (x_2 - x_0) let two_y_0 = chip.scalar_mul_no_carry(ctx, &P.y, 2); @@ -398,7 +399,7 @@ pub fn ec_double_and_add_unequal>( EcPoint::new(x_res, y_res) } -pub fn ec_select( +pub fn ec_select( chip: &FC, ctx: &mut Context, P: EcPoint, @@ -415,7 +416,7 @@ where // takes the dot product of points with sel, where each is intepreted as // a _vector_ -pub fn ec_select_by_indicator( +pub fn ec_select_by_indicator( chip: &FC, ctx: &mut Context, points: &[Pt], @@ -438,7 +439,7 @@ where } // `sel` is little-endian binary -pub fn ec_select_from_bits( +pub fn ec_select_from_bits( chip: &FC, ctx: &mut Context, points: &[Pt], @@ -455,7 +456,7 @@ where } // `sel` is little-endian binary -pub fn strict_ec_select_from_bits( +pub fn strict_ec_select_from_bits( chip: &FC, ctx: &mut Context, points: &[StrictEcPoint], @@ -484,7 +485,7 @@ where /// - The curve has no points of order 2. /// - `scalar_i < 2^{max_bits} for all i` /// - `max_bits <= modulus::.bits()`, and equality only allowed when the order of `P` equals the modulus of `F` -pub fn scalar_multiply( +pub fn scalar_multiply( chip: &FC, ctx: &mut Context, P: EcPoint, @@ -587,7 +588,7 @@ where /// Checks that `P` is indeed a point on the elliptic curve `C`. pub fn check_is_on_curve(chip: &FC, ctx: &mut Context, P: &EcPoint) where - F: PrimeField, + F: BigPrimeField, FC: FieldChip, C: CurveAffine, { @@ -602,7 +603,7 @@ where pub fn load_random_point(chip: &FC, ctx: &mut Context) -> EcPoint where - F: PrimeField, + F: BigPrimeField, FC: FieldChip, C: CurveAffineExt, { @@ -624,7 +625,7 @@ pub fn into_strict_point( pt: EcPoint, ) -> StrictEcPoint where - F: PrimeField, + F: BigPrimeField, FC: FieldChip, { let x = chip.enforce_less_than(ctx, pt.x); @@ -647,7 +648,7 @@ where /// * `points` are all on the curve or the point at infinity /// * `points[i]` is allowed to be (0, 0) to represent the point at infinity (identity point) /// * Currently implementation assumes that the only point on curve with y-coordinate equal to `0` is identity point -pub fn multi_scalar_multiply( +pub fn multi_scalar_multiply( chip: &FC, ctx: &mut Context, P: &[EcPoint], @@ -811,12 +812,12 @@ pub type BaseFieldEccChip<'chip, C> = EccChip< >; #[derive(Clone, Debug)] -pub struct EccChip<'chip, F: PrimeField, FC: FieldChip> { +pub struct EccChip<'chip, F: BigPrimeField, FC: FieldChip> { pub field_chip: &'chip FC, _marker: PhantomData, } -impl<'chip, F: PrimeField, FC: FieldChip> EccChip<'chip, F, FC> { +impl<'chip, F: BigPrimeField, FC: FieldChip> EccChip<'chip, F, FC> { pub fn new(field_chip: &'chip FC) -> Self { Self { field_chip, _marker: PhantomData } } @@ -856,11 +857,11 @@ impl<'chip, F: PrimeField, FC: FieldChip> EccChip<'chip, F, FC> { pub fn assign_point(&self, ctx: &mut Context, g: C) -> EcPoint where C: CurveAffineExt, - C::Base: ff::PrimeField, + C::Base: crate::ff::PrimeField, { let pt = self.assign_point_unchecked(ctx, g); let is_on_curve = self.is_on_curve_or_infinity::(ctx, &pt); - self.field_chip.gate().assert_is_const(ctx, &is_on_curve, &F::one()); + self.field_chip.gate().assert_is_const(ctx, &is_on_curve, &F::ONE); pt } @@ -1009,7 +1010,7 @@ impl<'chip, F: PrimeField, FC: FieldChip> EccChip<'chip, F, FC> { } } -impl<'chip, F: PrimeField, FC: FieldChip> EccChip<'chip, F, FC> +impl<'chip, F: BigPrimeField, FC: FieldChip> EccChip<'chip, F, FC> where FC: Selectable, { @@ -1103,7 +1104,7 @@ where } } -impl<'chip, F: PrimeField, FC: FieldChip> EccChip<'chip, F, FC> { +impl<'chip, F: BigPrimeField, FC: FieldChip> EccChip<'chip, F, FC> { /// See [`fixed_base::scalar_multiply`] for more details. // TODO: put a check in place that scalar is < modulus of C::Scalar pub fn fixed_base_scalar_mult( diff --git a/halo2-ecc/src/ecc/pippenger.rs b/halo2-ecc/src/ecc/pippenger.rs index 934a7432..6dc8071f 100644 --- a/halo2-ecc/src/ecc/pippenger.rs +++ b/halo2-ecc/src/ecc/pippenger.rs @@ -4,14 +4,14 @@ use super::{ }; use crate::{ ecc::ec_sub_strict, - fields::{FieldChip, PrimeField, Selectable}, + fields::{FieldChip, Selectable}, }; use halo2_base::{ gates::{ builder::{parallelize_in, GateThreadBuilder}, GateInstructions, }, - utils::CurveAffineExt, + utils::{BigPrimeField, CurveAffineExt}, AssignedValue, }; @@ -216,7 +216,7 @@ where /// * `points` are all on the curve or the point at infinity /// * `points[i]` is allowed to be (0, 0) to represent the point at infinity (identity point) /// * Currently implementation assumes that the only point on curve with y-coordinate equal to `0` is identity point -pub fn multi_exp_par( +pub fn multi_exp_par( chip: &FC, // these are the "threads" within a single Phase builder: &mut GateThreadBuilder, @@ -270,7 +270,7 @@ where let multi_prods = parallelize_in( phase, builder, - points.chunks(c).into_iter().zip(any_points.iter()).enumerate().collect(), + points.chunks(c).zip(any_points.iter()).enumerate().collect(), |ctx, (round, (points_clump, any_point))| { // compute all possible multi-products of elements in points[round * c .. round * (c+1)] // stores { any_point, any_point + points[0], any_point + points[1], any_point + points[0] + points[1] , ... } diff --git a/halo2-ecc/src/ecc/tests.rs b/halo2-ecc/src/ecc/tests.rs index 887f7cfc..d850ed89 100644 --- a/halo2-ecc/src/ecc/tests.rs +++ b/halo2-ecc/src/ecc/tests.rs @@ -1,14 +1,14 @@ #![allow(unused_assignments, unused_imports, unused_variables)] use super::*; use crate::fields::fp2::Fp2Chip; +use crate::group::Group; use crate::halo2_proofs::{ circuit::*, dev::MockProver, halo2curves::bn256::{Fq, Fr, G1Affine, G2Affine, G1, G2}, plonk::*, }; -use group::Group; -use halo2_base::gates::builder::{set_lookup_bits, RangeCircuitBuilder}; +use halo2_base::gates::builder::RangeCircuitBuilder; use halo2_base::gates::RangeChip; use halo2_base::utils::bigint_to_fe; use halo2_base::SKIP_FIRST_PASS; @@ -18,7 +18,7 @@ use rand_core::OsRng; use std::marker::PhantomData; use std::ops::Neg; -fn basic_g1_tests( +fn basic_g1_tests( ctx: &mut Context, lookup_bits: usize, limb_bits: usize, @@ -26,7 +26,6 @@ fn basic_g1_tests( P: G1Affine, Q: G1Affine, ) { - set_lookup_bits(lookup_bits); let range = RangeChip::::default(lookup_bits); let fp_chip = FpChip::::new(&range, limb_bits, num_limbs); let chip = EccChip::new(&fp_chip); @@ -66,10 +65,12 @@ fn test_ecc() { let Q = G1Affine::random(OsRng); let mut builder = GateThreadBuilder::::mock(); - basic_g1_tests(builder.main(0), k - 1, 88, 3, P, Q); + let lookup_bits = k - 1; + basic_g1_tests(builder.main(0), lookup_bits, 88, 3, P, Q); - builder.config(k, Some(20)); - let circuit = RangeCircuitBuilder::mock(builder); + let mut config_params = builder.config(k, Some(20)); + config_params.lookup_bits = Some(lookup_bits); + let circuit = RangeCircuitBuilder::mock(builder, config_params); MockProver::run(k as u32, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -90,8 +91,9 @@ fn plot_ecc() { let mut builder = GateThreadBuilder::::keygen(); basic_g1_tests(builder.main(0), 22, 88, 3, P, Q); - builder.config(k, Some(10)); - let circuit = RangeCircuitBuilder::mock(builder); + let mut config_params = builder.config(k, Some(10)); + config_params.lookup_bits = Some(22); + let circuit = RangeCircuitBuilder::mock(builder, config_params); halo2_proofs::dev::CircuitLayout::default().render(k, &circuit, &root).unwrap(); } diff --git a/halo2-ecc/src/fields/fp.rs b/halo2-ecc/src/fields/fp.rs index 54cffa1d..c26d8cc6 100644 --- a/halo2-ecc/src/fields/fp.rs +++ b/halo2-ecc/src/fields/fp.rs @@ -1,4 +1,4 @@ -use super::{FieldChip, PrimeField, PrimeFieldChip, Selectable}; +use super::{FieldChip, PrimeFieldChip, Selectable}; use crate::bigint::{ add_no_carry, big_is_equal, big_is_zero, carry_mod, check_carry_mod_to_zero, mul_no_carry, scalar_mul_and_add_no_carry, scalar_mul_no_carry, select, select_by_indicator, sub, @@ -6,7 +6,7 @@ use crate::bigint::{ }; use crate::halo2_proofs::halo2curves::CurveAffine; use halo2_base::gates::RangeChip; -use halo2_base::utils::ScalarField; +use halo2_base::utils::{BigPrimeField, ScalarField}; use halo2_base::{ gates::{range::RangeConfig, GateInstructions, RangeInstructions}, utils::{bigint_to_fe, biguint_to_fe, bit_length, decompose_biguint, fe_to_biguint, modulus}, @@ -48,7 +48,7 @@ impl From, Fp>> for ProperCrtUint { +pub struct FpChip<'range, F: BigPrimeField, Fp: BigPrimeField> { pub range: &'range RangeChip, pub limb_bits: usize, @@ -68,7 +68,7 @@ pub struct FpChip<'range, F: PrimeField, Fp: PrimeField> { _marker: PhantomData, } -impl<'range, F: PrimeField, Fp: PrimeField> FpChip<'range, F, Fp> { +impl<'range, F: BigPrimeField, Fp: BigPrimeField> FpChip<'range, F, Fp> { pub fn new(range: &'range RangeChip, limb_bits: usize, num_limbs: usize) -> Self { assert!(limb_bits > 0); assert!(num_limbs > 0); @@ -81,7 +81,7 @@ impl<'range, F: PrimeField, Fp: PrimeField> FpChip<'range, F, Fp> { let limb_base = biguint_to_fe::(&(BigUint::one() << limb_bits)); let mut limb_bases = Vec::with_capacity(num_limbs); - limb_bases.push(F::one()); + limb_bases.push(F::ONE); while limb_bases.len() != num_limbs { limb_bases.push(limb_base * limb_bases.last().unwrap()); } @@ -121,7 +121,7 @@ impl<'range, F: PrimeField, Fp: PrimeField> FpChip<'range, F, Fp> { }; borrow = Some(lt); } - self.gate().assert_is_const(ctx, &borrow.unwrap(), &F::one()); + self.gate().assert_is_const(ctx, &borrow.unwrap(), &F::ONE); } pub fn load_constant_uint(&self, ctx: &mut Context, a: BigUint) -> ProperCrtUint { @@ -133,7 +133,7 @@ impl<'range, F: PrimeField, Fp: PrimeField> FpChip<'range, F, Fp> { } } -impl<'range, F: PrimeField, Fp: PrimeField> PrimeFieldChip for FpChip<'range, F, Fp> { +impl<'range, F: BigPrimeField, Fp: BigPrimeField> PrimeFieldChip for FpChip<'range, F, Fp> { fn num_limbs(&self) -> usize { self.num_limbs } @@ -145,7 +145,7 @@ impl<'range, F: PrimeField, Fp: PrimeField> PrimeFieldChip for FpChip<'range, } } -impl<'range, F: PrimeField, Fp: PrimeField> FieldChip for FpChip<'range, F, Fp> { +impl<'range, F: BigPrimeField, Fp: BigPrimeField> FieldChip for FpChip<'range, F, Fp> { const PRIME_FIELD_NUM_BITS: u32 = Fp::NUM_BITS; type UnsafeFieldPoint = CRTInteger; type FieldPoint = ProperCrtUint; @@ -234,7 +234,7 @@ impl<'range, F: PrimeField, Fp: PrimeField> FieldChip for FpChip<'range, F, F let (out_or_p, underflow) = sub::crt(self.range(), ctx, p, a.clone(), self.limb_bits, self.limb_bases[1]); // constrain underflow to equal 0 - self.gate().assert_is_const(ctx, &underflow, &F::zero()); + self.gate().assert_is_const(ctx, &underflow, &F::ZERO); let a_is_zero = big_is_zero::positive(self.gate(), ctx, a.0.truncation.clone()); ProperCrtUint(select::crt(self.gate(), ctx, a.0, out_or_p, a_is_zero)) @@ -402,7 +402,9 @@ impl<'range, F: PrimeField, Fp: PrimeField> FieldChip for FpChip<'range, F, F } } -impl<'range, F: PrimeField, Fp: PrimeField> Selectable> for FpChip<'range, F, Fp> { +impl<'range, F: BigPrimeField, Fp: BigPrimeField> Selectable> + for FpChip<'range, F, Fp> +{ fn select( &self, ctx: &mut Context, @@ -423,7 +425,7 @@ impl<'range, F: PrimeField, Fp: PrimeField> Selectable> for FpC } } -impl<'range, F: PrimeField, Fp: PrimeField> Selectable> +impl<'range, F: BigPrimeField, Fp: BigPrimeField> Selectable> for FpChip<'range, F, Fp> { fn select( @@ -447,7 +449,7 @@ impl<'range, F: PrimeField, Fp: PrimeField> Selectable> } } -impl Selectable> for FC +impl Selectable> for FC where FC: Selectable, { diff --git a/halo2-ecc/src/fields/fp12.rs b/halo2-ecc/src/fields/fp12.rs index 156ca452..bdb9f790 100644 --- a/halo2-ecc/src/fields/fp12.rs +++ b/halo2-ecc/src/fields/fp12.rs @@ -1,15 +1,19 @@ use std::marker::PhantomData; -use halo2_base::{utils::modulus, AssignedValue, Context}; -use num_bigint::BigUint; - +use crate::ff::PrimeField as _; use crate::impl_field_ext_chip_common; use super::{ vector::{FieldVector, FieldVectorChip}, - FieldChip, FieldExtConstructor, PrimeField, PrimeFieldChip, + FieldChip, FieldExtConstructor, PrimeFieldChip, }; +use halo2_base::{ + utils::{modulus, BigPrimeField}, + AssignedValue, Context, +}; +use num_bigint::BigUint; + /// Represent Fp12 point as FqPoint with degree = 12 /// `Fp12 = Fp2[w] / (w^6 - u - xi)` /// This implementation assumes p = 3 (mod 4) in order for the polynomial u^2 + 1 to @@ -17,17 +21,17 @@ use super::{ /// This means we store an Fp12 point as `\sum_{i = 0}^6 (a_{i0} + a_{i1} * u) * w^i` /// This is encoded in an FqPoint of degree 12 as `(a_{00}, ..., a_{50}, a_{01}, ..., a_{51})` #[derive(Clone, Copy, Debug)] -pub struct Fp12Chip<'a, F: PrimeField, FpChip: FieldChip, Fp12, const XI_0: i64>( +pub struct Fp12Chip<'a, F: BigPrimeField, FpChip: FieldChip, Fp12, const XI_0: i64>( pub FieldVectorChip<'a, F, FpChip>, PhantomData, ); impl<'a, F, FpChip, Fp12, const XI_0: i64> Fp12Chip<'a, F, FpChip, Fp12, XI_0> where - F: PrimeField, + F: BigPrimeField, FpChip: PrimeFieldChip, - FpChip::FieldType: PrimeField, - Fp12: ff::Field, + FpChip::FieldType: BigPrimeField, + Fp12: crate::ff::Field, { /// User must construct an `FpChip` first using a config. This is intended so everything shares a single `FlexGateChip`, which is needed for the column allocation to work. pub fn new(fp_chip: &'a FpChip) -> Self { @@ -93,7 +97,7 @@ where /// /// # Assumptions /// * `a` is `Fp2` point represented as `FieldVector` with degree = 2 -pub fn mul_no_carry_w6, const XI_0: i64>( +pub fn mul_no_carry_w6, const XI_0: i64>( fp_chip: &FC, ctx: &mut Context, a: FieldVector, @@ -112,10 +116,10 @@ pub fn mul_no_carry_w6, const XI_0: i64>( impl<'a, F, FpChip, Fp12, const XI_0: i64> FieldChip for Fp12Chip<'a, F, FpChip, Fp12, XI_0> where - F: PrimeField, + F: BigPrimeField, FpChip: PrimeFieldChip, - FpChip::FieldType: PrimeField, - Fp12: ff::Field + FieldExtConstructor, + FpChip::FieldType: BigPrimeField, + Fp12: crate::ff::Field + FieldExtConstructor, FieldVector: From>, FieldVector: From>, { diff --git a/halo2-ecc/src/fields/fp2.rs b/halo2-ecc/src/fields/fp2.rs index 55e3243a..71c5d446 100644 --- a/halo2-ecc/src/fields/fp2.rs +++ b/halo2-ecc/src/fields/fp2.rs @@ -1,29 +1,30 @@ use std::fmt::Debug; use std::marker::PhantomData; -use halo2_base::{utils::modulus, AssignedValue, Context}; -use num_bigint::BigUint; - +use crate::ff::PrimeField as _; use crate::impl_field_ext_chip_common; use super::{ vector::{FieldVector, FieldVectorChip}, - FieldChip, FieldExtConstructor, PrimeField, PrimeFieldChip, + BigPrimeField, FieldChip, FieldExtConstructor, PrimeFieldChip, }; +use halo2_base::{utils::modulus, AssignedValue, Context}; +use num_bigint::BigUint; /// Represent Fp2 point as `FieldVector` with degree = 2 /// `Fp2 = Fp[u] / (u^2 + 1)` /// This implementation assumes p = 3 (mod 4) in order for the polynomial u^2 + 1 to be irreducible over Fp; i.e., in order for -1 to not be a square (quadratic residue) in Fp /// This means we store an Fp2 point as `a_0 + a_1 * u` where `a_0, a_1 in Fp` #[derive(Clone, Copy, Debug)] -pub struct Fp2Chip<'a, F: PrimeField, FpChip: FieldChip, Fp2>( +pub struct Fp2Chip<'a, F: BigPrimeField, FpChip: FieldChip, Fp2>( pub FieldVectorChip<'a, F, FpChip>, PhantomData, ); -impl<'a, F: PrimeField, FpChip: PrimeFieldChip, Fp2: ff::Field> Fp2Chip<'a, F, FpChip, Fp2> +impl<'a, F: BigPrimeField, FpChip: PrimeFieldChip, Fp2: crate::ff::Field> + Fp2Chip<'a, F, FpChip, Fp2> where - FpChip::FieldType: PrimeField, + FpChip::FieldType: BigPrimeField, { /// User must construct an `FpChip` first using a config. This is intended so everything shares a single `FlexGateChip`, which is needed for the column allocation to work. pub fn new(fp_chip: &'a FpChip) -> Self { @@ -66,10 +67,10 @@ where impl<'a, F, FpChip, Fp2> FieldChip for Fp2Chip<'a, F, FpChip, Fp2> where - F: PrimeField, - FpChip::FieldType: PrimeField, + F: BigPrimeField, + FpChip::FieldType: BigPrimeField, FpChip: PrimeFieldChip, - Fp2: ff::Field + FieldExtConstructor, + Fp2: crate::ff::Field + FieldExtConstructor, FieldVector: From>, FieldVector: From>, { diff --git a/halo2-ecc/src/fields/mod.rs b/halo2-ecc/src/fields/mod.rs index 0c55affa..5b3bde39 100644 --- a/halo2-ecc/src/fields/mod.rs +++ b/halo2-ecc/src/fields/mod.rs @@ -16,13 +16,11 @@ pub mod vector; #[cfg(test)] mod tests; -pub trait PrimeField = BigPrimeField; - /// Trait for common functionality for finite field chips. /// Primarily intended to emulate a "non-native" finite field using "native" values in a prime field `F`. /// Most functions are designed for the case when the non-native field is larger than the native field, but /// the trait can still be implemented and used in other cases. -pub trait FieldChip: Clone + Send + Sync { +pub trait FieldChip: Clone + Send + Sync { const PRIME_FIELD_NUM_BITS: u32; /// A representation of a field element that is used for intermediate computations. @@ -211,7 +209,7 @@ pub trait FieldChip: Clone + Send + Sync { ) -> Self::FieldPoint { let b = b.into(); let b_is_zero = self.is_zero(ctx, b.clone()); - self.gate().assert_is_const(ctx, &b_is_zero, &F::zero()); + self.gate().assert_is_const(ctx, &b_is_zero, &F::ZERO); self.divide_unsafe(ctx, a.into(), b) } @@ -253,7 +251,7 @@ pub trait FieldChip: Clone + Send + Sync { ) -> Self::FieldPoint { let b = b.into(); let b_is_zero = self.is_zero(ctx, b.clone()); - self.gate().assert_is_const(ctx, &b_is_zero, &F::zero()); + self.gate().assert_is_const(ctx, &b_is_zero, &F::ZERO); self.neg_divide_unsafe(ctx, a.into(), b) } @@ -296,9 +294,9 @@ pub trait Selectable { } // Common functionality for prime field chips -pub trait PrimeFieldChip: FieldChip +pub trait PrimeFieldChip: FieldChip where - Self::FieldType: PrimeField, + Self::FieldType: BigPrimeField, { fn num_limbs(&self) -> usize; fn limb_mask(&self) -> &BigUint; @@ -307,7 +305,7 @@ where // helper trait so we can actually construct and read the Fp2 struct // needs to be implemented for Fp2 struct for use cases below -pub trait FieldExtConstructor { +pub trait FieldExtConstructor { fn new(c: [Fp; DEGREE]) -> Self; fn coeffs(&self) -> Vec; diff --git a/halo2-ecc/src/fields/tests/fp/assert_eq.rs b/halo2-ecc/src/fields/tests/fp/assert_eq.rs index c364bb56..1765c7d5 100644 --- a/halo2-ecc/src/fields/tests/fp/assert_eq.rs +++ b/halo2-ecc/src/fields/tests/fp/assert_eq.rs @@ -1,7 +1,9 @@ -use ff::Field; +use crate::ff::Field; +use crate::{bn254::FpChip, fields::FieldChip}; + use halo2_base::{ gates::{ - builder::{set_lookup_bits, GateThreadBuilder, RangeCircuitBuilder}, + builder::{GateThreadBuilder, RangeCircuitBuilder}, RangeChip, }, halo2_proofs::{ @@ -10,14 +12,11 @@ use halo2_base::{ }, utils::testing::{check_proof, gen_proof}, }; - -use crate::{bn254::FpChip, fields::FieldChip}; use rand::thread_rng; // soundness checks for `` function fn test_fp_assert_eq_gen(k: u32, lookup_bits: usize, num_tries: usize) { let mut rng = thread_rng(); - set_lookup_bits(lookup_bits); // first create proving and verifying key let mut builder = GateThreadBuilder::keygen(); @@ -28,9 +27,9 @@ fn test_fp_assert_eq_gen(k: u32, lookup_bits: usize, num_tries: usize) { let a = chip.load_private(ctx, Fq::zero()); let b = chip.load_private(ctx, Fq::zero()); chip.assert_equal(ctx, &a, &b); - // set env vars - builder.config(k as usize, Some(9)); - let circuit = RangeCircuitBuilder::keygen(builder); + let mut config_params = builder.config(k as usize, Some(9)); + config_params.lookup_bits = Some(lookup_bits); + let circuit = RangeCircuitBuilder::keygen(builder, config_params.clone()); let params = ParamsKZG::setup(k, &mut rng); // generate proving key @@ -48,7 +47,7 @@ fn test_fp_assert_eq_gen(k: u32, lookup_bits: usize, num_tries: usize) { let ctx = builder.main(0); let [a, b] = [a, b].map(|x| chip.load_private(ctx, x)); chip.assert_equal(ctx, &a, &b); - let circuit = RangeCircuitBuilder::prover(builder, vec![vec![]]); // no break points + let circuit = RangeCircuitBuilder::prover(builder, config_params.clone(), vec![vec![]]); // no break points gen_proof(¶ms, &pk, circuit) }; diff --git a/halo2-ecc/src/fields/tests/fp/mod.rs b/halo2-ecc/src/fields/tests/fp/mod.rs index 9bfb9691..7eb9ead2 100644 --- a/halo2-ecc/src/fields/tests/fp/mod.rs +++ b/halo2-ecc/src/fields/tests/fp/mod.rs @@ -1,11 +1,12 @@ +use crate::ff::{Field as _, PrimeField as _}; use crate::fields::fp::FpChip; -use crate::fields::{FieldChip, PrimeField}; +use crate::fields::FieldChip; use crate::halo2_proofs::{ dev::MockProver, halo2curves::bn256::{Fq, Fr}, }; -use halo2_base::gates::builder::{set_lookup_bits, GateThreadBuilder, RangeCircuitBuilder}; +use halo2_base::gates::builder::{GateThreadBuilder, RangeCircuitBuilder}; use halo2_base::gates::RangeChip; use halo2_base::utils::biguint_to_fe; use halo2_base::utils::{fe_to_biguint, modulus}; @@ -23,15 +24,15 @@ fn fp_chip_test( num_limbs: usize, f: impl Fn(&mut Context, &FpChip), ) { - set_lookup_bits(lookup_bits); let range = RangeChip::::default(lookup_bits); let chip = FpChip::::new(&range, limb_bits, num_limbs); let mut builder = GateThreadBuilder::mock(); f(builder.main(0), &chip); - builder.config(k, Some(10)); - let circuit = RangeCircuitBuilder::mock(builder); + let mut config_params = builder.config(k, Some(10)); + config_params.lookup_bits = Some(lookup_bits); + let circuit = RangeCircuitBuilder::mock(builder, config_params); MockProver::run(k as u32, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -84,7 +85,7 @@ fn plot_fp() { let mut builder = GateThreadBuilder::keygen(); fp_mul_test(builder.main(0), k - 1, 88, 3, a, b); - builder.config(k, Some(10)); - let circuit = RangeCircuitBuilder::keygen(builder); + let config_params = builder.config(k, Some(10), Some(k - 1)); + let circuit = RangeCircuitBuilder::keygen(builder, config_params); halo2_proofs::dev::CircuitLayout::default().render(k as u32, &circuit, &root).unwrap(); } diff --git a/halo2-ecc/src/fields/tests/fp12/mod.rs b/halo2-ecc/src/fields/tests/fp12/mod.rs index 2a743401..148f411a 100644 --- a/halo2-ecc/src/fields/tests/fp12/mod.rs +++ b/halo2-ecc/src/fields/tests/fp12/mod.rs @@ -1,18 +1,20 @@ +use crate::ff::Field as _; use crate::fields::fp::FpChip; use crate::fields::fp12::Fp12Chip; -use crate::fields::{FieldChip, PrimeField}; +use crate::fields::FieldChip; use crate::halo2_proofs::{ dev::MockProver, halo2curves::bn256::{Fq, Fq12, Fr}, }; -use halo2_base::gates::builder::{set_lookup_bits, GateThreadBuilder, RangeCircuitBuilder}; +use halo2_base::gates::builder::{GateThreadBuilder, RangeCircuitBuilder}; use halo2_base::gates::RangeChip; +use halo2_base::utils::BigPrimeField; use halo2_base::Context; use rand_core::OsRng; const XI_0: i64 = 9; -fn fp12_mul_test( +fn fp12_mul_test( ctx: &mut Context, lookup_bits: usize, limb_bits: usize, @@ -20,7 +22,6 @@ fn fp12_mul_test( _a: Fq12, _b: Fq12, ) { - set_lookup_bits(lookup_bits); let range = RangeChip::::default(lookup_bits); let fp_chip = FpChip::::new(&range, limb_bits, num_limbs); let chip = Fp12Chip::::new(&fp_chip); @@ -41,10 +42,12 @@ fn test_fp12() { let b = Fq12::random(OsRng); let mut builder = GateThreadBuilder::::mock(); - fp12_mul_test(builder.main(0), k - 1, 88, 3, a, b); + let lookup_bits = k - 1; + fp12_mul_test(builder.main(0), lookup_bits, 88, 3, a, b); - builder.config(k, Some(20)); - let circuit = RangeCircuitBuilder::mock(builder); + let mut config_params = builder.config(k, Some(20)); + config_params.lookup_bits = Some(lookup_bits); + let circuit = RangeCircuitBuilder::mock(builder, config_params); MockProver::run(k as u32, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -64,10 +67,11 @@ fn plot_fp12() { let b = Fq12::zero(); let mut builder = GateThreadBuilder::::mock(); - fp12_mul_test(builder.main(0), k - 1, 88, 3, a, b); + let lookup_bits = k - 1; + fp12_mul_test(builder.main(0), lookup_bits, 88, 3, a, b); - builder.config(k, Some(20)); - let circuit = RangeCircuitBuilder::mock(builder); + let config_params = builder.config(k, Some(20), Some(lookup_bits)); + let circuit = RangeCircuitBuilder::mock(builder, config_params); halo2_proofs::dev::CircuitLayout::default().render(k, &circuit, &root).unwrap(); } diff --git a/halo2-ecc/src/fields/vector.rs b/halo2-ecc/src/fields/vector.rs index 6aea9d97..d27dc25f 100644 --- a/halo2-ecc/src/fields/vector.rs +++ b/halo2-ecc/src/fields/vector.rs @@ -1,4 +1,8 @@ -use halo2_base::{gates::GateInstructions, utils::ScalarField, AssignedValue, Context}; +use halo2_base::{ + gates::GateInstructions, + utils::{BigPrimeField, ScalarField}, + AssignedValue, Context, +}; use itertools::Itertools; use std::{ marker::PhantomData, @@ -7,7 +11,7 @@ use std::{ use crate::bigint::{CRTInteger, ProperCrtUint}; -use super::{fp::Reduced, FieldChip, FieldExtConstructor, PrimeField, PrimeFieldChip, Selectable}; +use super::{fp::Reduced, FieldChip, FieldExtConstructor, PrimeFieldChip, Selectable}; /// A fixed length vector of `FieldPoint`s #[repr(transparent)] @@ -63,16 +67,16 @@ impl IntoIterator for FieldVector { /// Contains common functionality for vector operations that can be derived from those of the underlying `FpChip` #[derive(Clone, Copy, Debug)] -pub struct FieldVectorChip<'fp, F: PrimeField, FpChip: FieldChip> { +pub struct FieldVectorChip<'fp, F: BigPrimeField, FpChip: FieldChip> { pub fp_chip: &'fp FpChip, _f: PhantomData, } impl<'fp, F, FpChip> FieldVectorChip<'fp, F, FpChip> where - F: PrimeField, + F: BigPrimeField, FpChip: PrimeFieldChip, - FpChip::FieldType: PrimeField, + FpChip::FieldType: BigPrimeField, { pub fn new(fp_chip: &'fp FpChip) -> Self { Self { fp_chip, _f: PhantomData } diff --git a/halo2-ecc/src/lib.rs b/halo2-ecc/src/lib.rs index 10da56bc..c4a47c15 100644 --- a/halo2-ecc/src/lib.rs +++ b/halo2-ecc/src/lib.rs @@ -1,7 +1,6 @@ #![allow(clippy::too_many_arguments)] #![allow(clippy::op_ref)] #![allow(clippy::type_complexity)] -#![feature(int_log)] #![feature(trait_alias)] pub mod bigint; @@ -13,3 +12,6 @@ pub mod secp256k1; pub use halo2_base; pub(crate) use halo2_base::halo2_proofs; +use halo2_proofs::halo2curves; +use halo2curves::ff; +use halo2curves::group; diff --git a/halo2-ecc/src/secp256k1/tests/ecdsa.rs b/halo2-ecc/src/secp256k1/tests/ecdsa.rs index b4e07a8b..7a677aa5 100644 --- a/halo2-ecc/src/secp256k1/tests/ecdsa.rs +++ b/halo2-ecc/src/secp256k1/tests/ecdsa.rs @@ -1,4 +1,5 @@ #![allow(non_snake_case)] +use crate::ff::Field as _; use crate::fields::FpStrategy; use crate::halo2_proofs::{ arithmetic::CurveAffine, @@ -20,16 +21,16 @@ use crate::halo2_proofs::{ use crate::secp256k1::{FpChip, FqChip}; use crate::{ ecc::{ecdsa::ecdsa_verify_no_pubkey_check, EccChip}, - fields::{FieldChip, PrimeField}, + fields::FieldChip, }; use ark_std::{end_timer, start_timer}; use halo2_base::gates::builder::{ - set_lookup_bits, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, + BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder, }; use halo2_base::gates::RangeChip; use halo2_base::utils::fs::gen_srs; -use halo2_base::utils::{biguint_to_fe, fe_to_biguint, modulus}; +use halo2_base::utils::{biguint_to_fe, fe_to_biguint, modulus, BigPrimeField}; use halo2_base::Context; use rand_core::OsRng; use serde::{Deserialize, Serialize}; @@ -50,7 +51,7 @@ struct CircuitParams { num_limbs: usize, } -fn ecdsa_test( +fn ecdsa_test( ctx: &mut Context, params: CircuitParams, r: Fq, @@ -58,7 +59,6 @@ fn ecdsa_test( msghash: Fq, pk: Secp256k1Affine, ) { - set_lookup_bits(params.lookup_bits); let range = RangeChip::::default(params.lookup_bits); let fp_chip = FpChip::::new(&range, params.limb_bits, params.num_limbs); let fq_chip = FqChip::::new(&range, params.limb_bits, params.num_limbs); @@ -71,12 +71,13 @@ fn ecdsa_test( let res = ecdsa_verify_no_pubkey_check::( &ecc_chip, ctx, pk, r, s, m, 4, 4, ); - assert_eq!(res.value(), &F::one()); + assert_eq!(res.value(), &F::ONE); } fn random_ecdsa_circuit( params: CircuitParams, stage: CircuitBuilderStage, + config_params: Option, break_points: Option, ) -> RangeCircuitBuilder { let mut builder = match stage { @@ -100,16 +101,15 @@ fn random_ecdsa_circuit( let start0 = start_timer!(|| format!("Witness generation for circuit in {stage:?} stage")); ecdsa_test(builder.main(0), params, r, s, msg_hash, pubkey); + let mut config_params = + config_params.unwrap_or_else(|| builder.config(params.degree as usize, Some(20))); + config_params.lookup_bits = Some(params.lookup_bits); let circuit = match stage { - CircuitBuilderStage::Mock => { - builder.config(params.degree as usize, Some(20)); - RangeCircuitBuilder::mock(builder) + CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder, config_params), + CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder, config_params), + CircuitBuilderStage::Prover => { + RangeCircuitBuilder::prover(builder, config_params, break_points.unwrap()) } - CircuitBuilderStage::Keygen => { - builder.config(params.degree as usize, Some(20)); - RangeCircuitBuilder::keygen(builder) - } - CircuitBuilderStage::Prover => RangeCircuitBuilder::prover(builder, break_points.unwrap()), }; end_timer!(start0); circuit @@ -123,7 +123,7 @@ fn test_secp256k1_ecdsa() { ) .unwrap(); - let circuit = random_ecdsa_circuit(params, CircuitBuilderStage::Mock, None); + let circuit = random_ecdsa_circuit(params, CircuitBuilderStage::Mock, None, None); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -148,7 +148,7 @@ fn bench_secp256k1_ecdsa() -> Result<(), Box> { let params = gen_srs(k); println!("{bench_params:?}"); - let circuit = random_ecdsa_circuit(bench_params, CircuitBuilderStage::Keygen, None); + let circuit = random_ecdsa_circuit(bench_params, CircuitBuilderStage::Keygen, None, None); let vk_time = start_timer!(|| "Generating vkey"); let vk = keygen_vk(¶ms, &circuit)?; @@ -159,11 +159,16 @@ fn bench_secp256k1_ecdsa() -> Result<(), Box> { end_timer!(pk_time); let break_points = circuit.0.break_points.take(); + let config_params = circuit.0.config_params.clone(); drop(circuit); // create a proof let proof_time = start_timer!(|| "Proving time"); - let circuit = - random_ecdsa_circuit(bench_params, CircuitBuilderStage::Prover, Some(break_points)); + let circuit = random_ecdsa_circuit( + bench_params, + CircuitBuilderStage::Prover, + Some(config_params), + Some(break_points), + ); let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); create_proof::< KZGCommitmentScheme, diff --git a/halo2-ecc/src/secp256k1/tests/ecdsa_tests.rs b/halo2-ecc/src/secp256k1/tests/ecdsa_tests.rs index da55f3df..0195231f 100644 --- a/halo2-ecc/src/secp256k1/tests/ecdsa_tests.rs +++ b/halo2-ecc/src/secp256k1/tests/ecdsa_tests.rs @@ -1,4 +1,5 @@ #![allow(non_snake_case)] +use crate::ff::Field as _; use crate::halo2_proofs::{ arithmetic::CurveAffine, dev::MockProver, @@ -8,12 +9,15 @@ use crate::halo2_proofs::{ use crate::secp256k1::{FpChip, FqChip}; use crate::{ ecc::{ecdsa::ecdsa_verify_no_pubkey_check, EccChip}, - fields::{FieldChip, PrimeField}, + fields::FieldChip, }; use ark_std::{end_timer, start_timer}; -use halo2_base::gates::builder::{ - set_lookup_bits, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, - RangeCircuitBuilder, +use halo2_base::gates::builder::BaseConfigParams; +use halo2_base::{ + gates::builder::{ + CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder, + }, + utils::BigPrimeField, }; use halo2_base::gates::RangeChip; @@ -26,7 +30,7 @@ use test_case::test_case; use super::CircuitParams; -fn ecdsa_test( +fn ecdsa_test( ctx: &mut Context, params: CircuitParams, r: Fq, @@ -34,7 +38,6 @@ fn ecdsa_test( msghash: Fq, pk: Secp256k1Affine, ) { - set_lookup_bits(params.lookup_bits); let range = RangeChip::::default(params.lookup_bits); let fp_chip = FpChip::::new(&range, params.limb_bits, params.num_limbs); let fq_chip = FqChip::::new(&range, params.limb_bits, params.num_limbs); @@ -47,7 +50,7 @@ fn ecdsa_test( let res = ecdsa_verify_no_pubkey_check::( &ecc_chip, ctx, pk, r, s, m, 4, 4, ); - assert_eq!(res.value(), &F::one()); + assert_eq!(res.value(), &F::ONE); } fn random_parameters_ecdsa() -> (Fq, Fq, Fq, Secp256k1Affine) { @@ -93,6 +96,7 @@ fn ecdsa_circuit( pubkey: Secp256k1Affine, params: CircuitParams, stage: CircuitBuilderStage, + config_params: Option, break_points: Option, ) -> RangeCircuitBuilder { let mut builder = match stage { @@ -103,16 +107,15 @@ fn ecdsa_circuit( let start0 = start_timer!(|| format!("Witness generation for circuit in {stage:?} stage")); ecdsa_test(builder.main(0), params, r, s, msg_hash, pubkey); + let mut config_params = + config_params.unwrap_or_else(|| builder.config(params.degree as usize, Some(20))); + config_params.lookup_bits = Some(params.lookup_bits); let circuit = match stage { - CircuitBuilderStage::Mock => { - builder.config(params.degree as usize, Some(20)); - RangeCircuitBuilder::mock(builder) + CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder, config_params), + CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder, config_params), + CircuitBuilderStage::Prover => { + RangeCircuitBuilder::prover(builder, config_params, break_points.unwrap()) } - CircuitBuilderStage::Keygen => { - builder.config(params.degree as usize, Some(20)); - RangeCircuitBuilder::keygen(builder) - } - CircuitBuilderStage::Prover => RangeCircuitBuilder::prover(builder, break_points.unwrap()), }; end_timer!(start0); circuit @@ -129,7 +132,8 @@ fn test_ecdsa_msg_hash_zero() { let (r, s, msg_hash, pubkey) = custom_parameters_ecdsa(random::(), 0, random::()); - let circuit = ecdsa_circuit(r, s, msg_hash, pubkey, params, CircuitBuilderStage::Mock, None); + let circuit = + ecdsa_circuit(r, s, msg_hash, pubkey, params, CircuitBuilderStage::Mock, None, None); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -144,7 +148,8 @@ fn test_ecdsa_private_key_zero() { let (r, s, msg_hash, pubkey) = custom_parameters_ecdsa(0, random::(), random::()); - let circuit = ecdsa_circuit(r, s, msg_hash, pubkey, params, CircuitBuilderStage::Mock, None); + let circuit = + ecdsa_circuit(r, s, msg_hash, pubkey, params, CircuitBuilderStage::Mock, None, None); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -158,7 +163,8 @@ fn test_ecdsa_random_valid_inputs() { let (r, s, msg_hash, pubkey) = random_parameters_ecdsa(); - let circuit = ecdsa_circuit(r, s, msg_hash, pubkey, params, CircuitBuilderStage::Mock, None); + let circuit = + ecdsa_circuit(r, s, msg_hash, pubkey, params, CircuitBuilderStage::Mock, None, None); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -172,7 +178,8 @@ fn test_ecdsa_custom_valid_inputs(sk: u64, msg_hash: u64, k: u64) { let (r, s, msg_hash, pubkey) = custom_parameters_ecdsa(sk, msg_hash, k); - let circuit = ecdsa_circuit(r, s, msg_hash, pubkey, params, CircuitBuilderStage::Mock, None); + let circuit = + ecdsa_circuit(r, s, msg_hash, pubkey, params, CircuitBuilderStage::Mock, None, None); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } @@ -187,6 +194,7 @@ fn test_ecdsa_custom_valid_inputs_negative_s(sk: u64, msg_hash: u64, k: u64) { let (r, s, msg_hash, pubkey) = custom_parameters_ecdsa(sk, msg_hash, k); let s = -s; - let circuit = ecdsa_circuit(r, s, msg_hash, pubkey, params, CircuitBuilderStage::Mock, None); + let circuit = + ecdsa_circuit(r, s, msg_hash, pubkey, params, CircuitBuilderStage::Mock, None, None); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } diff --git a/halo2-ecc/src/secp256k1/tests/mod.rs b/halo2-ecc/src/secp256k1/tests/mod.rs index 997b432e..dde635ee 100644 --- a/halo2-ecc/src/secp256k1/tests/mod.rs +++ b/halo2-ecc/src/secp256k1/tests/mod.rs @@ -1,12 +1,12 @@ #![allow(non_snake_case)] use std::fs::File; -use ff::Field; -use group::Curve; +use crate::ff::Field; +use crate::group::Curve; use halo2_base::{ gates::{ builder::{ - set_lookup_bits, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, + BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder, }, RangeChip, @@ -53,7 +53,6 @@ fn sm_test( scalar: Fq, window_bits: usize, ) { - set_lookup_bits(params.lookup_bits); let range = RangeChip::::default(params.lookup_bits); let fp_chip = FpChip::::new(&range, params.limb_bits, params.num_limbs); let fq_chip = FqChip::::new(&range, params.limb_bits, params.num_limbs); @@ -81,6 +80,7 @@ fn sm_test( fn sm_circuit( params: CircuitParams, stage: CircuitBuilderStage, + config_params: Option, break_points: Option, base: Secp256k1Affine, scalar: Fq, @@ -90,16 +90,14 @@ fn sm_circuit( sm_test(builder.main(0), params, base, scalar, 4); + let mut config_params = config_params.unwrap_or_else(|| builder.config(k, Some(20))); + config_params.lookup_bits = Some(params.lookup_bits); match stage { - CircuitBuilderStage::Mock => { - builder.config(k, Some(20)); - RangeCircuitBuilder::mock(builder) + CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder, config_params), + CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder, config_params), + CircuitBuilderStage::Prover => { + RangeCircuitBuilder::prover(builder, config_params, break_points.unwrap()) } - CircuitBuilderStage::Keygen => { - builder.config(k, Some(20)); - RangeCircuitBuilder::keygen(builder) - } - CircuitBuilderStage::Prover => RangeCircuitBuilder::prover(builder, break_points.unwrap()), } } @@ -115,6 +113,7 @@ fn test_secp_sm_random() { params, CircuitBuilderStage::Mock, None, + None, Secp256k1Affine::random(OsRng), Fq::random(OsRng), ); @@ -133,7 +132,7 @@ fn test_secp_sm_minus_1() { let mut s = -Fq::one(); let mut n = fe_to_biguint(&s); loop { - let circuit = sm_circuit(params, CircuitBuilderStage::Mock, None, base, s); + let circuit = sm_circuit(params, CircuitBuilderStage::Mock, None, None, base, s); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); if &n % BigUint::from(2usize) == BigUint::from(0usize) { break; @@ -153,10 +152,10 @@ fn test_secp_sm_0_1() { let base = Secp256k1Affine::random(OsRng); let s = Fq::zero(); - let circuit = sm_circuit(params, CircuitBuilderStage::Mock, None, base, s); + let circuit = sm_circuit(params, CircuitBuilderStage::Mock, None, None, base, s); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); let s = Fq::one(); - let circuit = sm_circuit(params, CircuitBuilderStage::Mock, None, base, s); + let circuit = sm_circuit(params, CircuitBuilderStage::Mock, None, None, base, s); MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); } diff --git a/hashes/zkevm-keccak/Cargo.toml b/hashes/zkevm-keccak/Cargo.toml index abbad893..542abb23 100644 --- a/hashes/zkevm-keccak/Cargo.toml +++ b/hashes/zkevm-keccak/Cargo.toml @@ -1,26 +1,26 @@ [package] name = "zkevm-keccak" -version = "0.1.0" +version = "0.1.1" edition = "2021" license = "MIT OR Apache-2.0" [dependencies] array-init = "2.0.0" -ethers-core = "0.17.0" +ethers-core = "2.0.8" rand = "0.8" -itertools = "0.10.3" +itertools = "0.11" lazy_static = "1.4" log = "0.4" num-bigint = { version = "0.4" } halo2-base = { path = "../../halo2-base", default-features = false } -rayon = "1.6.1" +rayon = "1.7" [dev-dependencies] criterion = "0.3" ctor = "0.1.22" -ethers-signers = "0.17.0" +ethers-signers = "2.0.8" hex = "0.4.3" -itertools = "0.10.1" +itertools = "0.11" pretty_assertions = "1.0.0" rand_core = "0.6.4" rand_xorshift = "0.3" @@ -32,3 +32,6 @@ default = ["halo2-axiom", "display"] display = ["halo2-base/display"] halo2-pse = ["halo2-base/halo2-pse"] halo2-axiom = ["halo2-base/halo2-axiom"] +jemallocator = ["halo2-base/jemallocator"] +mimalloc = ["halo2-base/mimalloc"] +asm = ["halo2-base/asm"] \ No newline at end of file diff --git a/hashes/zkevm-keccak/src/keccak_packed_multi.rs b/hashes/zkevm-keccak/src/keccak_packed_multi.rs index f7df8cd5..d6e04c38 100644 --- a/hashes/zkevm-keccak/src/keccak_packed_multi.rs +++ b/hashes/zkevm-keccak/src/keccak_packed_multi.rs @@ -8,8 +8,8 @@ use super::util::{ NUM_WORDS_TO_ABSORB, NUM_WORDS_TO_SQUEEZE, RATE, RATE_IN_BITS, RHO_MATRIX, ROUND_CST, }; use crate::halo2_proofs::{ - arithmetic::FieldExt, circuit::{Layouter, Region, Value}, + halo2curves::ff::PrimeField, plonk::{ Advice, Challenge, Column, ConstraintSystem, Error, Expression, Fixed, SecondPhase, TableColumn, VirtualCells, @@ -20,7 +20,7 @@ use halo2_base::halo2_proofs::{circuit::AssignedCell, plonk::Assigned}; use itertools::Itertools; use log::{debug, info}; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; -use std::{cell::RefCell, marker::PhantomData}; +use std::marker::PhantomData; #[cfg(test)] mod tests; @@ -31,10 +31,6 @@ const THETA_C_LOOKUP_RANGE: usize = 6; const RHO_PI_LOOKUP_RANGE: usize = 4; const CHI_BASE_LOOKUP_RANGE: usize = 5; -thread_local! { - pub static KECCAK_CONFIG_PARAMS: RefCell = RefCell::new(Default::default()); -} - fn get_num_bits_per_absorb_lookup(k: u32) -> usize { get_num_bits_per_lookup(ABSORB_LOOKUP_RANGE, k) } @@ -67,7 +63,7 @@ pub fn get_num_keccak_f(byte_length: usize) -> usize { /// AbsorbData #[derive(Clone, Default, Debug, PartialEq)] -pub(crate) struct AbsorbData { +pub(crate) struct AbsorbData { from: F, absorb: F, result: F, @@ -75,13 +71,13 @@ pub(crate) struct AbsorbData { /// SqueezeData #[derive(Clone, Default, Debug, PartialEq)] -pub(crate) struct SqueezeData { +pub(crate) struct SqueezeData { packed: F, } /// KeccakRow #[derive(Clone, Debug)] -pub struct KeccakRow { +pub struct KeccakRow { q_enable: bool, // q_enable_row: bool, q_round: bool, @@ -99,7 +95,7 @@ pub struct KeccakRow { // hash_rlc: Value, } -impl KeccakRow { +impl KeccakRow { pub fn dummy_rows(num_rows: usize) -> Vec { (0..num_rows) .map(|idx| KeccakRow { @@ -110,7 +106,7 @@ impl KeccakRow { q_round_last: false, q_padding: false, q_padding_last: false, - round_cst: F::zero(), + round_cst: F::ZERO, is_final: false, cell_values: Vec::new(), }) @@ -120,7 +116,7 @@ impl KeccakRow { /// Part #[derive(Clone, Debug)] -pub(crate) struct Part { +pub(crate) struct Part { cell: Cell, expr: Expression, num_bits: usize, @@ -128,7 +124,7 @@ pub(crate) struct Part { /// Part Value #[derive(Clone, Copy, Debug)] -pub(crate) struct PartValue { +pub(crate) struct PartValue { value: F, rot: i32, num_bits: usize, @@ -139,7 +135,7 @@ pub(crate) struct KeccakRegion { pub(crate) rows: Vec>, } -impl KeccakRegion { +impl KeccakRegion { pub(crate) fn new() -> Self { Self { rows: Vec::new() } } @@ -150,7 +146,7 @@ impl KeccakRegion { } let row = &mut self.rows[offset]; while column >= row.len() { - row.push(F::zero()); + row.push(F::ZERO); } row[column] = value; } @@ -165,7 +161,7 @@ pub(crate) struct Cell { rotation: i32, } -impl Cell { +impl Cell { pub(crate) fn new( meta: &mut VirtualCells, column: Column, @@ -212,13 +208,13 @@ impl Cell { } } -impl Expr for Cell { +impl Expr for Cell { fn expr(&self) -> Expression { self.expression.clone() } } -impl Expr for &Cell { +impl Expr for &Cell { fn expr(&self) -> Expression { self.expression.clone() } @@ -243,7 +239,7 @@ pub(crate) struct CellManager { num_unused_cells: usize, } -impl CellManager { +impl CellManager { pub(crate) fn new(height: usize) -> Self { Self { height, @@ -427,18 +423,18 @@ pub fn assign_fixed_custom( /// Recombines parts back together mod decode { - use super::{Expr, FieldExt, Part, PartValue}; + use super::{Expr, Part, PartValue, PrimeField}; use crate::halo2_proofs::plonk::Expression; use crate::util::BIT_COUNT; - pub(crate) fn expr(parts: Vec>) -> Expression { + pub(crate) fn expr(parts: Vec>) -> Expression { parts.iter().rev().fold(0.expr(), |acc, part| { acc * F::from(1u64 << (BIT_COUNT * part.num_bits)) + part.expr.clone() }) } - pub(crate) fn value(parts: Vec>) -> F { - parts.iter().rev().fold(F::zero(), |acc, part| { + pub(crate) fn value(parts: Vec>) -> F { + parts.iter().rev().fold(F::ZERO, |acc, part| { acc * F::from(1u64 << (BIT_COUNT * part.num_bits)) + part.value }) } @@ -447,14 +443,14 @@ mod decode { /// Splits a word into parts mod split { use super::{ - decode, BaseConstraintBuilder, CellManager, Expr, Field, FieldExt, KeccakRegion, Part, - PartValue, + decode, BaseConstraintBuilder, CellManager, Expr, Field, KeccakRegion, Part, PartValue, + PrimeField, }; use crate::halo2_proofs::plonk::{ConstraintSystem, Expression}; use crate::util::{pack, pack_part, unpack, WordParts}; #[allow(clippy::too_many_arguments)] - pub(crate) fn expr( + pub(crate) fn expr( meta: &mut ConstraintSystem, cell_manager: &mut CellManager, cb: &mut BaseConstraintBuilder, @@ -519,8 +515,8 @@ mod split { // table layout in `output_cells` regardless of rotation. mod split_uniform { use super::{ - decode, target_part_sizes, BaseConstraintBuilder, Cell, CellManager, Expr, FieldExt, - KeccakRegion, Part, PartValue, + decode, target_part_sizes, BaseConstraintBuilder, Cell, CellManager, Expr, KeccakRegion, + Part, PartValue, PrimeField, }; use crate::halo2_proofs::plonk::{ConstraintSystem, Expression}; use crate::util::{ @@ -528,7 +524,7 @@ mod split_uniform { }; #[allow(clippy::too_many_arguments)] - pub(crate) fn expr( + pub(crate) fn expr( meta: &mut ConstraintSystem, output_cells: &[Cell], cell_manager: &mut CellManager, @@ -688,12 +684,12 @@ mod split_uniform { // Transform values using a lookup table mod transform { - use super::{transform_to, CellManager, Field, FieldExt, KeccakRegion, Part, PartValue}; + use super::{transform_to, CellManager, Field, KeccakRegion, Part, PartValue, PrimeField}; use crate::halo2_proofs::plonk::{ConstraintSystem, TableColumn}; use itertools::Itertools; #[allow(clippy::too_many_arguments)] - pub(crate) fn expr( + pub(crate) fn expr( name: &'static str, meta: &mut ConstraintSystem, cell_manager: &mut CellManager, @@ -747,12 +743,12 @@ mod transform { // Transfroms values to cells mod transform_to { - use super::{Cell, Expr, Field, FieldExt, KeccakRegion, Part, PartValue}; + use super::{Cell, Expr, Field, KeccakRegion, Part, PartValue, PrimeField}; use crate::halo2_proofs::plonk::{ConstraintSystem, TableColumn}; use crate::util::{pack, to_bytes, unpack}; #[allow(clippy::too_many_arguments)] - pub(crate) fn expr( + pub(crate) fn expr( name: &'static str, meta: &mut ConstraintSystem, cells: &[Cell], @@ -1609,19 +1605,19 @@ impl KeccakCircuitConfig { /// Computes and assigns the input RLC values (but not the output RLC values: /// see `multi_keccak_phase1`). -pub fn keccak_phase1<'v, F: Field>( +pub fn keccak_phase1( region: &mut Region, keccak_table: &KeccakTable, bytes: &[u8], challenge: Value, - input_rlcs: &mut Vec>, + input_rlcs: &mut Vec>, offset: &mut usize, rows_per_round: usize, ) { let num_chunks = get_num_keccak_f(bytes.len()); let mut byte_idx = 0; - let mut data_rlc = Value::known(F::zero()); + let mut data_rlc = Value::known(F::ZERO); for _ in 0..num_chunks { for round in 0..NUM_ROUNDS + 1 { @@ -1662,7 +1658,7 @@ pub fn keccak_phase0( let num_rows_per_round = parameters.rows_per_round; let mut bits = into_bits(bytes); - let mut s = [[F::zero(); 5]; 5]; + let mut s = [[F::ZERO; 5]; 5]; let absorb_positions = get_absorb_positions(); let num_bytes_in_last_block = bytes.len() % RATE; let two = F::from(2u64); @@ -1679,7 +1675,7 @@ pub fn keccak_phase0( let mut cell_managers = Vec::with_capacity(NUM_ROUNDS + 1); let mut regions = Vec::with_capacity(NUM_ROUNDS + 1); - let mut hash_words = [F::zero(); NUM_WORDS_TO_SQUEEZE]; + let mut hash_words = [F::ZERO; NUM_WORDS_TO_SQUEEZE]; for (idx, chunk) in chunks.enumerate() { let is_final_block = idx == num_chunks - 1; @@ -1784,7 +1780,7 @@ pub fn keccak_phase0( bc.push(bc_norm); } cell_manager.start_region(); - let mut os = [[F::zero(); 5]; 5]; + let mut os = [[F::ZERO; 5]; 5]; for i in 0..5 { let t = decode::value(bc[(i + 4) % 5].clone()) + decode::value(rotate(bc[(i + 1) % 5].clone(), 1, part_size)); @@ -1847,7 +1843,7 @@ pub fn keccak_phase0( // Chi let part_size_base = get_num_bits_per_base_chi_lookup(k); let three_packed = pack::(&vec![3u8; part_size_base]); - let mut os = [[F::zero(); 5]; 5]; + let mut os = [[F::ZERO; 5]; 5]; for j in 0..5 { for i in 0..5 { let mut s_parts = Vec::new(); @@ -1988,7 +1984,7 @@ pub fn multi_keccak_phase1<'a, 'v, F: Field>( let rows_per_round = parameters.rows_per_round; for idx in 0..rows_per_round { [keccak_table.input_rlc, keccak_table.output_rlc] - .map(|column| assign_advice_custom(region, column, idx, Value::known(F::zero()))); + .map(|column| assign_advice_custom(region, column, idx, Value::known(F::ZERO))); } let mut offset = rows_per_round; diff --git a/hashes/zkevm-keccak/src/keccak_packed_multi/tests.rs b/hashes/zkevm-keccak/src/keccak_packed_multi/tests.rs index 0797ef13..a0c3f28a 100644 --- a/hashes/zkevm-keccak/src/keccak_packed_multi/tests.rs +++ b/hashes/zkevm-keccak/src/keccak_packed_multi/tests.rs @@ -18,13 +18,14 @@ use crate::halo2_proofs::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, }; -use halo2_base::SKIP_FIRST_PASS; +use halo2_base::{halo2_proofs::halo2curves::ff::FromUniformBytes, SKIP_FIRST_PASS}; use rand_core::OsRng; use test_case::test_case; /// KeccakCircuit #[derive(Default, Clone, Debug)] pub struct KeccakCircuit { + config: KeccakConfigParams, inputs: Vec>, num_rows: Option, _marker: PhantomData, @@ -34,20 +35,28 @@ pub struct KeccakCircuit { impl Circuit for KeccakCircuit { type Config = KeccakCircuitConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = KeccakConfigParams; + + fn params(&self) -> Self::Params { + self.config + } fn without_witnesses(&self) -> Self { Self::default() } - fn configure(meta: &mut ConstraintSystem) -> Self::Config { + fn configure_with_params(meta: &mut ConstraintSystem, params: Self::Params) -> Self::Config { // MockProver complains if you only have columns in SecondPhase, so let's just make an empty column in FirstPhase meta.advice_column(); let challenge = meta.challenge_usable_after(FirstPhase); - let params = KECCAK_CONFIG_PARAMS.with(|conf| *conf.borrow()); KeccakCircuitConfig::new(meta, challenge, params) } + fn configure(_: &mut ConstraintSystem) -> Self::Config { + unreachable!() + } + fn synthesize( &self, config: Self::Config, @@ -95,13 +104,18 @@ impl Circuit for KeccakCircuit { impl KeccakCircuit { /// Creates a new circuit instance - pub fn new(num_rows: Option, inputs: Vec>) -> Self { - KeccakCircuit { inputs, num_rows, _marker: PhantomData } + pub fn new(config: KeccakConfigParams, num_rows: Option, inputs: Vec>) -> Self { + KeccakCircuit { config, inputs, num_rows, _marker: PhantomData } } } -fn verify(k: u32, inputs: Vec>, _success: bool) { - let circuit = KeccakCircuit::new(Some(2usize.pow(k) - 109), inputs); +fn verify>( + config: KeccakConfigParams, + inputs: Vec>, + _success: bool, +) { + let k = config.k; + let circuit = KeccakCircuit::new(config, Some(2usize.pow(k) - 109), inputs); let prover = MockProver::::run(k, &circuit, vec![]).unwrap(); prover.assert_satisfied(); @@ -109,10 +123,6 @@ fn verify(k: u32, inputs: Vec>, _success: bool) { #[test_case(14, 28; "k: 14, rows_per_round: 28")] fn packed_multi_keccak_simple(k: u32, rows_per_round: usize) { - KECCAK_CONFIG_PARAMS.with(|conf| { - conf.borrow_mut().k = k; - conf.borrow_mut().rows_per_round = rows_per_round; - }); let _ = env_logger::builder().is_test(true).try_init(); let inputs = vec![ @@ -122,15 +132,12 @@ fn packed_multi_keccak_simple(k: u32, rows_per_round: usize) { (0u8..136).collect::>(), (0u8..200).collect::>(), ]; - verify::(k, inputs, true); + verify::(KeccakConfigParams { k, rows_per_round }, inputs, true); } #[test_case(14, 25 ; "k: 14, rows_per_round: 25")] +#[test_case(18, 9 ; "k: 18, rows_per_round: 9")] fn packed_multi_keccak_prover(k: u32, rows_per_round: usize) { - KECCAK_CONFIG_PARAMS.with(|conf| { - conf.borrow_mut().k = k; - conf.borrow_mut().rows_per_round = rows_per_round; - }); let _ = env_logger::builder().is_test(true).try_init(); let params = ParamsKZG::::setup(k, OsRng); @@ -142,7 +149,8 @@ fn packed_multi_keccak_prover(k: u32, rows_per_round: usize) { (0u8..136).collect::>(), (0u8..200).collect::>(), ]; - let circuit = KeccakCircuit::new(Some(2usize.pow(k)), inputs); + let circuit = + KeccakCircuit::new(KeccakConfigParams { k, rows_per_round }, Some(2usize.pow(k)), inputs); let vk = keygen_vk(¶ms, &circuit).unwrap(); let pk = keygen_pk(¶ms, vk, &circuit).unwrap(); diff --git a/hashes/zkevm-keccak/src/util.rs b/hashes/zkevm-keccak/src/util.rs index 4ddf8590..7f2863e2 100644 --- a/hashes/zkevm-keccak/src/util.rs +++ b/hashes/zkevm-keccak/src/util.rs @@ -168,7 +168,7 @@ pub fn pack(bits: &[u8]) -> F { /// specified bit base pub fn pack_with_base(bits: &[u8], base: usize) -> F { let base = F::from(base as u64); - bits.iter().rev().fold(F::zero(), |acc, &bit| acc * base + F::from(bit as u64)) + bits.iter().rev().fold(F::ZERO, |acc, &bit| acc * base + F::from(bit as u64)) } /// Decodes the bits using the position data found in the part info diff --git a/hashes/zkevm-keccak/src/util/constraint_builder.rs b/hashes/zkevm-keccak/src/util/constraint_builder.rs index bae9f4a4..aa2b10f9 100644 --- a/hashes/zkevm-keccak/src/util/constraint_builder.rs +++ b/hashes/zkevm-keccak/src/util/constraint_builder.rs @@ -1,5 +1,5 @@ use super::expression::Expr; -use crate::halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; +use crate::halo2_proofs::{halo2curves::ff::PrimeField, plonk::Expression}; #[derive(Default)] pub struct BaseConstraintBuilder { @@ -8,7 +8,7 @@ pub struct BaseConstraintBuilder { pub condition: Option>, } -impl BaseConstraintBuilder { +impl BaseConstraintBuilder { pub(crate) fn new(max_degree: usize) -> Self { BaseConstraintBuilder { constraints: Vec::new(), max_degree, condition: None } } diff --git a/hashes/zkevm-keccak/src/util/expression.rs b/hashes/zkevm-keccak/src/util/expression.rs index fa0ee216..60b75b5a 100644 --- a/hashes/zkevm-keccak/src/util/expression.rs +++ b/hashes/zkevm-keccak/src/util/expression.rs @@ -1,34 +1,34 @@ -use crate::halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; +use crate::halo2_proofs::{halo2curves::ff::PrimeField, plonk::Expression}; /// Returns the sum of the passed in cells pub mod sum { - use super::{Expr, Expression, FieldExt}; + use super::{Expr, Expression, PrimeField}; /// Returns an expression for the sum of the list of expressions. - pub fn expr, I: IntoIterator>(inputs: I) -> Expression { + pub fn expr, I: IntoIterator>(inputs: I) -> Expression { inputs.into_iter().fold(0.expr(), |acc, input| acc + input.expr()) } /// Returns the sum of the given list of values within the field. - pub fn value(values: &[u8]) -> F { - values.iter().fold(F::zero(), |acc, value| acc + F::from(*value as u64)) + pub fn value(values: &[u8]) -> F { + values.iter().fold(F::ZERO, |acc, value| acc + F::from(*value as u64)) } } /// Returns `1` when `expr[0] && expr[1] && ... == 1`, and returns `0` /// otherwise. Inputs need to be boolean pub mod and { - use super::{Expr, Expression, FieldExt}; + use super::{Expr, Expression, PrimeField}; /// Returns an expression that evaluates to 1 only if all the expressions in /// the given list are 1, else returns 0. - pub fn expr, I: IntoIterator>(inputs: I) -> Expression { + pub fn expr, I: IntoIterator>(inputs: I) -> Expression { inputs.into_iter().fold(1.expr(), |acc, input| acc * input.expr()) } /// Returns the product of all given values. - pub fn value(inputs: Vec) -> F { - inputs.iter().fold(F::one(), |acc, input| acc * input) + pub fn value(inputs: Vec) -> F { + inputs.iter().fold(F::ONE, |acc, input| acc * input) } } @@ -36,16 +36,16 @@ pub mod and { /// otherwise. Inputs need to be boolean pub mod or { use super::{and, not}; - use super::{Expr, Expression, FieldExt}; + use super::{Expr, Expression, PrimeField}; /// Returns an expression that evaluates to 1 if any expression in the given /// list is 1. Returns 0 if all the expressions were 0. - pub fn expr, I: IntoIterator>(inputs: I) -> Expression { + pub fn expr, I: IntoIterator>(inputs: I) -> Expression { not::expr(and::expr(inputs.into_iter().map(not::expr))) } /// Returns the value after passing all given values through the OR gate. - pub fn value(inputs: Vec) -> F { + pub fn value(inputs: Vec) -> F { not::value(and::value(inputs.into_iter().map(not::value).collect())) } } @@ -53,31 +53,31 @@ pub mod or { /// Returns `1` when `b == 0`, and returns `0` otherwise. /// `b` needs to be boolean pub mod not { - use super::{Expr, Expression, FieldExt}; + use super::{Expr, Expression, PrimeField}; /// Returns an expression that represents the NOT of the given expression. - pub fn expr>(b: E) -> Expression { + pub fn expr>(b: E) -> Expression { 1.expr() - b.expr() } /// Returns a value that represents the NOT of the given value. - pub fn value(b: F) -> F { - F::one() - b + pub fn value(b: F) -> F { + F::ONE - b } } /// Returns `a ^ b`. /// `a` and `b` needs to be boolean pub mod xor { - use super::{Expr, Expression, FieldExt}; + use super::{Expr, Expression, PrimeField}; /// Returns an expression that represents the XOR of the given expression. - pub fn expr>(a: E, b: E) -> Expression { + pub fn expr>(a: E, b: E) -> Expression { a.expr() + b.expr() - 2.expr() * a.expr() * b.expr() } /// Returns a value that represents the XOR of the given value. - pub fn value(a: F, b: F) -> F { + pub fn value(a: F, b: F) -> F { a + b - F::from(2u64) * a * b } } @@ -85,11 +85,11 @@ pub mod xor { /// Returns `when_true` when `selector == 1`, and returns `when_false` when /// `selector == 0`. `selector` needs to be boolean. pub mod select { - use super::{Expr, Expression, FieldExt}; + use super::{Expr, Expression, PrimeField}; /// Returns the `when_true` expression when the selector is true, else /// returns the `when_false` expression. - pub fn expr( + pub fn expr( selector: Expression, when_true: Expression, when_false: Expression, @@ -99,18 +99,18 @@ pub mod select { /// Returns the `when_true` value when the selector is true, else returns /// the `when_false` value. - pub fn value(selector: F, when_true: F, when_false: F) -> F { - selector * when_true + (F::one() - selector) * when_false + pub fn value(selector: F, when_true: F, when_false: F) -> F { + selector * when_true + (F::ONE - selector) * when_false } /// Returns the `when_true` word when selector is true, else returns the /// `when_false` word. - pub fn value_word( + pub fn value_word( selector: F, when_true: [u8; 32], when_false: [u8; 32], ) -> [u8; 32] { - if selector == F::one() { + if selector == F::ONE { when_true } else { when_false @@ -120,7 +120,7 @@ pub mod select { /// Trait that implements functionality to get a constant expression from /// commonly used types. -pub trait Expr { +pub trait Expr { /// Returns an expression for the type. fn expr(&self) -> Expression; } @@ -129,7 +129,7 @@ pub trait Expr { #[macro_export] macro_rules! impl_expr { ($type:ty) => { - impl Expr for $type { + impl Expr for $type { #[inline] fn expr(&self) -> Expression { Expression::Constant(F::from(*self as u64)) @@ -137,7 +137,7 @@ macro_rules! impl_expr { } }; ($type:ty, $method:path) => { - impl Expr for $type { + impl Expr for $type { #[inline] fn expr(&self) -> Expression { Expression::Constant(F::from($method(self) as u64)) @@ -151,35 +151,34 @@ impl_expr!(u8); impl_expr!(u64); impl_expr!(usize); -impl Expr for Expression { +impl Expr for Expression { #[inline] fn expr(&self) -> Expression { self.clone() } } -impl Expr for &Expression { +impl Expr for &Expression { #[inline] fn expr(&self) -> Expression { (*self).clone() } } -impl Expr for i32 { +impl Expr for i32 { #[inline] fn expr(&self) -> Expression { Expression::Constant( - F::from(self.unsigned_abs() as u64) - * if self.is_negative() { -F::one() } else { F::one() }, + F::from(self.unsigned_abs() as u64) * if self.is_negative() { -F::ONE } else { F::ONE }, ) } } /// Given a bytes-representation of an expression, it computes and returns the /// single expression. -pub fn expr_from_bytes>(bytes: &[E]) -> Expression { +pub fn expr_from_bytes>(bytes: &[E]) -> Expression { let mut value = 0.expr(); - let mut multiplier = F::one(); + let mut multiplier = F::ONE; for byte in bytes.iter() { value = value + byte.expr() * multiplier; multiplier *= F::from(256); @@ -187,7 +186,7 @@ pub fn expr_from_bytes>(bytes: &[E]) -> Expression { value } -/// Returns 2**by as FieldExt -pub fn pow_of_two(by: usize) -> F { - F::from(2).pow(&[by as u64, 0, 0, 0]) +/// Returns 2**by as PrimeField +pub fn pow_of_two(by: usize) -> F { + F::from(2).pow([by as u64]) } diff --git a/rust-toolchain b/rust-toolchain index 51ab4759..ee2d639b 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2022-10-28 \ No newline at end of file +nightly-2023-08-12 \ No newline at end of file