From 78576fed6ae3e8fab9f71aac370249840fafa64f Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Thu, 31 Oct 2024 09:58:08 +0100 Subject: [PATCH 1/3] Circuit model account for ZK and PIs --- halo2_frontend/src/dev/cost_model.rs | 52 ++++++++++++++++++++++------ halo2_proofs/examples/proof-size.rs | 2 +- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/halo2_frontend/src/dev/cost_model.rs b/halo2_frontend/src/dev/cost_model.rs index b64e194160..00c2194fb0 100644 --- a/halo2_frontend/src/dev/cost_model.rs +++ b/halo2_frontend/src/dev/cost_model.rs @@ -2,7 +2,8 @@ //! verification cost, as well as resulting proof size. use std::collections::HashSet; -use std::{iter, num::ParseIntError, str::FromStr}; +use std::panic::AssertUnwindSafe; +use std::{iter, num::ParseIntError, panic, str::FromStr}; use crate::plonk::Circuit; use halo2_middleware::ff::{Field, FromUniformBytes}; @@ -49,8 +50,8 @@ pub struct CostOptions { /// A shuffle over N columns with max input degree I and max shuffle degree T. May be repeated. pub shuffle: Vec, - /// 2^K bound on the number of rows. - pub k: usize, + /// 2^K bound on the number of rows, accounting for ZK, PIs and Lookup tables. + pub min_k: usize, /// Rows count, not including table rows and not accounting for compression /// (where multiple regions can use the same rows). @@ -220,7 +221,7 @@ impl CostOptions { // - inner product argument (k rounds * 2 * COMM bytes) // - a (SCALAR bytes) // - xi (SCALAR bytes) - comp_bytes(1 + 2 * self.k, 2) + comp_bytes(1 + 2 * self.min_k, 2) } CommitmentScheme::KZGGWC => { let mut nr_rotations = HashSet::new(); @@ -248,7 +249,7 @@ impl CostOptions { let size = plonk + vanishing + multiopen + polycomm; ModelCircuit { - k: self.k, + k: self.min_k, rows: self.rows_count, table_rows: self.table_rows_count, max_deg: self.max_degree, @@ -270,7 +271,7 @@ pub fn from_circuit_to_model_circuit< const COMM: usize, const SCALAR: usize, >( - k: u32, + k: Option, circuit: &C, instances: Vec>, comm_scheme: CommitmentScheme, @@ -279,13 +280,35 @@ pub fn from_circuit_to_model_circuit< options.into_model_circuit::(comm_scheme) } -/// Given a Plonk circuit, this function returns [CostOptions] +fn run_mock_prover_with_fallback, C: Circuit>( + circuit: &C, + instances: Vec>, +) -> MockProver { + (5..25) + .find_map(|k| { + panic::catch_unwind(AssertUnwindSafe(|| { + MockProver::run(k, circuit, instances.clone()).unwrap() + })) + .ok() + }) + .expect("No valid prover found within the range") +} + +/// Given a Plonk circuit, this function returns [CostOptions]. If no upper bound for `k` is +/// provided, the function iterates until a valid `k` is found. This might delay computation. pub fn from_circuit_to_cost_model_options, C: Circuit>( - k: u32, + k_upper_bound: Option, circuit: &C, instances: Vec>, ) -> CostOptions { - let prover = MockProver::run(k, circuit, instances).unwrap(); + let instance_len = instances.first().map_or(0, Vec::len); + + let prover = if let Some(k) = k_upper_bound { + MockProver::run(k, circuit, instances).unwrap() + } else { + run_mock_prover_with_fallback(circuit, instances.clone()) + }; + let cs = prover.cs; let fixed = { @@ -362,7 +385,14 @@ pub fn from_circuit_to_cost_model_options, (rows_count, table_rows_count, compressed_rows_count) }; - let k = prover.k.try_into().unwrap(); + let min_k = [ + rows_count + cs.blinding_factors(), + table_rows_count + cs.blinding_factors(), + instance_len, + ] + .into_iter() + .max() + .unwrap(); CostOptions { advice, @@ -373,7 +403,7 @@ pub fn from_circuit_to_cost_model_options, lookup, permutation, shuffle, - k, + min_k, rows_count, table_rows_count, compressed_rows_count, diff --git a/halo2_proofs/examples/proof-size.rs b/halo2_proofs/examples/proof-size.rs index f1504e6f96..46f0fbd6da 100644 --- a/halo2_proofs/examples/proof-size.rs +++ b/halo2_proofs/examples/proof-size.rs @@ -93,7 +93,7 @@ fn main() { let circuit = TestCircuit {}; let model = from_circuit_to_model_circuit::<_, _, 56, 56>( - K, + Some(K), &circuit, vec![], CommitmentScheme::KZGGWC, From d452e4df3d47b04f5909b33f780bf8deee3c114a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?I=C3=B1igo=20Querejeta=20Azurmendi?= <31273774+iquerejeta@users.noreply.github.com> Date: Wed, 13 Nov 2024 08:46:52 +0100 Subject: [PATCH 2/3] Apply suggestions from code review Co-authored-by: Miguel Ambrona --- halo2_frontend/src/dev/cost_model.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/halo2_frontend/src/dev/cost_model.rs b/halo2_frontend/src/dev/cost_model.rs index 00c2194fb0..a9571f23f4 100644 --- a/halo2_frontend/src/dev/cost_model.rs +++ b/halo2_frontend/src/dev/cost_model.rs @@ -291,17 +291,17 @@ fn run_mock_prover_with_fallback, C: Circu })) .ok() }) - .expect("No valid prover found within the range") + .expect("A circuit which can be implemented with at most 2^24 rows.") } -/// Given a Plonk circuit, this function returns [CostOptions]. If no upper bound for `k` is -/// provided, the function iterates until a valid `k` is found. This might delay computation. +/// Given a circuit, this function returns [CostOptions]. If no upper bound for `k` is +/// provided, we iterate until a valid `k` is found (this might delay the computation). pub fn from_circuit_to_cost_model_options, C: Circuit>( k_upper_bound: Option, circuit: &C, instances: Vec>, ) -> CostOptions { - let instance_len = instances.first().map_or(0, Vec::len); + let instance_len = instances.iter().map(Vec::len).max().unwrap_or(0); let prover = if let Some(k) = k_upper_bound { MockProver::run(k, circuit, instances).unwrap() From 7c88d290b6dbc183fd22a25ffa20c77556cad842 Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Wed, 13 Nov 2024 08:47:18 +0100 Subject: [PATCH 3/3] Warning if PI is dominant factor --- halo2_frontend/src/dev/cost_model.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/halo2_frontend/src/dev/cost_model.rs b/halo2_frontend/src/dev/cost_model.rs index a9571f23f4..a430eb41fa 100644 --- a/halo2_frontend/src/dev/cost_model.rs +++ b/halo2_frontend/src/dev/cost_model.rs @@ -394,6 +394,10 @@ pub fn from_circuit_to_cost_model_options, .max() .unwrap(); + if min_k == instance_len { + println!("WARNING: The dominant factor in your circuit's size is the number of public inputs, which causes the verifier to perform linear work."); + } + CostOptions { advice, instance,