From b9955c3ff5be25bfa0596cf9a2452c28cf1a1a64 Mon Sep 17 00:00:00 2001 From: Alex Kuzmin Date: Thu, 1 Feb 2024 17:19:15 +0800 Subject: [PATCH] Bring back the range check --- kzg_prover/benches/kzg.rs | 16 +++- kzg_prover/src/circuits/tests.rs | 8 +- .../src/circuits/univariate_grand_sum.rs | 90 +++++++++---------- kzg_prover/src/circuits/utils.rs | 25 +++++- kzg_prover/src/utils/batched_kzg.rs | 33 +++---- 5 files changed, 94 insertions(+), 78 deletions(-) diff --git a/kzg_prover/benches/kzg.rs b/kzg_prover/benches/kzg.rs index 58da721e..a2d60b17 100644 --- a/kzg_prover/benches/kzg.rs +++ b/kzg_prover/benches/kzg.rs @@ -8,8 +8,8 @@ use summa_solvency::{ circuits::{ univariate_grand_sum::UnivariateGrandSum, utils::{ - full_prover, generate_setup_artifacts, open_grand_sums, open_user_points, - verify_grand_sum_openings, verify_user_inclusion, + batch_open_user_points, full_prover, generate_setup_artifacts, open_grand_sums, + open_user_points, verify_grand_sum_openings, verify_user_inclusion, }, }, cryptocurrency::Cryptocurrency, @@ -32,6 +32,8 @@ fn bench_kzg range check", name); let opening_grand_sum_bench_name = format!("<{}> opening grand sum", name); let opening_user_bench_name = format!("<{}> opening user inclusion", name); + let batch_opening_user_bench_name = + format!("<{}> batch opening all 2^{} user inclusions", name, K); let verifying_grand_sum_bench_name = format!("<{}> verifying grand sum", name); let verifying_user_bench_name = format!("<{}> verifying user inclusion", name); @@ -115,6 +117,16 @@ fn bench_kzg, balances: [Column; N_CURRENCIES], - // range_check_configs: [RangeCheckU64Config; N_CURRENCIES], + range_check_configs: [RangeCheckU64Config; N_CURRENCIES], range_u16: Column, } @@ -65,21 +65,21 @@ where meta.annotate_lookup_any_column(range_u16, || "LOOKUP_MAXBITS_RANGE"); // Create an empty array of range check configs - // let mut range_check_configs = Vec::with_capacity(N_CURRENCIES); + let mut range_check_configs = Vec::with_capacity(N_CURRENCIES); - // for item in balances.iter().take(N_CURRENCIES) { - // let z = *item; - // // Create 4 advice columns for each range check chip - // let zs = [(); 4].map(|_| meta.advice_column()); + for item in balances.iter().take(N_CURRENCIES) { + let z = *item; + // Create 4 advice columns for each range check chip + let zs = [(); 4].map(|_| meta.advice_column()); - // for column in &zs { - // meta.enable_equality(*column); - // } + for column in &zs { + meta.enable_equality(*column); + } - // let range_check_config = RangeCheckU64Chip::configure(meta, z, zs, range_u16); + let range_check_config = RangeCheckU64Chip::configure(meta, z, zs, range_u16); - // range_check_configs.push(range_check_config); - // } + range_check_configs.push(range_check_config); + } let instance = meta.instance_column(); meta.enable_equality(instance); @@ -87,7 +87,7 @@ where Self { username, balances, - // range_check_configs: range_check_configs.try_into().unwrap(), + range_check_configs: range_check_configs.try_into().unwrap(), range_u16, } } @@ -157,46 +157,46 @@ where mut layouter: impl Layouter, ) -> Result<(), Error> { // Initiate the range check chips - // let range_check_chips = config - // .range_check_configs - // .iter() - // .map(|config| RangeCheckU64Chip::construct(*config)) - // .collect::>(); + let range_check_chips = config + .range_check_configs + .iter() + .map(|config| RangeCheckU64Chip::construct(*config)) + .collect::>(); // Load lookup table for range check u64 chip - // let range = 1 << 16; - - // layouter.assign_region( - // || format!("load range check table of 16 bits"), - // |mut region| { - // for i in 0..range { - // region.assign_fixed( - // || "assign cell in fixed column", - // config.range_u16, - // i, - // || Value::known(Fp::from(i as u64)), - // )?; - // } - // Ok(()) - // }, - // )?; + let range = 1 << 16; + + layouter.assign_region( + || format!("load range check table of 16 bits"), + |mut region| { + for i in 0..range { + region.assign_fixed( + || "assign cell in fixed column", + config.range_u16, + i, + || Value::known(Fp::from(i as u64)), + )?; + } + Ok(()) + }, + )?; // Assign entries let assigned_balances = config.assign_entries(layouter.namespace(|| "assign entries"), &self.entries)?; // Perform range check on the assigned balances - // for i in 0..N_USERS { - // for j in 0..N_CURRENCIES { - // layouter.assign_region( - // || format!("Perform range check on balance {} of user {}", j, i), - // |mut region| { - // range_check_chips[j].assign(&mut region, &assigned_balances[i][j])?; - // Ok(()) - // }, - // )?; - // } - // } + for i in 0..N_USERS { + for j in 0..N_CURRENCIES { + layouter.assign_region( + || format!("Perform range check on balance {} of user {}", j, i), + |mut region| { + range_check_chips[j].assign(&mut region, &assigned_balances[i][j])?; + Ok(()) + }, + )?; + } + } Ok(()) } diff --git a/kzg_prover/src/circuits/utils.rs b/kzg_prover/src/circuits/utils.rs index f40aca8e..d99cfcf2 100644 --- a/kzg_prover/src/circuits/utils.rs +++ b/kzg_prover/src/circuits/utils.rs @@ -3,9 +3,9 @@ use std::{fs::File, ops::Range}; use ark_std::{end_timer, start_timer}; use ethers::types::U256; use halo2_proofs::{ - arithmetic::Field, + arithmetic::{best_fft, Field}, halo2curves::{ - bn256::{Bn256, Fr as Fp, G1Affine}, + bn256::{Bn256, Fr as Fp, G1Affine, G1}, ff::{PrimeField, WithSmallOrderMulGroup}, }, plonk::{ @@ -28,8 +28,9 @@ use halo2_proofs::{ }; use num_bigint::BigUint; use rand::rngs::OsRng; +use rayon::prelude::*; -use crate::utils::fp_to_big_uint; +use crate::utils::{batched_kzg::compute_h, fp_to_big_uint}; /// Generate setup artifacts for a circuit of size `k`, where 2^k represents the number of rows in the circuit. /// @@ -198,6 +199,24 @@ pub fn open_user_points( ) } +pub fn batch_open_user_points( + advice_polys: &[Polynomial], + params: &ParamsKZG, + column_range: Range, + omega: Fp, +) -> Vec { + // Use Rayon's par_iter() to iterate over the slice in parallel + advice_polys[column_range] + .par_iter() + .map(|poly| { + let mut h = compute_h(params, poly); + best_fft(&mut h, omega, poly.len().trailing_zeros()); + h + }) + .flatten() // Flatten to combine all the h vectors into one + .collect() +} + /// Verifies the univariate polynomial grand sum openings /// and calculates the grand sums /// diff --git a/kzg_prover/src/utils/batched_kzg.rs b/kzg_prover/src/utils/batched_kzg.rs index 9e3206ae..0e00699f 100644 --- a/kzg_prover/src/utils/batched_kzg.rs +++ b/kzg_prover/src/utils/batched_kzg.rs @@ -6,7 +6,7 @@ use halo2_proofs::{ pairing::{Engine, PairingCurveAffine}, }, poly::{ - commitment::{Blind, CommitmentScheme, ParamsProver}, + commitment::{Blind, CommitmentScheme, Params, ParamsProver}, kzg::commitment::ParamsKZG, Coeff, EvaluationDomain, Polynomial, }, @@ -17,14 +17,12 @@ pub fn commit_kzg(params: &ParamsKZG, poly: &Polynomial) -> G1 } /// Computes the polynomial h(X) for the batch KZG algorithm. -pub fn compute_h( - params: &ParamsKZG, - f_poly: &Polynomial, - double_domain: &EvaluationDomain, -) -> Vec { +pub fn compute_h(params: &ParamsKZG, f_poly: &Polynomial) -> Vec { + // Double the polynomial length, thus K + 1 + let double_domain = EvaluationDomain::new(1, params.k() + 1); + let d = f_poly.len(); // Degree of the polynomial - println!("d: {}", d); // Extract s_commitments from ParamsKZG and extend with neutral elements let mut s_commitments_reversed = params .get_g() @@ -38,30 +36,21 @@ pub fn compute_h( // Prepare coefficients vector and zero-pad at the beginning let mut v = vec![Fp::zero(); 2 * d]; - v[d..(2 * d)].copy_from_slice(&f_poly); + v[d..(2 * d)].copy_from_slice(f_poly); - println!("c_fft and s_fft assigned"); let nu = double_domain.get_omega(); // 2d-th root of unity - println!("performing FFT on s"); + // Perform FFT on s best_fft(&mut y, nu, (2 * d).trailing_zeros()); - println!("performing FFT on c"); + // Perform FFT on c best_fft(&mut v, nu, (2 * d).trailing_zeros()); - println!("Computing powers of nu"); - // Compute powers of nu - let mut nu_powers = vec![Fp::one(); 2 * d]; - for i in 1..(2 * d) { - nu_powers[i] = nu_powers[i - 1] * nu; - } - - println!("Performing Hadamard product"); // Perform the Hadamard product let u: Vec = y.iter().zip(v.iter()).map(|(&y, &v)| y * v).collect(); // Perform inverse FFT let nu_inv = nu.invert().unwrap(); // Inverse of 2d-th root of unity let mut h = u; - println!("Performing inverse FFT on h"); + // Perform inverse FFT on h best_fft(&mut h, nu_inv, (2 * d).trailing_zeros()); // Scale the result by the size of the vector (part of the iFFT) @@ -84,7 +73,7 @@ pub fn create_standard_kzg_proof< f_poly: &Polynomial<::Scalar, Coeff>, challenge: Fp, ) -> G1 { - let z = eval_polynomial(&f_poly, challenge); + let z = eval_polynomial(f_poly, challenge); let numerator = f_poly - z; let mut t_y_vals = kate_division(&numerator.to_vec(), challenge); // The resulting degree is one less than the degree of the numerator, so we need to pad it with zeros back to the original polynomial size @@ -103,7 +92,7 @@ where let c_g_to_minus_z: G1 = c + g_to_minus_z; let left_side = Bn256::pairing(&c_g_to_minus_z.to_affine(), &G2Affine::generator()); - let g_to_minus_y = G2Affine::generator() * &(-challenge); + let g_to_minus_y = G2Affine::generator() * (-challenge); let g_tau = params.s_g2(); let g_tau_g_to_minus_y = g_tau + g_to_minus_y; let right_side = Bn256::pairing(&pi.to_affine(), &g_tau_g_to_minus_y.to_affine());