From 306fd6995e944a3fef131dad5bf88d064aad0dfa Mon Sep 17 00:00:00 2001 From: zhenfei Date: Fri, 16 May 2025 09:21:02 -0400 Subject: [PATCH 01/57] simplify benches --- poly_commit/benches/pcs_all.rs | 167 ++++++++++++++++----------------- 1 file changed, 82 insertions(+), 85 deletions(-) diff --git a/poly_commit/benches/pcs_all.rs b/poly_commit/benches/pcs_all.rs index 0185f506..c7196707 100644 --- a/poly_commit/benches/pcs_all.rs +++ b/poly_commit/benches/pcs_all.rs @@ -5,7 +5,7 @@ use gkr_engine::StructuredReferenceString; use gkr_engine::{root_println, MPIConfig, MPIEngine, Transcript}; use gkr_hashers::Keccak256hasher; use halo2curves::bn256::{Bn256, G1Affine}; -use poly_commit::{HyperKZGPCS, HyraxPCS, PolynomialCommitmentScheme}; +use poly_commit::{HyperKZGPCS, HyraxPCS, OrionBaseFieldPCS, PolynomialCommitmentScheme}; use polynomials::MultiLinearPoly; use rand::RngCore; use serdes::ExpSerde; @@ -15,147 +15,136 @@ use utils::timer::Timer; fn main() { let mpi_config = MPIConfig::prover_new(); println!("=========================="); - for num_vars in 10..19 { + for num_vars in 10..21 { root_println!(mpi_config, "num vars: {}", num_vars); bench_hyrax(&mpi_config, num_vars); bench_kzg(&mpi_config, num_vars); + bench_orion(&mpi_config, num_vars); println!("=========================="); } } -fn bench_hyrax(mpi_config: &MPIConfig, num_vars: usize) { +fn bench_orion(mpi_config: &MPIConfig, num_vars: usize) { // full scalar let mut rng = test_rng(); + let (srs, _) = OrionBaseFieldPCS::::gen_srs_for_testing(&num_vars, &mut rng); let poly = MultiLinearPoly::::random(num_vars, &mut rng); - bench_hyrax_helper(mpi_config, num_vars, &poly, "full scalar "); + let eval_point: Vec<_> = (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(); + pcs_bench::>( + mpi_config, + &num_vars, + &srs, + &poly, + &eval_point, + "orion full scalar ", + ); // small scalar let input = (0..1 << num_vars) .map(|_| Fr::from(rng.next_u32())) .collect::>(); let poly = MultiLinearPoly::::new(input); - bench_hyrax_helper(mpi_config, num_vars, &poly, "small scalar"); + pcs_bench::>( + mpi_config, + &num_vars, + &srs, + &poly, + &eval_point, + "orion small scalar", + ); } -fn bench_hyrax_helper( - mpi_config: &MPIConfig, - num_vars: usize, - poly: &MultiLinearPoly, - label: &str, -) { +fn bench_hyrax(mpi_config: &MPIConfig, num_vars: usize) { + // full scalar let mut rng = test_rng(); - let timer = Timer::new( - format!("{} hyrax commit ", label).as_ref(), - mpi_config.is_root(), - ); - let (srs, _) = HyraxPCS::::gen_srs_for_testing(&num_vars, &mut rng); + let poly = MultiLinearPoly::::random(num_vars, &mut rng); let eval_point: Vec<_> = (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(); - let mut transcript = BytesHashTranscript::::new(); - let mut scratch_pad = (); - - let com = black_box(HyraxPCS::::commit( + pcs_bench::>( + mpi_config, &num_vars, &srs, &poly, - &mut scratch_pad, - )); - timer.stop(); - - let timer = Timer::new( - format!("{} hyrax open ", label).as_ref(), - mpi_config.is_root(), + &eval_point, + "hyrax full scalar ", ); - let (eval, open) = black_box(HyraxPCS::::open( + + // small scalar + let input = (0..1 << num_vars) + .map(|_| Fr::from(rng.next_u32())) + .collect::>(); + let poly = MultiLinearPoly::::new(input); + pcs_bench::>( + mpi_config, &num_vars, &srs, &poly, &eval_point, - &scratch_pad, - &mut transcript, - )); - timer.stop(); - - let timer = Timer::new( - format!("{} hyrax verify ", label).as_ref(), - mpi_config.is_root(), + "hyrax small scalar", ); - let mut transcript = BytesHashTranscript::::new(); - assert!(black_box(HyraxPCS::::verify( - &num_vars, - &srs, - &com, - &eval_point, - eval, - &open, - &mut transcript, - ))); - timer.stop(); - - let mut buf = vec![]; - com.serialize_into(&mut buf).unwrap(); - let com_size = buf.len(); - - let mut buf = vec![]; - open.serialize_into(&mut buf).unwrap(); - let open_size = buf.len(); - - root_println!(mpi_config, "hyrax com size {}", com_size); - root_println!(mpi_config, "hyrax open size {}", open_size); - - root_println!(mpi_config, " --- "); } fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { // full scalar let mut rng = test_rng(); + let (srs, _) = HyperKZGPCS::::gen_srs_for_testing(&num_vars, &mut rng); let poly = MultiLinearPoly::::random(num_vars, &mut rng); - bench_kzg_helper(mpi_config, num_vars, &poly, "full scalar "); + let eval_point: Vec<_> = (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(); + + pcs_bench::>( + mpi_config, + &num_vars, + &srs, + &poly, + &eval_point, + "kzg full scalar ", + ); // small scalar let input = (0..1 << num_vars) .map(|_| Fr::from(rng.next_u32())) .collect::>(); let poly = MultiLinearPoly::::new(input); - bench_kzg_helper(mpi_config, num_vars, &poly, "small scalar"); + pcs_bench::>( + mpi_config, + &num_vars, + &srs, + &poly, + &eval_point, + "kzg small scalar ", + ); } -fn bench_kzg_helper( +fn pcs_bench>( mpi_config: &MPIConfig, - num_vars: usize, - poly: &MultiLinearPoly, + num_vars: &PCS::Params, + srs: &PCS::SRS, + poly: &PCS::Poly, + eval_point: &PCS::EvalPoint, label: &str, ) { - let mut rng = test_rng(); + let timer = Timer::new( + format!("{} commit ", label).as_ref(), + mpi_config.is_root(), + ); - let (srs, _) = HyperKZGPCS::::gen_srs_for_testing(&num_vars, &mut rng); let (pk, vk) = srs.clone().into_keys(); - let eval_point: Vec<_> = (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(); let mut transcript = BytesHashTranscript::::new(); - let mut scratch_pad = HyperKZGPCS::::init_scratch_pad(&num_vars); + let mut scratch_pad = PCS::init_scratch_pad(&num_vars); - let timer = Timer::new( - format!("{} kzg commit ", label).as_ref(), - mpi_config.is_root(), - ); - let com = black_box(HyperKZGPCS::::commit( - &num_vars, - &pk, - &poly, - &mut scratch_pad, - )); + let com = black_box(PCS::commit(&num_vars, &pk, &poly, &mut scratch_pad)); timer.stop(); let timer = Timer::new( - format!("{} kzg open ", label).as_ref(), + format!("{} open ", label).as_ref(), mpi_config.is_root(), ); - let (eval, open) = black_box(HyperKZGPCS::::open( + let (eval, open) = black_box(PCS::open( &num_vars, &pk, &poly, @@ -166,11 +155,11 @@ fn bench_kzg_helper( timer.stop(); let timer = Timer::new( - format!("{} kzg verify ", label).as_ref(), + format!("{} verify ", label).as_ref(), mpi_config.is_root(), ); let mut transcript = BytesHashTranscript::::new(); - assert!(black_box(HyperKZGPCS::::verify( + assert!(black_box(PCS::verify( &num_vars, &vk, &com, @@ -189,8 +178,16 @@ fn bench_kzg_helper( open.serialize_into(&mut buf).unwrap(); let open_size = buf.len(); - root_println!(mpi_config, "kzg com size {}", com_size); - root_println!(mpi_config, "kzg open size {}", open_size); + root_println!( + mpi_config, + "{}", + format!("{} commit size {}", label, com_size), + ); + root_println!( + mpi_config, + "{}", + format!("{} open size {}", label, open_size), + ); root_println!(mpi_config, " --- "); } From 5447786787379634388c4dfe19c9793f531fa144 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 20 May 2025 08:02:59 -0400 Subject: [PATCH 02/57] wip --- gkr_engine/src/poly_commit/definition.rs | 19 ++++++++ poly_commit/src/kzg.rs | 2 + poly_commit/src/kzg/deferred_pairing.rs | 62 ++++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 poly_commit/src/kzg/deferred_pairing.rs diff --git a/gkr_engine/src/poly_commit/definition.rs b/gkr_engine/src/poly_commit/definition.rs index f4a870b7..65b08ede 100644 --- a/gkr_engine/src/poly_commit/definition.rs +++ b/gkr_engine/src/poly_commit/definition.rs @@ -37,6 +37,9 @@ pub trait ExpanderPCS { type Commitment: Clone + Debug + Default + ExpSerde; type Opening: Clone + Debug + Default + ExpSerde; + /// An accumulator to be used for deferred batch verification for KZG. + type Accumulator: Clone + Debug + Default; + /// Generate a random structured reference string (SRS) for testing purposes. /// Each process should return the SRS share used for its committing and opening. /// @@ -115,6 +118,22 @@ pub trait ExpanderPCS { transcript: &mut impl Transcript, opening: &Self::Opening, ) -> bool; + + /// Partially verify the opening of a polynomial at a point. + /// Deffer some of the checks to the batch verification via accumulator. + fn partial_verify( + params: &Self::Params, + verifying_key: &::VKey, + commitment: &Self::Commitment, + x: &ExpanderSingleVarChallenge, + v: F::ChallengeField, + transcript: &mut impl Transcript, + opening: &Self::Opening, + accumulator: &mut Self::Accumulator, + ); + + /// Perform the finally batch verification for the accumulated opening proofs. + fn batch_verify(accumulator: &mut Self::Accumulator) -> bool; } impl StructuredReferenceString for () { diff --git a/poly_commit/src/kzg.rs b/poly_commit/src/kzg.rs index e83fc036..072dacae 100644 --- a/poly_commit/src/kzg.rs +++ b/poly_commit/src/kzg.rs @@ -28,3 +28,5 @@ mod pcs_trait_impl; pub use pcs_trait_impl::HyperKZGPCS; mod expander_api; + +mod deferred_pairing; diff --git a/poly_commit/src/kzg/deferred_pairing.rs b/poly_commit/src/kzg/deferred_pairing.rs new file mode 100644 index 00000000..996af930 --- /dev/null +++ b/poly_commit/src/kzg/deferred_pairing.rs @@ -0,0 +1,62 @@ +use halo2curves::group::prime::PrimeCurveAffine; +use halo2curves::group::Curve; +use halo2curves::{ + group::Group, + pairing::{Engine, MillerLoopResult, MultiMillerLoop}, +}; + +/// Deferred pairing checks +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct PairingAccumulator { + pub g1s: Vec, + pub g2s: Vec, +} + +pub trait DeferredPairingCheck { + /// Data type to be accumulated + type AccumulatedValues; + + /// Add a new pairing check to the accumulator + fn add_pairing_check(&mut self, _accumulated_values: &Self::AccumulatedValues) {} + + /// Check if all pairings are valid + fn check_pairings(&self) -> bool { + true + } +} + +impl DeferredPairingCheck for () { + type AccumulatedValues = (); +} + +impl DeferredPairingCheck for PairingAccumulator { + type AccumulatedValues = (E::G1, E::G2); + + fn add_pairing_check(&mut self, accumulated_values: &(E::G1, E::G2)) { + self.g1s.push(accumulated_values.0); + self.g2s.push(accumulated_values.1); + } + + fn check_pairings(&self) -> bool { + if self.g1s.is_empty() || self.g2s.is_empty() { + return true; + } + + let mut g1_affines = vec![::G1Affine::identity(); self.g1s.len()]; + E::G1::batch_normalize(&self.g1s, &mut g1_affines); + + let mut g2_affines = vec![::G2Affine::identity(); self.g2s.len()]; + E::G2::batch_normalize(&self.g2s, &mut g2_affines); + let g2_prepared: Vec = + g2_affines.iter().map(|&g2| g2.into()).collect::>(); + + let g1g2_pairs = g1_affines + .iter() + .zip(g2_prepared.iter()) + .map(|(g1, g2)| (g1, g2)) + .collect::>(); + + let gt_result = E::multi_miller_loop(g1g2_pairs.as_slice()); + gt_result.final_exponentiation().is_identity().into() + } +} From 598d574040e2d96e9d39a9b4b50ce705acfa0c8f Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 20 May 2025 08:18:45 -0400 Subject: [PATCH 03/57] wip --- gkr_engine/src/poly_commit/definition.rs | 4 +- poly_commit/src/kzg/deferred_pairing.rs | 3 +- poly_commit/src/kzg/expander_api.rs | 19 ++ poly_commit/src/kzg/hyper_bikzg.rs | 210 +++++++++++++++++++++++ poly_commit/src/kzg/hyper_kzg.rs | 71 ++++++++ poly_commit/src/kzg/univariate.rs | 47 +++-- poly_commit/src/lib.rs | 12 +- 7 files changed, 345 insertions(+), 21 deletions(-) diff --git a/gkr_engine/src/poly_commit/definition.rs b/gkr_engine/src/poly_commit/definition.rs index 65b08ede..b54a264b 100644 --- a/gkr_engine/src/poly_commit/definition.rs +++ b/gkr_engine/src/poly_commit/definition.rs @@ -38,7 +38,7 @@ pub trait ExpanderPCS { type Opening: Clone + Debug + Default + ExpSerde; /// An accumulator to be used for deferred batch verification for KZG. - type Accumulator: Clone + Debug + Default; + type Accumulator: Clone + Debug; /// Generate a random structured reference string (SRS) for testing purposes. /// Each process should return the SRS share used for its committing and opening. @@ -133,7 +133,7 @@ pub trait ExpanderPCS { ); /// Perform the finally batch verification for the accumulated opening proofs. - fn batch_verify(accumulator: &mut Self::Accumulator) -> bool; + fn batch_deferred_verification(accumulator: &mut Self::Accumulator) -> bool; } impl StructuredReferenceString for () { diff --git a/poly_commit/src/kzg/deferred_pairing.rs b/poly_commit/src/kzg/deferred_pairing.rs index 996af930..c0f03a12 100644 --- a/poly_commit/src/kzg/deferred_pairing.rs +++ b/poly_commit/src/kzg/deferred_pairing.rs @@ -6,7 +6,7 @@ use halo2curves::{ }; /// Deferred pairing checks -#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Default)] pub struct PairingAccumulator { pub g1s: Vec, pub g2s: Vec, @@ -25,6 +25,7 @@ pub trait DeferredPairingCheck { } } +// Empty implementation for the case where no pairing checks are needed impl DeferredPairingCheck for () { type AccumulatedValues = (); } diff --git a/poly_commit/src/kzg/expander_api.rs b/poly_commit/src/kzg/expander_api.rs index 11042c72..d097cbc4 100644 --- a/poly_commit/src/kzg/expander_api.rs +++ b/poly_commit/src/kzg/expander_api.rs @@ -13,6 +13,8 @@ use serdes::ExpSerde; use crate::*; +use super::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}; + impl ExpanderPCS for HyperKZGPCS where G: FieldEngine, @@ -30,6 +32,7 @@ where type Params = usize; type SRS = CoefFormBiKZGLocalSRS; type ScratchPad = (); + type Accumulator = PairingAccumulator; fn init_scratch_pad(_params: &Self::Params, _mpi_engine: &impl MPIEngine) -> Self::ScratchPad {} @@ -118,4 +121,20 @@ where transcript, ) } + + fn partial_verify( + _params: &Self::Params, + verifying_key: &::VKey, + commitment: &Self::Commitment, + x: &ExpanderSingleVarChallenge, + v: ::ChallengeField, + transcript: &mut impl Transcript, + opening: &Self::Opening, + accumulator: &mut Self::Accumulator, + ) { + } + + fn batch_deferred_verification(accumulator: &mut Self::Accumulator) -> bool { + accumulator.check_pairings() + } } diff --git a/poly_commit/src/kzg/hyper_bikzg.rs b/poly_commit/src/kzg/hyper_bikzg.rs index 2571fb50..a4e52bdc 100644 --- a/poly_commit/src/kzg/hyper_bikzg.rs +++ b/poly_commit/src/kzg/hyper_bikzg.rs @@ -18,6 +18,8 @@ use transcript::{transcript_root_broadcast, transcript_verifier_sync}; use crate::*; +use super::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}; + pub fn coeff_form_hyper_bikzg_open( srs: &CoefFormBiKZGLocalSRS, mpi_engine: &impl MPIEngine, @@ -648,3 +650,211 @@ where final_opening, ) } + +#[allow(clippy::too_many_arguments)] +pub fn coeff_form_hyper_bikzg_verify_minus_pairing( + vk: &BiKZGVerifierParam, + local_alphas: &[E::Fr], + mpi_alphas: &[E::Fr], + eval: E::Fr, + commitment: E::G1Affine, + opening: &HyperBiKZGOpening, + fs_transcript: &mut T, + pairing_accumulator: &mut PairingAccumulator, +) -> bool +where + E: MultiMillerLoop, + T: Transcript, + E::G1Affine: CurveAffine + ExpSerde, + E::G2Affine: CurveAffine + ExpSerde, + E::Fr: ExtensionField, +{ + // NOTE(HS) deteriorate to vanilla HyperKZG verify if mpi_alphas is empty + if mpi_alphas.is_empty() { + let hyper_bikzg_opening = opening.clone(); + let hyper_kzg_opening: HyperKZGOpening = hyper_bikzg_opening.into(); + + let what = coeff_form_uni_hyperkzg_verify( + vk.into(), + commitment, + local_alphas, + eval, + &hyper_kzg_opening, + fs_transcript, + ); + + return what; + } + + let mpi_world_size = 1 << mpi_alphas.len(); + + opening + .folded_oracle_commitments + .iter() + .for_each(|f| fs_transcript.append_u8_slice(f.to_bytes().as_ref())); + + // NOTE(HS) transcript MPI thing ... + transcript_verifier_sync(fs_transcript, mpi_world_size); + + let beta_x = fs_transcript.generate_field_element::(); + let beta_y = fs_transcript.generate_field_element::(); + + // dbg!(beta_x, beta_y); + + // NOTE(HS) evaluation checks + + let beta_y2_local = HyperKZGLocalEvals::new_from_exported_evals( + &opening.aggregated_evals.beta_y2_evals, + local_alphas, + beta_x, + ); + + let pos_beta_y_local = HyperKZGLocalEvals::new_from_exported_evals( + &opening.aggregated_evals.pos_beta_y_evals, + local_alphas, + beta_x, + ); + + let neg_beta_y_local = HyperKZGLocalEvals::new_from_exported_evals( + &opening.aggregated_evals.neg_beta_y_evals, + local_alphas, + beta_x, + ); + + let beta_y2_final_eval = beta_y2_local.multilinear_final_eval(); + let pos_beta_y_final_eval = pos_beta_y_local.multilinear_final_eval(); + let neg_beta_y_final_eval = neg_beta_y_local.multilinear_final_eval(); + + // dbg!( + // &beta_y2_final_eval, + // &pos_beta_y_final_eval, + // &neg_beta_y_final_eval + // ); + + // dbg!( + // &opening.leader_evals.beta_x2_eval, + // &opening.leader_evals.pos_beta_x_evals[0], + // &opening.leader_evals.neg_beta_x_evals[0] + // ); + + if beta_y2_final_eval != opening.leader_evals.beta_x2_eval { + return false; + } + if pos_beta_y_final_eval != opening.leader_evals.pos_beta_x_evals[0] { + return false; + } + if neg_beta_y_final_eval != opening.leader_evals.neg_beta_x_evals[0] { + return false; + } + + let local_final_eval = + HyperKZGLocalEvals::new_from_exported_evals(&opening.leader_evals, mpi_alphas, beta_y); + if eval != local_final_eval.multilinear_final_eval() { + return false; + } + + opening.aggregated_evals.append_to_transcript(fs_transcript); + opening.leader_evals.append_to_transcript(fs_transcript); + + // NOTE(HS) transcript MPI thing ... + transcript_verifier_sync(fs_transcript, mpi_world_size); + + let gamma = fs_transcript.generate_field_element::(); + + // dbg!(gamma); + + let aggregated_oracle_commitment: E::G1Affine = { + let gamma_power_series = powers_series(&gamma, local_alphas.len() + mpi_alphas.len() + 1); + + let com_g1: E::G1 = izip!( + iter::once(&commitment).chain(&opening.folded_oracle_commitments), + &gamma_power_series + ) + .map(|(com, g)| com.to_curve() * g) + .sum(); + + com_g1.into() + }; + + // NOTE(HS) aggregate lagrange degree 2 polys + let (y_beta2, y_beta, y_neg_beta) = { + let gamma_n = gamma.pow_vartime([local_alphas.len() as u64]); + let (v_beta2, v_beta, v_neg_beta) = local_final_eval.gamma_aggregate_evals(gamma); + + (v_beta2 * gamma_n, v_beta * gamma_n, v_neg_beta * gamma_n) + }; + + let mut aggregated_beta_y2_locals = + beta_y2_local.interpolate_degree2_aggregated_evals(beta_x, gamma); + aggregated_beta_y2_locals[0] += y_beta2; + + let mut aggregated_pos_beta_y_locals = + pos_beta_y_local.interpolate_degree2_aggregated_evals(beta_x, gamma); + aggregated_pos_beta_y_locals[0] += y_beta; + + let mut aggregated_neg_beta_y_locals = + neg_beta_y_local.interpolate_degree2_aggregated_evals(beta_x, gamma); + aggregated_neg_beta_y_locals[0] += y_neg_beta; + + fs_transcript.append_u8_slice(opening.beta_x_commitment.to_bytes().as_ref()); + + // NOTE(HS) transcript MPI thing ... + transcript_verifier_sync(fs_transcript, mpi_world_size); + + let delta_x = fs_transcript.generate_field_element::(); + + // dbg!(delta_x); + + let delta_x_pow_series = powers_series(&delta_x, 3); + let at_beta_y2 = univariate_evaluate(&aggregated_beta_y2_locals, &delta_x_pow_series); + let at_beta_y = univariate_evaluate(&aggregated_pos_beta_y_locals, &delta_x_pow_series); + let at_neg_beta_y = univariate_evaluate(&aggregated_neg_beta_y_locals, &delta_x_pow_series); + + // dbg!(at_beta_y2, at_beta_y, at_neg_beta_y); + + let lagrange_degree2_delta_y = coeff_form_degree2_lagrange( + [beta_y, -beta_y, beta_y * beta_y], + [at_beta_y, at_neg_beta_y, at_beta_y2], + ); + + // dbg!(lagrange_degree2_delta_y); + + fs_transcript.append_u8_slice(opening.beta_y_commitment.to_bytes().as_ref()); + + // NOTE(HS) transcript MPI thing ... + transcript_verifier_sync(fs_transcript, mpi_world_size); + + let delta_y = fs_transcript.generate_field_element::(); + + // dbg!(delta_y); + + let delta_y_pow_series = powers_series(&delta_y, 3); + let degree_2_final_eval = univariate_evaluate(&lagrange_degree2_delta_y, &delta_y_pow_series); + + // dbg!(degree_2_final_eval); + + // NOTE(HS) f_gamma_s - (delta_x - beta_x) ... (delta_x - beta_x2) f_gamma_quotient_s + // - (delta_y - beta_y) ... (delta_y - beta_y2) lagrange_quotient_y + let delta_x_denom = (delta_x - beta_x) * (delta_x - beta_x * beta_x) * (delta_x + beta_x); + let delta_y_denom = (delta_y - beta_y) * (delta_y - beta_y * beta_y) * (delta_y + beta_y); + + let com_r = aggregated_oracle_commitment.to_curve() + - (opening.beta_x_commitment * delta_x_denom) + - (opening.beta_y_commitment * delta_y_denom); + + // dbg!(com_r); + + let final_opening = BiKZGProof { + quotient_x: opening.quotient_delta_x_commitment, + quotient_y: opening.quotient_delta_y_commitment, + }; + + coeff_form_bi_kzg_verify( + vk.clone(), + com_r.to_affine(), + delta_x, + delta_y, + degree_2_final_eval, + final_opening, + ) +} diff --git a/poly_commit/src/kzg/hyper_kzg.rs b/poly_commit/src/kzg/hyper_kzg.rs index 5caf9cce..3fe13569 100644 --- a/poly_commit/src/kzg/hyper_kzg.rs +++ b/poly_commit/src/kzg/hyper_kzg.rs @@ -13,6 +13,8 @@ use serdes::ExpSerde; use crate::*; +use super::deferred_pairing::PairingAccumulator; + #[inline(always)] pub(crate) fn coeff_form_hyperkzg_local_poly_oracles( srs: &CoefFormUniKZGSRS, @@ -231,3 +233,72 @@ where opening.quotient_delta_x_commitment, ) } + +#[inline(always)] +pub fn coeff_form_uni_hyperkzg_partial_verify( + vk: UniKZGVerifierParams, + comm: E::G1Affine, + alphas: &[E::Fr], + eval: E::Fr, + opening: &HyperKZGOpening, + fs_transcript: &mut T, + pairing_accumulator: &mut PairingAccumulator, +) -> bool +where + E: MultiMillerLoop, + E::G1Affine: CurveAffine + ExpSerde, + E::G2Affine: ExpSerde, + E::Fr: ExtensionField + ExpSerde, + T: Transcript, +{ + opening + .folded_oracle_commitments + .iter() + .for_each(|f| fs_transcript.append_u8_slice(f.to_bytes().as_ref())); + + let beta = fs_transcript.generate_field_element::(); + let beta2 = beta * beta; + + let local_evals = + HyperKZGLocalEvals::::new_from_exported_evals(&opening.evals_at_x, alphas, beta); + + opening.evals_at_x.append_to_transcript(fs_transcript); + + if local_evals.multilinear_final_eval() != eval { + return false; + } + + let gamma = fs_transcript.generate_field_element::(); + let gamma_pow_series = powers_series(&gamma, alphas.len()); + let v_beta = univariate_evaluate(&local_evals.pos_beta_evals, &gamma_pow_series); + let v_neg_beta = univariate_evaluate(&local_evals.neg_beta_evals, &gamma_pow_series); + let v_beta2 = univariate_evaluate(&local_evals.beta2_evals, &gamma_pow_series); + let lagrange_degree2 = + coeff_form_degree2_lagrange([beta, -beta, beta2], [v_beta, v_neg_beta, v_beta2]); + + let folded_g1_oracle_comms: Vec = opening + .folded_oracle_commitments + .iter() + .map(|c| c.to_curve()) + .collect(); + let commitment_agg_g1: E::G1 = + comm.to_curve() + univariate_evaluate(&folded_g1_oracle_comms, &gamma_pow_series[1..]); + + fs_transcript.append_u8_slice(opening.beta_x_commitment.to_bytes().as_ref()); + let tau = fs_transcript.generate_field_element::(); + + let q_weight = (tau - beta) * (tau - beta2) * (tau + beta); + let lagrange_eval = + lagrange_degree2[0] + lagrange_degree2[1] * tau + lagrange_degree2[2] * tau * tau; + + coeff_form_uni_kzg_partial_verify( + vk, + (commitment_agg_g1 - opening.beta_x_commitment.to_curve() * q_weight).into(), + tau, + lagrange_eval, + opening.quotient_delta_x_commitment, + pairing_accumulator, + ); + + true +} diff --git a/poly_commit/src/kzg/univariate.rs b/poly_commit/src/kzg/univariate.rs index 66b49671..76cac906 100644 --- a/poly_commit/src/kzg/univariate.rs +++ b/poly_commit/src/kzg/univariate.rs @@ -10,6 +10,8 @@ use serdes::ExpSerde; use crate::*; +use super::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}; + #[inline(always)] pub(crate) fn generate_coef_form_uni_kzg_srs_for_testing( length: usize, @@ -86,30 +88,49 @@ where (eval, opening.into()) } +// #[inline(always)] +// pub(crate) fn coeff_form_uni_kzg_verify( +// vk: UniKZGVerifierParams, +// comm: E::G1Affine, +// alpha: E::Fr, +// eval: E::Fr, +// opening: E::G1Affine, +// ) -> bool +// where +// E::G1Affine: CurveAffine, +// E::G2Affine: ExpSerde, +// { +// let g1_eval: E::G1Affine = (E::G1Affine::generator() * eval).into(); +// let g2_alpha: E::G2 = E::G2Affine::generator() * alpha; + +// let gt_result = E::multi_miller_loop(&[ +// ( +// &opening, +// &(vk.tau_g2.to_curve() - g2_alpha).to_affine().into(), +// ), +// (&(g1_eval - comm).into(), &E::G2Affine::generator().into()), +// ]); + +// gt_result.final_exponentiation().is_identity().into() +// } + #[inline(always)] -pub(crate) fn coeff_form_uni_kzg_verify( +pub(crate) fn coeff_form_uni_kzg_partial_verify( vk: UniKZGVerifierParams, comm: E::G1Affine, alpha: E::Fr, eval: E::Fr, opening: E::G1Affine, -) -> bool -where + pairing_accumulator: &mut PairingAccumulator, +) where E::G1Affine: CurveAffine, E::G2Affine: ExpSerde, { let g1_eval: E::G1Affine = (E::G1Affine::generator() * eval).into(); let g2_alpha: E::G2 = E::G2Affine::generator() * alpha; - let gt_result = E::multi_miller_loop(&[ - ( - &opening, - &(vk.tau_g2.to_curve() - g2_alpha).to_affine().into(), - ), - (&(g1_eval - comm).into(), &E::G2Affine::generator().into()), - ]); - - gt_result.final_exponentiation().is_identity().into() + pairing_accumulator.add_pairing_check(&(opening.to_curve(), (vk.tau_g2.to_curve() - g2_alpha))); + pairing_accumulator.add_pairing_check(&((g1_eval - comm).into(), E::G2::generator())); } #[cfg(test)] @@ -142,6 +163,7 @@ mod tests { let (actual_eval, opening) = coeff_form_uni_kzg_open_eval(&srs, &poly, alpha); assert_eq!(actual_eval, eval); + assert!(coeff_form_uni_kzg_verify(vk, com, alpha, eval, opening)) } @@ -158,6 +180,7 @@ mod tests { let (actual_eval, opening) = coeff_form_uni_kzg_open_eval(&srs, &poly, alpha); assert_eq!(actual_eval, eval); + assert!(coeff_form_uni_kzg_verify(vk, com, alpha, eval, opening)) } } diff --git a/poly_commit/src/lib.rs b/poly_commit/src/lib.rs index b3e158c5..5173c3bc 100644 --- a/poly_commit/src/lib.rs +++ b/poly_commit/src/lib.rs @@ -8,14 +8,14 @@ pub const PCS_SOUNDNESS_BITS: usize = 128; mod utils; pub use utils::expander_pcs_init_testing_only; -pub mod raw; -pub use raw::RawExpanderGKR; +// pub mod raw; +// pub use raw::RawExpanderGKR; -pub mod orion; -pub use orion::*; +// pub mod orion; +// pub use orion::*; -pub mod hyrax; -pub use hyrax::*; +// pub mod hyrax; +// pub use hyrax::*; pub mod kzg; pub use kzg::*; From 86dbbd5ad0eda4756a9799ad4b592a0c66932369 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 20 May 2025 09:16:14 -0400 Subject: [PATCH 04/57] kzg batch verify works --- gkr_engine/src/poly_commit/definition.rs | 2 +- poly_commit/src/kzg.rs | 2 + poly_commit/src/kzg/bivariate.rs | 72 ++++-- poly_commit/src/kzg/deferred_pairing.rs | 14 +- poly_commit/src/kzg/expander_api.rs | 29 ++- poly_commit/src/kzg/hyper_bikzg.rs | 204 ++-------------- poly_commit/src/kzg/hyper_kzg.rs | 60 ++--- poly_commit/src/kzg/pcs_trait_impl.rs | 13 +- poly_commit/src/kzg/univariate.rs | 51 ++-- poly_commit/tests/test_hyrax.rs | 166 ++++++------- poly_commit/tests/test_kzg.rs | 93 +++++++- poly_commit/tests/test_orion.rs | 282 +++++++++++------------ poly_commit/tests/test_raw.rs | 128 +++++----- 13 files changed, 535 insertions(+), 581 deletions(-) diff --git a/gkr_engine/src/poly_commit/definition.rs b/gkr_engine/src/poly_commit/definition.rs index b54a264b..2101764f 100644 --- a/gkr_engine/src/poly_commit/definition.rs +++ b/gkr_engine/src/poly_commit/definition.rs @@ -130,7 +130,7 @@ pub trait ExpanderPCS { transcript: &mut impl Transcript, opening: &Self::Opening, accumulator: &mut Self::Accumulator, - ); + ) -> bool; /// Perform the finally batch verification for the accumulated opening proofs. fn batch_deferred_verification(accumulator: &mut Self::Accumulator) -> bool; diff --git a/poly_commit/src/kzg.rs b/poly_commit/src/kzg.rs index 072dacae..ab1c79f2 100644 --- a/poly_commit/src/kzg.rs +++ b/poly_commit/src/kzg.rs @@ -30,3 +30,5 @@ pub use pcs_trait_impl::HyperKZGPCS; mod expander_api; mod deferred_pairing; +pub use deferred_pairing::DeferredPairingCheck; +pub use deferred_pairing::PairingAccumulator; diff --git a/poly_commit/src/kzg/bivariate.rs b/poly_commit/src/kzg/bivariate.rs index c38117ea..20682794 100644 --- a/poly_commit/src/kzg/bivariate.rs +++ b/poly_commit/src/kzg/bivariate.rs @@ -2,7 +2,7 @@ use halo2curves::{ ff::Field, group::{prime::PrimeCurveAffine, Curve, Group}, msm, - pairing::{MillerLoopResult, MultiMillerLoop}, + pairing::MultiMillerLoop, CurveAffine, }; use itertools::izip; @@ -10,6 +10,8 @@ use serdes::ExpSerde; use crate::*; +use super::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}; + #[inline(always)] pub fn generate_coef_form_bi_kzg_local_srs_for_testing( local_length: usize, @@ -110,6 +112,34 @@ pub fn coeff_form_bi_kzg_verify( eval: E::Fr, opening: BiKZGProof, ) -> bool +where + E::G1Affine: CurveAffine + ExpSerde, + E::G2Affine: CurveAffine + ExpSerde, +{ + let mut pairing_accumulator = PairingAccumulator::default(); + let partial_check = coeff_form_bi_kzg_partial_verify( + vk, + comm, + alpha, + beta, + eval, + opening, + &mut pairing_accumulator, + ); + let pairing_check = pairing_accumulator.check_pairings(); + partial_check && pairing_check +} + +#[inline(always)] +pub fn coeff_form_bi_kzg_partial_verify( + vk: BiKZGVerifierParam, + comm: E::G1Affine, + alpha: E::Fr, + beta: E::Fr, + eval: E::Fr, + opening: BiKZGProof, + pairing_accumulator: &mut PairingAccumulator, +) -> bool where E::G1Affine: CurveAffine + ExpSerde, E::G2Affine: CurveAffine + ExpSerde, @@ -118,19 +148,19 @@ where let g2_alpha: E::G2 = E::G2Affine::generator() * alpha; let g2_beta: E::G2 = E::G2Affine::generator() * beta; - let gt_result = E::multi_miller_loop(&[ - ( - &opening.quotient_x, - &(vk.tau_x_g2.to_curve() - g2_alpha).to_affine().into(), - ), - ( - &opening.quotient_y, - &(vk.tau_y_g2.to_curve() - g2_beta).to_affine().into(), - ), - (&(g1_eval - comm).into(), &E::G2Affine::generator().into()), - ]); - - gt_result.final_exponentiation().is_identity().into() + pairing_accumulator.add_pairing_check(&( + opening.quotient_x.to_curve(), + (vk.tau_x_g2.to_curve() - g2_alpha), + )); + + pairing_accumulator.add_pairing_check(&( + opening.quotient_y.to_curve(), + (vk.tau_y_g2.to_curve() - g2_beta), + )); + + pairing_accumulator.add_pairing_check(&((g1_eval - comm), E::G2::generator())); + + true } #[cfg(test)] @@ -143,7 +173,10 @@ mod tests { }; use itertools::izip; - use crate::*; + use crate::{ + kzg::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}, + *, + }; #[test] fn test_coefficient_form_bivariate_kzg_e2e() { @@ -184,13 +217,18 @@ mod tests { coeff_form_bi_kzg_open_leader(&party_srs[0], &evals_and_opens, beta); let vk: BiKZGVerifierParam = From::from(&party_srs[0]); - assert!(coeff_form_bi_kzg_verify( + + let mut pairing_accumulator = PairingAccumulator::default(); + coeff_form_bi_kzg_partial_verify( vk, global_commitment, alpha, beta, final_eval, final_opening, - )); + &mut pairing_accumulator, + ); + + assert!(pairing_accumulator.check_pairings()); } } diff --git a/poly_commit/src/kzg/deferred_pairing.rs b/poly_commit/src/kzg/deferred_pairing.rs index c0f03a12..a3e96e7d 100644 --- a/poly_commit/src/kzg/deferred_pairing.rs +++ b/poly_commit/src/kzg/deferred_pairing.rs @@ -6,12 +6,24 @@ use halo2curves::{ }; /// Deferred pairing checks -#[derive(Clone, Debug, PartialEq, Eq, Default)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct PairingAccumulator { pub g1s: Vec, pub g2s: Vec, } +impl Default for PairingAccumulator +where + E: Engine, +{ + fn default() -> Self { + Self { + g1s: Vec::new(), + g2s: Vec::new(), + } + } +} + pub trait DeferredPairingCheck { /// Data type to be accumulated type AccumulatedValues; diff --git a/poly_commit/src/kzg/expander_api.rs b/poly_commit/src/kzg/expander_api.rs index d097cbc4..267cada6 100644 --- a/poly_commit/src/kzg/expander_api.rs +++ b/poly_commit/src/kzg/expander_api.rs @@ -111,15 +111,20 @@ where transcript: &mut impl Transcript, opening: &Self::Opening, ) -> bool { - coeff_form_hyper_bikzg_verify( + let mut accumulator = PairingAccumulator::default(); + + let partial_check = Self::partial_verify( + _params, verifying_key, - &x.local_xs(), - &x.r_mpi, + commitment, + &x, v, - commitment.0, - opening, transcript, - ) + opening, + &mut accumulator, + ); + let pairing_check = accumulator.check_pairings(); + partial_check && pairing_check } fn partial_verify( @@ -131,7 +136,17 @@ where transcript: &mut impl Transcript, opening: &Self::Opening, accumulator: &mut Self::Accumulator, - ) { + ) -> bool { + coeff_form_hyper_bikzg_partial_verify( + verifying_key, + &x.local_xs(), + &x.r_mpi, + v, + commitment.0, + opening, + transcript, + accumulator, + ) } fn batch_deferred_verification(accumulator: &mut Self::Accumulator) -> bool { diff --git a/poly_commit/src/kzg/hyper_bikzg.rs b/poly_commit/src/kzg/hyper_bikzg.rs index a4e52bdc..13855b3f 100644 --- a/poly_commit/src/kzg/hyper_bikzg.rs +++ b/poly_commit/src/kzg/hyper_bikzg.rs @@ -461,198 +461,24 @@ where E::G2Affine: CurveAffine + ExpSerde, E::Fr: ExtensionField, { - // NOTE(HS) deteriorate to vanilla HyperKZG verify if mpi_alphas is empty - if mpi_alphas.is_empty() { - let hyper_bikzg_opening = opening.clone(); - let hyper_kzg_opening: HyperKZGOpening = hyper_bikzg_opening.into(); - - let what = coeff_form_uni_hyperkzg_verify( - vk.into(), - commitment, - local_alphas, - eval, - &hyper_kzg_opening, - fs_transcript, - ); - - return what; - } - - let mpi_world_size = 1 << mpi_alphas.len(); - - opening - .folded_oracle_commitments - .iter() - .for_each(|f| fs_transcript.append_u8_slice(f.to_bytes().as_ref())); - - // NOTE(HS) transcript MPI thing ... - transcript_verifier_sync(fs_transcript, mpi_world_size); - - let beta_x = fs_transcript.generate_field_element::(); - let beta_y = fs_transcript.generate_field_element::(); - - // dbg!(beta_x, beta_y); - - // NOTE(HS) evaluation checks - - let beta_y2_local = HyperKZGLocalEvals::new_from_exported_evals( - &opening.aggregated_evals.beta_y2_evals, - local_alphas, - beta_x, - ); - - let pos_beta_y_local = HyperKZGLocalEvals::new_from_exported_evals( - &opening.aggregated_evals.pos_beta_y_evals, - local_alphas, - beta_x, - ); - - let neg_beta_y_local = HyperKZGLocalEvals::new_from_exported_evals( - &opening.aggregated_evals.neg_beta_y_evals, + let mut pairing_accumulator = PairingAccumulator::default(); + let partial_check = coeff_form_hyper_bikzg_partial_verify( + vk, local_alphas, - beta_x, + mpi_alphas, + eval, + commitment, + opening, + fs_transcript, + &mut pairing_accumulator, ); + let pairing_check = pairing_accumulator.check_pairings(); - let beta_y2_final_eval = beta_y2_local.multilinear_final_eval(); - let pos_beta_y_final_eval = pos_beta_y_local.multilinear_final_eval(); - let neg_beta_y_final_eval = neg_beta_y_local.multilinear_final_eval(); - - // dbg!( - // &beta_y2_final_eval, - // &pos_beta_y_final_eval, - // &neg_beta_y_final_eval - // ); - - // dbg!( - // &opening.leader_evals.beta_x2_eval, - // &opening.leader_evals.pos_beta_x_evals[0], - // &opening.leader_evals.neg_beta_x_evals[0] - // ); - - if beta_y2_final_eval != opening.leader_evals.beta_x2_eval { - return false; - } - if pos_beta_y_final_eval != opening.leader_evals.pos_beta_x_evals[0] { - return false; - } - if neg_beta_y_final_eval != opening.leader_evals.neg_beta_x_evals[0] { - return false; - } - - let local_final_eval = - HyperKZGLocalEvals::new_from_exported_evals(&opening.leader_evals, mpi_alphas, beta_y); - if eval != local_final_eval.multilinear_final_eval() { - return false; - } - - opening.aggregated_evals.append_to_transcript(fs_transcript); - opening.leader_evals.append_to_transcript(fs_transcript); - - // NOTE(HS) transcript MPI thing ... - transcript_verifier_sync(fs_transcript, mpi_world_size); - - let gamma = fs_transcript.generate_field_element::(); - - // dbg!(gamma); - - let aggregated_oracle_commitment: E::G1Affine = { - let gamma_power_series = powers_series(&gamma, local_alphas.len() + mpi_alphas.len() + 1); - - let com_g1: E::G1 = izip!( - iter::once(&commitment).chain(&opening.folded_oracle_commitments), - &gamma_power_series - ) - .map(|(com, g)| com.to_curve() * g) - .sum(); - - com_g1.into() - }; - - // NOTE(HS) aggregate lagrange degree 2 polys - let (y_beta2, y_beta, y_neg_beta) = { - let gamma_n = gamma.pow_vartime([local_alphas.len() as u64]); - let (v_beta2, v_beta, v_neg_beta) = local_final_eval.gamma_aggregate_evals(gamma); - - (v_beta2 * gamma_n, v_beta * gamma_n, v_neg_beta * gamma_n) - }; - - let mut aggregated_beta_y2_locals = - beta_y2_local.interpolate_degree2_aggregated_evals(beta_x, gamma); - aggregated_beta_y2_locals[0] += y_beta2; - - let mut aggregated_pos_beta_y_locals = - pos_beta_y_local.interpolate_degree2_aggregated_evals(beta_x, gamma); - aggregated_pos_beta_y_locals[0] += y_beta; - - let mut aggregated_neg_beta_y_locals = - neg_beta_y_local.interpolate_degree2_aggregated_evals(beta_x, gamma); - aggregated_neg_beta_y_locals[0] += y_neg_beta; - - fs_transcript.append_u8_slice(opening.beta_x_commitment.to_bytes().as_ref()); - - // NOTE(HS) transcript MPI thing ... - transcript_verifier_sync(fs_transcript, mpi_world_size); - - let delta_x = fs_transcript.generate_field_element::(); - - // dbg!(delta_x); - - let delta_x_pow_series = powers_series(&delta_x, 3); - let at_beta_y2 = univariate_evaluate(&aggregated_beta_y2_locals, &delta_x_pow_series); - let at_beta_y = univariate_evaluate(&aggregated_pos_beta_y_locals, &delta_x_pow_series); - let at_neg_beta_y = univariate_evaluate(&aggregated_neg_beta_y_locals, &delta_x_pow_series); - - // dbg!(at_beta_y2, at_beta_y, at_neg_beta_y); - - let lagrange_degree2_delta_y = coeff_form_degree2_lagrange( - [beta_y, -beta_y, beta_y * beta_y], - [at_beta_y, at_neg_beta_y, at_beta_y2], - ); - - // dbg!(lagrange_degree2_delta_y); - - fs_transcript.append_u8_slice(opening.beta_y_commitment.to_bytes().as_ref()); - - // NOTE(HS) transcript MPI thing ... - transcript_verifier_sync(fs_transcript, mpi_world_size); - - let delta_y = fs_transcript.generate_field_element::(); - - // dbg!(delta_y); - - let delta_y_pow_series = powers_series(&delta_y, 3); - let degree_2_final_eval = univariate_evaluate(&lagrange_degree2_delta_y, &delta_y_pow_series); - - // dbg!(degree_2_final_eval); - - // NOTE(HS) f_gamma_s - (delta_x - beta_x) ... (delta_x - beta_x2) f_gamma_quotient_s - // - (delta_y - beta_y) ... (delta_y - beta_y2) lagrange_quotient_y - let delta_x_denom = (delta_x - beta_x) * (delta_x - beta_x * beta_x) * (delta_x + beta_x); - let delta_y_denom = (delta_y - beta_y) * (delta_y - beta_y * beta_y) * (delta_y + beta_y); - - let com_r = aggregated_oracle_commitment.to_curve() - - (opening.beta_x_commitment * delta_x_denom) - - (opening.beta_y_commitment * delta_y_denom); - - // dbg!(com_r); - - let final_opening = BiKZGProof { - quotient_x: opening.quotient_delta_x_commitment, - quotient_y: opening.quotient_delta_y_commitment, - }; - - coeff_form_bi_kzg_verify( - vk.clone(), - com_r.to_affine(), - delta_x, - delta_y, - degree_2_final_eval, - final_opening, - ) + partial_check && pairing_check } #[allow(clippy::too_many_arguments)] -pub fn coeff_form_hyper_bikzg_verify_minus_pairing( +pub fn coeff_form_hyper_bikzg_partial_verify( vk: &BiKZGVerifierParam, local_alphas: &[E::Fr], mpi_alphas: &[E::Fr], @@ -674,13 +500,14 @@ where let hyper_bikzg_opening = opening.clone(); let hyper_kzg_opening: HyperKZGOpening = hyper_bikzg_opening.into(); - let what = coeff_form_uni_hyperkzg_verify( + let what = coeff_form_uni_hyperkzg_partial_verify( vk.into(), commitment, local_alphas, eval, &hyper_kzg_opening, fs_transcript, + pairing_accumulator, ); return what; @@ -849,12 +676,13 @@ where quotient_y: opening.quotient_delta_y_commitment, }; - coeff_form_bi_kzg_verify( + coeff_form_bi_kzg_partial_verify( vk.clone(), com_r.to_affine(), delta_x, delta_y, degree_2_final_eval, final_opening, + pairing_accumulator, ) } diff --git a/poly_commit/src/kzg/hyper_kzg.rs b/poly_commit/src/kzg/hyper_kzg.rs index 3fe13569..50bbee4d 100644 --- a/poly_commit/src/kzg/hyper_kzg.rs +++ b/poly_commit/src/kzg/hyper_kzg.rs @@ -13,7 +13,7 @@ use serdes::ExpSerde; use crate::*; -use super::deferred_pairing::PairingAccumulator; +use super::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}; #[inline(always)] pub(crate) fn coeff_form_hyperkzg_local_poly_oracles( @@ -185,53 +185,19 @@ where E::Fr: ExtensionField + ExpSerde, T: Transcript, { - opening - .folded_oracle_commitments - .iter() - .for_each(|f| fs_transcript.append_u8_slice(f.to_bytes().as_ref())); - - let beta = fs_transcript.generate_field_element::(); - let beta2 = beta * beta; - - let local_evals = - HyperKZGLocalEvals::::new_from_exported_evals(&opening.evals_at_x, alphas, beta); - - opening.evals_at_x.append_to_transcript(fs_transcript); - - if local_evals.multilinear_final_eval() != eval { - return false; - } - - let gamma = fs_transcript.generate_field_element::(); - let gamma_pow_series = powers_series(&gamma, alphas.len()); - let v_beta = univariate_evaluate(&local_evals.pos_beta_evals, &gamma_pow_series); - let v_neg_beta = univariate_evaluate(&local_evals.neg_beta_evals, &gamma_pow_series); - let v_beta2 = univariate_evaluate(&local_evals.beta2_evals, &gamma_pow_series); - let lagrange_degree2 = - coeff_form_degree2_lagrange([beta, -beta, beta2], [v_beta, v_neg_beta, v_beta2]); - - let folded_g1_oracle_comms: Vec = opening - .folded_oracle_commitments - .iter() - .map(|c| c.to_curve()) - .collect(); - let commitment_agg_g1: E::G1 = - comm.to_curve() + univariate_evaluate(&folded_g1_oracle_comms, &gamma_pow_series[1..]); - - fs_transcript.append_u8_slice(opening.beta_x_commitment.to_bytes().as_ref()); - let tau = fs_transcript.generate_field_element::(); - - let q_weight = (tau - beta) * (tau - beta2) * (tau + beta); - let lagrange_eval = - lagrange_degree2[0] + lagrange_degree2[1] * tau + lagrange_degree2[2] * tau * tau; - - coeff_form_uni_kzg_verify( + let mut pairing_accumulator = PairingAccumulator::default(); + let partial_check = coeff_form_uni_hyperkzg_partial_verify( vk, - (commitment_agg_g1 - opening.beta_x_commitment.to_curve() * q_weight).into(), - tau, - lagrange_eval, - opening.quotient_delta_x_commitment, - ) + comm, + alphas, + eval, + opening, + fs_transcript, + &mut pairing_accumulator, + ); + let pairing_check = pairing_accumulator.check_pairings(); + + partial_check && pairing_check } #[inline(always)] diff --git a/poly_commit/src/kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/pcs_trait_impl.rs index e1d003e3..83fb9305 100644 --- a/poly_commit/src/kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/pcs_trait_impl.rs @@ -13,6 +13,8 @@ use serdes::ExpSerde; use crate::*; use kzg::hyper_kzg::*; +use super::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}; + pub struct HyperKZGPCS where E: Engine, @@ -78,13 +80,20 @@ where opening: &Self::Opening, transcript: &mut impl Transcript, ) -> bool { - coeff_form_uni_hyperkzg_verify( + let mut accumulator = PairingAccumulator::default(); + + let partial_check = coeff_form_uni_hyperkzg_partial_verify( verifying_key.clone(), commitment.0, x, v, opening, transcript, - ) + &mut accumulator, + ); + + let pairing_check = accumulator.check_pairings(); + + pairing_check && partial_check } } diff --git a/poly_commit/src/kzg/univariate.rs b/poly_commit/src/kzg/univariate.rs index 76cac906..0135b889 100644 --- a/poly_commit/src/kzg/univariate.rs +++ b/poly_commit/src/kzg/univariate.rs @@ -2,7 +2,7 @@ use halo2curves::{ ff::Field, group::{prime::PrimeCurveAffine, Curve, Group}, msm, - pairing::{MillerLoopResult, MultiMillerLoop}, + pairing::MultiMillerLoop, CurveAffine, }; use itertools::izip; @@ -88,31 +88,25 @@ where (eval, opening.into()) } -// #[inline(always)] -// pub(crate) fn coeff_form_uni_kzg_verify( -// vk: UniKZGVerifierParams, -// comm: E::G1Affine, -// alpha: E::Fr, -// eval: E::Fr, -// opening: E::G1Affine, -// ) -> bool -// where -// E::G1Affine: CurveAffine, -// E::G2Affine: ExpSerde, -// { -// let g1_eval: E::G1Affine = (E::G1Affine::generator() * eval).into(); -// let g2_alpha: E::G2 = E::G2Affine::generator() * alpha; - -// let gt_result = E::multi_miller_loop(&[ -// ( -// &opening, -// &(vk.tau_g2.to_curve() - g2_alpha).to_affine().into(), -// ), -// (&(g1_eval - comm).into(), &E::G2Affine::generator().into()), -// ]); - -// gt_result.final_exponentiation().is_identity().into() -// } +#[inline(always)] +#[cfg(test)] +pub(crate) fn coeff_form_uni_kzg_verify( + vk: UniKZGVerifierParams, + comm: E::G1Affine, + alpha: E::Fr, + eval: E::Fr, + opening: E::G1Affine, +) -> bool +where + E::G1Affine: CurveAffine, + E::G2Affine: ExpSerde, +{ + let mut pairing_accumulator = PairingAccumulator::default(); + coeff_form_uni_kzg_partial_verify(vk, comm, alpha, eval, opening, &mut pairing_accumulator); + let pairing_check = pairing_accumulator.check_pairings(); + + pairing_check +} #[inline(always)] pub(crate) fn coeff_form_uni_kzg_partial_verify( @@ -122,7 +116,8 @@ pub(crate) fn coeff_form_uni_kzg_partial_verify( eval: E::Fr, opening: E::G1Affine, pairing_accumulator: &mut PairingAccumulator, -) where +) -> bool +where E::G1Affine: CurveAffine, E::G2Affine: ExpSerde, { @@ -131,6 +126,8 @@ pub(crate) fn coeff_form_uni_kzg_partial_verify( pairing_accumulator.add_pairing_check(&(opening.to_curve(), (vk.tau_g2.to_curve() - g2_alpha))); pairing_accumulator.add_pairing_check(&((g1_eval - comm).into(), E::G2::generator())); + + true } #[cfg(test)] diff --git a/poly_commit/tests/test_hyrax.rs b/poly_commit/tests/test_hyrax.rs index f3095cd6..20c505d7 100644 --- a/poly_commit/tests/test_hyrax.rs +++ b/poly_commit/tests/test_hyrax.rs @@ -1,83 +1,83 @@ -mod common; - -use arith::{Field, Fr}; -use ark_std::test_rng; -use gkr_engine::{BN254Config, ExpanderSingleVarChallenge, MPIConfig, MPIEngine, Transcript}; -use gkr_hashers::Keccak256hasher; -use halo2curves::bn256::G1Affine; -use poly_commit::HyraxPCS; -use polynomials::MultiLinearPoly; -use transcript::BytesHashTranscript; - -const TEST_REPETITION: usize = 3; - -fn test_hyrax_pcs_generics(num_vars_start: usize, num_vars_end: usize) { - let mut rng = test_rng(); - - (num_vars_start..=num_vars_end).for_each(|num_vars| { - let xs: Vec<_> = (0..TEST_REPETITION) - .map(|_| -> Vec { (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect() }) - .collect(); - let poly = MultiLinearPoly::::random(num_vars, &mut rng); - - common::test_pcs::, HyraxPCS>( - &num_vars, &poly, &xs, - ); - }) -} - -#[test] -fn test_hyrax_pcs_e2e() { - test_hyrax_pcs_generics(3, 17) -} - -fn test_hyrax_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_num_vars: usize) { - let mut rng = test_rng(); - - // NOTE BN254 GKR SIMD pack size = 1, num vars in SIMD is 0 - let num_vars_in_mpi = mpi_config_ref.world_size().ilog2() as usize; - let num_vars_in_each_poly = total_num_vars - num_vars_in_mpi; - - let global_poly = MultiLinearPoly::::random(total_num_vars, &mut rng); - let challenge_point = ExpanderSingleVarChallenge:: { - r_mpi: (0..num_vars_in_mpi) - .map(|_| Fr::random_unsafe(&mut rng)) - .collect(), - r_simd: Vec::new(), - rz: (0..num_vars_in_each_poly) - .map(|_| Fr::random_unsafe(&mut rng)) - .collect(), - }; - - let mut transcript = BytesHashTranscript::::new(); - - // NOTE separate polynomial into different pieces by mpi rank - let poly_vars_stride = (1 << global_poly.get_num_vars()) / mpi_config_ref.world_size(); - let poly_coeff_starts = mpi_config_ref.world_rank() * poly_vars_stride; - let poly_coeff_ends = poly_coeff_starts + poly_vars_stride; - let local_poly = - MultiLinearPoly::new(global_poly.coeffs[poly_coeff_starts..poly_coeff_ends].to_vec()); - - dbg!(local_poly.get_num_vars(), local_poly.coeffs[0]); - - common::test_pcs_for_expander_gkr::< - BN254Config, - BytesHashTranscript, - HyraxPCS, - >( - &num_vars_in_each_poly, - mpi_config_ref, - &mut transcript, - &local_poly, - &[challenge_point], - ); -} - -#[test] -fn test_hyrax_for_expander_gkr() { - let mpi_config = MPIConfig::prover_new(); - - test_hyrax_for_expander_gkr_generics(&mpi_config, 19); - - MPIConfig::finalize() -} +// mod common; + +// use arith::{Field, Fr}; +// use ark_std::test_rng; +// use gkr_engine::{BN254Config, ExpanderSingleVarChallenge, MPIConfig, MPIEngine, Transcript}; +// use gkr_hashers::Keccak256hasher; +// use halo2curves::bn256::G1Affine; +// use poly_commit::HyraxPCS; +// use polynomials::MultiLinearPoly; +// use transcript::BytesHashTranscript; + +// const TEST_REPETITION: usize = 3; + +// fn test_hyrax_pcs_generics(num_vars_start: usize, num_vars_end: usize) { +// let mut rng = test_rng(); + +// (num_vars_start..=num_vars_end).for_each(|num_vars| { +// let xs: Vec<_> = (0..TEST_REPETITION) +// .map(|_| -> Vec { (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect() }) +// .collect(); +// let poly = MultiLinearPoly::::random(num_vars, &mut rng); + +// common::test_pcs::, HyraxPCS>( +// &num_vars, &poly, &xs, +// ); +// }) +// } + +// #[test] +// fn test_hyrax_pcs_e2e() { +// test_hyrax_pcs_generics(3, 17) +// } + +// fn test_hyrax_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_num_vars: usize) { +// let mut rng = test_rng(); + +// // NOTE BN254 GKR SIMD pack size = 1, num vars in SIMD is 0 +// let num_vars_in_mpi = mpi_config_ref.world_size().ilog2() as usize; +// let num_vars_in_each_poly = total_num_vars - num_vars_in_mpi; + +// let global_poly = MultiLinearPoly::::random(total_num_vars, &mut rng); +// let challenge_point = ExpanderSingleVarChallenge:: { +// r_mpi: (0..num_vars_in_mpi) +// .map(|_| Fr::random_unsafe(&mut rng)) +// .collect(), +// r_simd: Vec::new(), +// rz: (0..num_vars_in_each_poly) +// .map(|_| Fr::random_unsafe(&mut rng)) +// .collect(), +// }; + +// let mut transcript = BytesHashTranscript::::new(); + +// // NOTE separate polynomial into different pieces by mpi rank +// let poly_vars_stride = (1 << global_poly.get_num_vars()) / mpi_config_ref.world_size(); +// let poly_coeff_starts = mpi_config_ref.world_rank() * poly_vars_stride; +// let poly_coeff_ends = poly_coeff_starts + poly_vars_stride; +// let local_poly = +// MultiLinearPoly::new(global_poly.coeffs[poly_coeff_starts..poly_coeff_ends].to_vec()); + +// dbg!(local_poly.get_num_vars(), local_poly.coeffs[0]); + +// common::test_pcs_for_expander_gkr::< +// BN254Config, +// BytesHashTranscript, +// HyraxPCS, +// >( +// &num_vars_in_each_poly, +// mpi_config_ref, +// &mut transcript, +// &local_poly, +// &[challenge_point], +// ); +// } + +// #[test] +// fn test_hyrax_for_expander_gkr() { +// let mpi_config = MPIConfig::prover_new(); + +// test_hyrax_for_expander_gkr_generics(&mpi_config, 19); + +// MPIConfig::finalize() +// } diff --git a/poly_commit/tests/test_kzg.rs b/poly_commit/tests/test_kzg.rs index 24f1bc10..05850313 100644 --- a/poly_commit/tests/test_kzg.rs +++ b/poly_commit/tests/test_kzg.rs @@ -2,11 +2,14 @@ mod common; use arith::{Field, Fr}; use ark_std::test_rng; -use gkr_engine::{BN254Config, ExpanderSingleVarChallenge, MPIConfig, MPIEngine, Transcript}; +use gkr_engine::{ + BN254Config, ExpanderSingleVarChallenge, FieldEngine, MPIConfig, MPIEngine, Transcript, +}; +use gkr_engine::{ExpanderPCS, StructuredReferenceString}; use gkr_hashers::Keccak256hasher; use halo2curves::bn256::Bn256; -use poly_commit::HyperKZGPCS; -use polynomials::MultiLinearPoly; +use poly_commit::{DeferredPairingCheck, HyperKZGPCS, PairingAccumulator}; +use polynomials::{MultiLinearPoly, MultilinearExtension}; use transcript::BytesHashTranscript; const TEST_REPETITION: usize = 3; @@ -81,3 +84,87 @@ fn test_hyper_bikzg_for_expander_gkr() { MPIConfig::finalize() } + +#[test] +fn test_hyper_bikzg_batch_verification() { + let mut rng = test_rng(); + let mpi_config = MPIConfig::prover_new(); + + for num_vars in 2..=15 { + let (srs, _) = as ExpanderPCS>::gen_srs_for_testing( + &num_vars, + &mpi_config, + &mut rng, + ); + let (proving_key, verification_key) = srs.into_keys(); + + let transcript = BytesHashTranscript::::new(); + let mut scratch_pad = as ExpanderPCS>::init_scratch_pad( + &num_vars, + &mpi_config, + ); + let mut pairing_accumulator = PairingAccumulator::::default(); + + let polys = (0..3).map(|_| MultiLinearPoly::::random(num_vars, &mut rng)); + + for poly in polys { + let mut rng = test_rng(); + let challenge_point_1 = ExpanderSingleVarChallenge:: { + r_mpi: Vec::new(), + r_simd: Vec::new(), + rz: (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(), + }; + let challenge_point_2 = ExpanderSingleVarChallenge:: { + r_mpi: Vec::new(), + r_simd: Vec::new(), + rz: (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(), + }; + let commitment = as ExpanderPCS>::commit( + &num_vars, + &mpi_config, + &proving_key, + &poly, + &mut scratch_pad, + ) + .unwrap(); + + for c in [challenge_point_1, challenge_point_2] { + // open + let mut local_transcript = transcript.clone(); + let opening = as ExpanderPCS>::open( + &num_vars, + &mpi_config, + &proving_key, + &poly, + &c, + &mut local_transcript, + &mut scratch_pad, + ) + .unwrap(); + + // partial verify + let mut local_transcript = transcript.clone(); + let v = BN254Config::single_core_eval_circuit_vals_at_expander_challenge( + &poly.hypercube_basis_ref(), + &c, + ); + + let partial_verify = + as ExpanderPCS>::partial_verify( + &num_vars, + &verification_key, + &commitment, + &c, + v, + &mut local_transcript, + &opening, + &mut pairing_accumulator, + ); + + assert!(partial_verify); + } + } + // finalize the pairing check + assert!(pairing_accumulator.check_pairings()); + } +} diff --git a/poly_commit/tests/test_orion.rs b/poly_commit/tests/test_orion.rs index 07de977c..b1c07019 100644 --- a/poly_commit/tests/test_orion.rs +++ b/poly_commit/tests/test_orion.rs @@ -1,141 +1,141 @@ -mod common; - -use arith::{ExtensionField, Field, SimdField}; -use ark_std::test_rng; -use gf2::{GF2x128, GF2x64, GF2x8, GF2}; -use gf2_128::GF2_128; -use gkr_engine::{ - ExpanderSingleVarChallenge, FieldEngine, GF2ExtConfig, Goldilocksx8Config, M31x16Config, - MPIConfig, MPIEngine, Transcript, -}; -use gkr_hashers::Keccak256hasher; -use goldilocks::{Goldilocks, GoldilocksExt2, Goldilocksx8}; -use mersenne31::{M31Ext3, M31x16, M31}; -use poly_commit::*; -use polynomials::MultiLinearPoly; -use transcript::BytesHashTranscript; - -const TEST_REPETITION: usize = 3; - -fn test_orion_simd_pcs_generics( - num_vars_start: usize, - num_vars_end: usize, -) where - F: Field, - SimdF: SimdField, - EvalF: ExtensionField, - ComPackF: SimdField, -{ - let mut rng = test_rng(); - - (num_vars_start..=num_vars_end).for_each(|num_vars| { - let poly_num_vars = num_vars - SimdF::PACK_SIZE.ilog2() as usize; - let xs: Vec<_> = (0..TEST_REPETITION) - .map(|_| -> Vec { - (0..num_vars) - .map(|_| EvalF::random_unsafe(&mut rng)) - .collect() - }) - .collect(); - let poly = MultiLinearPoly::::random(poly_num_vars, &mut rng); - - common::test_pcs::< - EvalF, - BytesHashTranscript, - OrionSIMDFieldPCS, - >(&num_vars, &poly, &xs); - }) -} - -#[test] -fn test_orion_simd_pcs_full_e2e() { - test_orion_simd_pcs_generics::(19, 25); - test_orion_simd_pcs_generics::(19, 25); - test_orion_simd_pcs_generics::(16, 22); - test_orion_simd_pcs_generics::(16, 22) -} - -fn test_orion_for_expander_gkr_generics( - mpi_config_ref: &MPIConfig, - total_num_vars: usize, -) where - C: FieldEngine, - ComPackF: SimdField, - T: Transcript, -{ - let mut rng = test_rng(); - - // NOTE: generate global random polynomial - let num_vars_in_simd = C::SimdCircuitField::PACK_SIZE.ilog2() as usize; - let num_vars_in_mpi = mpi_config_ref.world_size().ilog2() as usize; - let num_vars_in_each_poly = total_num_vars - num_vars_in_mpi - num_vars_in_simd; - let num_vars_in_global_poly = total_num_vars - num_vars_in_simd; - - let global_poly = - MultiLinearPoly::::random(num_vars_in_global_poly, &mut rng); - - // NOTE generate srs for each party, and shared challenge point in each party - let challenge_point = ExpanderSingleVarChallenge:: { - r_mpi: (0..num_vars_in_mpi) - .map(|_| C::ChallengeField::random_unsafe(&mut rng)) - .collect(), - r_simd: (0..num_vars_in_simd) - .map(|_| C::ChallengeField::random_unsafe(&mut rng)) - .collect(), - rz: (0..num_vars_in_each_poly) - .map(|_| C::ChallengeField::random_unsafe(&mut rng)) - .collect(), - }; - - let mut transcript = T::new(); - - dbg!(global_poly.get_num_vars(), global_poly.coeffs[0]); - dbg!(&challenge_point.r_mpi); - dbg!(mpi_config_ref.world_size(), mpi_config_ref.world_rank()); - - // NOTE separate polynomial into different pieces by mpi rank - let poly_vars_stride = (1 << global_poly.get_num_vars()) / mpi_config_ref.world_size(); - let poly_coeff_starts = mpi_config_ref.world_rank() * poly_vars_stride; - let poly_coeff_ends = poly_coeff_starts + poly_vars_stride; - let local_poly = - MultiLinearPoly::new(global_poly.coeffs[poly_coeff_starts..poly_coeff_ends].to_vec()); - - dbg!(local_poly.get_num_vars(), local_poly.coeffs[0]); - - common::test_pcs_for_expander_gkr::< - C, - T, - OrionSIMDFieldPCS, - >( - &num_vars_in_each_poly, - mpi_config_ref, - &mut transcript, - &local_poly, - &[challenge_point], - ); -} - -#[test] -fn test_orion_for_expander_gkr() { - let mpi_config = MPIConfig::prover_new(); - - test_orion_for_expander_gkr_generics::< - GF2ExtConfig, - GF2x128, - BytesHashTranscript, - >(&mpi_config, 25); - - test_orion_for_expander_gkr_generics::< - M31x16Config, - M31x16, - BytesHashTranscript, - >(&mpi_config, 25); - - test_orion_for_expander_gkr_generics::< - Goldilocksx8Config, - Goldilocksx8, - BytesHashTranscript, - >(&mpi_config, 25); - - MPIConfig::finalize() -} +// mod common; + +// use arith::{ExtensionField, Field, SimdField}; +// use ark_std::test_rng; +// use gf2::{GF2x128, GF2x64, GF2x8, GF2}; +// use gf2_128::GF2_128; +// use gkr_engine::{ +// ExpanderSingleVarChallenge, FieldEngine, GF2ExtConfig, Goldilocksx8Config, M31x16Config, +// MPIConfig, MPIEngine, Transcript, +// }; +// use gkr_hashers::Keccak256hasher; +// use goldilocks::{Goldilocks, GoldilocksExt2, Goldilocksx8}; +// use mersenne31::{M31Ext3, M31x16, M31}; +// use poly_commit::*; +// use polynomials::MultiLinearPoly; +// use transcript::BytesHashTranscript; + +// const TEST_REPETITION: usize = 3; + +// fn test_orion_simd_pcs_generics( +// num_vars_start: usize, +// num_vars_end: usize, +// ) where +// F: Field, +// SimdF: SimdField, +// EvalF: ExtensionField, +// ComPackF: SimdField, +// { +// let mut rng = test_rng(); + +// (num_vars_start..=num_vars_end).for_each(|num_vars| { +// let poly_num_vars = num_vars - SimdF::PACK_SIZE.ilog2() as usize; +// let xs: Vec<_> = (0..TEST_REPETITION) +// .map(|_| -> Vec { +// (0..num_vars) +// .map(|_| EvalF::random_unsafe(&mut rng)) +// .collect() +// }) +// .collect(); +// let poly = MultiLinearPoly::::random(poly_num_vars, &mut rng); + +// common::test_pcs::< +// EvalF, +// BytesHashTranscript, +// OrionSIMDFieldPCS, +// >(&num_vars, &poly, &xs); +// }) +// } + +// #[test] +// fn test_orion_simd_pcs_full_e2e() { +// test_orion_simd_pcs_generics::(19, 25); +// test_orion_simd_pcs_generics::(19, 25); +// test_orion_simd_pcs_generics::(16, 22); +// test_orion_simd_pcs_generics::(16, +// 22) } + +// fn test_orion_for_expander_gkr_generics( +// mpi_config_ref: &MPIConfig, +// total_num_vars: usize, +// ) where +// C: FieldEngine, +// ComPackF: SimdField, +// T: Transcript, +// { +// let mut rng = test_rng(); + +// // NOTE: generate global random polynomial +// let num_vars_in_simd = C::SimdCircuitField::PACK_SIZE.ilog2() as usize; +// let num_vars_in_mpi = mpi_config_ref.world_size().ilog2() as usize; +// let num_vars_in_each_poly = total_num_vars - num_vars_in_mpi - num_vars_in_simd; +// let num_vars_in_global_poly = total_num_vars - num_vars_in_simd; + +// let global_poly = +// MultiLinearPoly::::random(num_vars_in_global_poly, &mut rng); + +// // NOTE generate srs for each party, and shared challenge point in each party +// let challenge_point = ExpanderSingleVarChallenge:: { +// r_mpi: (0..num_vars_in_mpi) +// .map(|_| C::ChallengeField::random_unsafe(&mut rng)) +// .collect(), +// r_simd: (0..num_vars_in_simd) +// .map(|_| C::ChallengeField::random_unsafe(&mut rng)) +// .collect(), +// rz: (0..num_vars_in_each_poly) +// .map(|_| C::ChallengeField::random_unsafe(&mut rng)) +// .collect(), +// }; + +// let mut transcript = T::new(); + +// dbg!(global_poly.get_num_vars(), global_poly.coeffs[0]); +// dbg!(&challenge_point.r_mpi); +// dbg!(mpi_config_ref.world_size(), mpi_config_ref.world_rank()); + +// // NOTE separate polynomial into different pieces by mpi rank +// let poly_vars_stride = (1 << global_poly.get_num_vars()) / mpi_config_ref.world_size(); +// let poly_coeff_starts = mpi_config_ref.world_rank() * poly_vars_stride; +// let poly_coeff_ends = poly_coeff_starts + poly_vars_stride; +// let local_poly = +// MultiLinearPoly::new(global_poly.coeffs[poly_coeff_starts..poly_coeff_ends].to_vec()); + +// dbg!(local_poly.get_num_vars(), local_poly.coeffs[0]); + +// common::test_pcs_for_expander_gkr::< +// C, +// T, +// OrionSIMDFieldPCS, +// >( +// &num_vars_in_each_poly, +// mpi_config_ref, +// &mut transcript, +// &local_poly, +// &[challenge_point], +// ); +// } + +// #[test] +// fn test_orion_for_expander_gkr() { +// let mpi_config = MPIConfig::prover_new(); + +// test_orion_for_expander_gkr_generics::< +// GF2ExtConfig, +// GF2x128, +// BytesHashTranscript, +// >(&mpi_config, 25); + +// test_orion_for_expander_gkr_generics::< +// M31x16Config, +// M31x16, +// BytesHashTranscript, +// >(&mpi_config, 25); + +// test_orion_for_expander_gkr_generics::< +// Goldilocksx8Config, +// Goldilocksx8, +// BytesHashTranscript, +// >(&mpi_config, 25); + +// MPIConfig::finalize() +// } diff --git a/poly_commit/tests/test_raw.rs b/poly_commit/tests/test_raw.rs index bf2851ae..9e115217 100644 --- a/poly_commit/tests/test_raw.rs +++ b/poly_commit/tests/test_raw.rs @@ -1,73 +1,73 @@ -mod common; +// mod common; -use arith::{Field, Fr}; -use gkr_engine::{ - BN254Config, ExpanderSingleVarChallenge, FieldEngine, GF2ExtConfig, M31x16Config, MPIConfig, - MPIEngine, Transcript, -}; -use gkr_hashers::{Keccak256hasher, SHA256hasher}; -use poly_commit::raw::{RawExpanderGKR, RawMultiLinearPCS}; -use polynomials::{MultiLinearPoly, RefMultiLinearPoly}; -use rand::thread_rng; -use transcript::BytesHashTranscript; +// use arith::{Field, Fr}; +// use gkr_engine::{ +// BN254Config, ExpanderSingleVarChallenge, FieldEngine, GF2ExtConfig, M31x16Config, MPIConfig, +// MPIEngine, Transcript, +// }; +// use gkr_hashers::{Keccak256hasher, SHA256hasher}; +// use poly_commit::raw::{RawExpanderGKR, RawMultiLinearPCS}; +// use polynomials::{MultiLinearPoly, RefMultiLinearPoly}; +// use rand::thread_rng; +// use transcript::BytesHashTranscript; -#[test] -fn test_raw() { - // NOTE(HS) 8 variables - let params = 8; - let mut rng = thread_rng(); - let poly = MultiLinearPoly::random(params, &mut rng); - let xs = (0..100) - .map(|_| { - (0..params) - .map(|_| Fr::random_unsafe(&mut rng)) - .collect::>() - }) - .collect::>>(); +// #[test] +// fn test_raw() { +// // NOTE(HS) 8 variables +// let params = 8; +// let mut rng = thread_rng(); +// let poly = MultiLinearPoly::random(params, &mut rng); +// let xs = (0..100) +// .map(|_| { +// (0..params) +// .map(|_| Fr::random_unsafe(&mut rng)) +// .collect::>() +// }) +// .collect::>>(); - common::test_pcs::, RawMultiLinearPCS>( - ¶ms, &poly, &xs, - ); -} +// common::test_pcs::, RawMultiLinearPCS>( +// ¶ms, &poly, &xs, +// ); +// } -fn test_raw_gkr_helper(mpi_config: &MPIConfig, transcript: &mut T) { - // NOTE(HS) local variables being 8 - let params = 8; - let mut rng = thread_rng(); - let hypercube_basis = (0..(1 << params)) - .map(|_| C::SimdCircuitField::random_unsafe(&mut rng)) - .collect(); - let poly = RefMultiLinearPoly::from_ref(&hypercube_basis); - let xs = (0..100) - .map(|_| ExpanderSingleVarChallenge:: { - rz: (0..params) - .map(|_| C::ChallengeField::random_unsafe(&mut rng)) - .collect::>(), - r_simd: (0..C::get_field_pack_size().trailing_zeros()) - .map(|_| C::ChallengeField::random_unsafe(&mut rng)) - .collect::>(), - r_mpi: (0..mpi_config.world_size().trailing_zeros()) - .map(|_| C::ChallengeField::random_unsafe(&mut rng)) - .collect::>(), - }) - .collect::>>(); - common::test_pcs_for_expander_gkr::>( - ¶ms, mpi_config, transcript, &poly, &xs, - ); -} +// fn test_raw_gkr_helper(mpi_config: &MPIConfig, transcript: &mut T) +// { // NOTE(HS) local variables being 8 +// let params = 8; +// let mut rng = thread_rng(); +// let hypercube_basis = (0..(1 << params)) +// .map(|_| C::SimdCircuitField::random_unsafe(&mut rng)) +// .collect(); +// let poly = RefMultiLinearPoly::from_ref(&hypercube_basis); +// let xs = (0..100) +// .map(|_| ExpanderSingleVarChallenge:: { +// rz: (0..params) +// .map(|_| C::ChallengeField::random_unsafe(&mut rng)) +// .collect::>(), +// r_simd: (0..C::get_field_pack_size().trailing_zeros()) +// .map(|_| C::ChallengeField::random_unsafe(&mut rng)) +// .collect::>(), +// r_mpi: (0..mpi_config.world_size().trailing_zeros()) +// .map(|_| C::ChallengeField::random_unsafe(&mut rng)) +// .collect::>(), +// }) +// .collect::>>(); +// common::test_pcs_for_expander_gkr::>( +// ¶ms, mpi_config, transcript, &poly, &xs, +// ); +// } -#[test] -fn test_raw_gkr() { - let mpi_config = MPIConfig::prover_new(); +// #[test] +// fn test_raw_gkr() { +// let mpi_config = MPIConfig::prover_new(); - type TM31 = BytesHashTranscript; - test_raw_gkr_helper::(&mpi_config, &mut TM31::new()); +// type TM31 = BytesHashTranscript; +// test_raw_gkr_helper::(&mpi_config, &mut TM31::new()); - type TGF2 = BytesHashTranscript; - test_raw_gkr_helper::(&mpi_config, &mut TGF2::new()); +// type TGF2 = BytesHashTranscript; +// test_raw_gkr_helper::(&mpi_config, &mut TGF2::new()); - type TBN254 = BytesHashTranscript; - test_raw_gkr_helper::(&mpi_config, &mut TBN254::new()); +// type TBN254 = BytesHashTranscript; +// test_raw_gkr_helper::(&mpi_config, &mut TBN254::new()); - MPIConfig::finalize(); -} +// MPIConfig::finalize(); +// } From f525e609dd79594e698814c2e7f12f070687abff Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 20 May 2025 09:25:40 -0400 Subject: [PATCH 05/57] clean up --- .../src/babybearx16/babybear_avx512.rs | 2 +- arith/mersenne31/src/m31x16/m31_avx512.rs | 2 +- gkr_engine/src/poly_commit/definition.rs | 25 +++++++++++-------- poly_commit/src/hyrax/expander_api.rs | 2 ++ poly_commit/src/kzg/deferred_pairing.rs | 1 - poly_commit/src/kzg/expander_api.rs | 2 +- poly_commit/src/kzg/univariate.rs | 2 +- poly_commit/src/lib.rs | 12 ++++----- poly_commit/src/orion/expander_api.rs | 2 ++ poly_commit/src/raw.rs | 2 ++ 10 files changed, 31 insertions(+), 21 deletions(-) diff --git a/arith/babybear/src/babybearx16/babybear_avx512.rs b/arith/babybear/src/babybearx16/babybear_avx512.rs index 8fd1754c..891779b2 100644 --- a/arith/babybear/src/babybearx16/babybear_avx512.rs +++ b/arith/babybear/src/babybearx16/babybear_avx512.rs @@ -241,7 +241,7 @@ impl Debug for AVXBabyBear { } ) } else { - write!(f, "mm512i<{:?}>", data) + write!(f, "mm512i<{data:?}>",) } } } diff --git a/arith/mersenne31/src/m31x16/m31_avx512.rs b/arith/mersenne31/src/m31x16/m31_avx512.rs index 3fb09dcb..e91a98ac 100644 --- a/arith/mersenne31/src/m31x16/m31_avx512.rs +++ b/arith/mersenne31/src/m31x16/m31_avx512.rs @@ -276,7 +276,7 @@ impl Debug for AVXM31 { } ) } else { - write!(f, "mm512i<{:?}>", data) + write!(f, "mm512i<{data:?}>",) } } } diff --git a/gkr_engine/src/poly_commit/definition.rs b/gkr_engine/src/poly_commit/definition.rs index 2101764f..25518f6d 100644 --- a/gkr_engine/src/poly_commit/definition.rs +++ b/gkr_engine/src/poly_commit/definition.rs @@ -121,19 +121,24 @@ pub trait ExpanderPCS { /// Partially verify the opening of a polynomial at a point. /// Deffer some of the checks to the batch verification via accumulator. + #[allow(clippy::too_many_arguments)] fn partial_verify( - params: &Self::Params, - verifying_key: &::VKey, - commitment: &Self::Commitment, - x: &ExpanderSingleVarChallenge, - v: F::ChallengeField, - transcript: &mut impl Transcript, - opening: &Self::Opening, - accumulator: &mut Self::Accumulator, - ) -> bool; + _params: &Self::Params, + _verifying_key: &::VKey, + _commitment: &Self::Commitment, + _x: &ExpanderSingleVarChallenge, + _v: F::ChallengeField, + _transcript: &mut impl Transcript, + _opening: &Self::Opening, + _accumulator: &mut Self::Accumulator, + ) -> bool { + unimplemented!("Partial verification is not implemented for this PCS.") + } /// Perform the finally batch verification for the accumulated opening proofs. - fn batch_deferred_verification(accumulator: &mut Self::Accumulator) -> bool; + fn batch_deferred_verification(_accumulator: &mut Self::Accumulator) -> bool { + unimplemented!("Batch verification is not implemented for this PCS.") + } } impl StructuredReferenceString for () { diff --git a/poly_commit/src/hyrax/expander_api.rs b/poly_commit/src/hyrax/expander_api.rs index 7ebd4e48..3815112b 100644 --- a/poly_commit/src/hyrax/expander_api.rs +++ b/poly_commit/src/hyrax/expander_api.rs @@ -36,6 +36,8 @@ where type Opening = HyraxOpening; type SRS = PedersenParams; + type Accumulator = (); + fn gen_params(n_input_vars: usize) -> Self::Params { n_input_vars } diff --git a/poly_commit/src/kzg/deferred_pairing.rs b/poly_commit/src/kzg/deferred_pairing.rs index a3e96e7d..111ba1d1 100644 --- a/poly_commit/src/kzg/deferred_pairing.rs +++ b/poly_commit/src/kzg/deferred_pairing.rs @@ -66,7 +66,6 @@ impl DeferredPairingCheck for PairingAccumulator { let g1g2_pairs = g1_affines .iter() .zip(g2_prepared.iter()) - .map(|(g1, g2)| (g1, g2)) .collect::>(); let gt_result = E::multi_miller_loop(g1g2_pairs.as_slice()); diff --git a/poly_commit/src/kzg/expander_api.rs b/poly_commit/src/kzg/expander_api.rs index 267cada6..4cc3f2f5 100644 --- a/poly_commit/src/kzg/expander_api.rs +++ b/poly_commit/src/kzg/expander_api.rs @@ -117,7 +117,7 @@ where _params, verifying_key, commitment, - &x, + x, v, transcript, opening, diff --git a/poly_commit/src/kzg/univariate.rs b/poly_commit/src/kzg/univariate.rs index 0135b889..98a12e5a 100644 --- a/poly_commit/src/kzg/univariate.rs +++ b/poly_commit/src/kzg/univariate.rs @@ -125,7 +125,7 @@ where let g2_alpha: E::G2 = E::G2Affine::generator() * alpha; pairing_accumulator.add_pairing_check(&(opening.to_curve(), (vk.tau_g2.to_curve() - g2_alpha))); - pairing_accumulator.add_pairing_check(&((g1_eval - comm).into(), E::G2::generator())); + pairing_accumulator.add_pairing_check(&(g1_eval - comm, E::G2::generator())); true } diff --git a/poly_commit/src/lib.rs b/poly_commit/src/lib.rs index 5173c3bc..b3e158c5 100644 --- a/poly_commit/src/lib.rs +++ b/poly_commit/src/lib.rs @@ -8,14 +8,14 @@ pub const PCS_SOUNDNESS_BITS: usize = 128; mod utils; pub use utils::expander_pcs_init_testing_only; -// pub mod raw; -// pub use raw::RawExpanderGKR; +pub mod raw; +pub use raw::RawExpanderGKR; -// pub mod orion; -// pub use orion::*; +pub mod orion; +pub use orion::*; -// pub mod hyrax; -// pub use hyrax::*; +pub mod hyrax; +pub use hyrax::*; pub mod kzg; pub use kzg::*; diff --git a/poly_commit/src/orion/expander_api.rs b/poly_commit/src/orion/expander_api.rs index 404250ea..656126eb 100644 --- a/poly_commit/src/orion/expander_api.rs +++ b/poly_commit/src/orion/expander_api.rs @@ -30,6 +30,8 @@ where type Opening = OrionProof; type SRS = OrionSRS; + type Accumulator = (); + /// NOTE(HS): this is the number of variables for local polynomial w.r.t. SIMD field elements. fn gen_params(n_input_vars: usize) -> Self::Params { n_input_vars diff --git a/poly_commit/src/raw.rs b/poly_commit/src/raw.rs index ba6968a2..370e4f6a 100644 --- a/poly_commit/src/raw.rs +++ b/poly_commit/src/raw.rs @@ -136,6 +136,8 @@ impl ExpanderPCS for RawExpanderGKR { type Opening = (); + type Accumulator = (); + fn gen_srs_for_testing( params: &Self::Params, _mpi_engine: &impl MPIEngine, From 6cef0f82eea6f991bad5074844c1282010d394e4 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 20 May 2025 09:27:56 -0400 Subject: [PATCH 06/57] bring back the tests --- poly_commit/tests/test_hyrax.rs | 166 +++++++++---------- poly_commit/tests/test_orion.rs | 282 ++++++++++++++++---------------- poly_commit/tests/test_raw.rs | 128 +++++++-------- 3 files changed, 288 insertions(+), 288 deletions(-) diff --git a/poly_commit/tests/test_hyrax.rs b/poly_commit/tests/test_hyrax.rs index 20c505d7..f3095cd6 100644 --- a/poly_commit/tests/test_hyrax.rs +++ b/poly_commit/tests/test_hyrax.rs @@ -1,83 +1,83 @@ -// mod common; - -// use arith::{Field, Fr}; -// use ark_std::test_rng; -// use gkr_engine::{BN254Config, ExpanderSingleVarChallenge, MPIConfig, MPIEngine, Transcript}; -// use gkr_hashers::Keccak256hasher; -// use halo2curves::bn256::G1Affine; -// use poly_commit::HyraxPCS; -// use polynomials::MultiLinearPoly; -// use transcript::BytesHashTranscript; - -// const TEST_REPETITION: usize = 3; - -// fn test_hyrax_pcs_generics(num_vars_start: usize, num_vars_end: usize) { -// let mut rng = test_rng(); - -// (num_vars_start..=num_vars_end).for_each(|num_vars| { -// let xs: Vec<_> = (0..TEST_REPETITION) -// .map(|_| -> Vec { (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect() }) -// .collect(); -// let poly = MultiLinearPoly::::random(num_vars, &mut rng); - -// common::test_pcs::, HyraxPCS>( -// &num_vars, &poly, &xs, -// ); -// }) -// } - -// #[test] -// fn test_hyrax_pcs_e2e() { -// test_hyrax_pcs_generics(3, 17) -// } - -// fn test_hyrax_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_num_vars: usize) { -// let mut rng = test_rng(); - -// // NOTE BN254 GKR SIMD pack size = 1, num vars in SIMD is 0 -// let num_vars_in_mpi = mpi_config_ref.world_size().ilog2() as usize; -// let num_vars_in_each_poly = total_num_vars - num_vars_in_mpi; - -// let global_poly = MultiLinearPoly::::random(total_num_vars, &mut rng); -// let challenge_point = ExpanderSingleVarChallenge:: { -// r_mpi: (0..num_vars_in_mpi) -// .map(|_| Fr::random_unsafe(&mut rng)) -// .collect(), -// r_simd: Vec::new(), -// rz: (0..num_vars_in_each_poly) -// .map(|_| Fr::random_unsafe(&mut rng)) -// .collect(), -// }; - -// let mut transcript = BytesHashTranscript::::new(); - -// // NOTE separate polynomial into different pieces by mpi rank -// let poly_vars_stride = (1 << global_poly.get_num_vars()) / mpi_config_ref.world_size(); -// let poly_coeff_starts = mpi_config_ref.world_rank() * poly_vars_stride; -// let poly_coeff_ends = poly_coeff_starts + poly_vars_stride; -// let local_poly = -// MultiLinearPoly::new(global_poly.coeffs[poly_coeff_starts..poly_coeff_ends].to_vec()); - -// dbg!(local_poly.get_num_vars(), local_poly.coeffs[0]); - -// common::test_pcs_for_expander_gkr::< -// BN254Config, -// BytesHashTranscript, -// HyraxPCS, -// >( -// &num_vars_in_each_poly, -// mpi_config_ref, -// &mut transcript, -// &local_poly, -// &[challenge_point], -// ); -// } - -// #[test] -// fn test_hyrax_for_expander_gkr() { -// let mpi_config = MPIConfig::prover_new(); - -// test_hyrax_for_expander_gkr_generics(&mpi_config, 19); - -// MPIConfig::finalize() -// } +mod common; + +use arith::{Field, Fr}; +use ark_std::test_rng; +use gkr_engine::{BN254Config, ExpanderSingleVarChallenge, MPIConfig, MPIEngine, Transcript}; +use gkr_hashers::Keccak256hasher; +use halo2curves::bn256::G1Affine; +use poly_commit::HyraxPCS; +use polynomials::MultiLinearPoly; +use transcript::BytesHashTranscript; + +const TEST_REPETITION: usize = 3; + +fn test_hyrax_pcs_generics(num_vars_start: usize, num_vars_end: usize) { + let mut rng = test_rng(); + + (num_vars_start..=num_vars_end).for_each(|num_vars| { + let xs: Vec<_> = (0..TEST_REPETITION) + .map(|_| -> Vec { (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect() }) + .collect(); + let poly = MultiLinearPoly::::random(num_vars, &mut rng); + + common::test_pcs::, HyraxPCS>( + &num_vars, &poly, &xs, + ); + }) +} + +#[test] +fn test_hyrax_pcs_e2e() { + test_hyrax_pcs_generics(3, 17) +} + +fn test_hyrax_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_num_vars: usize) { + let mut rng = test_rng(); + + // NOTE BN254 GKR SIMD pack size = 1, num vars in SIMD is 0 + let num_vars_in_mpi = mpi_config_ref.world_size().ilog2() as usize; + let num_vars_in_each_poly = total_num_vars - num_vars_in_mpi; + + let global_poly = MultiLinearPoly::::random(total_num_vars, &mut rng); + let challenge_point = ExpanderSingleVarChallenge:: { + r_mpi: (0..num_vars_in_mpi) + .map(|_| Fr::random_unsafe(&mut rng)) + .collect(), + r_simd: Vec::new(), + rz: (0..num_vars_in_each_poly) + .map(|_| Fr::random_unsafe(&mut rng)) + .collect(), + }; + + let mut transcript = BytesHashTranscript::::new(); + + // NOTE separate polynomial into different pieces by mpi rank + let poly_vars_stride = (1 << global_poly.get_num_vars()) / mpi_config_ref.world_size(); + let poly_coeff_starts = mpi_config_ref.world_rank() * poly_vars_stride; + let poly_coeff_ends = poly_coeff_starts + poly_vars_stride; + let local_poly = + MultiLinearPoly::new(global_poly.coeffs[poly_coeff_starts..poly_coeff_ends].to_vec()); + + dbg!(local_poly.get_num_vars(), local_poly.coeffs[0]); + + common::test_pcs_for_expander_gkr::< + BN254Config, + BytesHashTranscript, + HyraxPCS, + >( + &num_vars_in_each_poly, + mpi_config_ref, + &mut transcript, + &local_poly, + &[challenge_point], + ); +} + +#[test] +fn test_hyrax_for_expander_gkr() { + let mpi_config = MPIConfig::prover_new(); + + test_hyrax_for_expander_gkr_generics(&mpi_config, 19); + + MPIConfig::finalize() +} diff --git a/poly_commit/tests/test_orion.rs b/poly_commit/tests/test_orion.rs index b1c07019..475ebf01 100644 --- a/poly_commit/tests/test_orion.rs +++ b/poly_commit/tests/test_orion.rs @@ -1,141 +1,141 @@ -// mod common; - -// use arith::{ExtensionField, Field, SimdField}; -// use ark_std::test_rng; -// use gf2::{GF2x128, GF2x64, GF2x8, GF2}; -// use gf2_128::GF2_128; -// use gkr_engine::{ -// ExpanderSingleVarChallenge, FieldEngine, GF2ExtConfig, Goldilocksx8Config, M31x16Config, -// MPIConfig, MPIEngine, Transcript, -// }; -// use gkr_hashers::Keccak256hasher; -// use goldilocks::{Goldilocks, GoldilocksExt2, Goldilocksx8}; -// use mersenne31::{M31Ext3, M31x16, M31}; -// use poly_commit::*; -// use polynomials::MultiLinearPoly; -// use transcript::BytesHashTranscript; - -// const TEST_REPETITION: usize = 3; - -// fn test_orion_simd_pcs_generics( -// num_vars_start: usize, -// num_vars_end: usize, -// ) where -// F: Field, -// SimdF: SimdField, -// EvalF: ExtensionField, -// ComPackF: SimdField, -// { -// let mut rng = test_rng(); - -// (num_vars_start..=num_vars_end).for_each(|num_vars| { -// let poly_num_vars = num_vars - SimdF::PACK_SIZE.ilog2() as usize; -// let xs: Vec<_> = (0..TEST_REPETITION) -// .map(|_| -> Vec { -// (0..num_vars) -// .map(|_| EvalF::random_unsafe(&mut rng)) -// .collect() -// }) -// .collect(); -// let poly = MultiLinearPoly::::random(poly_num_vars, &mut rng); - -// common::test_pcs::< -// EvalF, -// BytesHashTranscript, -// OrionSIMDFieldPCS, -// >(&num_vars, &poly, &xs); -// }) -// } - -// #[test] -// fn test_orion_simd_pcs_full_e2e() { -// test_orion_simd_pcs_generics::(19, 25); -// test_orion_simd_pcs_generics::(19, 25); -// test_orion_simd_pcs_generics::(16, 22); -// test_orion_simd_pcs_generics::(16, -// 22) } - -// fn test_orion_for_expander_gkr_generics( -// mpi_config_ref: &MPIConfig, -// total_num_vars: usize, -// ) where -// C: FieldEngine, -// ComPackF: SimdField, -// T: Transcript, -// { -// let mut rng = test_rng(); - -// // NOTE: generate global random polynomial -// let num_vars_in_simd = C::SimdCircuitField::PACK_SIZE.ilog2() as usize; -// let num_vars_in_mpi = mpi_config_ref.world_size().ilog2() as usize; -// let num_vars_in_each_poly = total_num_vars - num_vars_in_mpi - num_vars_in_simd; -// let num_vars_in_global_poly = total_num_vars - num_vars_in_simd; - -// let global_poly = -// MultiLinearPoly::::random(num_vars_in_global_poly, &mut rng); - -// // NOTE generate srs for each party, and shared challenge point in each party -// let challenge_point = ExpanderSingleVarChallenge:: { -// r_mpi: (0..num_vars_in_mpi) -// .map(|_| C::ChallengeField::random_unsafe(&mut rng)) -// .collect(), -// r_simd: (0..num_vars_in_simd) -// .map(|_| C::ChallengeField::random_unsafe(&mut rng)) -// .collect(), -// rz: (0..num_vars_in_each_poly) -// .map(|_| C::ChallengeField::random_unsafe(&mut rng)) -// .collect(), -// }; - -// let mut transcript = T::new(); - -// dbg!(global_poly.get_num_vars(), global_poly.coeffs[0]); -// dbg!(&challenge_point.r_mpi); -// dbg!(mpi_config_ref.world_size(), mpi_config_ref.world_rank()); - -// // NOTE separate polynomial into different pieces by mpi rank -// let poly_vars_stride = (1 << global_poly.get_num_vars()) / mpi_config_ref.world_size(); -// let poly_coeff_starts = mpi_config_ref.world_rank() * poly_vars_stride; -// let poly_coeff_ends = poly_coeff_starts + poly_vars_stride; -// let local_poly = -// MultiLinearPoly::new(global_poly.coeffs[poly_coeff_starts..poly_coeff_ends].to_vec()); - -// dbg!(local_poly.get_num_vars(), local_poly.coeffs[0]); - -// common::test_pcs_for_expander_gkr::< -// C, -// T, -// OrionSIMDFieldPCS, -// >( -// &num_vars_in_each_poly, -// mpi_config_ref, -// &mut transcript, -// &local_poly, -// &[challenge_point], -// ); -// } - -// #[test] -// fn test_orion_for_expander_gkr() { -// let mpi_config = MPIConfig::prover_new(); - -// test_orion_for_expander_gkr_generics::< -// GF2ExtConfig, -// GF2x128, -// BytesHashTranscript, -// >(&mpi_config, 25); - -// test_orion_for_expander_gkr_generics::< -// M31x16Config, -// M31x16, -// BytesHashTranscript, -// >(&mpi_config, 25); - -// test_orion_for_expander_gkr_generics::< -// Goldilocksx8Config, -// Goldilocksx8, -// BytesHashTranscript, -// >(&mpi_config, 25); - -// MPIConfig::finalize() -// } +mod common; + +use arith::{ExtensionField, Field, SimdField}; +use ark_std::test_rng; +use gf2::{GF2x128, GF2x64, GF2x8, GF2}; +use gf2_128::GF2_128; +use gkr_engine::{ + ExpanderSingleVarChallenge, FieldEngine, GF2ExtConfig, Goldilocksx8Config, M31x16Config, + MPIConfig, MPIEngine, Transcript, +}; +use gkr_hashers::Keccak256hasher; +use goldilocks::{Goldilocks, GoldilocksExt2, Goldilocksx8}; +use mersenne31::{M31Ext3, M31x16, M31}; +use poly_commit::*; +use polynomials::MultiLinearPoly; +use transcript::BytesHashTranscript; + +const TEST_REPETITION: usize = 3; + +fn test_orion_simd_pcs_generics( + num_vars_start: usize, + num_vars_end: usize, +) where + F: Field, + SimdF: SimdField, + EvalF: ExtensionField, + ComPackF: SimdField, +{ + let mut rng = test_rng(); + + (num_vars_start..=num_vars_end).for_each(|num_vars| { + let poly_num_vars = num_vars - SimdF::PACK_SIZE.ilog2() as usize; + let xs: Vec<_> = (0..TEST_REPETITION) + .map(|_| -> Vec { + (0..num_vars) + .map(|_| EvalF::random_unsafe(&mut rng)) + .collect() + }) + .collect(); + let poly = MultiLinearPoly::::random(poly_num_vars, &mut rng); + + common::test_pcs::< + EvalF, + BytesHashTranscript, + OrionSIMDFieldPCS, + >(&num_vars, &poly, &xs); + }) +} + +#[test] +fn test_orion_simd_pcs_full_e2e() { + test_orion_simd_pcs_generics::(19, 25); + test_orion_simd_pcs_generics::(19, 25); + test_orion_simd_pcs_generics::(16, 22); + test_orion_simd_pcs_generics::(16, +22) } + +fn test_orion_for_expander_gkr_generics( + mpi_config_ref: &MPIConfig, + total_num_vars: usize, +) where + C: FieldEngine, + ComPackF: SimdField, + T: Transcript, +{ + let mut rng = test_rng(); + + // NOTE: generate global random polynomial + let num_vars_in_simd = C::SimdCircuitField::PACK_SIZE.ilog2() as usize; + let num_vars_in_mpi = mpi_config_ref.world_size().ilog2() as usize; + let num_vars_in_each_poly = total_num_vars - num_vars_in_mpi - num_vars_in_simd; + let num_vars_in_global_poly = total_num_vars - num_vars_in_simd; + + let global_poly = + MultiLinearPoly::::random(num_vars_in_global_poly, &mut rng); + + // NOTE generate srs for each party, and shared challenge point in each party + let challenge_point = ExpanderSingleVarChallenge:: { + r_mpi: (0..num_vars_in_mpi) + .map(|_| C::ChallengeField::random_unsafe(&mut rng)) + .collect(), + r_simd: (0..num_vars_in_simd) + .map(|_| C::ChallengeField::random_unsafe(&mut rng)) + .collect(), + rz: (0..num_vars_in_each_poly) + .map(|_| C::ChallengeField::random_unsafe(&mut rng)) + .collect(), + }; + + let mut transcript = T::new(); + + dbg!(global_poly.get_num_vars(), global_poly.coeffs[0]); + dbg!(&challenge_point.r_mpi); + dbg!(mpi_config_ref.world_size(), mpi_config_ref.world_rank()); + + // NOTE separate polynomial into different pieces by mpi rank + let poly_vars_stride = (1 << global_poly.get_num_vars()) / mpi_config_ref.world_size(); + let poly_coeff_starts = mpi_config_ref.world_rank() * poly_vars_stride; + let poly_coeff_ends = poly_coeff_starts + poly_vars_stride; + let local_poly = + MultiLinearPoly::new(global_poly.coeffs[poly_coeff_starts..poly_coeff_ends].to_vec()); + + dbg!(local_poly.get_num_vars(), local_poly.coeffs[0]); + + common::test_pcs_for_expander_gkr::< + C, + T, + OrionSIMDFieldPCS, + >( + &num_vars_in_each_poly, + mpi_config_ref, + &mut transcript, + &local_poly, + &[challenge_point], + ); +} + +#[test] +fn test_orion_for_expander_gkr() { + let mpi_config = MPIConfig::prover_new(); + + test_orion_for_expander_gkr_generics::< + GF2ExtConfig, + GF2x128, + BytesHashTranscript, + >(&mpi_config, 25); + + test_orion_for_expander_gkr_generics::< + M31x16Config, + M31x16, + BytesHashTranscript, + >(&mpi_config, 25); + + test_orion_for_expander_gkr_generics::< + Goldilocksx8Config, + Goldilocksx8, + BytesHashTranscript, + >(&mpi_config, 25); + + MPIConfig::finalize() +} diff --git a/poly_commit/tests/test_raw.rs b/poly_commit/tests/test_raw.rs index 9e115217..f709fa6d 100644 --- a/poly_commit/tests/test_raw.rs +++ b/poly_commit/tests/test_raw.rs @@ -1,73 +1,73 @@ -// mod common; +mod common; -// use arith::{Field, Fr}; -// use gkr_engine::{ -// BN254Config, ExpanderSingleVarChallenge, FieldEngine, GF2ExtConfig, M31x16Config, MPIConfig, -// MPIEngine, Transcript, -// }; -// use gkr_hashers::{Keccak256hasher, SHA256hasher}; -// use poly_commit::raw::{RawExpanderGKR, RawMultiLinearPCS}; -// use polynomials::{MultiLinearPoly, RefMultiLinearPoly}; -// use rand::thread_rng; -// use transcript::BytesHashTranscript; +use arith::{Field, Fr}; +use gkr_engine::{ + BN254Config, ExpanderSingleVarChallenge, FieldEngine, GF2ExtConfig, M31x16Config, MPIConfig, + MPIEngine, Transcript, +}; +use gkr_hashers::{Keccak256hasher, SHA256hasher}; +use poly_commit::raw::{RawExpanderGKR, RawMultiLinearPCS}; +use polynomials::{MultiLinearPoly, RefMultiLinearPoly}; +use rand::thread_rng; +use transcript::BytesHashTranscript; -// #[test] -// fn test_raw() { -// // NOTE(HS) 8 variables -// let params = 8; -// let mut rng = thread_rng(); -// let poly = MultiLinearPoly::random(params, &mut rng); -// let xs = (0..100) -// .map(|_| { -// (0..params) -// .map(|_| Fr::random_unsafe(&mut rng)) -// .collect::>() -// }) -// .collect::>>(); +#[test] +fn test_raw() { + // NOTE(HS) 8 variables + let params = 8; + let mut rng = thread_rng(); + let poly = MultiLinearPoly::random(params, &mut rng); + let xs = (0..100) + .map(|_| { + (0..params) + .map(|_| Fr::random_unsafe(&mut rng)) + .collect::>() + }) + .collect::>>(); -// common::test_pcs::, RawMultiLinearPCS>( -// ¶ms, &poly, &xs, -// ); -// } + common::test_pcs::, RawMultiLinearPCS>( + ¶ms, &poly, &xs, + ); +} -// fn test_raw_gkr_helper(mpi_config: &MPIConfig, transcript: &mut T) -// { // NOTE(HS) local variables being 8 -// let params = 8; -// let mut rng = thread_rng(); -// let hypercube_basis = (0..(1 << params)) -// .map(|_| C::SimdCircuitField::random_unsafe(&mut rng)) -// .collect(); -// let poly = RefMultiLinearPoly::from_ref(&hypercube_basis); -// let xs = (0..100) -// .map(|_| ExpanderSingleVarChallenge:: { -// rz: (0..params) -// .map(|_| C::ChallengeField::random_unsafe(&mut rng)) -// .collect::>(), -// r_simd: (0..C::get_field_pack_size().trailing_zeros()) -// .map(|_| C::ChallengeField::random_unsafe(&mut rng)) -// .collect::>(), -// r_mpi: (0..mpi_config.world_size().trailing_zeros()) -// .map(|_| C::ChallengeField::random_unsafe(&mut rng)) -// .collect::>(), -// }) -// .collect::>>(); -// common::test_pcs_for_expander_gkr::>( -// ¶ms, mpi_config, transcript, &poly, &xs, -// ); -// } +fn test_raw_gkr_helper(mpi_config: &MPIConfig, transcript: &mut T) +{ // NOTE(HS) local variables being 8 + let params = 8; + let mut rng = thread_rng(); + let hypercube_basis = (0..(1 << params)) + .map(|_| C::SimdCircuitField::random_unsafe(&mut rng)) + .collect(); + let poly = RefMultiLinearPoly::from_ref(&hypercube_basis); + let xs = (0..100) + .map(|_| ExpanderSingleVarChallenge:: { + rz: (0..params) + .map(|_| C::ChallengeField::random_unsafe(&mut rng)) + .collect::>(), + r_simd: (0..C::get_field_pack_size().trailing_zeros()) + .map(|_| C::ChallengeField::random_unsafe(&mut rng)) + .collect::>(), + r_mpi: (0..mpi_config.world_size().trailing_zeros()) + .map(|_| C::ChallengeField::random_unsafe(&mut rng)) + .collect::>(), + }) + .collect::>>(); + common::test_pcs_for_expander_gkr::>( + ¶ms, mpi_config, transcript, &poly, &xs, + ); +} -// #[test] -// fn test_raw_gkr() { -// let mpi_config = MPIConfig::prover_new(); +#[test] +fn test_raw_gkr() { + let mpi_config = MPIConfig::prover_new(); -// type TM31 = BytesHashTranscript; -// test_raw_gkr_helper::(&mpi_config, &mut TM31::new()); + type TM31 = BytesHashTranscript; + test_raw_gkr_helper::(&mpi_config, &mut TM31::new()); -// type TGF2 = BytesHashTranscript; -// test_raw_gkr_helper::(&mpi_config, &mut TGF2::new()); + type TGF2 = BytesHashTranscript; + test_raw_gkr_helper::(&mpi_config, &mut TGF2::new()); -// type TBN254 = BytesHashTranscript; -// test_raw_gkr_helper::(&mpi_config, &mut TBN254::new()); + type TBN254 = BytesHashTranscript; + test_raw_gkr_helper::(&mpi_config, &mut TBN254::new()); -// MPIConfig::finalize(); -// } + MPIConfig::finalize(); +} From 310683e3ee5598e27da37ba46db853e4f66b26d2 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 20 May 2025 09:30:15 -0400 Subject: [PATCH 07/57] fmt --- poly_commit/tests/test_orion.rs | 4 ++-- poly_commit/tests/test_raw.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/poly_commit/tests/test_orion.rs b/poly_commit/tests/test_orion.rs index 475ebf01..07de977c 100644 --- a/poly_commit/tests/test_orion.rs +++ b/poly_commit/tests/test_orion.rs @@ -52,8 +52,8 @@ fn test_orion_simd_pcs_full_e2e() { test_orion_simd_pcs_generics::(19, 25); test_orion_simd_pcs_generics::(19, 25); test_orion_simd_pcs_generics::(16, 22); - test_orion_simd_pcs_generics::(16, -22) } + test_orion_simd_pcs_generics::(16, 22) +} fn test_orion_for_expander_gkr_generics( mpi_config_ref: &MPIConfig, diff --git a/poly_commit/tests/test_raw.rs b/poly_commit/tests/test_raw.rs index f709fa6d..bf2851ae 100644 --- a/poly_commit/tests/test_raw.rs +++ b/poly_commit/tests/test_raw.rs @@ -30,8 +30,8 @@ fn test_raw() { ); } -fn test_raw_gkr_helper(mpi_config: &MPIConfig, transcript: &mut T) -{ // NOTE(HS) local variables being 8 +fn test_raw_gkr_helper(mpi_config: &MPIConfig, transcript: &mut T) { + // NOTE(HS) local variables being 8 let params = 8; let mut rng = thread_rng(); let hypercube_basis = (0..(1 << params)) From 5bd3d3e07211ea05ccb9dcc0216ed0a223ead62b Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 20 May 2025 14:29:21 -0400 Subject: [PATCH 08/57] better API --- gkr_engine/src/poly_commit/definition.rs | 62 ++++++++++++++++++------ poly_commit/src/hyrax/expander_api.rs | 3 +- poly_commit/src/kzg.rs | 1 - poly_commit/src/kzg/bivariate.rs | 19 ++++---- poly_commit/src/kzg/deferred_pairing.rs | 25 ++-------- poly_commit/src/kzg/expander_api.rs | 31 +----------- poly_commit/src/kzg/hyper_bikzg.rs | 6 +-- poly_commit/src/kzg/hyper_kzg.rs | 6 +-- poly_commit/src/kzg/pcs_trait_impl.rs | 6 +-- poly_commit/src/kzg/univariate.rs | 9 ++-- poly_commit/src/orion/expander_api.rs | 3 +- poly_commit/src/raw.rs | 3 +- poly_commit/tests/test_kzg.rs | 7 +-- 13 files changed, 85 insertions(+), 96 deletions(-) diff --git a/gkr_engine/src/poly_commit/definition.rs b/gkr_engine/src/poly_commit/definition.rs index 25518f6d..a35569f4 100644 --- a/gkr_engine/src/poly_commit/definition.rs +++ b/gkr_engine/src/poly_commit/definition.rs @@ -19,6 +19,24 @@ pub trait PCSParams: Clone + Debug + Default + Send + Sync + 'static { fn num_vars(&self) -> usize; } +pub trait DeferredCheck { + /// Data type to be accumulated + type AccumulatedValues; + + /// Add a new pairing check to the accumulator + fn accumulate(&mut self, _accumulated_values: &Self::AccumulatedValues) {} + + /// Check if all pairings are valid + fn final_check(&self) -> bool { + true + } +} + +// Empty implementation for the case where no pairing checks are needed +impl DeferredCheck for () { + type AccumulatedValues = (); +} + impl PCSParams for usize { fn num_vars(&self) -> usize { *self @@ -38,7 +56,7 @@ pub trait ExpanderPCS { type Opening: Clone + Debug + Default + ExpSerde; /// An accumulator to be used for deferred batch verification for KZG. - type Accumulator: Clone + Debug; + type Accumulator: Clone + Debug + Default + DeferredCheck; /// Generate a random structured reference string (SRS) for testing purposes. /// Each process should return the SRS share used for its committing and opening. @@ -117,27 +135,41 @@ pub trait ExpanderPCS { v: F::ChallengeField, transcript: &mut impl Transcript, opening: &Self::Opening, - ) -> bool; + ) -> bool { + let mut accumulator = Self::Accumulator::default(); + + let partial_check = Self::partial_verify( + params, + verifying_key, + commitment, + x, + v, + transcript, + opening, + &mut accumulator, + ); + let final_check = accumulator.final_check(); + + partial_check && final_check + } /// Partially verify the opening of a polynomial at a point. /// Deffer some of the checks to the batch verification via accumulator. #[allow(clippy::too_many_arguments)] fn partial_verify( - _params: &Self::Params, - _verifying_key: &::VKey, - _commitment: &Self::Commitment, - _x: &ExpanderSingleVarChallenge, - _v: F::ChallengeField, - _transcript: &mut impl Transcript, - _opening: &Self::Opening, - _accumulator: &mut Self::Accumulator, - ) -> bool { - unimplemented!("Partial verification is not implemented for this PCS.") - } + params: &Self::Params, + verifying_key: &::VKey, + commitment: &Self::Commitment, + x: &ExpanderSingleVarChallenge, + v: F::ChallengeField, + transcript: &mut impl Transcript, + opening: &Self::Opening, + accumulator: &mut Self::Accumulator, + ) -> bool; /// Perform the finally batch verification for the accumulated opening proofs. - fn batch_deferred_verification(_accumulator: &mut Self::Accumulator) -> bool { - unimplemented!("Batch verification is not implemented for this PCS.") + fn batch_deferred_verification(accumulator: &mut Self::Accumulator) -> bool { + accumulator.final_check() } } diff --git a/poly_commit/src/hyrax/expander_api.rs b/poly_commit/src/hyrax/expander_api.rs index 3815112b..5de07c01 100644 --- a/poly_commit/src/hyrax/expander_api.rs +++ b/poly_commit/src/hyrax/expander_api.rs @@ -113,7 +113,7 @@ where HyraxOpening(combined_coeffs).into() } - fn verify( + fn partial_verify( _params: &Self::Params, verifying_key: &::VKey, commitment: &Self::Commitment, @@ -121,6 +121,7 @@ where v: ::ChallengeField, _transcript: &mut impl Transcript, opening: &Self::Opening, + _accumulator: &mut Self::Accumulator, ) -> bool { if x.r_mpi.is_empty() { return hyrax_verify(verifying_key, commitment, &x.local_xs(), v, opening); diff --git a/poly_commit/src/kzg.rs b/poly_commit/src/kzg.rs index ab1c79f2..8b065854 100644 --- a/poly_commit/src/kzg.rs +++ b/poly_commit/src/kzg.rs @@ -30,5 +30,4 @@ pub use pcs_trait_impl::HyperKZGPCS; mod expander_api; mod deferred_pairing; -pub use deferred_pairing::DeferredPairingCheck; pub use deferred_pairing::PairingAccumulator; diff --git a/poly_commit/src/kzg/bivariate.rs b/poly_commit/src/kzg/bivariate.rs index 20682794..d280af77 100644 --- a/poly_commit/src/kzg/bivariate.rs +++ b/poly_commit/src/kzg/bivariate.rs @@ -1,3 +1,4 @@ +use gkr_engine::DeferredCheck; use halo2curves::{ ff::Field, group::{prime::PrimeCurveAffine, Curve, Group}, @@ -10,7 +11,7 @@ use serdes::ExpSerde; use crate::*; -use super::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}; +use super::deferred_pairing::PairingAccumulator; #[inline(always)] pub fn generate_coef_form_bi_kzg_local_srs_for_testing( @@ -126,7 +127,7 @@ where opening, &mut pairing_accumulator, ); - let pairing_check = pairing_accumulator.check_pairings(); + let pairing_check = pairing_accumulator.final_check(); partial_check && pairing_check } @@ -148,17 +149,17 @@ where let g2_alpha: E::G2 = E::G2Affine::generator() * alpha; let g2_beta: E::G2 = E::G2Affine::generator() * beta; - pairing_accumulator.add_pairing_check(&( + pairing_accumulator.accumulate(&( opening.quotient_x.to_curve(), (vk.tau_x_g2.to_curve() - g2_alpha), )); - pairing_accumulator.add_pairing_check(&( + pairing_accumulator.accumulate(&( opening.quotient_y.to_curve(), (vk.tau_y_g2.to_curve() - g2_beta), )); - pairing_accumulator.add_pairing_check(&((g1_eval - comm), E::G2::generator())); + pairing_accumulator.accumulate(&((g1_eval - comm), E::G2::generator())); true } @@ -166,6 +167,7 @@ where #[cfg(test)] mod tests { use ark_std::test_rng; + use gkr_engine::DeferredCheck; use halo2curves::{ bn256::{Bn256, Fr, G1Affine, G1}, ff::Field, @@ -173,10 +175,7 @@ mod tests { }; use itertools::izip; - use crate::{ - kzg::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}, - *, - }; + use crate::{kzg::deferred_pairing::PairingAccumulator, *}; #[test] fn test_coefficient_form_bivariate_kzg_e2e() { @@ -229,6 +228,6 @@ mod tests { &mut pairing_accumulator, ); - assert!(pairing_accumulator.check_pairings()); + assert!(pairing_accumulator.final_check()); } } diff --git a/poly_commit/src/kzg/deferred_pairing.rs b/poly_commit/src/kzg/deferred_pairing.rs index 111ba1d1..89fe42ae 100644 --- a/poly_commit/src/kzg/deferred_pairing.rs +++ b/poly_commit/src/kzg/deferred_pairing.rs @@ -1,3 +1,4 @@ +use gkr_engine::DeferredCheck; use halo2curves::group::prime::PrimeCurveAffine; use halo2curves::group::Curve; use halo2curves::{ @@ -24,33 +25,15 @@ where } } -pub trait DeferredPairingCheck { - /// Data type to be accumulated - type AccumulatedValues; - - /// Add a new pairing check to the accumulator - fn add_pairing_check(&mut self, _accumulated_values: &Self::AccumulatedValues) {} - - /// Check if all pairings are valid - fn check_pairings(&self) -> bool { - true - } -} - -// Empty implementation for the case where no pairing checks are needed -impl DeferredPairingCheck for () { - type AccumulatedValues = (); -} - -impl DeferredPairingCheck for PairingAccumulator { +impl DeferredCheck for PairingAccumulator { type AccumulatedValues = (E::G1, E::G2); - fn add_pairing_check(&mut self, accumulated_values: &(E::G1, E::G2)) { + fn accumulate(&mut self, accumulated_values: &(E::G1, E::G2)) { self.g1s.push(accumulated_values.0); self.g2s.push(accumulated_values.1); } - fn check_pairings(&self) -> bool { + fn final_check(&self) -> bool { if self.g1s.is_empty() || self.g2s.is_empty() { return true; } diff --git a/poly_commit/src/kzg/expander_api.rs b/poly_commit/src/kzg/expander_api.rs index 4cc3f2f5..e398f8c9 100644 --- a/poly_commit/src/kzg/expander_api.rs +++ b/poly_commit/src/kzg/expander_api.rs @@ -13,7 +13,7 @@ use serdes::ExpSerde; use crate::*; -use super::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}; +use super::deferred_pairing::PairingAccumulator; impl ExpanderPCS for HyperKZGPCS where @@ -102,31 +102,6 @@ where ) } - fn verify( - _params: &Self::Params, - verifying_key: &::VKey, - commitment: &Self::Commitment, - x: &ExpanderSingleVarChallenge, - v: ::ChallengeField, - transcript: &mut impl Transcript, - opening: &Self::Opening, - ) -> bool { - let mut accumulator = PairingAccumulator::default(); - - let partial_check = Self::partial_verify( - _params, - verifying_key, - commitment, - x, - v, - transcript, - opening, - &mut accumulator, - ); - let pairing_check = accumulator.check_pairings(); - partial_check && pairing_check - } - fn partial_verify( _params: &Self::Params, verifying_key: &::VKey, @@ -148,8 +123,4 @@ where accumulator, ) } - - fn batch_deferred_verification(accumulator: &mut Self::Accumulator) -> bool { - accumulator.check_pairings() - } } diff --git a/poly_commit/src/kzg/hyper_bikzg.rs b/poly_commit/src/kzg/hyper_bikzg.rs index 13855b3f..6260ccd0 100644 --- a/poly_commit/src/kzg/hyper_bikzg.rs +++ b/poly_commit/src/kzg/hyper_bikzg.rs @@ -4,7 +4,7 @@ use std::{io::Cursor, iter}; use arith::ExtensionField; -use gkr_engine::{MPIEngine, Transcript}; +use gkr_engine::{DeferredCheck, MPIEngine, Transcript}; use halo2curves::{ ff::Field, group::{prime::PrimeCurveAffine, Curve, Group, GroupEncoding}, @@ -18,7 +18,7 @@ use transcript::{transcript_root_broadcast, transcript_verifier_sync}; use crate::*; -use super::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}; +use super::deferred_pairing::PairingAccumulator; pub fn coeff_form_hyper_bikzg_open( srs: &CoefFormBiKZGLocalSRS, @@ -472,7 +472,7 @@ where fs_transcript, &mut pairing_accumulator, ); - let pairing_check = pairing_accumulator.check_pairings(); + let pairing_check = pairing_accumulator.final_check(); partial_check && pairing_check } diff --git a/poly_commit/src/kzg/hyper_kzg.rs b/poly_commit/src/kzg/hyper_kzg.rs index 50bbee4d..9195256f 100644 --- a/poly_commit/src/kzg/hyper_kzg.rs +++ b/poly_commit/src/kzg/hyper_kzg.rs @@ -1,7 +1,7 @@ use std::iter; use arith::ExtensionField; -use gkr_engine::Transcript; +use gkr_engine::{DeferredCheck, Transcript}; use halo2curves::{ ff::Field, group::{prime::PrimeCurveAffine, GroupEncoding}, @@ -13,7 +13,7 @@ use serdes::ExpSerde; use crate::*; -use super::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}; +use super::deferred_pairing::PairingAccumulator; #[inline(always)] pub(crate) fn coeff_form_hyperkzg_local_poly_oracles( @@ -195,7 +195,7 @@ where fs_transcript, &mut pairing_accumulator, ); - let pairing_check = pairing_accumulator.check_pairings(); + let pairing_check = pairing_accumulator.final_check(); partial_check && pairing_check } diff --git a/poly_commit/src/kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/pcs_trait_impl.rs index 83fb9305..bb1ca844 100644 --- a/poly_commit/src/kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/pcs_trait_impl.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; use arith::ExtensionField; -use gkr_engine::{StructuredReferenceString, Transcript}; +use gkr_engine::{DeferredCheck, StructuredReferenceString, Transcript}; use halo2curves::{ ff::PrimeField, pairing::{Engine, MultiMillerLoop}, @@ -13,7 +13,7 @@ use serdes::ExpSerde; use crate::*; use kzg::hyper_kzg::*; -use super::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}; +use super::deferred_pairing::PairingAccumulator; pub struct HyperKZGPCS where @@ -92,7 +92,7 @@ where &mut accumulator, ); - let pairing_check = accumulator.check_pairings(); + let pairing_check = accumulator.final_check(); pairing_check && partial_check } diff --git a/poly_commit/src/kzg/univariate.rs b/poly_commit/src/kzg/univariate.rs index 98a12e5a..05c57190 100644 --- a/poly_commit/src/kzg/univariate.rs +++ b/poly_commit/src/kzg/univariate.rs @@ -1,3 +1,4 @@ +use gkr_engine::DeferredCheck; use halo2curves::{ ff::Field, group::{prime::PrimeCurveAffine, Curve, Group}, @@ -10,7 +11,7 @@ use serdes::ExpSerde; use crate::*; -use super::deferred_pairing::{DeferredPairingCheck, PairingAccumulator}; +use super::deferred_pairing::PairingAccumulator; #[inline(always)] pub(crate) fn generate_coef_form_uni_kzg_srs_for_testing( @@ -103,7 +104,7 @@ where { let mut pairing_accumulator = PairingAccumulator::default(); coeff_form_uni_kzg_partial_verify(vk, comm, alpha, eval, opening, &mut pairing_accumulator); - let pairing_check = pairing_accumulator.check_pairings(); + let pairing_check = pairing_accumulator.final_check(); pairing_check } @@ -124,8 +125,8 @@ where let g1_eval: E::G1Affine = (E::G1Affine::generator() * eval).into(); let g2_alpha: E::G2 = E::G2Affine::generator() * alpha; - pairing_accumulator.add_pairing_check(&(opening.to_curve(), (vk.tau_g2.to_curve() - g2_alpha))); - pairing_accumulator.add_pairing_check(&(g1_eval - comm, E::G2::generator())); + pairing_accumulator.accumulate(&(opening.to_curve(), (vk.tau_g2.to_curve() - g2_alpha))); + pairing_accumulator.accumulate(&(g1_eval - comm, E::G2::generator())); true } diff --git a/poly_commit/src/orion/expander_api.rs b/poly_commit/src/orion/expander_api.rs index 656126eb..16497805 100644 --- a/poly_commit/src/orion/expander_api.rs +++ b/poly_commit/src/orion/expander_api.rs @@ -122,7 +122,7 @@ where ) } - fn verify( + fn partial_verify( _params: &Self::Params, verifying_key: &::VKey, commitment: &Self::Commitment, @@ -131,6 +131,7 @@ where transcript: &mut impl Transcript, /* add transcript here to allow * interactive arguments */ opening: &Self::Opening, + _accumulator: &mut Self::Accumulator, ) -> bool { orion_verify::<_, C::SimdCircuitField, _, ComPackF>( verifying_key, diff --git a/poly_commit/src/raw.rs b/poly_commit/src/raw.rs index 370e4f6a..dcf33eb4 100644 --- a/poly_commit/src/raw.rs +++ b/poly_commit/src/raw.rs @@ -195,7 +195,7 @@ impl ExpanderPCS for RawExpanderGKR { Some(()) } - fn verify( + fn partial_verify( _params: &Self::Params, _verifying_key: &::VKey, commitment: &Self::Commitment, @@ -203,6 +203,7 @@ impl ExpanderPCS for RawExpanderGKR { v: C::ChallengeField, _transcript: &mut impl Transcript, _opening: &Self::Opening, + _accumulator: &mut Self::Accumulator, ) -> bool { let v_target = C::single_core_eval_circuit_vals_at_expander_challenge(&commitment.evals, challenge); diff --git a/poly_commit/tests/test_kzg.rs b/poly_commit/tests/test_kzg.rs index 05850313..4e11e1fd 100644 --- a/poly_commit/tests/test_kzg.rs +++ b/poly_commit/tests/test_kzg.rs @@ -3,12 +3,13 @@ mod common; use arith::{Field, Fr}; use ark_std::test_rng; use gkr_engine::{ - BN254Config, ExpanderSingleVarChallenge, FieldEngine, MPIConfig, MPIEngine, Transcript, + BN254Config, DeferredCheck, ExpanderSingleVarChallenge, FieldEngine, MPIConfig, MPIEngine, + Transcript, }; use gkr_engine::{ExpanderPCS, StructuredReferenceString}; use gkr_hashers::Keccak256hasher; use halo2curves::bn256::Bn256; -use poly_commit::{DeferredPairingCheck, HyperKZGPCS, PairingAccumulator}; +use poly_commit::{HyperKZGPCS, PairingAccumulator}; use polynomials::{MultiLinearPoly, MultilinearExtension}; use transcript::BytesHashTranscript; @@ -165,6 +166,6 @@ fn test_hyper_bikzg_batch_verification() { } } // finalize the pairing check - assert!(pairing_accumulator.check_pairings()); + assert!(pairing_accumulator.final_check()); } } From c0b64edcd7fdd14f688faa2c069953601aca2a08 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 20 May 2025 14:47:12 -0400 Subject: [PATCH 09/57] update gkr verifier --- gkr/src/verifier/snark.rs | 83 +++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 8 deletions(-) diff --git a/gkr/src/verifier/snark.rs b/gkr/src/verifier/snark.rs index 6061fed7..ec316a8e 100644 --- a/gkr/src/verifier/snark.rs +++ b/gkr/src/verifier/snark.rs @@ -8,8 +8,8 @@ use super::gkr_square::sumcheck_verify_gkr_square_layer; use arith::Field; use circuit::Circuit; use gkr_engine::{ - ExpanderPCS, ExpanderSingleVarChallenge, FieldEngine, GKREngine, GKRScheme, MPIConfig, - MPIEngine, PCSParams, Proof, StructuredReferenceString, Transcript, + DeferredCheck, ExpanderPCS, ExpanderSingleVarChallenge, FieldEngine, GKREngine, GKRScheme, + MPIConfig, MPIEngine, PCSParams, Proof, StructuredReferenceString, Transcript, }; use rayon::iter::{ IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator, @@ -253,6 +253,7 @@ impl Verifier { } /// Verify the PCS opening against the commitment and the claim from GKR. + /// Defer the pairing check to accumulator if any. #[inline(always)] #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] @@ -267,9 +268,10 @@ impl Verifier { claim_y: &Option<::ChallengeField>, transcript: &mut impl Transcript, mut proof_reader: impl Read, + accmulator: &mut >::Accumulator, ) -> bool { let timer = Timer::new("post_gkr", true); - let mut verified = self.get_pcs_opening_from_proof_and_verify( + let mut verified = self.get_pcs_opening_from_proof_and_partial_verify( pcs_params, pcs_verification_key, commitment, @@ -277,10 +279,11 @@ impl Verifier { claim_x, transcript, &mut proof_reader, + accmulator, ); if let Some(challenge_y) = challenge_y { - verified &= self.get_pcs_opening_from_proof_and_verify( + verified &= self.get_pcs_opening_from_proof_and_partial_verify( pcs_params, pcs_verification_key, commitment, @@ -288,6 +291,7 @@ impl Verifier { claim_y.as_ref().unwrap(), transcript, &mut proof_reader, + accmulator, ); } @@ -295,7 +299,9 @@ impl Verifier { verified } - pub fn verify( + /// Paritially verify the proof. + /// Conduct the whole procedure except for pairing, if any. + pub fn partial_verify( &self, circuit: &mut Circuit, public_input: &[::SimdCircuitField], @@ -303,6 +309,7 @@ impl Verifier { pcs_params: &>::Params, pcs_verification_key: &<>::SRS as StructuredReferenceString>::VKey, proof: &Proof, + accumulator: &mut >::Accumulator, ) -> bool { let timer = Timer::new("snark verify", true); @@ -331,6 +338,7 @@ impl Verifier { &claim_y, &mut transcript, &mut cursor, + accumulator, ); timer.stop(); @@ -338,7 +346,8 @@ impl Verifier { verified } - pub fn par_verify( + /// Verify the GKR proof := { GKR_IOP proof, PCS proof} + pub fn verify( &self, circuit: &mut Circuit, public_input: &[::SimdCircuitField], @@ -346,6 +355,35 @@ impl Verifier { pcs_params: &>::Params, pcs_verification_key: &<>::SRS as StructuredReferenceString>::VKey, proof: &Proof, + ) -> bool { + let mut accumulator = + >::Accumulator::default(); + + let partial_check = self.partial_verify( + circuit, + public_input, + claimed_v, + pcs_params, + pcs_verification_key, + proof, + &mut accumulator, + ); + let final_check = accumulator.final_check(); + + partial_check && final_check + } + + /// Paritially verify the proof. + /// Conduct the whole procedure except for pairing, if any. + pub fn par_partial_verify( + &self, + circuit: &mut Circuit, + public_input: &[::SimdCircuitField], + claimed_v: &::ChallengeField, + pcs_params: &>::Params, + pcs_verification_key: &<>::SRS as StructuredReferenceString>::VKey, + proof: &Proof, + accumulator: &mut >::Accumulator, ) -> bool { let timer = Timer::new("snark verify", true); @@ -374,16 +412,43 @@ impl Verifier { &claim_y, &mut transcript, &mut cursor, + accumulator, ); timer.stop(); verified } + + /// Verify the GKR proof with parallel GKR. + pub fn par_verify( + &self, + circuit: &mut Circuit, + public_input: &[::SimdCircuitField], + claimed_v: &::ChallengeField, + pcs_params: &>::Params, + pcs_verification_key: &<>::SRS as StructuredReferenceString>::VKey, + proof: &Proof, + ) -> bool { + let mut accumulator = + >::Accumulator::default(); + let partial_check = self.par_partial_verify( + circuit, + public_input, + claimed_v, + pcs_params, + pcs_verification_key, + proof, + &mut accumulator, + ); + let final_check = accumulator.final_check(); + + partial_check && final_check + } } impl Verifier { #[allow(clippy::too_many_arguments)] - fn get_pcs_opening_from_proof_and_verify( + fn get_pcs_opening_from_proof_and_partial_verify( &self, pcs_params: &>::Params, pcs_verification_key: &<>::SRS as StructuredReferenceString>::VKey, @@ -392,6 +457,7 @@ impl Verifier { v: &::ChallengeField, transcript: &mut impl Transcript, proof_reader: impl Read, + accumulator: &mut >::Accumulator, ) -> bool { let opening = >::Opening::deserialize_from( proof_reader, @@ -415,7 +481,7 @@ impl Verifier { } transcript.lock_proof(); - let verified = Cfg::PCSConfig::verify( + let verified = Cfg::PCSConfig::partial_verify( pcs_params, pcs_verification_key, commitment, @@ -423,6 +489,7 @@ impl Verifier { *v, transcript, &opening, + accumulator, ); transcript.unlock_proof(); From 22d47da67a292f100e8a267972517669b948f730 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 20 May 2025 15:30:42 -0400 Subject: [PATCH 10/57] clippy --- gkr/src/verifier/snark.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gkr/src/verifier/snark.rs b/gkr/src/verifier/snark.rs index ec316a8e..bcdb1d11 100644 --- a/gkr/src/verifier/snark.rs +++ b/gkr/src/verifier/snark.rs @@ -301,6 +301,7 @@ impl Verifier { /// Paritially verify the proof. /// Conduct the whole procedure except for pairing, if any. + #[allow(clippy::too_many_arguments)] pub fn partial_verify( &self, circuit: &mut Circuit, @@ -375,6 +376,7 @@ impl Verifier { /// Paritially verify the proof. /// Conduct the whole procedure except for pairing, if any. + #[allow(clippy::too_many_arguments)] pub fn par_partial_verify( &self, circuit: &mut Circuit, From 19fdff9f131900f0e25ae86011e9823121285cfd Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 21 May 2025 15:39:40 -0400 Subject: [PATCH 11/57] wip --- poly_commit/src/hyrax/hyrax_impl.rs | 120 +++++++++++++++++++++++- poly_commit/src/hyrax/pcs_trait_impl.rs | 32 +++++++ poly_commit/src/kzg/pcs_trait_impl.rs | 25 +++++ poly_commit/src/orion/pcs_trait_impl.rs | 46 +++++++++ poly_commit/src/raw.rs | 23 +++++ poly_commit/src/traits.rs | 21 +++++ poly_commit/tests/test_hyrax.rs | 68 +++++++++++++- 7 files changed, 329 insertions(+), 6 deletions(-) diff --git a/poly_commit/src/hyrax/hyrax_impl.rs b/poly_commit/src/hyrax/hyrax_impl.rs index 845f7d5a..feeabff2 100644 --- a/poly_commit/src/hyrax/hyrax_impl.rs +++ b/poly_commit/src/hyrax/hyrax_impl.rs @@ -1,4 +1,6 @@ -use arith::ExtensionField; +use arith::{ExtensionField, Field}; +use gkr_engine::Transcript; +use halo2curves::group::Group; use halo2curves::{ff::PrimeField, msm, CurveAffine}; use polynomials::{ EqPolynomial, MultilinearExtension, MutRefMultiLinearPoly, MutableMultilinearExtension, @@ -6,9 +8,12 @@ use polynomials::{ }; use serdes::ExpSerde; -use crate::hyrax::{ - pedersen::{pedersen_commit, pedersen_setup}, - PedersenParams, +use crate::{ + hyrax::{ + pedersen::{pedersen_commit, pedersen_setup}, + PedersenParams, + }, + powers_series, }; pub(crate) fn hyrax_setup( @@ -133,3 +138,110 @@ where eval == RefMultiLinearPoly::from_ref(&proof.0) .evaluate_with_buffer(&eval_point[..pedersen_vars], &mut scratch) } + +// batch open a set of mle_polys at the same point +// returns a set of eval points and a signle opening +// NOTE: random linear combination is used to merge polynomials +pub(crate) fn hyrax_batch_open( + params: &PedersenParams, + mle_poly_list: &[impl MultilinearExtension], + eval_point: &[C::Scalar], + transcript: &mut impl Transcript, +) -> (Vec, HyraxOpening) +where + C: CurveAffine + ExpSerde, + C::Scalar: ExtensionField + PrimeField, + C::ScalarExt: ExtensionField + PrimeField, +{ + let len = mle_poly_list.len(); + let pedersen_len = params.msm_len(); + let pedersen_vars = pedersen_len.ilog2() as usize; + + // let challenge = transcript.generate_field_element::(); + let challenge = C::Scalar::one(); + let challenge_power = powers_series(&challenge, len); + + // the opening is the random linearly combine all the polynomials + let mut res = vec![C::Scalar::default(); 1 << pedersen_vars]; + let mut evals = vec![]; + let mut buffer = vec![C::Scalar::default(); 1 << pedersen_vars]; + + for (mle_poly, challenge) in mle_poly_list.iter().zip(challenge_power.iter()) { + let mut local_basis = mle_poly.hypercube_basis(); + let mut local_mle = MutRefMultiLinearPoly::from_ref(&mut local_basis); + local_mle.fix_variables(&eval_point[pedersen_vars..]); + + evals.push( + local_mle.evaluate_with_buffer(&eval_point[..pedersen_vars], &mut buffer) * challenge, + ); + + res.iter_mut() + .zip(local_mle.coeffs.iter()) + .for_each(|(r, c)| { + *r += *challenge * *c; + }); + } + (evals, HyraxOpening(res)) +} + +/// Batch verify a list of hyrax commitments/proofs that are opened at the same point. +pub(crate) fn hyrax_batch_verify( + params: &PedersenParams, + comm_list: &[HyraxCommitment], + eval_point: &[C::Scalar], + eval_list: &[C::Scalar], + batch_proof: &HyraxOpening, + transcript: &mut impl Transcript, +) -> bool +where + C: CurveAffine + ExpSerde, + C::Scalar: ExtensionField + PrimeField, + C::ScalarExt: ExtensionField + PrimeField, +{ + let len = comm_list.len(); + assert_eq!(len, eval_list.len()); + + let pedersen_len = params.msm_len(); + let pedersen_vars = pedersen_len.ilog2() as usize; + + // let challenge = transcript.generate_field_element::(); + let challenge = C::Scalar::one(); + let challenge_power = powers_series(&challenge, len); + + // random linear combination of the commitments + // for each i we want to do + // comm_i * challenge_i * eq_combination + // we do the second mul first -- this is a field op + let mut row_comm = C::Curve::identity(); + let eq_combination: Vec = EqPolynomial::build_eq_x_r(&eval_point[pedersen_vars..]); + for (i, comm) in comm_list.iter().enumerate() { + let challenge = &challenge_power[i]; + let scaled_eq = scale(&eq_combination, challenge); + let this_row_comm = msm::best_multiexp(&scaled_eq, &comm.0); + + row_comm += this_row_comm; + } + + if pedersen_commit(params, &batch_proof.0) != row_comm.into() { + println!("commitment not matching"); + return false; + } + + // now we need to check the evaluations + let eval_sum = eval_list + .iter() + .zip(challenge_power.iter()) + .map(|(eval, challenge)| *eval * *challenge) + .sum::(); + + let mut scratch = vec![C::Scalar::default(); batch_proof.0.len()]; + eval_sum + == RefMultiLinearPoly::from_ref(&batch_proof.0) + .evaluate_with_buffer(&eval_point[..pedersen_vars], &mut scratch) +} + +#[inline(always)] +// scale a vector by a scalar +fn scale(base: &[F], scalar: &F) -> Vec { + base.iter().map(|x| *x * scalar).collect() +} diff --git a/poly_commit/src/hyrax/pcs_trait_impl.rs b/poly_commit/src/hyrax/pcs_trait_impl.rs index a879514e..dab1f347 100644 --- a/poly_commit/src/hyrax/pcs_trait_impl.rs +++ b/poly_commit/src/hyrax/pcs_trait_impl.rs @@ -11,6 +11,8 @@ use crate::{ HyraxCommitment, HyraxOpening, PedersenParams, PolynomialCommitmentScheme, }; +use super::hyrax_impl::{hyrax_batch_open, hyrax_batch_verify}; + pub struct HyraxPCS where C: CurveAffine + ExpSerde, @@ -74,4 +76,34 @@ where ) -> bool { hyrax_verify(verifying_key, commitment, x, v, opening) } + + fn batch_open( + _params: &Self::Params, + proving_key: &::PKey, + mle_poly_list: &[Self::Poly], + eval_point: &Self::EvalPoint, + _scratch_pad: &Self::ScratchPad, + transcript: &mut impl Transcript, + ) -> (Vec, Self::Opening) { + hyrax_batch_open(proving_key, mle_poly_list, eval_point, transcript) + } + + fn batch_verify( + _params: &Self::Params, + verifying_key: &::VKey, + comm_list: &[Self::Commitment], + eval_point: &Self::EvalPoint, + eval_list: &[C::Scalar], + batch_proof: &Self::Opening, + transcript: &mut impl Transcript, + ) -> bool { + hyrax_batch_verify( + verifying_key, + comm_list, + eval_point, + eval_list, + batch_proof, + transcript, + ) + } } diff --git a/poly_commit/src/kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/pcs_trait_impl.rs index bb1ca844..f7709674 100644 --- a/poly_commit/src/kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/pcs_trait_impl.rs @@ -96,4 +96,29 @@ where pairing_check && partial_check } + + fn batch_open( + _params: &Self::Params, + _proving_key: &::PKey, + _polys: &[Self::Poly], + _x: &Self::EvalPoint, + _scratch_pad: &Self::ScratchPad, + _transcript: &mut impl Transcript, + ) -> (Vec, Self::Opening) { + // todo: implement batch_open + unimplemented!("batch_open is not implemented for HyperKZGPCS"); + } + + fn batch_verify( + _params: &Self::Params, + _verifying_key: &::VKey, + _commitments: &[Self::Commitment], + _x: &Self::EvalPoint, + _vs: &[E::Fr], + _opening: &Self::Opening, + _transcript: &mut impl Transcript, + ) -> bool { + // todo: implement batch_verify + unimplemented!("batch_verify is not implemented for HyperKZGPCS"); + } } diff --git a/poly_commit/src/orion/pcs_trait_impl.rs b/poly_commit/src/orion/pcs_trait_impl.rs index bae848e5..2bde7fac 100644 --- a/poly_commit/src/orion/pcs_trait_impl.rs +++ b/poly_commit/src/orion/pcs_trait_impl.rs @@ -129,6 +129,29 @@ where assert_eq!(*params, vk.num_vars); orion_verify::<_, OpenPackF, _, ComPackF>(vk, commitment, x, &[], v, transcript, opening) } + + fn batch_open( + _params: &Self::Params, + _proving_key: &::PKey, + _polys: &[Self::Poly], + _x: &Self::EvalPoint, + _scratch_pad: &Self::ScratchPad, + _transcript: &mut impl Transcript, + ) -> (Vec, Self::Opening) { + unimplemented!("batch_open is not implemented for OrionBaseFieldPCS"); + } + + fn batch_verify( + _params: &Self::Params, + _verifying_key: &::VKey, + _commitments: &[Self::Commitment], + _x: &Self::EvalPoint, + _vs: &[EvalF], + _opening: &Self::Opening, + _transcript: &mut impl Transcript, + ) -> bool { + unimplemented!("batch_verify is not implemented for OrionBaseFieldPCS"); + } } pub struct OrionSIMDFieldPCS @@ -230,4 +253,27 @@ where assert_eq!(x.len(), vk.num_vars); orion_verify::<_, SimdF, _, ComPackF>(vk, commitment, x, &[], v, transcript, opening) } + + fn batch_open( + _params: &Self::Params, + _proving_key: &::PKey, + _polys: &[Self::Poly], + _x: &Self::EvalPoint, + _scratch_pad: &Self::ScratchPad, + _transcript: &mut impl Transcript, + ) -> (Vec, Self::Opening) { + unimplemented!("batch_open is not implemented for OrionSIMDFieldPCS"); + } + + fn batch_verify( + _params: &Self::Params, + _verifying_key: &::VKey, + _commitments: &[Self::Commitment], + _x: &Self::EvalPoint, + _vs: &[EvalF], + _opening: &Self::Opening, + _transcript: &mut impl Transcript, + ) -> bool { + unimplemented!("batch_verify is not implemented for OrionSIMDFieldPCS"); + } } diff --git a/poly_commit/src/raw.rs b/poly_commit/src/raw.rs index dcf33eb4..3659e808 100644 --- a/poly_commit/src/raw.rs +++ b/poly_commit/src/raw.rs @@ -113,6 +113,29 @@ impl PolynomialCommitmentScheme for RawMultiLinearPCS { &mut vec![F::ZERO; commitment.evals.len()], ) == v } + + fn batch_open( + _params: &Self::Params, + _proving_key: &::PKey, + _polys: &[Self::Poly], + _x: &Self::EvalPoint, + _scratch_pad: &Self::ScratchPad, + _transcript: &mut impl Transcript, + ) -> (Vec, Self::Opening) { + unimplemented!("batch_open is not implemented for RawMultiLinearPCS"); + } + + fn batch_verify( + _params: &Self::Params, + _verifying_key: &::VKey, + _commitments: &[Self::Commitment], + _x: &Self::EvalPoint, + _vs: &[F], + _opening: &Self::Opening, + _transcript: &mut impl Transcript, + ) -> bool { + unimplemented!("batch_verify is not implemented for RawMultiLinearPCS"); + } } // ================================================================================================= diff --git a/poly_commit/src/traits.rs b/poly_commit/src/traits.rs index 62fa8998..16385434 100644 --- a/poly_commit/src/traits.rs +++ b/poly_commit/src/traits.rs @@ -56,6 +56,27 @@ pub trait PolynomialCommitmentScheme { opening: &Self::Opening, transcript: &mut impl Transcript, ) -> bool; + + /// Open a set of polynomials at a point. + fn batch_open( + params: &Self::Params, + proving_key: &::PKey, + polys: &[Self::Poly], + x: &Self::EvalPoint, + scratch_pad: &Self::ScratchPad, + transcript: &mut impl Transcript, + ) -> (Vec, Self::Opening); + + /// Verify the opening of a set of polynomials at a point. + fn batch_verify( + params: &Self::Params, + verifying_key: &::VKey, + commitments: &[Self::Commitment], + x: &Self::EvalPoint, + vs: &[F], + opening: &Self::Opening, + transcript: &mut impl Transcript, + ) -> bool; } pub(crate) trait TensorCodeIOPPCS { diff --git a/poly_commit/tests/test_hyrax.rs b/poly_commit/tests/test_hyrax.rs index f3095cd6..87211c30 100644 --- a/poly_commit/tests/test_hyrax.rs +++ b/poly_commit/tests/test_hyrax.rs @@ -2,11 +2,13 @@ mod common; use arith::{Field, Fr}; use ark_std::test_rng; +use gkr_engine::StructuredReferenceString; use gkr_engine::{BN254Config, ExpanderSingleVarChallenge, MPIConfig, MPIEngine, Transcript}; -use gkr_hashers::Keccak256hasher; +use gkr_hashers::{Keccak256hasher, SHA256hasher}; use halo2curves::bn256::G1Affine; -use poly_commit::HyraxPCS; +use poly_commit::{HyraxPCS, PolynomialCommitmentScheme}; use polynomials::MultiLinearPoly; +use rand::thread_rng; use transcript::BytesHashTranscript; const TEST_REPETITION: usize = 3; @@ -81,3 +83,65 @@ fn test_hyrax_for_expander_gkr() { MPIConfig::finalize() } + +#[test] +fn test_hyrax_batch_open() { + let mut rng = thread_rng(); + + for num_vars in 2..3 { + // NOTE(HS) we assume that the polynomials we pass in are of sufficient length. + let (srs, _) = as PolynomialCommitmentScheme>::gen_srs_for_testing( + &num_vars, &mut rng, + ); + let (proving_key, verification_key) = srs.into_keys(); + let mut scratch_pad = + as PolynomialCommitmentScheme>::init_scratch_pad(&num_vars); + + // first poly + let poly_1 = MultiLinearPoly::::random(num_vars, &mut rng); + let commitment_1 = as PolynomialCommitmentScheme>::commit( + &num_vars, + &proving_key, + &poly_1, + &mut scratch_pad, + ); + + let poly_2 = MultiLinearPoly::::random(num_vars, &mut rng); + let commitment_2 = as PolynomialCommitmentScheme>::commit( + &num_vars, + &proving_key, + &poly_2, + &mut scratch_pad, + ); + + let x = (0..num_vars) + .map(|_| Fr::random_unsafe(&mut rng)) + .collect::>(); + + let mut transcript = BytesHashTranscript::::new(); + + let (values, batch_opening) = + as PolynomialCommitmentScheme>::batch_open( + &num_vars, + &proving_key, + &[poly_1, poly_2], + x.as_ref(), + &mut scratch_pad, + &mut transcript, + ); + + let mut transcript = BytesHashTranscript::::new(); + + assert!( + as PolynomialCommitmentScheme>::batch_verify( + &num_vars, + &verification_key, + &[commitment_1, commitment_2], + x.as_ref(), + &values, + &batch_opening, + &mut transcript + ) + ) + } +} From 65b87787dd7b68d38e7a4e4a425d49f68068605f Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 21 May 2025 16:08:34 -0400 Subject: [PATCH 12/57] hyrax batch opening now works properly --- poly_commit/src/hyrax/hyrax_impl.rs | 32 ++++---- poly_commit/tests/test_hyrax.rs | 110 ++++++++++++++-------------- 2 files changed, 72 insertions(+), 70 deletions(-) diff --git a/poly_commit/src/hyrax/hyrax_impl.rs b/poly_commit/src/hyrax/hyrax_impl.rs index feeabff2..e6d56f9e 100644 --- a/poly_commit/src/hyrax/hyrax_impl.rs +++ b/poly_commit/src/hyrax/hyrax_impl.rs @@ -1,6 +1,5 @@ use arith::{ExtensionField, Field}; use gkr_engine::Transcript; -use halo2curves::group::Group; use halo2curves::{ff::PrimeField, msm, CurveAffine}; use polynomials::{ EqPolynomial, MultilinearExtension, MutRefMultiLinearPoly, MutableMultilinearExtension, @@ -157,8 +156,7 @@ where let pedersen_len = params.msm_len(); let pedersen_vars = pedersen_len.ilog2() as usize; - // let challenge = transcript.generate_field_element::(); - let challenge = C::Scalar::one(); + let challenge = transcript.generate_field_element::(); let challenge_power = powers_series(&challenge, len); // the opening is the random linearly combine all the polynomials @@ -171,9 +169,7 @@ where let mut local_mle = MutRefMultiLinearPoly::from_ref(&mut local_basis); local_mle.fix_variables(&eval_point[pedersen_vars..]); - evals.push( - local_mle.evaluate_with_buffer(&eval_point[..pedersen_vars], &mut buffer) * challenge, - ); + evals.push(local_mle.evaluate_with_buffer(&eval_point[..pedersen_vars], &mut buffer)); res.iter_mut() .zip(local_mle.coeffs.iter()) @@ -204,26 +200,30 @@ where let pedersen_len = params.msm_len(); let pedersen_vars = pedersen_len.ilog2() as usize; - // let challenge = transcript.generate_field_element::(); - let challenge = C::Scalar::one(); + let challenge = transcript.generate_field_element::(); let challenge_power = powers_series(&challenge, len); // random linear combination of the commitments // for each i we want to do // comm_i * challenge_i * eq_combination // we do the second mul first -- this is a field op - let mut row_comm = C::Curve::identity(); - let eq_combination: Vec = EqPolynomial::build_eq_x_r(&eval_point[pedersen_vars..]); - for (i, comm) in comm_list.iter().enumerate() { - let challenge = &challenge_power[i]; - let scaled_eq = scale(&eq_combination, challenge); - let this_row_comm = msm::best_multiexp(&scaled_eq, &comm.0); + // then we do a single multiexp to take advantage of Pippenger's algorithm + + let bases = comm_list + .iter() + .flat_map(|comm| comm.0.clone()) + .collect::>(); - row_comm += this_row_comm; + let mut scalars = vec![]; + let eq_combination: Vec = EqPolynomial::build_eq_x_r(&eval_point[pedersen_vars..]); + for c in challenge_power.iter() { + scalars.extend_from_slice(scale(&eq_combination, c).as_ref()); } + let row_comm = msm::best_multiexp(&scalars, &bases); + if pedersen_commit(params, &batch_proof.0) != row_comm.into() { - println!("commitment not matching"); + eprintln!("commitment not matching"); return false; } diff --git a/poly_commit/tests/test_hyrax.rs b/poly_commit/tests/test_hyrax.rs index 87211c30..e15f10a3 100644 --- a/poly_commit/tests/test_hyrax.rs +++ b/poly_commit/tests/test_hyrax.rs @@ -88,60 +88,62 @@ fn test_hyrax_for_expander_gkr() { fn test_hyrax_batch_open() { let mut rng = thread_rng(); - for num_vars in 2..3 { - // NOTE(HS) we assume that the polynomials we pass in are of sufficient length. - let (srs, _) = as PolynomialCommitmentScheme>::gen_srs_for_testing( - &num_vars, &mut rng, - ); - let (proving_key, verification_key) = srs.into_keys(); - let mut scratch_pad = - as PolynomialCommitmentScheme>::init_scratch_pad(&num_vars); - - // first poly - let poly_1 = MultiLinearPoly::::random(num_vars, &mut rng); - let commitment_1 = as PolynomialCommitmentScheme>::commit( - &num_vars, - &proving_key, - &poly_1, - &mut scratch_pad, - ); - - let poly_2 = MultiLinearPoly::::random(num_vars, &mut rng); - let commitment_2 = as PolynomialCommitmentScheme>::commit( - &num_vars, - &proving_key, - &poly_2, - &mut scratch_pad, - ); - - let x = (0..num_vars) - .map(|_| Fr::random_unsafe(&mut rng)) - .collect::>(); - - let mut transcript = BytesHashTranscript::::new(); - - let (values, batch_opening) = - as PolynomialCommitmentScheme>::batch_open( - &num_vars, - &proving_key, - &[poly_1, poly_2], - x.as_ref(), - &mut scratch_pad, - &mut transcript, - ); - - let mut transcript = BytesHashTranscript::::new(); - - assert!( - as PolynomialCommitmentScheme>::batch_verify( - &num_vars, - &verification_key, - &[commitment_1, commitment_2], - x.as_ref(), - &values, - &batch_opening, - &mut transcript + for num_vars in 2..10 { + for num_poly in [1, 2, 10, 100] { + // NOTE(HS) we assume that the polynomials we pass in are of sufficient length. + let (srs, _) = + as PolynomialCommitmentScheme>::gen_srs_for_testing( + &num_vars, &mut rng, + ); + let (proving_key, verification_key) = srs.into_keys(); + let mut scratch_pad = + as PolynomialCommitmentScheme>::init_scratch_pad(&num_vars); + + let polys = (0..num_poly) + .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) + .collect::>(); + let commitments = polys + .iter() + .map(|poly| { + as PolynomialCommitmentScheme>::commit( + &num_vars, + &proving_key, + poly, + &mut scratch_pad, + ) + }) + .collect::>(); + + // open all polys at a single point + let x = (0..num_vars) + .map(|_| Fr::random_unsafe(&mut rng)) + .collect::>(); + + let mut transcript = BytesHashTranscript::::new(); + + let (values, batch_opening) = + as PolynomialCommitmentScheme>::batch_open( + &num_vars, + &proving_key, + &polys, + x.as_ref(), + &mut scratch_pad, + &mut transcript, + ); + + let mut transcript = BytesHashTranscript::::new(); + + assert!( + as PolynomialCommitmentScheme>::batch_verify( + &num_vars, + &verification_key, + &commitments, + x.as_ref(), + &values, + &batch_opening, + &mut transcript + ) ) - ) + } } } From 330425e990b13c86af939c527760678725ddf5f8 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 21 May 2025 16:26:55 -0400 Subject: [PATCH 13/57] update bench --- poly_commit/benches/pcs_all.rs | 95 +++++++++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/poly_commit/benches/pcs_all.rs b/poly_commit/benches/pcs_all.rs index c7196707..c3059fad 100644 --- a/poly_commit/benches/pcs_all.rs +++ b/poly_commit/benches/pcs_all.rs @@ -3,7 +3,7 @@ use ark_std::test_rng; use criterion::black_box; use gkr_engine::StructuredReferenceString; use gkr_engine::{root_println, MPIConfig, MPIEngine, Transcript}; -use gkr_hashers::Keccak256hasher; +use gkr_hashers::{Keccak256hasher, SHA256hasher}; use halo2curves::bn256::{Bn256, G1Affine}; use poly_commit::{HyperKZGPCS, HyraxPCS, OrionBaseFieldPCS, PolynomialCommitmentScheme}; use polynomials::MultiLinearPoly; @@ -12,6 +12,8 @@ use serdes::ExpSerde; use transcript::BytesHashTranscript; use utils::timer::Timer; +const NUM_POLY_BATCH_OPEN: usize = 100; + fn main() { let mpi_config = MPIConfig::prover_new(); println!("=========================="); @@ -85,6 +87,9 @@ fn bench_hyrax(mpi_config: &MPIConfig, num_vars: usize) { &eval_point, "hyrax small scalar", ); + + // batch open + bench_hyrax_batch_open(mpi_config, num_vars, NUM_POLY_BATCH_OPEN); } fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { @@ -191,3 +196,91 @@ fn pcs_bench>( root_println!(mpi_config, " --- "); } + +fn bench_hyrax_batch_open(mpi_config: &MPIConfig, num_vars: usize, num_poly: usize) { + let mut rng = test_rng(); + + let (srs, _) = as PolynomialCommitmentScheme>::gen_srs_for_testing( + &num_vars, &mut rng, + ); + let (proving_key, verification_key) = srs.into_keys(); + let mut scratch_pad = + as PolynomialCommitmentScheme>::init_scratch_pad(&num_vars); + + let polys = (0..num_poly) + .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) + .collect::>(); + let commitments = polys + .iter() + .map(|poly| { + as PolynomialCommitmentScheme>::commit( + &num_vars, + &proving_key, + poly, + &mut scratch_pad, + ) + }) + .collect::>(); + let mut buf = vec![]; + commitments.serialize_into(&mut buf).unwrap(); + let com_size = buf.len(); + + + // open all polys at a single point + let x = (0..num_vars) + .map(|_| Fr::random_unsafe(&mut rng)) + .collect::>(); + + let mut transcript = BytesHashTranscript::::new(); + let timer = Timer::new( + format!("hyrax batch open {} polys ", num_poly).as_ref(), + mpi_config.is_root(), + ); + let (values, batch_opening) = + as PolynomialCommitmentScheme>::batch_open( + &num_vars, + &proving_key, + &polys, + x.as_ref(), + &mut scratch_pad, + &mut transcript, + ); + + timer.stop(); + + let mut buf = vec![]; + values.serialize_into(&mut buf).unwrap(); + batch_opening.serialize_into(&mut buf).unwrap(); + let open_size = buf.len(); + + let mut transcript = BytesHashTranscript::::new(); + let timer = Timer::new( + format!("hyrax batch verify {} polys ", num_poly).as_ref(), + mpi_config.is_root(), + ); + assert!( + as PolynomialCommitmentScheme>::batch_verify( + &num_vars, + &verification_key, + &commitments, + x.as_ref(), + &values, + &batch_opening, + &mut transcript + ) + ); + timer.stop(); + + root_println!( + mpi_config, + "{}", + format!("hyrax batch {} poly commit size {}", num_poly, com_size), + ); + root_println!( + mpi_config, + "{}", + format!("hyrax batch {} poly open size {}", num_poly, open_size), + ); + + root_println!(mpi_config, " --- "); +} From 51474a74cc01a148dc2a3b9a3a6a7e1918d34425 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 21 May 2025 16:53:30 -0400 Subject: [PATCH 14/57] cargo fmt --- poly_commit/benches/pcs_all.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/poly_commit/benches/pcs_all.rs b/poly_commit/benches/pcs_all.rs index c3059fad..5c96cbaf 100644 --- a/poly_commit/benches/pcs_all.rs +++ b/poly_commit/benches/pcs_all.rs @@ -225,7 +225,6 @@ fn bench_hyrax_batch_open(mpi_config: &MPIConfig, num_vars: usize, num_poly: usi commitments.serialize_into(&mut buf).unwrap(); let com_size = buf.len(); - // open all polys at a single point let x = (0..num_vars) .map(|_| Fr::random_unsafe(&mut rng)) From 0278307f516bf2d26152584518c2b35730d340d8 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 27 May 2025 16:29:43 -0400 Subject: [PATCH 15/57] ExpanderPCS api --- gkr_engine/src/poly_commit/definition.rs | 26 +++++ poly_commit/src/hyrax/expander_api.rs | 47 ++++++++- poly_commit/tests/common.rs | 120 ++++++++++++++++++++++- poly_commit/tests/test_hyrax.rs | 72 ++------------ 4 files changed, 196 insertions(+), 69 deletions(-) diff --git a/gkr_engine/src/poly_commit/definition.rs b/gkr_engine/src/poly_commit/definition.rs index 4df4dd73..c1efd132 100644 --- a/gkr_engine/src/poly_commit/definition.rs +++ b/gkr_engine/src/poly_commit/definition.rs @@ -172,6 +172,32 @@ pub trait ExpanderPCS { fn batch_deferred_verification(accumulator: &mut Self::Accumulator) -> bool { accumulator.final_check() } + + /// Open a set of polynomials at a point. + fn batch_open( + _params: &Self::Params, + _mpi_engine: &impl MPIEngine, + _proving_key: &::PKey, + _polys: &[impl MultilinearExtension], + _x: &ExpanderSingleVarChallenge, + _scratch_pad: &Self::ScratchPad, + _transcript: &mut impl Transcript, + ) -> (Vec, Self::Opening) { + unimplemented!("Batch opening is not implemented for this PCS type") + } + + /// Verify the opening of a set of polynomials at a point. + fn batch_verify( + _params: &Self::Params, + _verifying_key: &::VKey, + _commitments: &[Self::Commitment], + _x: &ExpanderSingleVarChallenge, + _evals: &[F::ChallengeField], + _opening: &Self::Opening, + _transcript: &mut impl Transcript, + ) -> bool { + unimplemented!("Batch verify is not implemented for this PCS type") + } } impl StructuredReferenceString for () { diff --git a/poly_commit/src/hyrax/expander_api.rs b/poly_commit/src/hyrax/expander_api.rs index fc0c28a9..fff6348c 100644 --- a/poly_commit/src/hyrax/expander_api.rs +++ b/poly_commit/src/hyrax/expander_api.rs @@ -18,6 +18,8 @@ use crate::{ HyraxCommitment, HyraxOpening, HyraxPCS, PedersenParams, }; +use super::hyrax_impl::{hyrax_batch_open, hyrax_batch_verify}; + impl ExpanderPCS for HyraxPCS where G: FieldEngine, @@ -118,13 +120,13 @@ where verifying_key: &::VKey, commitment: &Self::Commitment, x: &ExpanderSingleVarChallenge, - v: ::ChallengeField, + evals: ::ChallengeField, _transcript: &mut impl Transcript, opening: &Self::Opening, _accumulator: &mut Self::Accumulator, ) -> bool { if x.r_mpi.is_empty() { - return hyrax_verify(verifying_key, commitment, &x.local_xs(), v, opening); + return hyrax_verify(verifying_key, commitment, &x.local_xs(), evals, opening); } let pedersen_len = verifying_key.msm_len(); @@ -142,7 +144,44 @@ where } let mut scratch = vec![C::Scalar::default(); opening.0.len()]; - v == RefMultiLinearPoly::from_ref(&opening.0) - .evaluate_with_buffer(&local_vars[..pedersen_vars], &mut scratch) + evals + == RefMultiLinearPoly::from_ref(&opening.0) + .evaluate_with_buffer(&local_vars[..pedersen_vars], &mut scratch) + } + /// Open a set of polynomials at a point. + fn batch_open( + _params: &Self::Params, + _mpi_engine: &impl MPIEngine, + proving_key: &::PKey, + mle_poly_list: &[impl MultilinearExtension], + eval_point: &ExpanderSingleVarChallenge, + _scratch_pad: &Self::ScratchPad, + transcript: &mut impl Transcript, + ) -> (Vec, Self::Opening) { + hyrax_batch_open( + proving_key, + mle_poly_list, + &eval_point.local_xs(), + transcript, + ) + } + + fn batch_verify( + _params: &Self::Params, + verifying_key: &::VKey, + commitments: &[Self::Commitment], + x: &ExpanderSingleVarChallenge, + evals: &[::ChallengeField], + opening: &Self::Opening, + transcript: &mut impl Transcript, + ) -> bool { + hyrax_batch_verify( + verifying_key, + commitments, + &x.local_xs(), + evals, + opening, + transcript, + ) } } diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index a4d0bee7..39e22cc1 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -5,7 +5,7 @@ use gkr_engine::{ StructuredReferenceString, Transcript, }; use poly_commit::PolynomialCommitmentScheme; -use polynomials::MultilinearExtension; +use polynomials::{MultiLinearPoly, MultilinearExtension}; use rand::thread_rng; pub fn test_pcs>( @@ -44,6 +44,62 @@ pub fn test_pcs() +where + F: ExtensionField, + T: Transcript, + P: PolynomialCommitmentScheme, Poly = MultiLinearPoly>, +{ + let mut rng = thread_rng(); + + for num_vars in 2..10 { + // NOTE(HS) we assume that the polynomials we pass in are of sufficient length. + let (srs, _) = P::gen_srs_for_testing(&num_vars, &mut rng); + + let mut scratch_pad = P::init_scratch_pad(&num_vars); + + let (proving_key, verification_key) = srs.into_keys(); + + for num_poly in [1, 2, 10, 100] { + let polys = (0..num_poly) + .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) + .collect::>(); + let commitments = polys + .iter() + .map(|poly| P::commit(&num_vars, &proving_key, poly, &mut scratch_pad)) + .collect::>(); + + // open all polys at a single point + let x = (0..num_vars) + .map(|_| F::random_unsafe(&mut rng)) + .collect::>(); + + let mut transcript = T::new(); + + let (values, batch_opening) = P::batch_open( + &num_vars, + &proving_key, + &polys, + x.as_ref(), + &mut scratch_pad, + &mut transcript, + ); + + let mut transcript = T::new(); + + assert!(P::batch_verify( + &num_vars, + &verification_key, + &commitments, + x.as_ref(), + &values, + &batch_opening, + &mut transcript + )) + } + } +} + pub fn test_pcs_for_expander_gkr< C: FieldEngine, T: Transcript, @@ -106,3 +162,65 @@ pub fn test_pcs_for_expander_gkr< } } } + +pub fn test_batching_for_expander_gkr() +where + C: FieldEngine, + T: Transcript, + P: ExpanderPCS, +{ + let mut rng = test_rng(); + let mpi_config = MPIConfig::prover_new(); + for num_vars in 2..10 { + // NOTE(HS) we assume that the polynomials we pass in are of sufficient length. + let srs = P::gen_srs_for_testing(&num_vars, &mpi_config, &mut rng); + let (proving_key, verification_key) = srs.into_keys(); + let mut scratch_pad = P::init_scratch_pad(&num_vars, &mpi_config); + + for num_poly in [1, 2, 10, 100] { + let polys = (0..num_poly) + .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) + .collect::>(); + + let commitments = polys + .iter() + .map(|poly| { + P::commit(&num_vars, &mpi_config, &proving_key, poly, &mut scratch_pad).unwrap() + }) + .collect::>(); + + // open all polys at a single point + let challenge_point = ExpanderSingleVarChallenge:: { + r_mpi: Vec::new(), + r_simd: Vec::new(), + rz: (0..num_vars) + .map(|_| C::ChallengeField::random_unsafe(&mut rng)) + .collect(), + }; + + let mut transcript = T::new(); + + let (eval_list, opening) = P::batch_open( + &num_vars, + &mpi_config, + &proving_key, + &polys, + &challenge_point, + &mut scratch_pad, + &mut transcript, + ); + + let mut transcript = T::new(); + + assert!(P::batch_verify( + &num_vars, + &verification_key, + &commitments, + &challenge_point, + &eval_list, + &opening, + &mut transcript, + )); + } + } +} diff --git a/poly_commit/tests/test_hyrax.rs b/poly_commit/tests/test_hyrax.rs index e15f10a3..63b5f22c 100644 --- a/poly_commit/tests/test_hyrax.rs +++ b/poly_commit/tests/test_hyrax.rs @@ -2,13 +2,11 @@ mod common; use arith::{Field, Fr}; use ark_std::test_rng; -use gkr_engine::StructuredReferenceString; use gkr_engine::{BN254Config, ExpanderSingleVarChallenge, MPIConfig, MPIEngine, Transcript}; -use gkr_hashers::{Keccak256hasher, SHA256hasher}; +use gkr_hashers::Keccak256hasher; use halo2curves::bn256::G1Affine; -use poly_commit::{HyraxPCS, PolynomialCommitmentScheme}; +use poly_commit::HyraxPCS; use polynomials::MultiLinearPoly; -use rand::thread_rng; use transcript::BytesHashTranscript; const TEST_REPETITION: usize = 3; @@ -86,64 +84,10 @@ fn test_hyrax_for_expander_gkr() { #[test] fn test_hyrax_batch_open() { - let mut rng = thread_rng(); - - for num_vars in 2..10 { - for num_poly in [1, 2, 10, 100] { - // NOTE(HS) we assume that the polynomials we pass in are of sufficient length. - let (srs, _) = - as PolynomialCommitmentScheme>::gen_srs_for_testing( - &num_vars, &mut rng, - ); - let (proving_key, verification_key) = srs.into_keys(); - let mut scratch_pad = - as PolynomialCommitmentScheme>::init_scratch_pad(&num_vars); - - let polys = (0..num_poly) - .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) - .collect::>(); - let commitments = polys - .iter() - .map(|poly| { - as PolynomialCommitmentScheme>::commit( - &num_vars, - &proving_key, - poly, - &mut scratch_pad, - ) - }) - .collect::>(); - - // open all polys at a single point - let x = (0..num_vars) - .map(|_| Fr::random_unsafe(&mut rng)) - .collect::>(); - - let mut transcript = BytesHashTranscript::::new(); - - let (values, batch_opening) = - as PolynomialCommitmentScheme>::batch_open( - &num_vars, - &proving_key, - &polys, - x.as_ref(), - &mut scratch_pad, - &mut transcript, - ); - - let mut transcript = BytesHashTranscript::::new(); - - assert!( - as PolynomialCommitmentScheme>::batch_verify( - &num_vars, - &verification_key, - &commitments, - x.as_ref(), - &values, - &batch_opening, - &mut transcript - ) - ) - } - } + common::test_batching::, HyraxPCS>(); + common::test_batching_for_expander_gkr::< + BN254Config, + BytesHashTranscript, + HyraxPCS, + >(); } From a3e00636aa0f2e9ac28b781e0d37886aae6deb01 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 27 May 2025 17:02:50 -0400 Subject: [PATCH 16/57] impl batch opening for kzg --- arith/polynomials/src/mle.rs | 24 ++++++++ poly_commit/src/kzg/pcs_trait_impl.rs | 82 ++++++++++++++++++++++----- poly_commit/tests/test_kzg.rs | 10 ++++ 3 files changed, 102 insertions(+), 14 deletions(-) diff --git a/arith/polynomials/src/mle.rs b/arith/polynomials/src/mle.rs index 999e5533..fab5a0f6 100644 --- a/arith/polynomials/src/mle.rs +++ b/arith/polynomials/src/mle.rs @@ -156,6 +156,30 @@ impl MultiLinearPoly { } } +impl Add<&MultiLinearPoly> for MultiLinearPoly { + type Output = Self; + + fn add(self, other: &MultiLinearPoly) -> Self::Output { + assert_eq!(self.coeffs.len(), other.coeffs.len()); + let coeffs = self + .coeffs + .iter() + .zip(other.coeffs.iter()) + .map(|(a, b)| *a + *b) + .collect(); + MultiLinearPoly { coeffs } + } +} + +impl Mul<&F> for &MultiLinearPoly { + type Output = MultiLinearPoly; + + fn mul(self, scalar: &F) -> Self::Output { + let coeffs = self.coeffs.iter().map(|c| *c * scalar).collect(); + MultiLinearPoly { coeffs } + } +} + impl Index for MultiLinearPoly { type Output = F; diff --git a/poly_commit/src/kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/pcs_trait_impl.rs index f229d291..0dcf407e 100644 --- a/poly_commit/src/kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/pcs_trait_impl.rs @@ -1,9 +1,13 @@ use std::marker::PhantomData; use arith::ExtensionField; +use arith::Field; use gkr_engine::{DeferredCheck, StructuredReferenceString, Transcript}; +use halo2curves::group::Group; +use halo2curves::msm::multiexp_serial; use halo2curves::{ ff::PrimeField, + group::Curve, pairing::{Engine, MultiMillerLoop}, CurveAffine, }; @@ -107,26 +111,76 @@ where fn batch_open( _params: &Self::Params, - _proving_key: &::PKey, - _polys: &[Self::Poly], - _x: &Self::EvalPoint, + proving_key: &::PKey, + polys: &[Self::Poly], + x: &Self::EvalPoint, _scratch_pad: &Self::ScratchPad, - _transcript: &mut impl Transcript, + transcript: &mut impl Transcript, ) -> (Vec, Self::Opening) { - // todo: implement batch_open - unimplemented!("batch_open is not implemented for HyperKZGPCS"); + let rlc_randomness = transcript.generate_field_element::(); + let num_poly = polys.len(); + let rlcs = powers_series(&rlc_randomness, num_poly); + let mut buf = vec![E::Fr::default(); polys[0].coeffs.len()]; + + let merged_poly = polys + .iter() + .zip(rlcs.iter()) + .skip(1) + .fold(polys[0].clone(), |acc, (poly, r)| acc + &(poly * r)); + + let mut evals = polys + .iter() + .map(|p| MultiLinearPoly::evaluate_with_buffer(p.coeffs.as_ref(), x, &mut buf)) + .collect::>(); + + let (_batch_eval, open) = + coeff_form_uni_hyperkzg_open(proving_key, &merged_poly.coeffs, x, transcript); + + { + // sanity check: the merged evaluation should match the batch evaluation + // this step is not necessary if the performance is critical + let mut merged_eval = evals[0]; + for (eval, r) in evals.iter_mut().zip(rlcs.iter()).skip(1) { + merged_eval += *eval * r; + } + assert_eq!(_batch_eval, merged_eval); + } + + (evals, open) } fn batch_verify( _params: &Self::Params, - _verifying_key: &::VKey, - _commitments: &[Self::Commitment], - _x: &Self::EvalPoint, - _vs: &[E::Fr], - _opening: &Self::Opening, - _transcript: &mut impl Transcript, + verifying_key: &::VKey, + commitments: &[Self::Commitment], + x: &Self::EvalPoint, + evals: &[E::Fr], + opening: &Self::Opening, + transcript: &mut impl Transcript, ) -> bool { - // todo: implement batch_verify - unimplemented!("batch_verify is not implemented for HyperKZGPCS"); + let rlc_randomness = transcript.generate_field_element::(); + let num_poly = commitments.len(); + let rlcs = powers_series(&rlc_randomness, num_poly); + + let commitments_local = commitments.iter().map(|c| c.0).collect::>(); + + // stay with single thread as the num_poly is usually small + let mut merged_commitment = E::G1::identity(); + multiexp_serial(&rlcs, &commitments_local, &mut merged_commitment); + + let merged_eval = evals + .iter() + .zip(rlcs.iter()) + .fold(E::Fr::zero(), |acc, (e, r)| acc + (*e * r)); + + Self::verify( + _params, + verifying_key, + &KZGCommitment(merged_commitment.to_affine()), + x, + merged_eval, + opening, + transcript, + ) } } diff --git a/poly_commit/tests/test_kzg.rs b/poly_commit/tests/test_kzg.rs index 752ca830..074d0230 100644 --- a/poly_commit/tests/test_kzg.rs +++ b/poly_commit/tests/test_kzg.rs @@ -175,3 +175,13 @@ fn test_hyper_bikzg_batch_verification() { assert!(pairing_accumulator.final_check()); } } + +#[test] +fn test_kzg_batch_open() { + common::test_batching::, HyperKZGPCS>(); + // common::test_batching_for_expander_gkr::< + // BN254Config, + // BytesHashTranscript, + // HyraxPCS, + // >(); +} From 7cc57f8fa6198262ede9853d115b8cffdfb0b938 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 27 May 2025 17:23:39 -0400 Subject: [PATCH 17/57] clean up --- poly_commit/src/kzg.rs | 3 + poly_commit/src/kzg/batch.rs | 99 +++++++++++++++++++++++++++ poly_commit/src/kzg/expander_api.rs | 41 ++++++++++- poly_commit/src/kzg/pcs_trait_impl.rs | 57 ++------------- 4 files changed, 147 insertions(+), 53 deletions(-) create mode 100644 poly_commit/src/kzg/batch.rs diff --git a/poly_commit/src/kzg.rs b/poly_commit/src/kzg.rs index 8b065854..cd00c886 100644 --- a/poly_commit/src/kzg.rs +++ b/poly_commit/src/kzg.rs @@ -31,3 +31,6 @@ mod expander_api; mod deferred_pairing; pub use deferred_pairing::PairingAccumulator; + +mod batch; +pub use batch::{kzg_batch_open, kzg_batch_verify}; diff --git a/poly_commit/src/kzg/batch.rs b/poly_commit/src/kzg/batch.rs new file mode 100644 index 00000000..f202feb8 --- /dev/null +++ b/poly_commit/src/kzg/batch.rs @@ -0,0 +1,99 @@ +use arith::{ExtensionField, Field}; +use gkr_engine::{DeferredCheck, Transcript}; +use halo2curves::group::Group; +use halo2curves::{group::Curve, msm::multiexp_serial, pairing::MultiMillerLoop, CurveAffine}; +use polynomials::MultiLinearPoly; +use serdes::ExpSerde; + +use super::{ + coeff_form_uni_hyperkzg_open, coeff_form_uni_hyperkzg_partial_verify, powers_series, + CoefFormUniKZGSRS, HyperKZGOpening, PairingAccumulator, UniKZGVerifierParams, +}; + +pub fn kzg_batch_open( + proving_key: &CoefFormUniKZGSRS, + polys: &[MultiLinearPoly], + x: &[E::Fr], + transcript: &mut impl Transcript, +) -> (Vec, HyperKZGOpening) +where + E: MultiMillerLoop, + E::G1Affine: CurveAffine + ExpSerde, + E::G2Affine: CurveAffine + ExpSerde, + E::Fr: ExtensionField, +{ + let rlc_randomness = transcript.generate_field_element::(); + let num_poly = polys.len(); + let rlcs = powers_series(&rlc_randomness, num_poly); + let mut buf = vec![E::Fr::default(); polys[0].coeffs.len()]; + + let merged_poly = polys + .iter() + .zip(rlcs.iter()) + .skip(1) + .fold(polys[0].clone(), |acc, (poly, r)| acc + &(poly * r)); + + let mut evals = polys + .iter() + .map(|p| MultiLinearPoly::evaluate_with_buffer(p.coeffs.as_ref(), x, &mut buf)) + .collect::>(); + + let (_batch_eval, open) = + coeff_form_uni_hyperkzg_open(proving_key, &merged_poly.coeffs, x, transcript); + + { + // sanity check: the merged evaluation should match the batch evaluation + // this step is not necessary if the performance is critical + let mut merged_eval = evals[0]; + for (eval, r) in evals.iter_mut().zip(rlcs.iter()).skip(1) { + merged_eval += *eval * r; + } + assert_eq!(_batch_eval, merged_eval); + } + + (evals, open) +} + +pub fn kzg_batch_verify( + verifying_key: &UniKZGVerifierParams, + commitments: &[E::G1Affine], + x: &[E::Fr], + evals: &[E::Fr], + opening: &HyperKZGOpening, + transcript: &mut impl Transcript, +) -> bool +where + E: MultiMillerLoop, + E::G1Affine: CurveAffine + ExpSerde, + E::G2Affine: ExpSerde, + E::Fr: ExtensionField + ExpSerde, +{ + let rlc_randomness = transcript.generate_field_element::(); + let num_poly = commitments.len(); + let rlcs = powers_series(&rlc_randomness, num_poly); + + // stay with single thread as the num_poly is usually small + let mut merged_commitment = E::G1::identity(); + multiexp_serial(&rlcs, commitments, &mut merged_commitment); + + let merged_eval = evals + .iter() + .zip(rlcs.iter()) + .fold(E::Fr::zero(), |acc, (e, r)| acc + (*e * r)); + + let mut accumulator = PairingAccumulator::default(); + + let partial_check = coeff_form_uni_hyperkzg_partial_verify( + verifying_key.clone(), + merged_commitment.to_affine(), + x, + merged_eval, + opening, + transcript, + &mut accumulator, + ); + + let pairing_check = accumulator.final_check(); + + pairing_check && partial_check +} diff --git a/poly_commit/src/kzg/expander_api.rs b/poly_commit/src/kzg/expander_api.rs index 0265936f..77f8d904 100644 --- a/poly_commit/src/kzg/expander_api.rs +++ b/poly_commit/src/kzg/expander_api.rs @@ -9,6 +9,7 @@ use halo2curves::{ pairing::{Engine, MultiMillerLoop}, CurveAffine, }; +use polynomials::MultilinearExtension; use serdes::ExpSerde; use crate::{ @@ -104,7 +105,7 @@ where _params: &Self::Params, mpi_engine: &impl MPIEngine, proving_key: &::PKey, - poly: &impl polynomials::MultilinearExtension, + poly: &impl MultilinearExtension, x: &ExpanderSingleVarChallenge, transcript: &mut impl Transcript, _scratch_pad: &Self::ScratchPad, @@ -170,4 +171,42 @@ where accumulator, ) } + + // /// Open a set of polynomials at a point. + // fn batch_open( + // _params: &Self::Params, + // _mpi_engine: &impl MPIEngine, + // proving_key: &::PKey, + // mle_poly_list: &[impl MultilinearExtension], + // eval_point: &ExpanderSingleVarChallenge, + // _scratch_pad: &Self::ScratchPad, + // transcript: &mut impl Transcript, + // ) -> (Vec, Self::Opening) { + // let (eval, open) = kzg_batch_open( + // proving_key, + // mle_poly_list, + // &eval_point.local_xs(), + // transcript, + // ); + // (eval, open.into()) + // } + + // fn batch_verify( + // _params: &Self::Params, + // verifying_key: &::VKey, + // commitments: &[Self::Commitment], + // x: &ExpanderSingleVarChallenge, + // evals: &[::ChallengeField], + // opening: &Self::Opening, + // transcript: &mut impl Transcript, + // ) -> bool { + // kzg_batch_verify( + // verifying_key, + // commitments, + // &x.local_xs(), + // evals, + // opening, + // transcript, + // ) + // } } diff --git a/poly_commit/src/kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/pcs_trait_impl.rs index 0dcf407e..7e5bbf94 100644 --- a/poly_commit/src/kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/pcs_trait_impl.rs @@ -1,13 +1,9 @@ use std::marker::PhantomData; use arith::ExtensionField; -use arith::Field; use gkr_engine::{DeferredCheck, StructuredReferenceString, Transcript}; -use halo2curves::group::Group; -use halo2curves::msm::multiexp_serial; use halo2curves::{ ff::PrimeField, - group::Curve, pairing::{Engine, MultiMillerLoop}, CurveAffine, }; @@ -117,36 +113,7 @@ where _scratch_pad: &Self::ScratchPad, transcript: &mut impl Transcript, ) -> (Vec, Self::Opening) { - let rlc_randomness = transcript.generate_field_element::(); - let num_poly = polys.len(); - let rlcs = powers_series(&rlc_randomness, num_poly); - let mut buf = vec![E::Fr::default(); polys[0].coeffs.len()]; - - let merged_poly = polys - .iter() - .zip(rlcs.iter()) - .skip(1) - .fold(polys[0].clone(), |acc, (poly, r)| acc + &(poly * r)); - - let mut evals = polys - .iter() - .map(|p| MultiLinearPoly::evaluate_with_buffer(p.coeffs.as_ref(), x, &mut buf)) - .collect::>(); - - let (_batch_eval, open) = - coeff_form_uni_hyperkzg_open(proving_key, &merged_poly.coeffs, x, transcript); - - { - // sanity check: the merged evaluation should match the batch evaluation - // this step is not necessary if the performance is critical - let mut merged_eval = evals[0]; - for (eval, r) in evals.iter_mut().zip(rlcs.iter()).skip(1) { - merged_eval += *eval * r; - } - assert_eq!(_batch_eval, merged_eval); - } - - (evals, open) + kzg_batch_open(proving_key, polys, x, transcript) } fn batch_verify( @@ -158,27 +125,13 @@ where opening: &Self::Opening, transcript: &mut impl Transcript, ) -> bool { - let rlc_randomness = transcript.generate_field_element::(); - let num_poly = commitments.len(); - let rlcs = powers_series(&rlc_randomness, num_poly); + let commitment_unwrapped = commitments.iter().map(|c| c.0).collect::>(); - let commitments_local = commitments.iter().map(|c| c.0).collect::>(); - - // stay with single thread as the num_poly is usually small - let mut merged_commitment = E::G1::identity(); - multiexp_serial(&rlcs, &commitments_local, &mut merged_commitment); - - let merged_eval = evals - .iter() - .zip(rlcs.iter()) - .fold(E::Fr::zero(), |acc, (e, r)| acc + (*e * r)); - - Self::verify( - _params, + kzg_batch_verify( verifying_key, - &KZGCommitment(merged_commitment.to_affine()), + &commitment_unwrapped, x, - merged_eval, + evals, opening, transcript, ) From 231844dcee0e8a29ff5260789bb7b30a92eb4e06 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 27 May 2025 18:04:02 -0400 Subject: [PATCH 18/57] add bench --- poly_commit/benches/pcs_all.rs | 97 +++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/poly_commit/benches/pcs_all.rs b/poly_commit/benches/pcs_all.rs index 5c96cbaf..8e3fc0d0 100644 --- a/poly_commit/benches/pcs_all.rs +++ b/poly_commit/benches/pcs_all.rs @@ -1,4 +1,4 @@ -use arith::{Field, Fr}; +use arith::{ExtensionField, Field, Fr}; use ark_std::test_rng; use criterion::black_box; use gkr_engine::StructuredReferenceString; @@ -17,10 +17,10 @@ const NUM_POLY_BATCH_OPEN: usize = 100; fn main() { let mpi_config = MPIConfig::prover_new(); println!("=========================="); - for num_vars in 10..21 { + for num_vars in 18..21 { root_println!(mpi_config, "num vars: {}", num_vars); - bench_hyrax(&mpi_config, num_vars); bench_kzg(&mpi_config, num_vars); + bench_hyrax(&mpi_config, num_vars); bench_orion(&mpi_config, num_vars); println!("=========================="); } @@ -89,7 +89,7 @@ fn bench_hyrax(mpi_config: &MPIConfig, num_vars: usize) { ); // batch open - bench_hyrax_batch_open(mpi_config, num_vars, NUM_POLY_BATCH_OPEN); + bench_batch_open::>(mpi_config, num_vars, NUM_POLY_BATCH_OPEN); } fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { @@ -122,6 +122,9 @@ fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { &eval_point, "kzg small scalar ", ); + + // batch open + bench_batch_open::>(mpi_config, num_vars, NUM_POLY_BATCH_OPEN); } fn pcs_bench>( @@ -197,29 +200,28 @@ fn pcs_bench>( root_println!(mpi_config, " --- "); } -fn bench_hyrax_batch_open(mpi_config: &MPIConfig, num_vars: usize, num_poly: usize) { +fn bench_batch_open(mpi_config: &MPIConfig, num_vars: usize, num_poly: usize) +where + F: Field + ExtensionField, + PCS: PolynomialCommitmentScheme< + F, + Params = usize, + EvalPoint = Vec, + Poly = MultiLinearPoly, + >, +{ let mut rng = test_rng(); - let (srs, _) = as PolynomialCommitmentScheme>::gen_srs_for_testing( - &num_vars, &mut rng, - ); + let (srs, _) = PCS::gen_srs_for_testing(&num_vars, &mut rng); let (proving_key, verification_key) = srs.into_keys(); - let mut scratch_pad = - as PolynomialCommitmentScheme>::init_scratch_pad(&num_vars); + let mut scratch_pad = PCS::init_scratch_pad(&num_vars); let polys = (0..num_poly) - .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) + .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) .collect::>(); let commitments = polys .iter() - .map(|poly| { - as PolynomialCommitmentScheme>::commit( - &num_vars, - &proving_key, - poly, - &mut scratch_pad, - ) - }) + .map(|poly| PCS::commit(&num_vars, &proving_key, poly, &mut scratch_pad)) .collect::>(); let mut buf = vec![]; commitments.serialize_into(&mut buf).unwrap(); @@ -227,23 +229,22 @@ fn bench_hyrax_batch_open(mpi_config: &MPIConfig, num_vars: usize, num_poly: usi // open all polys at a single point let x = (0..num_vars) - .map(|_| Fr::random_unsafe(&mut rng)) + .map(|_| F::random_unsafe(&mut rng)) .collect::>(); let mut transcript = BytesHashTranscript::::new(); let timer = Timer::new( - format!("hyrax batch open {} polys ", num_poly).as_ref(), + format!("{} batch open {} polys ", PCS::NAME, num_poly).as_ref(), mpi_config.is_root(), ); - let (values, batch_opening) = - as PolynomialCommitmentScheme>::batch_open( - &num_vars, - &proving_key, - &polys, - x.as_ref(), - &mut scratch_pad, - &mut transcript, - ); + let (values, batch_opening) = PCS::batch_open( + &num_vars, + &proving_key, + &polys, + &x, + &mut scratch_pad, + &mut transcript, + ); timer.stop(); @@ -254,31 +255,39 @@ fn bench_hyrax_batch_open(mpi_config: &MPIConfig, num_vars: usize, num_poly: usi let mut transcript = BytesHashTranscript::::new(); let timer = Timer::new( - format!("hyrax batch verify {} polys ", num_poly).as_ref(), + format!("{} batch verify {} polys ", PCS::NAME, num_poly).as_ref(), mpi_config.is_root(), ); - assert!( - as PolynomialCommitmentScheme>::batch_verify( - &num_vars, - &verification_key, - &commitments, - x.as_ref(), - &values, - &batch_opening, - &mut transcript - ) - ); + assert!(PCS::batch_verify( + &num_vars, + &verification_key, + &commitments, + &x, + &values, + &batch_opening, + &mut transcript + )); timer.stop(); root_println!( mpi_config, "{}", - format!("hyrax batch {} poly commit size {}", num_poly, com_size), + format!( + "{} batch {} poly commit size {}", + PCS::NAME, + num_poly, + com_size + ), ); root_println!( mpi_config, "{}", - format!("hyrax batch {} poly open size {}", num_poly, open_size), + format!( + "{} batch {} poly open size {}", + PCS::NAME, + num_poly, + open_size + ), ); root_println!(mpi_config, " --- "); From 606c9f61cbd9512ee81f3aca2c85197a01891386 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 27 May 2025 18:08:37 -0400 Subject: [PATCH 19/57] fix warning --- poly_commit/tests/common.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index 39e22cc1..325eaaaf 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -44,6 +44,7 @@ pub fn test_pcs() where F: ExtensionField, @@ -100,6 +101,8 @@ where } } + +#[allow(dead_code)] pub fn test_pcs_for_expander_gkr< C: FieldEngine, T: Transcript, From 09fafa39493f5766b0c7330f939227dab3786127 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 27 May 2025 18:09:41 -0400 Subject: [PATCH 20/57] lint --- poly_commit/tests/common.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index 325eaaaf..924e74e4 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -101,7 +101,6 @@ where } } - #[allow(dead_code)] pub fn test_pcs_for_expander_gkr< C: FieldEngine, From 46ba7dd210cae2de4df2cc4b5ebb58caf0c2997e Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 27 May 2025 18:12:52 -0400 Subject: [PATCH 21/57] fix warnings --- poly_commit/tests/common.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index 924e74e4..58a9fcd0 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -165,6 +165,7 @@ pub fn test_pcs_for_expander_gkr< } } +#[allow(dead_code)] pub fn test_batching_for_expander_gkr() where C: FieldEngine, From 7d97254e2a0184cfbceb617892ea57fc7bbd1753 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 28 May 2025 10:43:37 -0400 Subject: [PATCH 22/57] refactor pcs trait --- poly_commit/src/hyrax/pcs_trait_impl.rs | 8 +++++ poly_commit/src/kzg/pcs_trait_impl.rs | 10 +++++- poly_commit/src/lib.rs | 2 +- poly_commit/src/orion/pcs_trait_impl.rs | 46 ------------------------- poly_commit/src/raw.rs | 23 ------------- poly_commit/src/traits.rs | 8 +++-- 6 files changed, 24 insertions(+), 73 deletions(-) diff --git a/poly_commit/src/hyrax/pcs_trait_impl.rs b/poly_commit/src/hyrax/pcs_trait_impl.rs index dab1f347..2998bba4 100644 --- a/poly_commit/src/hyrax/pcs_trait_impl.rs +++ b/poly_commit/src/hyrax/pcs_trait_impl.rs @@ -8,6 +8,7 @@ use serdes::ExpSerde; use crate::{ hyrax::hyrax_impl::{hyrax_commit, hyrax_open, hyrax_setup, hyrax_verify}, + traits::BatchOpeningPCS, HyraxCommitment, HyraxOpening, PedersenParams, PolynomialCommitmentScheme, }; @@ -76,7 +77,14 @@ where ) -> bool { hyrax_verify(verifying_key, commitment, x, v, opening) } +} +impl BatchOpeningPCS for HyraxPCS +where + C: CurveAffine + ExpSerde, + C::Scalar: ExtensionField + PrimeField, + C::ScalarExt: ExtensionField + PrimeField, +{ fn batch_open( _params: &Self::Params, proving_key: &::PKey, diff --git a/poly_commit/src/kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/pcs_trait_impl.rs index 7e5bbf94..ff296033 100644 --- a/poly_commit/src/kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/pcs_trait_impl.rs @@ -10,7 +10,7 @@ use halo2curves::{ use polynomials::MultiLinearPoly; use serdes::ExpSerde; -use crate::*; +use crate::{traits::BatchOpeningPCS, *}; use kzg::hyper_kzg::*; use super::deferred_pairing::PairingAccumulator; @@ -104,7 +104,15 @@ where pairing_check && partial_check } +} +impl BatchOpeningPCS for HyperKZGPCS +where + E: Engine + MultiMillerLoop, + E::Fr: ExtensionField + PrimeField, + E::G1Affine: ExpSerde + Default + CurveAffine, + E::G2Affine: ExpSerde + Default + CurveAffine, +{ fn batch_open( _params: &Self::Params, proving_key: &::PKey, diff --git a/poly_commit/src/lib.rs b/poly_commit/src/lib.rs index b3e158c5..2d131d8f 100644 --- a/poly_commit/src/lib.rs +++ b/poly_commit/src/lib.rs @@ -1,7 +1,7 @@ #![allow(clippy::manual_div_ceil)] mod traits; -pub use traits::PolynomialCommitmentScheme; +pub use traits::{BatchOpeningPCS, PolynomialCommitmentScheme}; pub const PCS_SOUNDNESS_BITS: usize = 128; diff --git a/poly_commit/src/orion/pcs_trait_impl.rs b/poly_commit/src/orion/pcs_trait_impl.rs index 2bde7fac..bae848e5 100644 --- a/poly_commit/src/orion/pcs_trait_impl.rs +++ b/poly_commit/src/orion/pcs_trait_impl.rs @@ -129,29 +129,6 @@ where assert_eq!(*params, vk.num_vars); orion_verify::<_, OpenPackF, _, ComPackF>(vk, commitment, x, &[], v, transcript, opening) } - - fn batch_open( - _params: &Self::Params, - _proving_key: &::PKey, - _polys: &[Self::Poly], - _x: &Self::EvalPoint, - _scratch_pad: &Self::ScratchPad, - _transcript: &mut impl Transcript, - ) -> (Vec, Self::Opening) { - unimplemented!("batch_open is not implemented for OrionBaseFieldPCS"); - } - - fn batch_verify( - _params: &Self::Params, - _verifying_key: &::VKey, - _commitments: &[Self::Commitment], - _x: &Self::EvalPoint, - _vs: &[EvalF], - _opening: &Self::Opening, - _transcript: &mut impl Transcript, - ) -> bool { - unimplemented!("batch_verify is not implemented for OrionBaseFieldPCS"); - } } pub struct OrionSIMDFieldPCS @@ -253,27 +230,4 @@ where assert_eq!(x.len(), vk.num_vars); orion_verify::<_, SimdF, _, ComPackF>(vk, commitment, x, &[], v, transcript, opening) } - - fn batch_open( - _params: &Self::Params, - _proving_key: &::PKey, - _polys: &[Self::Poly], - _x: &Self::EvalPoint, - _scratch_pad: &Self::ScratchPad, - _transcript: &mut impl Transcript, - ) -> (Vec, Self::Opening) { - unimplemented!("batch_open is not implemented for OrionSIMDFieldPCS"); - } - - fn batch_verify( - _params: &Self::Params, - _verifying_key: &::VKey, - _commitments: &[Self::Commitment], - _x: &Self::EvalPoint, - _vs: &[EvalF], - _opening: &Self::Opening, - _transcript: &mut impl Transcript, - ) -> bool { - unimplemented!("batch_verify is not implemented for OrionSIMDFieldPCS"); - } } diff --git a/poly_commit/src/raw.rs b/poly_commit/src/raw.rs index b9f42e3f..ce26f89c 100644 --- a/poly_commit/src/raw.rs +++ b/poly_commit/src/raw.rs @@ -113,29 +113,6 @@ impl PolynomialCommitmentScheme for RawMultiLinearPCS { &mut vec![F::ZERO; commitment.evals.len()], ) == v } - - fn batch_open( - _params: &Self::Params, - _proving_key: &::PKey, - _polys: &[Self::Poly], - _x: &Self::EvalPoint, - _scratch_pad: &Self::ScratchPad, - _transcript: &mut impl Transcript, - ) -> (Vec, Self::Opening) { - unimplemented!("batch_open is not implemented for RawMultiLinearPCS"); - } - - fn batch_verify( - _params: &Self::Params, - _verifying_key: &::VKey, - _commitments: &[Self::Commitment], - _x: &Self::EvalPoint, - _vs: &[F], - _opening: &Self::Opening, - _transcript: &mut impl Transcript, - ) -> bool { - unimplemented!("batch_verify is not implemented for RawMultiLinearPCS"); - } } // ================================================================================================= diff --git a/poly_commit/src/traits.rs b/poly_commit/src/traits.rs index 16385434..cef83ce0 100644 --- a/poly_commit/src/traits.rs +++ b/poly_commit/src/traits.rs @@ -56,8 +56,12 @@ pub trait PolynomialCommitmentScheme { opening: &Self::Opening, transcript: &mut impl Transcript, ) -> bool; +} - /// Open a set of polynomials at a point. +/// Batch opening polynomial commitment scheme trait. +/// This trait is implemented for homomorphic polynomial commitment schemes such as Hyrax and KZG +pub trait BatchOpeningPCS: PolynomialCommitmentScheme { + /// Open a set of polynomials at a single point. fn batch_open( params: &Self::Params, proving_key: &::PKey, @@ -67,7 +71,7 @@ pub trait PolynomialCommitmentScheme { transcript: &mut impl Transcript, ) -> (Vec, Self::Opening); - /// Verify the opening of a set of polynomials at a point. + /// Verify the opening of a set of polynomials at a single point. fn batch_verify( params: &Self::Params, verifying_key: &::VKey, From 1cb3117e51ae93479072df15964d5b9e9795e88e Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 28 May 2025 15:03:49 -0400 Subject: [PATCH 23/57] finally gets sumcheck correct --- Cargo.lock | 4 + arith/polynomials/Cargo.toml | 1 + arith/polynomials/src/lib.rs | 3 + arith/polynomials/src/mle.rs | 31 +- arith/polynomials/src/vp.rs | 618 ++++++++++++++++++++++ gkr_engine/src/transcript/definition.rs | 11 +- sumcheck/Cargo.toml | 6 + sumcheck/src/lib.rs | 3 + sumcheck/src/sumcheck_generic.rs | 141 +++++ sumcheck/src/sumcheck_generic/prover.rs | 241 +++++++++ sumcheck/src/sumcheck_generic/tests.rs | 195 +++++++ sumcheck/src/sumcheck_generic/verifier.rs | 285 ++++++++++ sumcheck/src/utils.rs | 51 +- 13 files changed, 1587 insertions(+), 3 deletions(-) create mode 100644 arith/polynomials/src/vp.rs create mode 100644 sumcheck/src/sumcheck_generic.rs create mode 100644 sumcheck/src/sumcheck_generic/prover.rs create mode 100644 sumcheck/src/sumcheck_generic/tests.rs create mode 100644 sumcheck/src/sumcheck_generic/verifier.rs diff --git a/Cargo.lock b/Cargo.lock index 00d0594e..9bd63176 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1773,6 +1773,7 @@ dependencies = [ "halo2curves", "itertools 0.13.0", "rand", + "serdes", ] [[package]] @@ -2161,11 +2162,14 @@ name = "sumcheck" version = "0.1.0" dependencies = [ "arith", + "ark-std", "circuit", "env_logger", "gkr_engine", + "gkr_hashers", "log", "polynomials", + "serdes", "transcript", "utils", ] diff --git a/arith/polynomials/Cargo.toml b/arith/polynomials/Cargo.toml index 41889d63..62ffdf63 100644 --- a/arith/polynomials/Cargo.toml +++ b/arith/polynomials/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] arith = { path = "../" } +serdes = { path = "../../serdes" } ark-std.workspace = true criterion.workspace = true diff --git a/arith/polynomials/src/lib.rs b/arith/polynomials/src/lib.rs index e1206ffd..6495100d 100644 --- a/arith/polynomials/src/lib.rs +++ b/arith/polynomials/src/lib.rs @@ -10,5 +10,8 @@ pub use univariate::*; mod eq; pub use eq::*; +mod vp; +pub use vp::*; + #[cfg(test)] mod tests; diff --git a/arith/polynomials/src/mle.rs b/arith/polynomials/src/mle.rs index fab5a0f6..55b23072 100644 --- a/arith/polynomials/src/mle.rs +++ b/arith/polynomials/src/mle.rs @@ -5,7 +5,7 @@ use ark_std::log2; use crate::{EqPolynomial, MultilinearExtension, MutableMultilinearExtension}; -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct MultiLinearPoly { pub coeffs: Vec, } @@ -87,6 +87,35 @@ impl MultiLinearPoly { self.coeffs.truncate(n); } + #[inline] + pub fn fix_bottom_variable(&mut self, point: &F) { + let n = self.coeffs.len() / 2; + + // evaluate single variable of partial point from left to right + + for i in 0..n { + self.coeffs[i] = + self.coeffs[i] + (self.coeffs[(i << 1) + 1] - self.coeffs[i << 1]) * point; + } + self.coeffs.truncate(n); + } + + /// Hyperplonk's implementation + /// Evaluate the polynomial at a set of variables, from top to bottom + /// This is equivalent to `evaluate` when partial_point.len() = nv + /// + /// This matches the behavior of Hyperplonk's polynomial evaluation + #[inline] + pub fn eval_reverse_order>(&self, partial_point: &[AF]) -> F { + // evaluate single variable of partial point from left to right + let mut tmp = self.clone(); + partial_point + .iter() + .for_each(|point| tmp.fix_top_variable(*point)); + + tmp.coeffs[0] + } + /// Hyperplonk's implementation /// Evaluate the polynomial at a set of variables, from bottom to top /// This is equivalent to `evaluate` when partial_point.len() = nv diff --git a/arith/polynomials/src/vp.rs b/arith/polynomials/src/vp.rs new file mode 100644 index 00000000..e9a711a5 --- /dev/null +++ b/arith/polynomials/src/vp.rs @@ -0,0 +1,618 @@ +// Copyright (c) 2023 Espresso Systems (espressosys.com) +// This file is part of the HyperPlonk library. + +// You should have received a copy of the MIT License +// along with the HyperPlonk library. If not, see . + +//! This module defines our main mathematical object `VirtualPolynomial`; and +//! various functions associated with it. + +use core::panic; +use std::{cmp::max, collections::HashMap, marker::PhantomData, ops::Add, sync::Arc}; + +use arith::Field; +use ark_std::{ + end_timer, + rand::{Rng, RngCore}, + start_timer, +}; +use serdes::ExpSerde; + +use crate::MultiLinearPoly; + +#[rustfmt::skip] +/// A virtual polynomial is a sum of products of multilinear polynomials; +/// where the multilinear polynomials are stored via their multilinear +/// extensions: `(coefficient, DenseMultilinearExtension)` +/// +/// * Number of products n = `polynomial.products.len()`, +/// * Number of multiplicands of ith product m_i = +/// `polynomial.products[i].1.len()`, +/// * Coefficient of ith product c_i = `polynomial.products[i].0` +/// +/// The resulting polynomial is +/// +/// $$ \sum_{i=0}^{n} c_i \cdot \prod_{j=0}^{m_i} P_{ij} $$ +/// +/// Example: +/// f = c0 * f0 * f1 * f2 + c1 * f3 * f4 +/// where f0 ... f4 are multilinear polynomials +/// +/// - flattened_ml_extensions stores the multilinear extension representation of +/// f0, f1, f2, f3 and f4 +/// - products is +/// \[ +/// (c0, \[0, 1, 2\]), +/// (c1, \[3, 4\]) +/// \] +/// - raw_pointers_lookup_table maps fi to i +/// +#[derive(Clone, Debug, Default, PartialEq)] +pub struct VirtualPolynomial { + /// Aux information about the multilinear polynomial + pub aux_info: VPAuxInfo, + /// list of reference to products (as usize) of multilinear extension + pub products: Vec<(F, Vec)>, + /// Stores multilinear extensions in which product multiplicand can refer + /// to. + pub flattened_ml_extensions: Vec>>, + /// Pointers to the above poly extensions + raw_pointers_lookup_table: HashMap<*const MultiLinearPoly, usize>, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +/// Auxiliary information about the multilinear polynomial +pub struct VPAuxInfo { + /// max number of multiplicands in each product + pub max_degree: usize, + /// number of variables of the polynomial + pub num_variables: usize, + /// Associated field + #[doc(hidden)] + pub phantom: PhantomData, +} + +impl ExpSerde for VPAuxInfo { + fn serialize_into(&self, mut writer: W) -> serdes::SerdeResult<()> { + self.max_degree.serialize_into(&mut writer)?; + self.num_variables.serialize_into(&mut writer)?; + + Ok(()) + } + + fn deserialize_from(mut reader: R) -> serdes::SerdeResult { + let max_degree = usize::deserialize_from(&mut reader)?; + let num_variables = usize::deserialize_from(&mut reader)?; + + Ok(VPAuxInfo { + max_degree, + num_variables, + phantom: PhantomData, + }) + } +} + +impl Add for &VirtualPolynomial { + type Output = VirtualPolynomial; + fn add(self, other: &VirtualPolynomial) -> Self::Output { + let start = start_timer!(|| "virtual poly add"); + let mut res = self.clone(); + for products in other.products.iter() { + let cur: Vec>> = products + .1 + .iter() + .map(|&x| other.flattened_ml_extensions[x].clone()) + .collect(); + + res.add_mle_list(cur, products.0) + } + end_timer!(start); + res + } +} + +// TODO: convert this into a trait +impl VirtualPolynomial { + /// Creates an empty virtual polynomial with `num_variables`. + pub fn new(num_variables: usize) -> Self { + VirtualPolynomial { + aux_info: VPAuxInfo { + max_degree: 0, + num_variables, + phantom: PhantomData, + }, + products: Vec::new(), + flattened_ml_extensions: Vec::new(), + raw_pointers_lookup_table: HashMap::new(), + } + } + + /// Creates an new virtual polynomial from a MLE and its coefficient. + pub fn new_from_mle(mle: &Arc>, coefficient: F) -> Self { + let mle_ptr: *const MultiLinearPoly = Arc::as_ptr(mle); + let mut hm = HashMap::new(); + hm.insert(mle_ptr, 0); + + VirtualPolynomial { + aux_info: VPAuxInfo { + // The max degree is the max degree of any individual variable + max_degree: 1, + num_variables: mle.get_num_vars(), + phantom: PhantomData, + }, + // here `0` points to the first polynomial of `flattened_ml_extensions` + products: vec![(coefficient, vec![0])], + flattened_ml_extensions: vec![mle.clone()], + raw_pointers_lookup_table: hm, + } + } + + /// Add a product of list of multilinear extensions to self + /// Returns an error if the list is empty, or the MLE has a different + /// `num_vars` from self. + /// + /// The MLEs will be multiplied together, and then multiplied by the scalar + /// `coefficient`. + pub fn add_mle_list( + &mut self, + mle_list: impl IntoIterator>>, + coefficient: F, + ) { + let mle_list: Vec>> = mle_list.into_iter().collect(); + let mut indexed_product = Vec::with_capacity(mle_list.len()); + + if mle_list.is_empty() { + panic!("input mle_list is empty"); + } + + self.aux_info.max_degree = max(self.aux_info.max_degree, mle_list.len()); + + for mle in mle_list { + if mle.get_num_vars() != self.aux_info.num_variables { + panic!( + "product has a multiplicand with wrong number of variables {} vs {}", + mle.get_num_vars(), + self.aux_info.num_variables + ); + } + + let mle_ptr: *const MultiLinearPoly = Arc::as_ptr(&mle); + if let Some(index) = self.raw_pointers_lookup_table.get(&mle_ptr) { + indexed_product.push(*index) + } else { + let curr_index = self.flattened_ml_extensions.len(); + self.flattened_ml_extensions.push(mle.clone()); + self.raw_pointers_lookup_table.insert(mle_ptr, curr_index); + indexed_product.push(curr_index); + } + } + self.products.push((coefficient, indexed_product)); + } + + /// Multiple the current VirtualPolynomial by an MLE: + /// - add the MLE to the MLE list; + /// - multiple each product by MLE and its coefficient. + /// + /// Returns an error if the MLE has a different `num_vars` from self. + pub fn mul_by_mle(&mut self, mle: Arc>, coefficient: F) { + let start = start_timer!(|| "mul by mle"); + + if mle.get_num_vars() != self.aux_info.num_variables { + panic!( + "product has a multiplicand with wrong number of variables {} vs {}", + mle.get_num_vars(), + self.aux_info.num_variables + ); + } + + let mle_ptr: *const MultiLinearPoly = Arc::as_ptr(&mle); + + // check if this mle already exists in the virtual polynomial + let mle_index = match self.raw_pointers_lookup_table.get(&mle_ptr) { + Some(&p) => p, + None => { + self.raw_pointers_lookup_table + .insert(mle_ptr, self.flattened_ml_extensions.len()); + self.flattened_ml_extensions.push(mle); + self.flattened_ml_extensions.len() - 1 + } + }; + + for (prod_coef, indices) in self.products.iter_mut() { + // - add the MLE to the MLE list; + // - multiple each product by MLE and its coefficient. + indices.push(mle_index); + *prod_coef *= coefficient; + } + + // increase the max degree by one as the MLE has degree 1. + self.aux_info.max_degree += 1; + end_timer!(start); + } + + /// Evaluate the virtual polynomial at point `point`. + /// Returns an error is point.len() does not match `num_variables`. + pub fn evaluate(&self, point: &[F]) -> F { + let start = start_timer!(|| "evaluation"); + + if self.aux_info.num_variables != point.len() { + panic!( + "wrong number of variables {} vs {}", + self.aux_info.num_variables, + point.len() + ); + } + + let evals: Vec = self + .flattened_ml_extensions + .iter() + .map(|x| x.eval_reverse_order(point)) + .collect(); + + let res = self + .products + .iter() + .map(|(c, p)| *c * p.iter().map(|&i| evals[i]).product::()) + .sum(); + + end_timer!(start); + res + } + + /// Sample a random virtual polynomial, return the polynomial and its sum. + pub fn rand( + nv: usize, + num_multiplicands_range: (usize, usize), + num_products: usize, + rng: &mut R, + ) -> (Self, F) { + let start = start_timer!(|| "sample random virtual polynomial"); + + let mut sum = F::zero(); + let mut poly = VirtualPolynomial::new(nv); + for _ in 0..num_products { + let num_multiplicands = + rng.gen_range(num_multiplicands_range.0..num_multiplicands_range.1); + let (product, product_sum) = random_mle_list(nv, num_multiplicands, rng); + // let coefficient = F::random_unsafe(&mut *rng); + let coefficient = F::one(); + poly.add_mle_list(product.into_iter(), coefficient); + sum += product_sum * coefficient; + } + + end_timer!(start); + (poly, sum) + } + + /// Sample a random virtual polynomial that evaluates to zero everywhere + /// over the boolean hypercube. + pub fn rand_zero( + nv: usize, + num_multiplicands_range: (usize, usize), + num_products: usize, + rng: &mut R, + ) -> Self { + let mut poly = VirtualPolynomial::new(nv); + for _ in 0..num_products { + let num_multiplicands = + rng.gen_range(num_multiplicands_range.0..num_multiplicands_range.1); + let product = random_zero_mle_list(nv, num_multiplicands, &mut *rng); + let coefficient = F::random_unsafe(&mut *rng); + poly.add_mle_list(product.into_iter(), coefficient); + } + + poly + } + + // Input poly f(x) and a random vector r, output + // \hat f(x) = \sum_{x_i \in eval_x} f(x_i) eq(x, r) + // where + // eq(x,y) = \prod_i=1^num_var (x_i * y_i + (1-x_i)*(1-y_i)) + // + // This function is used in ZeroCheck. + pub fn build_f_hat(&self, r: &[F]) -> Self { + let start = start_timer!(|| "zero check build hat f"); + + if self.aux_info.num_variables != r.len() { + panic!( + "r.len() is different from number of variables {} vs {}", + r.len(), + self.aux_info.num_variables + ); + } + + let eq_x_r = build_eq_x_r(r); + let mut res = self.clone(); + res.mul_by_mle(eq_x_r, F::one()); + + end_timer!(start); + res + } + + /// Print out the evaluation map for testing. Panic if the num_vars > 5. + pub fn print_evals(&self) { + if self.aux_info.num_variables > 5 { + panic!("this function is used for testing only. cannot print more than 5 num_vars") + } + for i in 0..1 << self.aux_info.num_variables { + let point = bit_decompose(i, self.aux_info.num_variables); + let point_fr: Vec = point.iter().map(|&x| F::from(x as u32)).collect(); + println!("{} {:?}", i, self.evaluate(point_fr.as_ref())) + } + println!() + } +} + +/// Evaluate eq polynomial. +pub fn eq_eval(x: &[F], y: &[F]) -> F { + if x.len() != y.len() { + panic!("x and y have different length {} vs {}", x.len(), y.len()); + } + let start = start_timer!(|| "eq_eval"); + let mut res = F::one(); + for (&xi, &yi) in x.iter().zip(y.iter()) { + let xi_yi = xi * yi; + res *= xi_yi + xi_yi - xi - yi + F::one(); + } + end_timer!(start); + res +} + +/// This function build the eq(x, r) polynomial for any given r. +/// +/// Evaluate +/// eq(x,y) = \prod_i=1^num_var (x_i * y_i + (1-x_i)*(1-y_i)) +/// over r, which is +/// eq(x,y) = \prod_i=1^num_var (x_i * r_i + (1-x_i)*(1-r_i)) +pub fn build_eq_x_r(r: &[F]) -> Arc> { + let evals = build_eq_x_r_vec(r); + let mle = MultiLinearPoly { coeffs: evals }; + + Arc::new(mle) +} +/// This function build the eq(x, r) polynomial for any given r, and output the +/// evaluation of eq(x, r) in its vector form. +/// +/// Evaluate +/// eq(x,y) = \prod_i=1^num_var (x_i * y_i + (1-x_i)*(1-y_i)) +/// over r, which is +/// eq(x,y) = \prod_i=1^num_var (x_i * r_i + (1-x_i)*(1-r_i)) +pub fn build_eq_x_r_vec(r: &[F]) -> Vec { + // we build eq(x,r) from its evaluations + // we want to evaluate eq(x,r) over x \in {0, 1}^num_vars + // for example, with num_vars = 4, x is a binary vector of 4, then + // 0 0 0 0 -> (1-r0) * (1-r1) * (1-r2) * (1-r3) + // 1 0 0 0 -> r0 * (1-r1) * (1-r2) * (1-r3) + // 0 1 0 0 -> (1-r0) * r1 * (1-r2) * (1-r3) + // 1 1 0 0 -> r0 * r1 * (1-r2) * (1-r3) + // .... + // 1 1 1 1 -> r0 * r1 * r2 * r3 + // we will need 2^num_var evaluations + + let mut eval = Vec::new(); + build_eq_x_r_helper(r, &mut eval); + + eval +} + +/// A helper function to build eq(x, r) recursively. +/// This function takes `r.len()` steps, and for each step it requires a maximum +/// `r.len()-1` multiplications. +fn build_eq_x_r_helper(r: &[F], buf: &mut Vec) { + if r.is_empty() { + panic!("r length is 0"); + } else if r.len() == 1 { + // initializing the buffer with [1-r_0, r_0] + buf.push(F::one() - r[0]); + buf.push(r[0]); + } else { + build_eq_x_r_helper(&r[1..], buf); + + // suppose at the previous step we received [b_1, ..., b_k] + // for the current step we will need + // if x_0 = 0: (1-r0) * [b_1, ..., b_k] + // if x_0 = 1: r0 * [b_1, ..., b_k] + // let mut res = vec![]; + // for &b_i in buf.iter() { + // let tmp = r[0] * b_i; + // res.push(b_i - tmp); + // res.push(tmp); + // } + // *buf = res; + + let mut res = vec![F::zero(); buf.len() << 1]; + res.iter_mut().enumerate().for_each(|(i, val)| { + let bi = buf[i >> 1]; + let tmp = r[0] * bi; + if i & 1 == 0 { + *val = bi - tmp; + } else { + *val = tmp; + } + }); + *buf = res; + } +} + +/// Decompose an integer into a binary vector in little endian. +pub fn bit_decompose(input: u64, num_var: usize) -> Vec { + let mut res = Vec::with_capacity(num_var); + let mut i = input; + for _ in 0..num_var { + res.push(i & 1 == 1); + i >>= 1; + } + res +} + +/// Sample a random list of multilinear polynomials. +/// Returns +/// - the list of polynomials, +/// - its sum of polynomial evaluations over the boolean hypercube. +pub fn random_mle_list( + nv: usize, + degree: usize, + rng: &mut R, +) -> (Vec>>, F) { + let mut ctr = 0u32; + + let mut multiplicands = Vec::with_capacity(degree); + for _ in 0..degree { + multiplicands.push(Vec::with_capacity(1 << nv)) + } + let mut sum = F::zero(); + + for _ in 0..(1 << nv) { + let mut product = F::one(); + + for e in multiplicands.iter_mut() { + // let val = F::random_unsafe(&mut *rng); + let val = F::from(ctr); + ctr += 1; + + e.push(val); + product *= val; + } + sum += product; + } + + let list = multiplicands + .into_iter() + .map(|x| Arc::new(MultiLinearPoly { coeffs: x })) + .collect(); + + (list, sum) +} + +// Build a randomize list of mle-s whose sum is zero. +pub fn random_zero_mle_list( + nv: usize, + degree: usize, + rng: &mut R, +) -> Vec>> { + let start = start_timer!(|| "sample random zero mle list"); + + let mut multiplicands = Vec::with_capacity(degree); + for _ in 0..degree { + multiplicands.push(Vec::with_capacity(1 << nv)) + } + for _ in 0..(1 << nv) { + multiplicands[0].push(F::zero()); + for e in multiplicands.iter_mut().skip(1) { + e.push(F::random_unsafe(&mut *rng)); + } + } + + let list = multiplicands + .into_iter() + .map(|x| Arc::new(MultiLinearPoly { coeffs: x })) + .collect(); + + end_timer!(start); + list +} + +#[cfg(test)] +mod test { + use super::*; + use arith::Fr; + use ark_std::test_rng; + + #[test] + fn test_virtual_polynomial_additions() { + let mut rng = test_rng(); + for nv in 2..5 { + for num_products in 2..5 { + let base: Vec = (0..nv).map(|_| Fr::random_unsafe(&mut rng)).collect(); + + let (a, _a_sum) = VirtualPolynomial::::rand(nv, (2, 3), num_products, &mut rng); + let (b, _b_sum) = VirtualPolynomial::::rand(nv, (2, 3), num_products, &mut rng); + let c = &a + &b; + + assert_eq!( + a.evaluate(base.as_ref()) + b.evaluate(base.as_ref()), + c.evaluate(base.as_ref()) + ); + } + } + } + + #[test] + fn test_virtual_polynomial_mul_by_mle() { + let mut rng = test_rng(); + for nv in 2..5 { + for num_products in 2..5 { + let base: Vec = (0..nv).map(|_| Fr::random_unsafe(&mut rng)).collect(); + + let (a, _a_sum) = VirtualPolynomial::::rand(nv, (2, 3), num_products, &mut rng); + let (b, _b_sum) = random_mle_list(nv, 1, &mut rng); + let b_mle = b[0].clone(); + let coeff = Fr::random_unsafe(&mut rng); + let b_vp = VirtualPolynomial::new_from_mle(&b_mle, coeff); + + let mut c = a.clone(); + + c.mul_by_mle(b_mle, coeff); + + assert_eq!( + a.evaluate(base.as_ref()) * b_vp.evaluate(base.as_ref()), + c.evaluate(base.as_ref()) + ); + } + } + } + + #[test] + fn test_eq_xr() { + let mut rng = test_rng(); + for nv in 4..10 { + let r: Vec = (0..nv).map(|_| Fr::random_unsafe(&mut rng)).collect(); + let eq_x_r = build_eq_x_r(r.as_ref()); + let eq_x_r2 = build_eq_x_r_for_test(r.as_ref()); + let eq_x_r3 = crate::EqPolynomial::build_eq_x_r(r.as_ref()); + assert_eq!(eq_x_r, eq_x_r2); + assert_eq!(eq_x_r.coeffs, eq_x_r3); + } + } + + /// Naive method to build eq(x, r). + /// Only used for testing purpose. + // Evaluate + // eq(x,y) = \prod_i=1^num_var (x_i * y_i + (1-x_i)*(1-y_i)) + // over r, which is + // eq(x,y) = \prod_i=1^num_var (x_i * r_i + (1-x_i)*(1-r_i)) + fn build_eq_x_r_for_test(r: &[F]) -> Arc> { + // we build eq(x,r) from its evaluations + // we want to evaluate eq(x,r) over x \in {0, 1}^num_vars + // for example, with num_vars = 4, x is a binary vector of 4, then + // 0 0 0 0 -> (1-r0) * (1-r1) * (1-r2) * (1-r3) + // 1 0 0 0 -> r0 * (1-r1) * (1-r2) * (1-r3) + // 0 1 0 0 -> (1-r0) * r1 * (1-r2) * (1-r3) + // 1 1 0 0 -> r0 * r1 * (1-r2) * (1-r3) + // .... + // 1 1 1 1 -> r0 * r1 * r2 * r3 + // we will need 2^num_var evaluations + + // First, we build array for {1 - r_i} + let one_minus_r: Vec = r.iter().map(|ri| F::one() - ri).collect(); + + let num_var = r.len(); + let mut eval = vec![]; + + for i in 0..1 << num_var { + let mut current_eval = F::one(); + let bit_sequence = bit_decompose(i, num_var); + + for (&bit, (ri, one_minus_ri)) in + bit_sequence.iter().zip(r.iter().zip(one_minus_r.iter())) + { + current_eval *= if bit { *ri } else { *one_minus_ri }; + } + eval.push(current_eval); + } + + let mle = MultiLinearPoly { coeffs: eval }; + + Arc::new(mle) + } +} diff --git a/gkr_engine/src/transcript/definition.rs b/gkr_engine/src/transcript/definition.rs index 76589698..971b0d8e 100644 --- a/gkr_engine/src/transcript/definition.rs +++ b/gkr_engine/src/transcript/definition.rs @@ -1,6 +1,7 @@ use std::{fmt::Debug, str::FromStr}; use arith::Field; +use serdes::ExpSerde; use crate::ExpErrors; @@ -27,6 +28,13 @@ pub trait Transcript: Clone + Debug { /// Append a slice of bytes fn append_u8_slice(&mut self, buffer: &[u8]); + + fn append_serializable_data(&mut self, data: &T) { + let mut buf = vec![]; + data.serialize_into(&mut buf).unwrap(); + self.append_u8_slice(&buf); + } + /* self.proof.bytes.extend_from_slice(buffer); */ @@ -47,7 +55,8 @@ pub trait Transcript: Clone + Debug { /// Generate a field element. #[inline(always)] fn generate_field_element(&mut self) -> F { - F::from_uniform_bytes(&self.generate_u8_slice(F::SIZE)) + F::from((self.generate_u8_slice(1)[0] + 1) as u32) + // F::from_uniform_bytes(&self.generate_u8_slice(F::SIZE)) } /// Generate a field element vector. diff --git a/sumcheck/Cargo.toml b/sumcheck/Cargo.toml index 4fa75da6..86445469 100644 --- a/sumcheck/Cargo.toml +++ b/sumcheck/Cargo.toml @@ -7,12 +7,18 @@ edition = "2021" arith = { path = "../arith" } circuit = { path = "../circuit" } gkr_engine = { path = "../gkr_engine" } +gkr_hashers = { path = "../hasher" } polynomials = { path = "../arith/polynomials" } +serdes = { path = "../serdes" } transcript = { path = "../transcript" } utils = { path = "../utils" } env_logger.workspace = true log.workspace = true +[dev-dependencies] +ark-std.workspace = true + + [features] profile = [ "utils/profile" ] diff --git a/sumcheck/src/lib.rs b/sumcheck/src/lib.rs index 18d61b7f..dbaed35c 100644 --- a/sumcheck/src/lib.rs +++ b/sumcheck/src/lib.rs @@ -1,6 +1,9 @@ mod sumcheck; pub use sumcheck::*; +mod sumcheck_generic; +pub use sumcheck_generic::*; + mod prover_helper; mod verifier_helper; diff --git a/sumcheck/src/sumcheck_generic.rs b/sumcheck/src/sumcheck_generic.rs new file mode 100644 index 00000000..a6b6aa71 --- /dev/null +++ b/sumcheck/src/sumcheck_generic.rs @@ -0,0 +1,141 @@ +use std::ops::Mul; + +use arith::Field; +use gkr_engine::Transcript; +use polynomials::{MultiLinearPoly, VPAuxInfo, VirtualPolynomial}; +use serdes::ExpSerde; + +mod prover; +pub use prover::*; + +mod verifier; +pub use verifier::*; + +#[cfg(test)] +mod tests; + +// /// An IOP proof is a collections of +// /// - messages from prover to verifier at each round through the interactive protocol. +// /// - a point that is generated by the transcript for evaluation +// #[derive(Clone, Debug, Default, PartialEq, Eq)] +// pub struct IOPProof { +// // pub point: Vec, +// pub proofs: Vec>, +// } + +/// An IOP proof is a collections of messages from prover to verifier at each +/// round through the interactive protocol. +#[derive(Clone, Debug, Default, PartialEq)] +pub struct IOPProof { + pub proofs: Vec>, +} + +/// A message from the prover to the verifier at a given round +/// is a list of evaluations. +#[derive(Clone, Debug, Default, PartialEq, Eq, ExpSerde)] +pub struct IOPProverMessage { + pub(crate) evaluations: Vec, +} + +/// Prover State of a PolyIOP. +pub struct IOPProverState { + /// sampled randomness given by the verifier + pub challenges: Vec, + /// number of variables in the polynomial + pub(crate) init_num_vars: usize, + /// the current round number + pub(crate) round: usize, + /// list of MLE poly + // todo: change this to reference + // pub mle_list: Vec>, + pub mle: MultiLinearPoly, + // /// pointer to the virtual polynomial + // pub(crate) poly: VirtualPolynomial, + // /// points with precomputed barycentric weights for extrapolating smaller + // /// degree uni-polys to `max_degree + 1` evaluations. + // pub(crate) extrapolation_aux: Vec<(Vec, Vec)>, +} + +/// Prover State of a PolyIOP +pub struct IOPVerifierState { + pub(crate) round: usize, + pub(crate) num_vars: usize, + // pub(crate) max_degree: usize, + pub(crate) finished: bool, + /// a list storing the univariate polynomial in evaluation form sent by the + /// prover at each round + pub(crate) polynomials_received: Vec>, + /// a list storing the randomness sampled by the verifier at each round + pub(crate) challenges: Vec, +} + +/// A SumCheckSubClaim is a claim generated by the verifier at the end of +/// verification when it is convinced. +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct SumCheckSubClaim { + /// the multi-dimensional point that this multilinear extension is evaluated + /// to + pub point: Vec, + /// the expected evaluation + pub expected_evaluation: F, +} + +// pub struct Sumcheck { +// phantom: std::marker::PhantomData, +// } + +// impl Sumcheck { +// /// Extract sum from the proof +// pub fn extract_sum(proof: &IOPProof) -> F { +// proof.proofs[0].evaluations[0] + proof.proofs[0].evaluations[1] +// } + +// /// Generate proof of the sum of polynomial over {0,1}^`num_vars` +// /// +// /// The polynomial is represented in the form of a VirtualPolynomial. +// pub fn prove( +// poly_list: &[MultiLinearPoly], +// // poly: &VirtualPolynomial, +// transcript: &mut impl Transcript) -> IOPProof { +// // transcript.append_serializable_data(&poly.aux_info); + +// let mut prover_state = IOPProverState::prover_init(poly); +// let mut challenge = None; +// let mut prover_msgs = Vec::with_capacity(poly.aux_info.num_variables); +// for _ in 0..poly.aux_info.num_variables { +// let prover_msg = +// IOPProverState::prove_round_and_update_state(&mut prover_state, &challenge); +// transcript.append_serializable_data(&prover_msg); +// prover_msgs.push(prover_msg); +// challenge = Some(transcript.generate_field_element::()); +// } + +// println!("prover challenges: {:?}", prover_state.challenges); +// IOPProof { +// proofs: prover_msgs, +// } +// } + +// /// Verify the claimed sum using the proof +// pub fn verify( +// claimed_sum: F, +// proof: &IOPProof, +// aux_info: &VPAuxInfo, +// transcript: &mut impl Transcript, +// ) -> SumCheckSubClaim { +// transcript.append_serializable_data(aux_info); +// let mut verifier_state = IOPVerifierState::verifier_init(aux_info); +// for i in 0..aux_info.num_variables { +// let prover_msg = proof.proofs.get(i).expect("proof is incomplete"); +// transcript.append_serializable_data(prover_msg); +// IOPVerifierState::verify_round_and_update_state( +// &mut verifier_state, +// prover_msg, +// transcript, +// ); +// } + +// println!("verifier challenges: {:?}", verifier_state.challenges); +// IOPVerifierState::check_and_generate_subclaim(&verifier_state, &claimed_sum) +// } +// } diff --git a/sumcheck/src/sumcheck_generic/prover.rs b/sumcheck/src/sumcheck_generic/prover.rs new file mode 100644 index 00000000..9175d8f1 --- /dev/null +++ b/sumcheck/src/sumcheck_generic/prover.rs @@ -0,0 +1,241 @@ +// Copyright (c) 2023 Espresso Systems (espressosys.com) +// This file is part of the HyperPlonk library. + +// You should have received a copy of the MIT License +// along with the HyperPlonk library. If not, see . + +//! Prover subroutines for a SumCheck protocol. + +use std::sync::Arc; + +use arith::Field; +use polynomials::{MultiLinearPoly, MultilinearExtension, VirtualPolynomial}; + +use crate::batch_inversion; + +use super::{IOPProverMessage, IOPProverState}; + +impl IOPProverState { + /// Initialize the prover state to argue for the sum of the input polynomial + /// over {0,1}^`num_vars`. + pub fn prover_init( + // polynomials: + // &[MultiLinearPoly] + polynomial: MultiLinearPoly, // &VirtualPolynomial + ) -> Self { + // if polynomial.aux_info.num_variables == 0 { + // panic!("Prover cannot prove a polynomial with no variables."); + // } + + Self { + challenges: Vec::with_capacity(polynomial.num_vars()), + round: 0, + init_num_vars: polynomial.num_vars(), + // mle_list: polynomials.to_vec(), + mle: polynomial.clone(), + // extrapolation_aux: (1..polynomial.aux_info.max_degree) + // .map(|degree| { + // let points = (0..1 + degree as u32).map(F::from).collect::>(); + // let weights = barycentric_weights(&points); + // (points, weights) + // }) + // .collect(), + } + } + + /// Receive message from verifier, generate prover message, and proceed to + /// next round. + /// + /// Main algorithm used is from section 3.2 of [XZZPS19](https://eprint.iacr.org/2019/317.pdf#subsection.3.2). + pub fn prove_round_and_update_state(&mut self, challenge: &Option) -> IOPProverMessage { + if self.round >= self.init_num_vars { + panic!("prover is not active") + } + + println!( + "Prover round {}: fixing variable with challenge {:?}", + self.round, challenge + ); + + let mut mle = self.mle.clone(); + println!("mle before eval: {:?}", mle); + + // let fix_argument = start_timer!(|| "fix argument"); + + // Step 1: + // fix argument and evaluate f(x) over x_m = r; where r is the challenge + // for the current round, and m is the round number, indexed from 1 + // + // i.e.: + // at round m <= n, for each mle g(x_1, ... x_n) within the flattened_mle + // which has already been evaluated to + // + // g(r_1, ..., r_{m-1}, x_m ... x_n) + // + // eval g over r_m, and mutate g to g(r_1, ... r_m,, x_{m+1}... x_n) + // let mut flattened_ml_extensions: Vec> = self + // .poly + // .flattened_ml_extensions + // .iter() + // .map(|x| x.as_ref().clone()) + // .collect(); + + if let Some(chal) = challenge { + if self.round == 0 { + panic!("first round should not have a challenge"); + } + self.challenges.push(*chal); + + let r = self.challenges[self.round - 1]; + + mle.fix_top_variable(r); + // mle.fix_bottom_variable(&r); + + // self.mle_list.iter_mut().for_each(|mle| + // // (ZZ: may be buggy) + // mle.fix_bottom_variable(&r)); + // // mle.fix_top_variable(r)); + } else if self.round > 0 { + panic!("verifier message is empty") + } + + println!("mle after eval: {:?}", mle); + + // end_timer!(fix_argument); + + self.round += 1; + + let len = mle.coeffs.len() / 2; + let f_0 = mle.coeffs[..len].iter().sum::(); + let f_1 = mle.coeffs[len..].iter().sum::(); + + self.mle = mle; + + let msg = IOPProverMessage { + evaluations: vec![f_0, f_1], + }; + + println!("Prover message: {:?}", msg); + msg + + // let products_list = self.poly.products.clone(); + // let mut products_sum = vec![F::zero(); self.poly.aux_info.max_degree + 1]; + + // println!("max degree: {:?}", self.poly.aux_info.max_degree); + // println!("product sum: {:?}", products_sum); + + // Step 2: generate sum for the partial evaluated polynomial: + // f(r_1, ... r_m,, x_{m+1}... x_n) + + // let mut sum = F::zero(); + // // products_sum.iter_mut().enumerate().for_each(|(t, e)| { + // // for b in 0..1 << (self.poly.aux_info.num_variables - self.round) { + // for b in 0..1 << (self.init_num_vars - self.round) { + // // evaluate P_round(t) + // for mle in self.mle_list.iter() { + // // let num_mles = products.len(); + // // let mut product = *coefficient; + // // for &f in products.iter().take(num_mles) { + // // let table = &flattened_ml_extensions[f]; // f's range is checked in + // init product *= mle[b << 1] * (F::one() - F::from(t as u32)) + // + mle[(b << 1) + 1] * F::from(t as u32); + // // } + // sum += product; + // } + // } + // } + // ); + + // products_list.iter().for_each(|(coefficient, products)| { + // let mut sum = (0..1 << (self.poly.aux_info.num_variables - self.round)) + // .into_iter() + // .fold( + // || { + // ( + // vec![(F::zero(), F::zero()); products.len()], + // vec![F::zero(); products.len() + 1], + // ) + // }, + // |(mut buf, mut acc), b| { + // buf.iter_mut() + // .zip(products.iter()) + // .for_each(|((eval, step), f)| { + // let table = &flattened_ml_extensions[*f]; + // *eval = table[b << 1]; + // *step = table[(b << 1) + 1] - table[b << 1]; + // }); + // acc[0] += buf.iter().map(|(eval, _)| eval).product::(); + // acc[1..].iter_mut().for_each(|acc| { + // buf.iter_mut().for_each(|(eval, step)| *eval += step as &_); + // *acc += buf.iter().map(|(eval, _)| eval).product::(); + // }); + // (buf, acc) + // }, + // ) + // .map(|(_, partial)| partial) + // .reduce( + // || vec![F::zero(); products.len() + 1], + // |mut sum, partial| { + // sum.iter_mut() + // .zip(partial.iter()) + // .for_each(|(sum, partial)| *sum += partial); + // sum + // }, + // ); + // sum.iter_mut().for_each(|sum| *sum *= coefficient); + // let extraploation = (0..self.poly.aux_info.max_degree - products.len()) + // .into_iter() + // .map(|i| { + // let (points, weights) = &self.extrapolation_aux[products.len() - 1]; + // let at = F::from((products.len() + 1 + i) as u32); + // extrapolate(points, weights, &sum, &at) + // }) + // .collect::>(); + // products_sum + // .iter_mut() + // .zip(sum.iter().chain(extraploation.iter())) + // .for_each(|(products_sum, sum)| *products_sum += sum); + // }); + + // update prover's state to the partial evaluated polynomial + // self.poly.flattened_ml_extensions = fl + + // todo!() + } +} + +fn barycentric_weights(points: &[F]) -> Vec { + let mut weights = points + .iter() + .enumerate() + .map(|(j, point_j)| { + points + .iter() + .enumerate() + .filter(|&(i, _point_i)| (i != j)) + .map(|(_i, point_i)| *point_j - point_i) + .reduce(|acc, value| acc * value) + .unwrap_or_else(F::one) + }) + .collect::>(); + batch_inversion(&mut weights); + weights +} + +fn extrapolate(points: &[F], weights: &[F], evals: &[F], at: &F) -> F { + let (coeffs, sum_inv) = { + let mut coeffs = points.iter().map(|point| *at - point).collect::>(); + batch_inversion(&mut coeffs); + coeffs.iter_mut().zip(weights).for_each(|(coeff, weight)| { + *coeff *= weight; + }); + let sum_inv = coeffs.iter().sum::().inv().unwrap_or_default(); + (coeffs, sum_inv) + }; + coeffs + .iter() + .zip(evals) + .map(|(coeff, eval)| *coeff * eval) + .sum::() + * sum_inv +} diff --git a/sumcheck/src/sumcheck_generic/tests.rs b/sumcheck/src/sumcheck_generic/tests.rs new file mode 100644 index 00000000..d7536216 --- /dev/null +++ b/sumcheck/src/sumcheck_generic/tests.rs @@ -0,0 +1,195 @@ +use super::*; +use arith::Fr; +use ark_std::test_rng; +use gkr_hashers::Keccak256hasher; +use polynomials::MultilinearExtension; +use transcript::BytesHashTranscript; + +#[test] +fn test_sumcheck() { + for num_vars in 1..10 { + let size = 1 << num_vars; + + let coeffs = (1..=size).map(|i| Fr::from(i as u32)).collect::>(); + let mle = MultiLinearPoly::::new(coeffs); + let asserted_sum = mle.coeffs.iter().sum::(); + + let mut transcript = BytesHashTranscript::::new(); + + let mut prover = IOPProverState::prover_init(mle.clone()); + let mut verifier = IOPVerifierState::verifier_init(prover.mle.num_vars()); + + let mut challenge = None; + + for _ in 0..prover.mle.num_vars() { + let prover_msg = IOPProverState::prove_round_and_update_state(&mut prover, &challenge); + // let challenge = IOPVerifierState::verify_round_and_update_state(&mut verifeir, + // &prover_msg, &mut transcript); transcript.append_serializable_data(&prover_msg); + + challenge = Some(IOPVerifierState::verify_round_and_update_state( + &mut verifier, + &prover_msg, + &mut transcript, + )); + } + + println!("prover challenges: {:?}", prover.challenges); + println!("verifier challenges: {:?}", verifier.challenges); + + let subclaim = IOPVerifierState::check_and_generate_subclaim(&verifier, &asserted_sum); + assert!( + mle.eval_reverse_order(&subclaim.point) == subclaim.expected_evaluation, + "wrong subclaim {:?} {:?} ", + mle.eval_reverse_order(&subclaim.point), + subclaim.expected_evaluation, + ); + } +} + +// fn test_sumcheck(nv: usize, num_multiplicands_range: (usize, usize), num_products: usize) { +// let mut rng = test_rng(); +// let mut transcript = BytesHashTranscript::::new(); + +// let (poly, asserted_sum) = +// VirtualPolynomial::rand(nv, num_multiplicands_range, num_products, &mut rng); + +// println!("poly: {:?}", poly); + +// let proof = Sumcheck::::prove(&poly, &mut transcript); +// let poly_info = poly.aux_info.clone(); + +// let mut transcript = BytesHashTranscript::::new(); +// let subclaim = Sumcheck::::verify(asserted_sum, &proof, &poly_info, &mut transcript); +// assert!( +// poly.evaluate(&subclaim.point) == subclaim.expected_evaluation, +// "wrong subclaim" +// ); +// } + +// fn test_sumcheck_internal(nv: usize, num_multiplicands_range: (usize, usize), num_products: +// usize) { let mut rng = test_rng(); +// let (poly, asserted_sum) = +// VirtualPolynomial::::rand(nv, num_multiplicands_range, num_products, &mut rng); +// let poly_info = poly.aux_info.clone(); +// let mut prover_state = IOPProverState::prover_init(&poly); +// let mut verifier_state = IOPVerifierState::verifier_init(&poly_info); +// let mut challenge = None; +// let mut transcript = BytesHashTranscript::::new(); +// // transcript +// // .append_message(b"testing", b"initializing transcript for testing") +// // .unwrap(); +// for _ in 0..poly.aux_info.num_variables { +// let prover_message = +// IOPProverState::prove_round_and_update_state(&mut prover_state, &challenge); + +// challenge = Some(IOPVerifierState::verify_round_and_update_state( +// &mut verifier_state, +// &prover_message, +// &mut transcript, +// )); +// } +// let subclaim = IOPVerifierState::check_and_generate_subclaim(&verifier_state, &asserted_sum); +// assert!( +// poly.evaluate(&subclaim.point) == subclaim.expected_evaluation, +// "wrong subclaim" +// ); +// } + +// #[test] +// fn test_trivial_polynomial() { +// let nv = 1; +// let num_multiplicands_range = (4, 13); +// let num_products = 5; + +// test_sumcheck(nv, num_multiplicands_range, num_products); +// test_sumcheck_internal(nv, num_multiplicands_range, num_products); +// } +// #[test] +// fn test_normal_polynomial() { +// let nv = 5; +// let num_multiplicands_range = (1,2); +// let num_products = 1; + +// test_sumcheck(nv, num_multiplicands_range, num_products); +// // test_sumcheck_internal(nv, num_multiplicands_range, num_products); +// } +// // #[test] +// // fn zero_polynomial_should_error() { +// // let nv = 0; +// // let num_multiplicands_range = (4, 13); +// // let num_products = 5; + +// // assert!(test_sumcheck(nv, num_multiplicands_range, num_products).is_err()); +// // assert!(test_sumcheck_internal(nv, num_multiplicands_range, num_products).is_err()); +// // } + +// #[test] +// fn test_extract_sum() { +// let mut rng = test_rng(); +// let mut transcript = BytesHashTranscript::::new(); +// let (poly, asserted_sum) = VirtualPolynomial::::rand(8, (3, 4), 3, &mut rng); + +// let proof = Sumcheck::::prove(&poly, &mut transcript); +// assert_eq!(Sumcheck::::extract_sum(&proof), asserted_sum); +// } + +// // #[test] +// // /// Test that the memory usage of shared-reference is linear to number of +// // /// unique MLExtensions instead of total number of multiplicands. +// // fn test_shared_reference() -> Result<(), PolyIOPErrors> { +// // let mut rng = test_rng(); +// // let ml_extensions: Vec<_> = (0..5) +// // .map(|_| Rc::new(DenseMultilinearExtension::::rand(8, &mut rng))) +// // .collect(); +// // let mut poly = VirtualPolynomial::new(8); +// // poly.add_mle_list( +// // vec![ +// // ml_extensions[2].clone(), +// // ml_extensions[3].clone(), +// // ml_extensions[0].clone(), +// // ], +// // Fr::rand(&mut rng), +// // )?; +// // poly.add_mle_list( +// // vec![ +// // ml_extensions[1].clone(), +// // ml_extensions[4].clone(), +// // ml_extensions[4].clone(), +// // ], +// // Fr::rand(&mut rng), +// // )?; +// // poly.add_mle_list( +// // vec![ +// // ml_extensions[3].clone(), +// // ml_extensions[2].clone(), +// // ml_extensions[1].clone(), +// // ], +// // Fr::rand(&mut rng), +// // )?; +// // poly.add_mle_list( +// // vec![ml_extensions[0].clone(), ml_extensions[0].clone()], +// // Fr::rand(&mut rng), +// // )?; +// // poly.add_mle_list(vec![ml_extensions[4].clone()], Fr::rand(&mut rng))?; + +// // assert_eq!(poly.flattened_ml_extensions.len(), 5); + +// // // test memory usage for prover +// // let prover = IOPProverState::prover_init(&poly).unwrap(); +// // assert_eq!(prover.poly.flattened_ml_extensions.len(), 5); +// // drop(prover); + +// // let mut transcript = as SumCheck>::init_transcript(); +// // let poly_info = poly.aux_info.clone(); +// // let proof = as SumCheck>::prove(&poly, &mut transcript)?; +// // let asserted_sum = as SumCheck>::extract_sum(&proof); + +// // let mut transcript = as SumCheck>::init_transcript(); +// // let subclaim = +// // as SumCheck>::verify(asserted_sum, &proof, &poly_info, &mut +// // transcript)?; assert!( +// // poly.evaluate(&subclaim.point)? == subclaim.expected_evaluation, +// // "wrong subclaim" +// // ); +// // Ok(()) +// // } diff --git a/sumcheck/src/sumcheck_generic/verifier.rs b/sumcheck/src/sumcheck_generic/verifier.rs new file mode 100644 index 00000000..d80fa659 --- /dev/null +++ b/sumcheck/src/sumcheck_generic/verifier.rs @@ -0,0 +1,285 @@ +use arith::Field; +use gkr_engine::Transcript; +use polynomials::VPAuxInfo; + +use super::{IOPProverMessage, IOPVerifierState, SumCheckSubClaim}; + +impl IOPVerifierState { + /// Initialize the verifier's state. + // pub fn verifier_init(index_info: &VPAuxInfo) -> Self { + pub fn verifier_init(num_vars: usize) -> Self { + let res = Self { + round: 1, + num_vars, //index_info.num_variables, + // max_degree: index_info.max_degree, + finished: false, + polynomials_received: Vec::with_capacity(num_vars), + challenges: Vec::with_capacity(num_vars), + }; + + res + } + + /// Run verifier for the current round, given a prover message. + /// + /// Note that `verify_round_and_update_state` only samples and stores + /// challenges; and update the verifier's state accordingly. The actual + /// verifications are deferred (in batch) to `check_and_generate_subclaim` + /// at the last step. + pub fn verify_round_and_update_state( + &mut self, + prover_msg: &IOPProverMessage, + transcript: &mut impl Transcript, + ) -> F { + if self.finished { + panic!("Incorrect verifier state: Verifier is already finished.") + } + + // In an interactive protocol, the verifier should + // + // 1. check if the received 'P(0) + P(1) = expected`. + // 2. set `expected` to P(r)` + // + // When we turn the protocol to a non-interactive one, it is sufficient to defer + // such checks to `check_and_generate_subclaim` after the last round. + + let challenge = transcript.generate_field_element::(); + self.challenges.push(challenge); + self.polynomials_received + .push(prover_msg.evaluations.clone()); + + println!( + "sum: {:?}", + prover_msg.evaluations[0] + prover_msg.evaluations[1] + ); + // println!("uni eval {:?}", ); + + if self.round == self.num_vars { + // accept and close + self.finished = true; + } else { + // proceed to the next round + self.round += 1; + } + + challenge + } + + /// This function verifies the deferred checks in the interactive version of + /// the protocol; and generate the subclaim. Returns an error if the + /// proof failed to verify. + /// + /// If the asserted sum is correct, then the multilinear polynomial + /// evaluated at `subclaim.point` will be `subclaim.expected_evaluation`. + /// Otherwise, it is highly unlikely that those two will be equal. + /// Larger field size guarantees smaller soundness error. + pub fn check_and_generate_subclaim(&self, asserted_sum: &F) -> SumCheckSubClaim { + if !self.finished { + panic!("Incorrect verifier state: Verifier has not finished."); + } + + if self.polynomials_received.len() != self.num_vars { + panic!("insufficient rounds") + } + + // let mut expected_vec = vec![F::zero(); self.num_vars + 1]; + + // let mut expected_vec = self + // .polynomials_received + // .clone() + // .into_iter() + // .zip(self.challenges.clone().into_iter()) + // .map(|(evaluations, challenge)| { + // // if evaluations.len() != 2 { + // // panic!( + // // "incorrect number of evaluations: {} vs {}", + // // evaluations.len(), + // // self.max_degree + 1 + // // ); + // // } + // // interpolate_uni_poly::(&evaluations, challenge) + + // evaluations[0]+ (evaluations[1] - evaluations[0]) * challenge + // }) + // .collect::>(); + + // insert the asserted_sum to the first position of the expected vector + // expected_vec.insert(0, *asserted_sum); + + let mut expected = *asserted_sum; + + for i in 0..self.num_vars { + let evals = &self.polynomials_received[i]; + let sum = evals[0] + evals[1]; + println!( + "{}th layer Prover message: {:?}, expected: {:?}", + i, sum, expected + ); + + expected = evals[0] + (evals[1] - evals[0]) * self.challenges[i]; + } + + // for (i, (evaluations, &expected)) in self + // .polynomials_received + // .iter() + // .zip(expected_vec.iter()) + // .take(self.num_vars) + // .enumerate() + // { + // // the deferred check during the interactive phase: + // // 1. check if the received 'P(0) + P(1) = expected`. + // println!( + // "{}th layer Prover message: {:?}, expected: {:?}", + // i, evaluations, expected + // ); + + // if evaluations[0] + evaluations[1] != expected { + // panic!("Prover message is not consistent with the claim.") + // } + // } + + SumCheckSubClaim { + point: self.challenges.clone(), + // the last expected value (not checked within this function) will be included in the + // subclaim + expected_evaluation: expected, + } + } +} + +// /// Interpolate a uni-variate degree-`p_i.len()-1` polynomial and evaluate this +// /// polynomial at `eval_at`: +// /// +// /// \sum_{i=0}^len p_i * (\prod_{j!=i} (eval_at - j)/(i-j) ) +// /// +// /// This implementation is linear in number of inputs in terms of field +// /// operations. It also has a quadratic term in primitive operations which is +// /// negligible compared to field operations. +// /// TODO: The quadratic term can be removed by precomputing the lagrange +// /// coefficients. +// fn interpolate_uni_poly(p_i: &[F], eval_at: F) -> F { +// let len = p_i.len(); +// let mut evals = vec![]; +// let mut prod = eval_at; +// evals.push(eval_at); + +// // `prod = \prod_{j} (eval_at - j)` +// for e in 1..len { +// let tmp = eval_at - F::from(e as u32); +// evals.push(tmp); +// prod *= tmp; +// } +// let mut res = F::zero(); +// // we want to compute \prod (j!=i) (i-j) for a given i +// // +// // we start from the last step, which is +// // denom[len-1] = (len-1) * (len-2) *... * 2 * 1 +// // the step before that is +// // denom[len-2] = (len-2) * (len-3) * ... * 2 * 1 * -1 +// // and the step before that is +// // denom[len-3] = (len-3) * (len-4) * ... * 2 * 1 * -1 * -2 +// // +// // i.e., for any i, the one before this will be derived from +// // denom[i-1] = denom[i] * (len-i) / i +// // +// // that is, we only need to store +// // - the last denom for i = len-1, and +// // - the ratio between current step and fhe last step, which is the product of (len-i) / i +// from // all previous steps and we store this product as a fraction number to reduce field +// // divisions. + +// // // We know +// // // - 2^61 < factorial(20) < 2^62 +// // // - 2^122 < factorial(33) < 2^123 +// // // so we will be able to compute the ratio +// // // - for len <= 20 with i64 +// // // - for len <= 33 with i128 +// // // - for len > 33 with BigInt +// // if p_i.len() <= 20 { +// // let last_denominator = F::from(u64_factorial(len - 1)); +// // let mut ratio_numerator = 1i64; +// // let mut ratio_denominator = 1u64; + +// // for i in (0..len).rev() { +// // let ratio_numerator_f = if ratio_numerator < 0 { +// // -F::from((-ratio_numerator) as u64) +// // } else { +// // F::from(ratio_numerator as u64) +// // }; + +// // res += p_i[i] * prod * F::from(ratio_denominator) +// // / (last_denominator * ratio_numerator_f * evals[i]); + +// // // compute denom for the next step is current_denom * (len-i)/i +// // if i != 0 { +// // ratio_numerator *= -(len as i64 - i as i64); +// // ratio_denominator *= i as u64; +// // } +// // } +// // } else if p_i.len() <= 33 { +// // let last_denominator = F::from(u128_factorial(len - 1)); +// // let mut ratio_numerator = 1i128; +// // let mut ratio_denominator = 1u128; + +// // for i in (0..len).rev() { +// // let ratio_numerator_f = if ratio_numerator < 0 { +// // -F::from((-ratio_numerator) as u128) +// // } else { +// // F::from(ratio_numerator as u128) +// // }; + +// // res += p_i[i] * prod * F::from(ratio_denominator) +// // / (last_denominator * ratio_numerator_f * evals[i]); + +// // // compute denom for the next step is current_denom * (len-i)/i +// // if i != 0 { +// // ratio_numerator *= -(len as i128 - i as i128); +// // ratio_denominator *= i as u128; +// // } +// // } +// // } else { +// let mut denom_up = field_factorial::(len - 1); +// let mut denom_down = F::one(); + +// for i in (0..len).rev() { +// res += p_i[i] * prod * denom_down * (denom_up * evals[i]).inv().unwrap(); + +// // compute denom for the next step is current_denom * (len-i)/i +// if i != 0 { +// denom_up *= -F::from((len - i) as u32); +// denom_down *= F::from(i as u32); +// } +// } +// // } +// res +// } + +// /// compute the factorial(a) = 1 * 2 * ... * a +// #[inline] +// fn field_factorial(a: usize) -> F { +// let mut res = F::one(); +// for i in 2..=a { +// res *= F::from(i as u32); +// } +// res +// } + +// // /// compute the factorial(a) = 1 * 2 * ... * a +// // #[inline] +// // fn u128_factorial(a: usize) -> u128 { +// // let mut res = 1u128; +// // for i in 2..=a { +// // res *= i as u128; +// // } +// // res +// // } + +// // /// compute the factorial(a) = 1 * 2 * ... * a +// // #[inline] +// // fn u64_factorial(a: usize) -> u64 { +// // let mut res = 1u64; +// // for i in 2..=a { +// // res *= i as u64; +// // } +// // res +// // } diff --git a/sumcheck/src/utils.rs b/sumcheck/src/utils.rs index 43728db1..108a39be 100644 --- a/sumcheck/src/utils.rs +++ b/sumcheck/src/utils.rs @@ -1,4 +1,4 @@ -use arith::{ExtensionField, SimdField}; +use arith::{ExtensionField, Field, SimdField}; use gkr_engine::{MPIEngine, Transcript}; #[inline(always)] @@ -41,3 +41,52 @@ where mpi_config.root_broadcast_f(&mut r); r } + +// Given a vector of field elements {v_i}, compute the vector {v_i^(-1)} +pub fn batch_inversion(v: &mut [F]) { + batch_inversion_and_mul(v, &F::one()); +} + +// Given a vector of field elements {v_i}, compute the vector {coeff * v_i^(-1)} +pub fn batch_inversion_and_mul(v: &mut [F], coeff: &F) { + serial_batch_inversion_and_mul(v, coeff); +} + +/// Given a vector of field elements {v_i}, compute the vector {coeff * v_i^(-1)}. +/// This method is explicitly single-threaded. +fn serial_batch_inversion_and_mul(v: &mut [F], coeff: &F) { + // Montgomery’s Trick and Fast Implementation of Masked AES + // Genelle, Prouff and Quisquater + // Section 3.2 + // but with an optimization to multiply every element in the returned vector by + // coeff + + // First pass: compute [a, ab, abc, ...] + let mut prod = Vec::with_capacity(v.len()); + let mut tmp = F::one(); + for f in v.iter().filter(|f| !f.is_zero()) { + tmp.mul_assign(f); + prod.push(tmp); + } + + // Invert `tmp`. + tmp = tmp.inv().unwrap(); // Guaranteed to be nonzero. + + // Multiply product by coeff, so all inverses will be scaled by coeff + tmp *= coeff; + + // Second pass: iterate backwards to compute inverses + for (f, s) in v.iter_mut() + // Backwards + .rev() + // Ignore normalized elements + .filter(|f| !f.is_zero()) + // Backwards, skip last element, fill in one for last term. + .zip(prod.into_iter().rev().skip(1).chain(Some(F::one()))) + { + // tmp := tmp * f; f := tmp * s = 1/f + let new_tmp = tmp * *f; + *f = tmp * &s; + tmp = new_tmp; + } +} From 01c0b49ccc8a15a5ddf188c498ff23f404be8df9 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 28 May 2025 15:29:53 -0400 Subject: [PATCH 24/57] finished sumcheck --- arith/polynomials/src/lib.rs | 3 - arith/polynomials/src/vp.rs | 618 ---------------------- sumcheck/src/sumcheck_generic.rs | 137 ++--- sumcheck/src/sumcheck_generic/prover.rs | 203 +------ sumcheck/src/sumcheck_generic/tests.rs | 263 +++------ sumcheck/src/sumcheck_generic/verifier.rs | 201 +------ 6 files changed, 166 insertions(+), 1259 deletions(-) delete mode 100644 arith/polynomials/src/vp.rs diff --git a/arith/polynomials/src/lib.rs b/arith/polynomials/src/lib.rs index 6495100d..e1206ffd 100644 --- a/arith/polynomials/src/lib.rs +++ b/arith/polynomials/src/lib.rs @@ -10,8 +10,5 @@ pub use univariate::*; mod eq; pub use eq::*; -mod vp; -pub use vp::*; - #[cfg(test)] mod tests; diff --git a/arith/polynomials/src/vp.rs b/arith/polynomials/src/vp.rs deleted file mode 100644 index e9a711a5..00000000 --- a/arith/polynomials/src/vp.rs +++ /dev/null @@ -1,618 +0,0 @@ -// Copyright (c) 2023 Espresso Systems (espressosys.com) -// This file is part of the HyperPlonk library. - -// You should have received a copy of the MIT License -// along with the HyperPlonk library. If not, see . - -//! This module defines our main mathematical object `VirtualPolynomial`; and -//! various functions associated with it. - -use core::panic; -use std::{cmp::max, collections::HashMap, marker::PhantomData, ops::Add, sync::Arc}; - -use arith::Field; -use ark_std::{ - end_timer, - rand::{Rng, RngCore}, - start_timer, -}; -use serdes::ExpSerde; - -use crate::MultiLinearPoly; - -#[rustfmt::skip] -/// A virtual polynomial is a sum of products of multilinear polynomials; -/// where the multilinear polynomials are stored via their multilinear -/// extensions: `(coefficient, DenseMultilinearExtension)` -/// -/// * Number of products n = `polynomial.products.len()`, -/// * Number of multiplicands of ith product m_i = -/// `polynomial.products[i].1.len()`, -/// * Coefficient of ith product c_i = `polynomial.products[i].0` -/// -/// The resulting polynomial is -/// -/// $$ \sum_{i=0}^{n} c_i \cdot \prod_{j=0}^{m_i} P_{ij} $$ -/// -/// Example: -/// f = c0 * f0 * f1 * f2 + c1 * f3 * f4 -/// where f0 ... f4 are multilinear polynomials -/// -/// - flattened_ml_extensions stores the multilinear extension representation of -/// f0, f1, f2, f3 and f4 -/// - products is -/// \[ -/// (c0, \[0, 1, 2\]), -/// (c1, \[3, 4\]) -/// \] -/// - raw_pointers_lookup_table maps fi to i -/// -#[derive(Clone, Debug, Default, PartialEq)] -pub struct VirtualPolynomial { - /// Aux information about the multilinear polynomial - pub aux_info: VPAuxInfo, - /// list of reference to products (as usize) of multilinear extension - pub products: Vec<(F, Vec)>, - /// Stores multilinear extensions in which product multiplicand can refer - /// to. - pub flattened_ml_extensions: Vec>>, - /// Pointers to the above poly extensions - raw_pointers_lookup_table: HashMap<*const MultiLinearPoly, usize>, -} - -#[derive(Clone, Debug, Default, PartialEq, Eq)] -/// Auxiliary information about the multilinear polynomial -pub struct VPAuxInfo { - /// max number of multiplicands in each product - pub max_degree: usize, - /// number of variables of the polynomial - pub num_variables: usize, - /// Associated field - #[doc(hidden)] - pub phantom: PhantomData, -} - -impl ExpSerde for VPAuxInfo { - fn serialize_into(&self, mut writer: W) -> serdes::SerdeResult<()> { - self.max_degree.serialize_into(&mut writer)?; - self.num_variables.serialize_into(&mut writer)?; - - Ok(()) - } - - fn deserialize_from(mut reader: R) -> serdes::SerdeResult { - let max_degree = usize::deserialize_from(&mut reader)?; - let num_variables = usize::deserialize_from(&mut reader)?; - - Ok(VPAuxInfo { - max_degree, - num_variables, - phantom: PhantomData, - }) - } -} - -impl Add for &VirtualPolynomial { - type Output = VirtualPolynomial; - fn add(self, other: &VirtualPolynomial) -> Self::Output { - let start = start_timer!(|| "virtual poly add"); - let mut res = self.clone(); - for products in other.products.iter() { - let cur: Vec>> = products - .1 - .iter() - .map(|&x| other.flattened_ml_extensions[x].clone()) - .collect(); - - res.add_mle_list(cur, products.0) - } - end_timer!(start); - res - } -} - -// TODO: convert this into a trait -impl VirtualPolynomial { - /// Creates an empty virtual polynomial with `num_variables`. - pub fn new(num_variables: usize) -> Self { - VirtualPolynomial { - aux_info: VPAuxInfo { - max_degree: 0, - num_variables, - phantom: PhantomData, - }, - products: Vec::new(), - flattened_ml_extensions: Vec::new(), - raw_pointers_lookup_table: HashMap::new(), - } - } - - /// Creates an new virtual polynomial from a MLE and its coefficient. - pub fn new_from_mle(mle: &Arc>, coefficient: F) -> Self { - let mle_ptr: *const MultiLinearPoly = Arc::as_ptr(mle); - let mut hm = HashMap::new(); - hm.insert(mle_ptr, 0); - - VirtualPolynomial { - aux_info: VPAuxInfo { - // The max degree is the max degree of any individual variable - max_degree: 1, - num_variables: mle.get_num_vars(), - phantom: PhantomData, - }, - // here `0` points to the first polynomial of `flattened_ml_extensions` - products: vec![(coefficient, vec![0])], - flattened_ml_extensions: vec![mle.clone()], - raw_pointers_lookup_table: hm, - } - } - - /// Add a product of list of multilinear extensions to self - /// Returns an error if the list is empty, or the MLE has a different - /// `num_vars` from self. - /// - /// The MLEs will be multiplied together, and then multiplied by the scalar - /// `coefficient`. - pub fn add_mle_list( - &mut self, - mle_list: impl IntoIterator>>, - coefficient: F, - ) { - let mle_list: Vec>> = mle_list.into_iter().collect(); - let mut indexed_product = Vec::with_capacity(mle_list.len()); - - if mle_list.is_empty() { - panic!("input mle_list is empty"); - } - - self.aux_info.max_degree = max(self.aux_info.max_degree, mle_list.len()); - - for mle in mle_list { - if mle.get_num_vars() != self.aux_info.num_variables { - panic!( - "product has a multiplicand with wrong number of variables {} vs {}", - mle.get_num_vars(), - self.aux_info.num_variables - ); - } - - let mle_ptr: *const MultiLinearPoly = Arc::as_ptr(&mle); - if let Some(index) = self.raw_pointers_lookup_table.get(&mle_ptr) { - indexed_product.push(*index) - } else { - let curr_index = self.flattened_ml_extensions.len(); - self.flattened_ml_extensions.push(mle.clone()); - self.raw_pointers_lookup_table.insert(mle_ptr, curr_index); - indexed_product.push(curr_index); - } - } - self.products.push((coefficient, indexed_product)); - } - - /// Multiple the current VirtualPolynomial by an MLE: - /// - add the MLE to the MLE list; - /// - multiple each product by MLE and its coefficient. - /// - /// Returns an error if the MLE has a different `num_vars` from self. - pub fn mul_by_mle(&mut self, mle: Arc>, coefficient: F) { - let start = start_timer!(|| "mul by mle"); - - if mle.get_num_vars() != self.aux_info.num_variables { - panic!( - "product has a multiplicand with wrong number of variables {} vs {}", - mle.get_num_vars(), - self.aux_info.num_variables - ); - } - - let mle_ptr: *const MultiLinearPoly = Arc::as_ptr(&mle); - - // check if this mle already exists in the virtual polynomial - let mle_index = match self.raw_pointers_lookup_table.get(&mle_ptr) { - Some(&p) => p, - None => { - self.raw_pointers_lookup_table - .insert(mle_ptr, self.flattened_ml_extensions.len()); - self.flattened_ml_extensions.push(mle); - self.flattened_ml_extensions.len() - 1 - } - }; - - for (prod_coef, indices) in self.products.iter_mut() { - // - add the MLE to the MLE list; - // - multiple each product by MLE and its coefficient. - indices.push(mle_index); - *prod_coef *= coefficient; - } - - // increase the max degree by one as the MLE has degree 1. - self.aux_info.max_degree += 1; - end_timer!(start); - } - - /// Evaluate the virtual polynomial at point `point`. - /// Returns an error is point.len() does not match `num_variables`. - pub fn evaluate(&self, point: &[F]) -> F { - let start = start_timer!(|| "evaluation"); - - if self.aux_info.num_variables != point.len() { - panic!( - "wrong number of variables {} vs {}", - self.aux_info.num_variables, - point.len() - ); - } - - let evals: Vec = self - .flattened_ml_extensions - .iter() - .map(|x| x.eval_reverse_order(point)) - .collect(); - - let res = self - .products - .iter() - .map(|(c, p)| *c * p.iter().map(|&i| evals[i]).product::()) - .sum(); - - end_timer!(start); - res - } - - /// Sample a random virtual polynomial, return the polynomial and its sum. - pub fn rand( - nv: usize, - num_multiplicands_range: (usize, usize), - num_products: usize, - rng: &mut R, - ) -> (Self, F) { - let start = start_timer!(|| "sample random virtual polynomial"); - - let mut sum = F::zero(); - let mut poly = VirtualPolynomial::new(nv); - for _ in 0..num_products { - let num_multiplicands = - rng.gen_range(num_multiplicands_range.0..num_multiplicands_range.1); - let (product, product_sum) = random_mle_list(nv, num_multiplicands, rng); - // let coefficient = F::random_unsafe(&mut *rng); - let coefficient = F::one(); - poly.add_mle_list(product.into_iter(), coefficient); - sum += product_sum * coefficient; - } - - end_timer!(start); - (poly, sum) - } - - /// Sample a random virtual polynomial that evaluates to zero everywhere - /// over the boolean hypercube. - pub fn rand_zero( - nv: usize, - num_multiplicands_range: (usize, usize), - num_products: usize, - rng: &mut R, - ) -> Self { - let mut poly = VirtualPolynomial::new(nv); - for _ in 0..num_products { - let num_multiplicands = - rng.gen_range(num_multiplicands_range.0..num_multiplicands_range.1); - let product = random_zero_mle_list(nv, num_multiplicands, &mut *rng); - let coefficient = F::random_unsafe(&mut *rng); - poly.add_mle_list(product.into_iter(), coefficient); - } - - poly - } - - // Input poly f(x) and a random vector r, output - // \hat f(x) = \sum_{x_i \in eval_x} f(x_i) eq(x, r) - // where - // eq(x,y) = \prod_i=1^num_var (x_i * y_i + (1-x_i)*(1-y_i)) - // - // This function is used in ZeroCheck. - pub fn build_f_hat(&self, r: &[F]) -> Self { - let start = start_timer!(|| "zero check build hat f"); - - if self.aux_info.num_variables != r.len() { - panic!( - "r.len() is different from number of variables {} vs {}", - r.len(), - self.aux_info.num_variables - ); - } - - let eq_x_r = build_eq_x_r(r); - let mut res = self.clone(); - res.mul_by_mle(eq_x_r, F::one()); - - end_timer!(start); - res - } - - /// Print out the evaluation map for testing. Panic if the num_vars > 5. - pub fn print_evals(&self) { - if self.aux_info.num_variables > 5 { - panic!("this function is used for testing only. cannot print more than 5 num_vars") - } - for i in 0..1 << self.aux_info.num_variables { - let point = bit_decompose(i, self.aux_info.num_variables); - let point_fr: Vec = point.iter().map(|&x| F::from(x as u32)).collect(); - println!("{} {:?}", i, self.evaluate(point_fr.as_ref())) - } - println!() - } -} - -/// Evaluate eq polynomial. -pub fn eq_eval(x: &[F], y: &[F]) -> F { - if x.len() != y.len() { - panic!("x and y have different length {} vs {}", x.len(), y.len()); - } - let start = start_timer!(|| "eq_eval"); - let mut res = F::one(); - for (&xi, &yi) in x.iter().zip(y.iter()) { - let xi_yi = xi * yi; - res *= xi_yi + xi_yi - xi - yi + F::one(); - } - end_timer!(start); - res -} - -/// This function build the eq(x, r) polynomial for any given r. -/// -/// Evaluate -/// eq(x,y) = \prod_i=1^num_var (x_i * y_i + (1-x_i)*(1-y_i)) -/// over r, which is -/// eq(x,y) = \prod_i=1^num_var (x_i * r_i + (1-x_i)*(1-r_i)) -pub fn build_eq_x_r(r: &[F]) -> Arc> { - let evals = build_eq_x_r_vec(r); - let mle = MultiLinearPoly { coeffs: evals }; - - Arc::new(mle) -} -/// This function build the eq(x, r) polynomial for any given r, and output the -/// evaluation of eq(x, r) in its vector form. -/// -/// Evaluate -/// eq(x,y) = \prod_i=1^num_var (x_i * y_i + (1-x_i)*(1-y_i)) -/// over r, which is -/// eq(x,y) = \prod_i=1^num_var (x_i * r_i + (1-x_i)*(1-r_i)) -pub fn build_eq_x_r_vec(r: &[F]) -> Vec { - // we build eq(x,r) from its evaluations - // we want to evaluate eq(x,r) over x \in {0, 1}^num_vars - // for example, with num_vars = 4, x is a binary vector of 4, then - // 0 0 0 0 -> (1-r0) * (1-r1) * (1-r2) * (1-r3) - // 1 0 0 0 -> r0 * (1-r1) * (1-r2) * (1-r3) - // 0 1 0 0 -> (1-r0) * r1 * (1-r2) * (1-r3) - // 1 1 0 0 -> r0 * r1 * (1-r2) * (1-r3) - // .... - // 1 1 1 1 -> r0 * r1 * r2 * r3 - // we will need 2^num_var evaluations - - let mut eval = Vec::new(); - build_eq_x_r_helper(r, &mut eval); - - eval -} - -/// A helper function to build eq(x, r) recursively. -/// This function takes `r.len()` steps, and for each step it requires a maximum -/// `r.len()-1` multiplications. -fn build_eq_x_r_helper(r: &[F], buf: &mut Vec) { - if r.is_empty() { - panic!("r length is 0"); - } else if r.len() == 1 { - // initializing the buffer with [1-r_0, r_0] - buf.push(F::one() - r[0]); - buf.push(r[0]); - } else { - build_eq_x_r_helper(&r[1..], buf); - - // suppose at the previous step we received [b_1, ..., b_k] - // for the current step we will need - // if x_0 = 0: (1-r0) * [b_1, ..., b_k] - // if x_0 = 1: r0 * [b_1, ..., b_k] - // let mut res = vec![]; - // for &b_i in buf.iter() { - // let tmp = r[0] * b_i; - // res.push(b_i - tmp); - // res.push(tmp); - // } - // *buf = res; - - let mut res = vec![F::zero(); buf.len() << 1]; - res.iter_mut().enumerate().for_each(|(i, val)| { - let bi = buf[i >> 1]; - let tmp = r[0] * bi; - if i & 1 == 0 { - *val = bi - tmp; - } else { - *val = tmp; - } - }); - *buf = res; - } -} - -/// Decompose an integer into a binary vector in little endian. -pub fn bit_decompose(input: u64, num_var: usize) -> Vec { - let mut res = Vec::with_capacity(num_var); - let mut i = input; - for _ in 0..num_var { - res.push(i & 1 == 1); - i >>= 1; - } - res -} - -/// Sample a random list of multilinear polynomials. -/// Returns -/// - the list of polynomials, -/// - its sum of polynomial evaluations over the boolean hypercube. -pub fn random_mle_list( - nv: usize, - degree: usize, - rng: &mut R, -) -> (Vec>>, F) { - let mut ctr = 0u32; - - let mut multiplicands = Vec::with_capacity(degree); - for _ in 0..degree { - multiplicands.push(Vec::with_capacity(1 << nv)) - } - let mut sum = F::zero(); - - for _ in 0..(1 << nv) { - let mut product = F::one(); - - for e in multiplicands.iter_mut() { - // let val = F::random_unsafe(&mut *rng); - let val = F::from(ctr); - ctr += 1; - - e.push(val); - product *= val; - } - sum += product; - } - - let list = multiplicands - .into_iter() - .map(|x| Arc::new(MultiLinearPoly { coeffs: x })) - .collect(); - - (list, sum) -} - -// Build a randomize list of mle-s whose sum is zero. -pub fn random_zero_mle_list( - nv: usize, - degree: usize, - rng: &mut R, -) -> Vec>> { - let start = start_timer!(|| "sample random zero mle list"); - - let mut multiplicands = Vec::with_capacity(degree); - for _ in 0..degree { - multiplicands.push(Vec::with_capacity(1 << nv)) - } - for _ in 0..(1 << nv) { - multiplicands[0].push(F::zero()); - for e in multiplicands.iter_mut().skip(1) { - e.push(F::random_unsafe(&mut *rng)); - } - } - - let list = multiplicands - .into_iter() - .map(|x| Arc::new(MultiLinearPoly { coeffs: x })) - .collect(); - - end_timer!(start); - list -} - -#[cfg(test)] -mod test { - use super::*; - use arith::Fr; - use ark_std::test_rng; - - #[test] - fn test_virtual_polynomial_additions() { - let mut rng = test_rng(); - for nv in 2..5 { - for num_products in 2..5 { - let base: Vec = (0..nv).map(|_| Fr::random_unsafe(&mut rng)).collect(); - - let (a, _a_sum) = VirtualPolynomial::::rand(nv, (2, 3), num_products, &mut rng); - let (b, _b_sum) = VirtualPolynomial::::rand(nv, (2, 3), num_products, &mut rng); - let c = &a + &b; - - assert_eq!( - a.evaluate(base.as_ref()) + b.evaluate(base.as_ref()), - c.evaluate(base.as_ref()) - ); - } - } - } - - #[test] - fn test_virtual_polynomial_mul_by_mle() { - let mut rng = test_rng(); - for nv in 2..5 { - for num_products in 2..5 { - let base: Vec = (0..nv).map(|_| Fr::random_unsafe(&mut rng)).collect(); - - let (a, _a_sum) = VirtualPolynomial::::rand(nv, (2, 3), num_products, &mut rng); - let (b, _b_sum) = random_mle_list(nv, 1, &mut rng); - let b_mle = b[0].clone(); - let coeff = Fr::random_unsafe(&mut rng); - let b_vp = VirtualPolynomial::new_from_mle(&b_mle, coeff); - - let mut c = a.clone(); - - c.mul_by_mle(b_mle, coeff); - - assert_eq!( - a.evaluate(base.as_ref()) * b_vp.evaluate(base.as_ref()), - c.evaluate(base.as_ref()) - ); - } - } - } - - #[test] - fn test_eq_xr() { - let mut rng = test_rng(); - for nv in 4..10 { - let r: Vec = (0..nv).map(|_| Fr::random_unsafe(&mut rng)).collect(); - let eq_x_r = build_eq_x_r(r.as_ref()); - let eq_x_r2 = build_eq_x_r_for_test(r.as_ref()); - let eq_x_r3 = crate::EqPolynomial::build_eq_x_r(r.as_ref()); - assert_eq!(eq_x_r, eq_x_r2); - assert_eq!(eq_x_r.coeffs, eq_x_r3); - } - } - - /// Naive method to build eq(x, r). - /// Only used for testing purpose. - // Evaluate - // eq(x,y) = \prod_i=1^num_var (x_i * y_i + (1-x_i)*(1-y_i)) - // over r, which is - // eq(x,y) = \prod_i=1^num_var (x_i * r_i + (1-x_i)*(1-r_i)) - fn build_eq_x_r_for_test(r: &[F]) -> Arc> { - // we build eq(x,r) from its evaluations - // we want to evaluate eq(x,r) over x \in {0, 1}^num_vars - // for example, with num_vars = 4, x is a binary vector of 4, then - // 0 0 0 0 -> (1-r0) * (1-r1) * (1-r2) * (1-r3) - // 1 0 0 0 -> r0 * (1-r1) * (1-r2) * (1-r3) - // 0 1 0 0 -> (1-r0) * r1 * (1-r2) * (1-r3) - // 1 1 0 0 -> r0 * r1 * (1-r2) * (1-r3) - // .... - // 1 1 1 1 -> r0 * r1 * r2 * r3 - // we will need 2^num_var evaluations - - // First, we build array for {1 - r_i} - let one_minus_r: Vec = r.iter().map(|ri| F::one() - ri).collect(); - - let num_var = r.len(); - let mut eval = vec![]; - - for i in 0..1 << num_var { - let mut current_eval = F::one(); - let bit_sequence = bit_decompose(i, num_var); - - for (&bit, (ri, one_minus_ri)) in - bit_sequence.iter().zip(r.iter().zip(one_minus_r.iter())) - { - current_eval *= if bit { *ri } else { *one_minus_ri }; - } - eval.push(current_eval); - } - - let mle = MultiLinearPoly { coeffs: eval }; - - Arc::new(mle) - } -} diff --git a/sumcheck/src/sumcheck_generic.rs b/sumcheck/src/sumcheck_generic.rs index a6b6aa71..cbe9b11b 100644 --- a/sumcheck/src/sumcheck_generic.rs +++ b/sumcheck/src/sumcheck_generic.rs @@ -1,28 +1,14 @@ -use std::ops::Mul; - use arith::Field; use gkr_engine::Transcript; -use polynomials::{MultiLinearPoly, VPAuxInfo, VirtualPolynomial}; +use polynomials::{MultiLinearPoly, MultilinearExtension}; use serdes::ExpSerde; mod prover; -pub use prover::*; - mod verifier; -pub use verifier::*; #[cfg(test)] mod tests; -// /// An IOP proof is a collections of -// /// - messages from prover to verifier at each round through the interactive protocol. -// /// - a point that is generated by the transcript for evaluation -// #[derive(Clone, Debug, Default, PartialEq, Eq)] -// pub struct IOPProof { -// // pub point: Vec, -// pub proofs: Vec>, -// } - /// An IOP proof is a collections of messages from prover to verifier at each /// round through the interactive protocol. #[derive(Clone, Debug, Default, PartialEq)] @@ -47,13 +33,7 @@ pub struct IOPProverState { pub(crate) round: usize, /// list of MLE poly // todo: change this to reference - // pub mle_list: Vec>, - pub mle: MultiLinearPoly, - // /// pointer to the virtual polynomial - // pub(crate) poly: VirtualPolynomial, - // /// points with precomputed barycentric weights for extrapolating smaller - // /// degree uni-polys to `max_degree + 1` evaluations. - // pub(crate) extrapolation_aux: Vec<(Vec, Vec)>, + pub mle_list: Vec>, } /// Prover State of a PolyIOP @@ -80,62 +60,59 @@ pub struct SumCheckSubClaim { pub expected_evaluation: F, } -// pub struct Sumcheck { -// phantom: std::marker::PhantomData, -// } - -// impl Sumcheck { -// /// Extract sum from the proof -// pub fn extract_sum(proof: &IOPProof) -> F { -// proof.proofs[0].evaluations[0] + proof.proofs[0].evaluations[1] -// } - -// /// Generate proof of the sum of polynomial over {0,1}^`num_vars` -// /// -// /// The polynomial is represented in the form of a VirtualPolynomial. -// pub fn prove( -// poly_list: &[MultiLinearPoly], -// // poly: &VirtualPolynomial, -// transcript: &mut impl Transcript) -> IOPProof { -// // transcript.append_serializable_data(&poly.aux_info); - -// let mut prover_state = IOPProverState::prover_init(poly); -// let mut challenge = None; -// let mut prover_msgs = Vec::with_capacity(poly.aux_info.num_variables); -// for _ in 0..poly.aux_info.num_variables { -// let prover_msg = -// IOPProverState::prove_round_and_update_state(&mut prover_state, &challenge); -// transcript.append_serializable_data(&prover_msg); -// prover_msgs.push(prover_msg); -// challenge = Some(transcript.generate_field_element::()); -// } - -// println!("prover challenges: {:?}", prover_state.challenges); -// IOPProof { -// proofs: prover_msgs, -// } -// } - -// /// Verify the claimed sum using the proof -// pub fn verify( -// claimed_sum: F, -// proof: &IOPProof, -// aux_info: &VPAuxInfo, -// transcript: &mut impl Transcript, -// ) -> SumCheckSubClaim { -// transcript.append_serializable_data(aux_info); -// let mut verifier_state = IOPVerifierState::verifier_init(aux_info); -// for i in 0..aux_info.num_variables { -// let prover_msg = proof.proofs.get(i).expect("proof is incomplete"); -// transcript.append_serializable_data(prover_msg); -// IOPVerifierState::verify_round_and_update_state( -// &mut verifier_state, -// prover_msg, -// transcript, -// ); -// } +pub struct SumCheck { + phantom: std::marker::PhantomData, +} -// println!("verifier challenges: {:?}", verifier_state.challenges); -// IOPVerifierState::check_and_generate_subclaim(&verifier_state, &claimed_sum) -// } -// } +impl SumCheck { + /// Extract sum from the proof + pub fn extract_sum(proof: &IOPProof) -> F { + proof.proofs[0].evaluations[0] + proof.proofs[0].evaluations[1] + } + + /// Generate proof of the sum of polynomial over {0,1}^`num_vars` + /// + /// The polynomial is represented in the form of a VirtualPolynomial. + pub fn prove( + poly_list: &[MultiLinearPoly], + transcript: &mut impl Transcript, + ) -> IOPProof { + let num_vars = poly_list[0].num_vars(); + + let mut prover_state = IOPProverState::prover_init(poly_list); + let mut challenge = None; + let mut prover_msgs = Vec::with_capacity(num_vars); + for _ in 0..num_vars { + let prover_msg = + IOPProverState::prove_round_and_update_state(&mut prover_state, &challenge); + transcript.append_serializable_data(&prover_msg); + prover_msgs.push(prover_msg); + challenge = Some(transcript.generate_field_element::()); + } + + IOPProof { + proofs: prover_msgs, + } + } + + /// Verify the claimed sum using the proof + pub fn verify( + claimed_sum: F, + proof: &IOPProof, + num_vars: usize, + transcript: &mut impl Transcript, + ) -> SumCheckSubClaim { + let mut verifier_state = IOPVerifierState::verifier_init(num_vars); + for i in 0..num_vars { + let prover_msg = proof.proofs.get(i).expect("proof is incomplete"); + transcript.append_serializable_data(prover_msg); + IOPVerifierState::verify_round_and_update_state( + &mut verifier_state, + prover_msg, + transcript, + ); + } + + IOPVerifierState::check_and_generate_subclaim(&verifier_state, &claimed_sum) + } +} diff --git a/sumcheck/src/sumcheck_generic/prover.rs b/sumcheck/src/sumcheck_generic/prover.rs index 9175d8f1..d5226165 100644 --- a/sumcheck/src/sumcheck_generic/prover.rs +++ b/sumcheck/src/sumcheck_generic/prover.rs @@ -1,45 +1,17 @@ -// Copyright (c) 2023 Espresso Systems (espressosys.com) -// This file is part of the HyperPlonk library. - -// You should have received a copy of the MIT License -// along with the HyperPlonk library. If not, see . - -//! Prover subroutines for a SumCheck protocol. - -use std::sync::Arc; - use arith::Field; -use polynomials::{MultiLinearPoly, MultilinearExtension, VirtualPolynomial}; - -use crate::batch_inversion; +use polynomials::{MultiLinearPoly, MultilinearExtension}; use super::{IOPProverMessage, IOPProverState}; impl IOPProverState { /// Initialize the prover state to argue for the sum of the input polynomial /// over {0,1}^`num_vars`. - pub fn prover_init( - // polynomials: - // &[MultiLinearPoly] - polynomial: MultiLinearPoly, // &VirtualPolynomial - ) -> Self { - // if polynomial.aux_info.num_variables == 0 { - // panic!("Prover cannot prove a polynomial with no variables."); - // } - + pub fn prover_init(polynomials: &[MultiLinearPoly]) -> Self { Self { - challenges: Vec::with_capacity(polynomial.num_vars()), + challenges: Vec::with_capacity(polynomials[0].num_vars()), round: 0, - init_num_vars: polynomial.num_vars(), - // mle_list: polynomials.to_vec(), - mle: polynomial.clone(), - // extrapolation_aux: (1..polynomial.aux_info.max_degree) - // .map(|degree| { - // let points = (0..1 + degree as u32).map(F::from).collect::>(); - // let weights = barycentric_weights(&points); - // (points, weights) - // }) - // .collect(), + init_num_vars: polynomials[0].num_vars(), + mle_list: polynomials.to_vec(), } } @@ -52,16 +24,6 @@ impl IOPProverState { panic!("prover is not active") } - println!( - "Prover round {}: fixing variable with challenge {:?}", - self.round, challenge - ); - - let mut mle = self.mle.clone(); - println!("mle before eval: {:?}", mle); - - // let fix_argument = start_timer!(|| "fix argument"); - // Step 1: // fix argument and evaluate f(x) over x_m = r; where r is the challenge // for the current round, and m is the round number, indexed from 1 @@ -73,12 +35,6 @@ impl IOPProverState { // g(r_1, ..., r_{m-1}, x_m ... x_n) // // eval g over r_m, and mutate g to g(r_1, ... r_m,, x_{m+1}... x_n) - // let mut flattened_ml_extensions: Vec> = self - // .poly - // .flattened_ml_extensions - // .iter() - // .map(|x| x.as_ref().clone()) - // .collect(); if let Some(chal) = challenge { if self.round == 0 { @@ -88,154 +44,31 @@ impl IOPProverState { let r = self.challenges[self.round - 1]; - mle.fix_top_variable(r); - // mle.fix_bottom_variable(&r); - - // self.mle_list.iter_mut().for_each(|mle| - // // (ZZ: may be buggy) - // mle.fix_bottom_variable(&r)); - // // mle.fix_top_variable(r)); + for mle in self.mle_list.iter_mut() { + mle.fix_top_variable(r); + } } else if self.round > 0 { panic!("verifier message is empty") } - println!("mle after eval: {:?}", mle); - - // end_timer!(fix_argument); - self.round += 1; - let len = mle.coeffs.len() / 2; - let f_0 = mle.coeffs[..len].iter().sum::(); - let f_1 = mle.coeffs[len..].iter().sum::(); + let len = self.mle_list[0].coeffs.len() / 2; + let mut f_0 = F::zero(); + let mut f_1 = F::zero(); - self.mle = mle; + for mle in self.mle_list.iter() { + // evaluate the polynomial at the current point + // and sum the evaluations for f_0 and f_1 + let coeffs = mle.coeffs.as_slice(); + f_0 += coeffs[..len].iter().sum::(); + f_1 += coeffs[len..].iter().sum::(); + } let msg = IOPProverMessage { evaluations: vec![f_0, f_1], }; - println!("Prover message: {:?}", msg); msg - - // let products_list = self.poly.products.clone(); - // let mut products_sum = vec![F::zero(); self.poly.aux_info.max_degree + 1]; - - // println!("max degree: {:?}", self.poly.aux_info.max_degree); - // println!("product sum: {:?}", products_sum); - - // Step 2: generate sum for the partial evaluated polynomial: - // f(r_1, ... r_m,, x_{m+1}... x_n) - - // let mut sum = F::zero(); - // // products_sum.iter_mut().enumerate().for_each(|(t, e)| { - // // for b in 0..1 << (self.poly.aux_info.num_variables - self.round) { - // for b in 0..1 << (self.init_num_vars - self.round) { - // // evaluate P_round(t) - // for mle in self.mle_list.iter() { - // // let num_mles = products.len(); - // // let mut product = *coefficient; - // // for &f in products.iter().take(num_mles) { - // // let table = &flattened_ml_extensions[f]; // f's range is checked in - // init product *= mle[b << 1] * (F::one() - F::from(t as u32)) - // + mle[(b << 1) + 1] * F::from(t as u32); - // // } - // sum += product; - // } - // } - // } - // ); - - // products_list.iter().for_each(|(coefficient, products)| { - // let mut sum = (0..1 << (self.poly.aux_info.num_variables - self.round)) - // .into_iter() - // .fold( - // || { - // ( - // vec![(F::zero(), F::zero()); products.len()], - // vec![F::zero(); products.len() + 1], - // ) - // }, - // |(mut buf, mut acc), b| { - // buf.iter_mut() - // .zip(products.iter()) - // .for_each(|((eval, step), f)| { - // let table = &flattened_ml_extensions[*f]; - // *eval = table[b << 1]; - // *step = table[(b << 1) + 1] - table[b << 1]; - // }); - // acc[0] += buf.iter().map(|(eval, _)| eval).product::(); - // acc[1..].iter_mut().for_each(|acc| { - // buf.iter_mut().for_each(|(eval, step)| *eval += step as &_); - // *acc += buf.iter().map(|(eval, _)| eval).product::(); - // }); - // (buf, acc) - // }, - // ) - // .map(|(_, partial)| partial) - // .reduce( - // || vec![F::zero(); products.len() + 1], - // |mut sum, partial| { - // sum.iter_mut() - // .zip(partial.iter()) - // .for_each(|(sum, partial)| *sum += partial); - // sum - // }, - // ); - // sum.iter_mut().for_each(|sum| *sum *= coefficient); - // let extraploation = (0..self.poly.aux_info.max_degree - products.len()) - // .into_iter() - // .map(|i| { - // let (points, weights) = &self.extrapolation_aux[products.len() - 1]; - // let at = F::from((products.len() + 1 + i) as u32); - // extrapolate(points, weights, &sum, &at) - // }) - // .collect::>(); - // products_sum - // .iter_mut() - // .zip(sum.iter().chain(extraploation.iter())) - // .for_each(|(products_sum, sum)| *products_sum += sum); - // }); - - // update prover's state to the partial evaluated polynomial - // self.poly.flattened_ml_extensions = fl - - // todo!() } } - -fn barycentric_weights(points: &[F]) -> Vec { - let mut weights = points - .iter() - .enumerate() - .map(|(j, point_j)| { - points - .iter() - .enumerate() - .filter(|&(i, _point_i)| (i != j)) - .map(|(_i, point_i)| *point_j - point_i) - .reduce(|acc, value| acc * value) - .unwrap_or_else(F::one) - }) - .collect::>(); - batch_inversion(&mut weights); - weights -} - -fn extrapolate(points: &[F], weights: &[F], evals: &[F], at: &F) -> F { - let (coeffs, sum_inv) = { - let mut coeffs = points.iter().map(|point| *at - point).collect::>(); - batch_inversion(&mut coeffs); - coeffs.iter_mut().zip(weights).for_each(|(coeff, weight)| { - *coeff *= weight; - }); - let sum_inv = coeffs.iter().sum::().inv().unwrap_or_default(); - (coeffs, sum_inv) - }; - coeffs - .iter() - .zip(evals) - .map(|(coeff, eval)| *coeff * eval) - .sum::() - * sum_inv -} diff --git a/sumcheck/src/sumcheck_generic/tests.rs b/sumcheck/src/sumcheck_generic/tests.rs index d7536216..640b036e 100644 --- a/sumcheck/src/sumcheck_generic/tests.rs +++ b/sumcheck/src/sumcheck_generic/tests.rs @@ -1,4 +1,5 @@ use super::*; + use arith::Fr; use ark_std::test_rng; use gkr_hashers::Keccak256hasher; @@ -6,190 +7,96 @@ use polynomials::MultilinearExtension; use transcript::BytesHashTranscript; #[test] -fn test_sumcheck() { +fn test_sumcheck_subroutine() { for num_vars in 1..10 { let size = 1 << num_vars; - let coeffs = (1..=size).map(|i| Fr::from(i as u32)).collect::>(); - let mle = MultiLinearPoly::::new(coeffs); - let asserted_sum = mle.coeffs.iter().sum::(); - - let mut transcript = BytesHashTranscript::::new(); - - let mut prover = IOPProverState::prover_init(mle.clone()); - let mut verifier = IOPVerifierState::verifier_init(prover.mle.num_vars()); + for num_poly in 1..10 { + let mle_list = (0..num_poly) + .map(|j| { + let coeffs = (1..=size) + .map(|i| Fr::from(j * 10 + i as u32)) + .collect::>(); + MultiLinearPoly::::new(coeffs) + }) + .collect::>(); + + let asserted_sum = mle_list + .iter() + .map(|mle| mle.coeffs.iter().sum::()) + .sum::(); + + let mut transcript = BytesHashTranscript::::new(); + + let mut prover = IOPProverState::prover_init(&mle_list); + let mut verifier = IOPVerifierState::verifier_init(prover.mle_list[0].num_vars()); + + let mut challenge = None; + + for _ in 0..prover.mle_list[0].num_vars() { + let prover_msg = + IOPProverState::prove_round_and_update_state(&mut prover, &challenge); + + challenge = Some(IOPVerifierState::verify_round_and_update_state( + &mut verifier, + &prover_msg, + &mut transcript, + )); + } + + let subclaim = IOPVerifierState::check_and_generate_subclaim(&verifier, &asserted_sum); + + let evals = mle_list + .iter() + .map(|mle| mle.eval_reverse_order(&subclaim.point)) + .sum::(); + + assert!( + evals == subclaim.expected_evaluation, + "wrong subclaim: {:?} != {:?}", + evals, + subclaim.expected_evaluation + ); + } + } +} - let mut challenge = None; +#[test] +fn test_sumcheck_e2e() { + let mut rng = test_rng(); - for _ in 0..prover.mle.num_vars() { - let prover_msg = IOPProverState::prove_round_and_update_state(&mut prover, &challenge); - // let challenge = IOPVerifierState::verify_round_and_update_state(&mut verifeir, - // &prover_msg, &mut transcript); transcript.append_serializable_data(&prover_msg); + for num_vars in 1..10 { + let size = 1 << num_vars; - challenge = Some(IOPVerifierState::verify_round_and_update_state( - &mut verifier, - &prover_msg, - &mut transcript, - )); + for num_poly in 1..10 { + let mle_list = (0..num_poly) + .map(|_| { + let coeffs = (1..=size) + .map(|_| Fr::random_unsafe(&mut rng)) + .collect::>(); + MultiLinearPoly::::new(coeffs) + }) + .collect::>(); + + let asserted_sum = mle_list + .iter() + .map(|mle| mle.coeffs.iter().sum::()) + .sum::(); + + // prover + let mut transcript = BytesHashTranscript::::new(); + let proof = SumCheck::::prove(&mle_list, &mut transcript); + + // verifier + let mut transcript = BytesHashTranscript::::new(); + let subclaim = SumCheck::::verify(asserted_sum, &proof, num_vars, &mut transcript); + + let evals = mle_list + .iter() + .map(|mle| mle.eval_reverse_order(&subclaim.point)) + .sum::(); + + assert!(evals == subclaim.expected_evaluation, "wrong subclaim"); } - - println!("prover challenges: {:?}", prover.challenges); - println!("verifier challenges: {:?}", verifier.challenges); - - let subclaim = IOPVerifierState::check_and_generate_subclaim(&verifier, &asserted_sum); - assert!( - mle.eval_reverse_order(&subclaim.point) == subclaim.expected_evaluation, - "wrong subclaim {:?} {:?} ", - mle.eval_reverse_order(&subclaim.point), - subclaim.expected_evaluation, - ); } } - -// fn test_sumcheck(nv: usize, num_multiplicands_range: (usize, usize), num_products: usize) { -// let mut rng = test_rng(); -// let mut transcript = BytesHashTranscript::::new(); - -// let (poly, asserted_sum) = -// VirtualPolynomial::rand(nv, num_multiplicands_range, num_products, &mut rng); - -// println!("poly: {:?}", poly); - -// let proof = Sumcheck::::prove(&poly, &mut transcript); -// let poly_info = poly.aux_info.clone(); - -// let mut transcript = BytesHashTranscript::::new(); -// let subclaim = Sumcheck::::verify(asserted_sum, &proof, &poly_info, &mut transcript); -// assert!( -// poly.evaluate(&subclaim.point) == subclaim.expected_evaluation, -// "wrong subclaim" -// ); -// } - -// fn test_sumcheck_internal(nv: usize, num_multiplicands_range: (usize, usize), num_products: -// usize) { let mut rng = test_rng(); -// let (poly, asserted_sum) = -// VirtualPolynomial::::rand(nv, num_multiplicands_range, num_products, &mut rng); -// let poly_info = poly.aux_info.clone(); -// let mut prover_state = IOPProverState::prover_init(&poly); -// let mut verifier_state = IOPVerifierState::verifier_init(&poly_info); -// let mut challenge = None; -// let mut transcript = BytesHashTranscript::::new(); -// // transcript -// // .append_message(b"testing", b"initializing transcript for testing") -// // .unwrap(); -// for _ in 0..poly.aux_info.num_variables { -// let prover_message = -// IOPProverState::prove_round_and_update_state(&mut prover_state, &challenge); - -// challenge = Some(IOPVerifierState::verify_round_and_update_state( -// &mut verifier_state, -// &prover_message, -// &mut transcript, -// )); -// } -// let subclaim = IOPVerifierState::check_and_generate_subclaim(&verifier_state, &asserted_sum); -// assert!( -// poly.evaluate(&subclaim.point) == subclaim.expected_evaluation, -// "wrong subclaim" -// ); -// } - -// #[test] -// fn test_trivial_polynomial() { -// let nv = 1; -// let num_multiplicands_range = (4, 13); -// let num_products = 5; - -// test_sumcheck(nv, num_multiplicands_range, num_products); -// test_sumcheck_internal(nv, num_multiplicands_range, num_products); -// } -// #[test] -// fn test_normal_polynomial() { -// let nv = 5; -// let num_multiplicands_range = (1,2); -// let num_products = 1; - -// test_sumcheck(nv, num_multiplicands_range, num_products); -// // test_sumcheck_internal(nv, num_multiplicands_range, num_products); -// } -// // #[test] -// // fn zero_polynomial_should_error() { -// // let nv = 0; -// // let num_multiplicands_range = (4, 13); -// // let num_products = 5; - -// // assert!(test_sumcheck(nv, num_multiplicands_range, num_products).is_err()); -// // assert!(test_sumcheck_internal(nv, num_multiplicands_range, num_products).is_err()); -// // } - -// #[test] -// fn test_extract_sum() { -// let mut rng = test_rng(); -// let mut transcript = BytesHashTranscript::::new(); -// let (poly, asserted_sum) = VirtualPolynomial::::rand(8, (3, 4), 3, &mut rng); - -// let proof = Sumcheck::::prove(&poly, &mut transcript); -// assert_eq!(Sumcheck::::extract_sum(&proof), asserted_sum); -// } - -// // #[test] -// // /// Test that the memory usage of shared-reference is linear to number of -// // /// unique MLExtensions instead of total number of multiplicands. -// // fn test_shared_reference() -> Result<(), PolyIOPErrors> { -// // let mut rng = test_rng(); -// // let ml_extensions: Vec<_> = (0..5) -// // .map(|_| Rc::new(DenseMultilinearExtension::::rand(8, &mut rng))) -// // .collect(); -// // let mut poly = VirtualPolynomial::new(8); -// // poly.add_mle_list( -// // vec![ -// // ml_extensions[2].clone(), -// // ml_extensions[3].clone(), -// // ml_extensions[0].clone(), -// // ], -// // Fr::rand(&mut rng), -// // )?; -// // poly.add_mle_list( -// // vec![ -// // ml_extensions[1].clone(), -// // ml_extensions[4].clone(), -// // ml_extensions[4].clone(), -// // ], -// // Fr::rand(&mut rng), -// // )?; -// // poly.add_mle_list( -// // vec![ -// // ml_extensions[3].clone(), -// // ml_extensions[2].clone(), -// // ml_extensions[1].clone(), -// // ], -// // Fr::rand(&mut rng), -// // )?; -// // poly.add_mle_list( -// // vec![ml_extensions[0].clone(), ml_extensions[0].clone()], -// // Fr::rand(&mut rng), -// // )?; -// // poly.add_mle_list(vec![ml_extensions[4].clone()], Fr::rand(&mut rng))?; - -// // assert_eq!(poly.flattened_ml_extensions.len(), 5); - -// // // test memory usage for prover -// // let prover = IOPProverState::prover_init(&poly).unwrap(); -// // assert_eq!(prover.poly.flattened_ml_extensions.len(), 5); -// // drop(prover); - -// // let mut transcript = as SumCheck>::init_transcript(); -// // let poly_info = poly.aux_info.clone(); -// // let proof = as SumCheck>::prove(&poly, &mut transcript)?; -// // let asserted_sum = as SumCheck>::extract_sum(&proof); - -// // let mut transcript = as SumCheck>::init_transcript(); -// // let subclaim = -// // as SumCheck>::verify(asserted_sum, &proof, &poly_info, &mut -// // transcript)?; assert!( -// // poly.evaluate(&subclaim.point)? == subclaim.expected_evaluation, -// // "wrong subclaim" -// // ); -// // Ok(()) -// // } diff --git a/sumcheck/src/sumcheck_generic/verifier.rs b/sumcheck/src/sumcheck_generic/verifier.rs index d80fa659..bdaae2b1 100644 --- a/sumcheck/src/sumcheck_generic/verifier.rs +++ b/sumcheck/src/sumcheck_generic/verifier.rs @@ -1,17 +1,14 @@ use arith::Field; use gkr_engine::Transcript; -use polynomials::VPAuxInfo; use super::{IOPProverMessage, IOPVerifierState, SumCheckSubClaim}; impl IOPVerifierState { /// Initialize the verifier's state. - // pub fn verifier_init(index_info: &VPAuxInfo) -> Self { pub fn verifier_init(num_vars: usize) -> Self { let res = Self { round: 1, - num_vars, //index_info.num_variables, - // max_degree: index_info.max_degree, + num_vars, finished: false, polynomials_received: Vec::with_capacity(num_vars), challenges: Vec::with_capacity(num_vars), @@ -48,12 +45,6 @@ impl IOPVerifierState { self.polynomials_received .push(prover_msg.evaluations.clone()); - println!( - "sum: {:?}", - prover_msg.evaluations[0] + prover_msg.evaluations[1] - ); - // println!("uni eval {:?}", ); - if self.round == self.num_vars { // accept and close self.finished = true; @@ -82,62 +73,19 @@ impl IOPVerifierState { panic!("insufficient rounds") } - // let mut expected_vec = vec![F::zero(); self.num_vars + 1]; - - // let mut expected_vec = self - // .polynomials_received - // .clone() - // .into_iter() - // .zip(self.challenges.clone().into_iter()) - // .map(|(evaluations, challenge)| { - // // if evaluations.len() != 2 { - // // panic!( - // // "incorrect number of evaluations: {} vs {}", - // // evaluations.len(), - // // self.max_degree + 1 - // // ); - // // } - // // interpolate_uni_poly::(&evaluations, challenge) - - // evaluations[0]+ (evaluations[1] - evaluations[0]) * challenge - // }) - // .collect::>(); - - // insert the asserted_sum to the first position of the expected vector - // expected_vec.insert(0, *asserted_sum); - let mut expected = *asserted_sum; for i in 0..self.num_vars { let evals = &self.polynomials_received[i]; - let sum = evals[0] + evals[1]; - println!( - "{}th layer Prover message: {:?}, expected: {:?}", - i, sum, expected - ); + // the univariate polynomial f is received in its extrapolated form, i.e., + // f(0) = evals[0] and f(1) = evals[1]. + // now we want to compute f(r) for the challenge r = self.challenges[i] + // that is + // f(0) + (f(1) - f(0)) * r expected = evals[0] + (evals[1] - evals[0]) * self.challenges[i]; } - // for (i, (evaluations, &expected)) in self - // .polynomials_received - // .iter() - // .zip(expected_vec.iter()) - // .take(self.num_vars) - // .enumerate() - // { - // // the deferred check during the interactive phase: - // // 1. check if the received 'P(0) + P(1) = expected`. - // println!( - // "{}th layer Prover message: {:?}, expected: {:?}", - // i, evaluations, expected - // ); - - // if evaluations[0] + evaluations[1] != expected { - // panic!("Prover message is not consistent with the claim.") - // } - // } - SumCheckSubClaim { point: self.challenges.clone(), // the last expected value (not checked within this function) will be included in the @@ -146,140 +94,3 @@ impl IOPVerifierState { } } } - -// /// Interpolate a uni-variate degree-`p_i.len()-1` polynomial and evaluate this -// /// polynomial at `eval_at`: -// /// -// /// \sum_{i=0}^len p_i * (\prod_{j!=i} (eval_at - j)/(i-j) ) -// /// -// /// This implementation is linear in number of inputs in terms of field -// /// operations. It also has a quadratic term in primitive operations which is -// /// negligible compared to field operations. -// /// TODO: The quadratic term can be removed by precomputing the lagrange -// /// coefficients. -// fn interpolate_uni_poly(p_i: &[F], eval_at: F) -> F { -// let len = p_i.len(); -// let mut evals = vec![]; -// let mut prod = eval_at; -// evals.push(eval_at); - -// // `prod = \prod_{j} (eval_at - j)` -// for e in 1..len { -// let tmp = eval_at - F::from(e as u32); -// evals.push(tmp); -// prod *= tmp; -// } -// let mut res = F::zero(); -// // we want to compute \prod (j!=i) (i-j) for a given i -// // -// // we start from the last step, which is -// // denom[len-1] = (len-1) * (len-2) *... * 2 * 1 -// // the step before that is -// // denom[len-2] = (len-2) * (len-3) * ... * 2 * 1 * -1 -// // and the step before that is -// // denom[len-3] = (len-3) * (len-4) * ... * 2 * 1 * -1 * -2 -// // -// // i.e., for any i, the one before this will be derived from -// // denom[i-1] = denom[i] * (len-i) / i -// // -// // that is, we only need to store -// // - the last denom for i = len-1, and -// // - the ratio between current step and fhe last step, which is the product of (len-i) / i -// from // all previous steps and we store this product as a fraction number to reduce field -// // divisions. - -// // // We know -// // // - 2^61 < factorial(20) < 2^62 -// // // - 2^122 < factorial(33) < 2^123 -// // // so we will be able to compute the ratio -// // // - for len <= 20 with i64 -// // // - for len <= 33 with i128 -// // // - for len > 33 with BigInt -// // if p_i.len() <= 20 { -// // let last_denominator = F::from(u64_factorial(len - 1)); -// // let mut ratio_numerator = 1i64; -// // let mut ratio_denominator = 1u64; - -// // for i in (0..len).rev() { -// // let ratio_numerator_f = if ratio_numerator < 0 { -// // -F::from((-ratio_numerator) as u64) -// // } else { -// // F::from(ratio_numerator as u64) -// // }; - -// // res += p_i[i] * prod * F::from(ratio_denominator) -// // / (last_denominator * ratio_numerator_f * evals[i]); - -// // // compute denom for the next step is current_denom * (len-i)/i -// // if i != 0 { -// // ratio_numerator *= -(len as i64 - i as i64); -// // ratio_denominator *= i as u64; -// // } -// // } -// // } else if p_i.len() <= 33 { -// // let last_denominator = F::from(u128_factorial(len - 1)); -// // let mut ratio_numerator = 1i128; -// // let mut ratio_denominator = 1u128; - -// // for i in (0..len).rev() { -// // let ratio_numerator_f = if ratio_numerator < 0 { -// // -F::from((-ratio_numerator) as u128) -// // } else { -// // F::from(ratio_numerator as u128) -// // }; - -// // res += p_i[i] * prod * F::from(ratio_denominator) -// // / (last_denominator * ratio_numerator_f * evals[i]); - -// // // compute denom for the next step is current_denom * (len-i)/i -// // if i != 0 { -// // ratio_numerator *= -(len as i128 - i as i128); -// // ratio_denominator *= i as u128; -// // } -// // } -// // } else { -// let mut denom_up = field_factorial::(len - 1); -// let mut denom_down = F::one(); - -// for i in (0..len).rev() { -// res += p_i[i] * prod * denom_down * (denom_up * evals[i]).inv().unwrap(); - -// // compute denom for the next step is current_denom * (len-i)/i -// if i != 0 { -// denom_up *= -F::from((len - i) as u32); -// denom_down *= F::from(i as u32); -// } -// } -// // } -// res -// } - -// /// compute the factorial(a) = 1 * 2 * ... * a -// #[inline] -// fn field_factorial(a: usize) -> F { -// let mut res = F::one(); -// for i in 2..=a { -// res *= F::from(i as u32); -// } -// res -// } - -// // /// compute the factorial(a) = 1 * 2 * ... * a -// // #[inline] -// // fn u128_factorial(a: usize) -> u128 { -// // let mut res = 1u128; -// // for i in 2..=a { -// // res *= i as u128; -// // } -// // res -// // } - -// // /// compute the factorial(a) = 1 * 2 * ... * a -// // #[inline] -// // fn u64_factorial(a: usize) -> u64 { -// // let mut res = 1u64; -// // for i in 2..=a { -// // res *= i as u64; -// // } -// // res -// // } From 4624176d680b24c23ece1c1e34d06f65c21dbad4 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 28 May 2025 15:32:52 -0400 Subject: [PATCH 25/57] clean up generic sumcheck --- sumcheck/src/sumcheck_generic.rs | 4 ++ sumcheck/src/sumcheck_generic/prover.rs | 6 +-- sumcheck/src/sumcheck_generic/verifier.rs | 7 ++-- sumcheck/src/utils.rs | 51 +---------------------- 4 files changed, 10 insertions(+), 58 deletions(-) diff --git a/sumcheck/src/sumcheck_generic.rs b/sumcheck/src/sumcheck_generic.rs index cbe9b11b..5ac2c4f5 100644 --- a/sumcheck/src/sumcheck_generic.rs +++ b/sumcheck/src/sumcheck_generic.rs @@ -1,3 +1,7 @@ +//! This module implements the SumCheck protocol for verifying the sum of +//! evaluations of a set of multi-linear polynomial over the hypercube {0,1}^n. +//! This is hardcoded for addition gate for simplicity and efficiency. + use arith::Field; use gkr_engine::Transcript; use polynomials::{MultiLinearPoly, MultilinearExtension}; diff --git a/sumcheck/src/sumcheck_generic/prover.rs b/sumcheck/src/sumcheck_generic/prover.rs index d5226165..eac55622 100644 --- a/sumcheck/src/sumcheck_generic/prover.rs +++ b/sumcheck/src/sumcheck_generic/prover.rs @@ -65,10 +65,8 @@ impl IOPProverState { f_1 += coeffs[len..].iter().sum::(); } - let msg = IOPProverMessage { + IOPProverMessage { evaluations: vec![f_0, f_1], - }; - - msg + } } } diff --git a/sumcheck/src/sumcheck_generic/verifier.rs b/sumcheck/src/sumcheck_generic/verifier.rs index bdaae2b1..6dc8cc72 100644 --- a/sumcheck/src/sumcheck_generic/verifier.rs +++ b/sumcheck/src/sumcheck_generic/verifier.rs @@ -6,15 +6,14 @@ use super::{IOPProverMessage, IOPVerifierState, SumCheckSubClaim}; impl IOPVerifierState { /// Initialize the verifier's state. pub fn verifier_init(num_vars: usize) -> Self { - let res = Self { + Self { round: 1, num_vars, finished: false, polynomials_received: Vec::with_capacity(num_vars), challenges: Vec::with_capacity(num_vars), - }; - - res + } + } /// Run verifier for the current round, given a prover message. diff --git a/sumcheck/src/utils.rs b/sumcheck/src/utils.rs index 108a39be..60bcb1ac 100644 --- a/sumcheck/src/utils.rs +++ b/sumcheck/src/utils.rs @@ -1,4 +1,4 @@ -use arith::{ExtensionField, Field, SimdField}; +use arith::{ExtensionField, SimdField}; use gkr_engine::{MPIEngine, Transcript}; #[inline(always)] @@ -41,52 +41,3 @@ where mpi_config.root_broadcast_f(&mut r); r } - -// Given a vector of field elements {v_i}, compute the vector {v_i^(-1)} -pub fn batch_inversion(v: &mut [F]) { - batch_inversion_and_mul(v, &F::one()); -} - -// Given a vector of field elements {v_i}, compute the vector {coeff * v_i^(-1)} -pub fn batch_inversion_and_mul(v: &mut [F], coeff: &F) { - serial_batch_inversion_and_mul(v, coeff); -} - -/// Given a vector of field elements {v_i}, compute the vector {coeff * v_i^(-1)}. -/// This method is explicitly single-threaded. -fn serial_batch_inversion_and_mul(v: &mut [F], coeff: &F) { - // Montgomery’s Trick and Fast Implementation of Masked AES - // Genelle, Prouff and Quisquater - // Section 3.2 - // but with an optimization to multiply every element in the returned vector by - // coeff - - // First pass: compute [a, ab, abc, ...] - let mut prod = Vec::with_capacity(v.len()); - let mut tmp = F::one(); - for f in v.iter().filter(|f| !f.is_zero()) { - tmp.mul_assign(f); - prod.push(tmp); - } - - // Invert `tmp`. - tmp = tmp.inv().unwrap(); // Guaranteed to be nonzero. - - // Multiply product by coeff, so all inverses will be scaled by coeff - tmp *= coeff; - - // Second pass: iterate backwards to compute inverses - for (f, s) in v.iter_mut() - // Backwards - .rev() - // Ignore normalized elements - .filter(|f| !f.is_zero()) - // Backwards, skip last element, fill in one for last term. - .zip(prod.into_iter().rev().skip(1).chain(Some(F::one()))) - { - // tmp := tmp * f; f := tmp * s = 1/f - let new_tmp = tmp * *f; - *f = tmp * &s; - tmp = new_tmp; - } -} From aed30f2eee869a5d48a47592de0c4da87bb6822f Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 28 May 2025 16:37:14 -0400 Subject: [PATCH 26/57] wip --- Cargo.lock | 1 + gkr_engine/src/transcript/definition.rs | 3 +- poly_commit/Cargo.toml | 1 + poly_commit/src/hyrax/pcs_trait_impl.rs | 155 +++++++++++++++++++++- poly_commit/src/kzg/pcs_trait_impl.rs | 4 +- poly_commit/src/traits.rs | 47 ++++++- poly_commit/tests/common.rs | 59 +++++++- sumcheck/src/sumcheck_generic.rs | 10 +- sumcheck/src/sumcheck_generic/verifier.rs | 3 +- sumcheck/src/utils.rs | 2 +- 10 files changed, 265 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9bd63176..9d5d8390 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1755,6 +1755,7 @@ dependencies = [ "polynomials", "rand", "serdes", + "sumcheck", "thiserror", "transcript", "transpose", diff --git a/gkr_engine/src/transcript/definition.rs b/gkr_engine/src/transcript/definition.rs index 971b0d8e..fbc6f0dd 100644 --- a/gkr_engine/src/transcript/definition.rs +++ b/gkr_engine/src/transcript/definition.rs @@ -55,8 +55,7 @@ pub trait Transcript: Clone + Debug { /// Generate a field element. #[inline(always)] fn generate_field_element(&mut self) -> F { - F::from((self.generate_u8_slice(1)[0] + 1) as u32) - // F::from_uniform_bytes(&self.generate_u8_slice(F::SIZE)) + F::from_uniform_bytes(&self.generate_u8_slice(F::SIZE)) } /// Generate a field element vector. diff --git a/poly_commit/Cargo.toml b/poly_commit/Cargo.toml index 69cfc3e0..8655622a 100644 --- a/poly_commit/Cargo.toml +++ b/poly_commit/Cargo.toml @@ -12,6 +12,7 @@ serdes = { path = "../serdes" } transcript = { path = "../transcript" } tree = { path = "../tree" } utils = { path = "../utils" } +sumcheck = { path = "../sumcheck" } rand.workspace = true ethnum.workspace = true diff --git a/poly_commit/src/hyrax/pcs_trait_impl.rs b/poly_commit/src/hyrax/pcs_trait_impl.rs index 2998bba4..26e96fad 100644 --- a/poly_commit/src/hyrax/pcs_trait_impl.rs +++ b/poly_commit/src/hyrax/pcs_trait_impl.rs @@ -1,11 +1,16 @@ use std::marker::PhantomData; use arith::ExtensionField; +use arith::Field; +use ark_std::log2; use gkr_engine::{StructuredReferenceString, Transcript}; +use halo2curves::group::Curve; use halo2curves::{ff::PrimeField, CurveAffine}; -use polynomials::MultiLinearPoly; +use polynomials::{EqPolynomial, MultiLinearPoly, MultilinearExtension}; use serdes::ExpSerde; +use sumcheck::SumCheck; +use crate::traits::BatchOpening; use crate::{ hyrax::hyrax_impl::{hyrax_commit, hyrax_open, hyrax_setup, hyrax_verify}, traits::BatchOpeningPCS, @@ -85,7 +90,7 @@ where C::Scalar: ExtensionField + PrimeField, C::ScalarExt: ExtensionField + PrimeField, { - fn batch_open( + fn single_point_batch_open( _params: &Self::Params, proving_key: &::PKey, mle_poly_list: &[Self::Poly], @@ -96,7 +101,7 @@ where hyrax_batch_open(proving_key, mle_poly_list, eval_point, transcript) } - fn batch_verify( + fn single_point_batch_verify( _params: &Self::Params, verifying_key: &::VKey, comm_list: &[Self::Commitment], @@ -114,4 +119,148 @@ where transcript, ) } + + /// Open a set of polynomials at a multiple points. + /// Requires the length of the polys to be the same as points. + fn multiple_points_batch_open( + _params: &Self::Params, + proving_key: &::PKey, + polys: &[Self::Poly], + points: &[Self::EvalPoint], + _scratch_pad: &Self::ScratchPad, + transcript: &mut impl Transcript, + ) -> BatchOpening { + let num_vars = polys[0].num_vars(); + let k = polys.len(); + let ell = log2(k) as usize; + + // generate evals for each polynomial at its corresponding point + let evals: Vec = polys + .iter() + .zip(points.iter()) + .map(|(poly, point)| poly.evaluate_jolt(point)) + .collect(); + + // challenge point t + let t = transcript.generate_field_elements::(ell); + + // eq(t, i) for i in [0..k] + let eq_t_i_list = EqPolynomial::build_eq_x_r(&t); + + // \tilde g_i(b) = eq(t, i) * f_i(b) + let mut tilde_gs = vec![]; + for (index, f_i) in polys.iter().enumerate() { + let mut tilde_g_eval = vec![C::Scalar::zero(); 1 << num_vars]; + for (j, &f_i_eval) in f_i.coeffs.iter().enumerate() { + tilde_g_eval[j] = f_i_eval * eq_t_i_list[index]; + } + tilde_gs.push(MultiLinearPoly { + coeffs: tilde_g_eval, + }); + } + + let tilde_eqs: Vec> = points + .iter() + .map(|point| { + let eq_b_zi = EqPolynomial::build_eq_x_r(point); + MultiLinearPoly { coeffs: eq_b_zi } + }) + .collect(); + + let mut sumcheck_poly = vec![]; + for (tilde_g, tilde_eq) in tilde_gs.iter().zip(tilde_eqs.into_iter()) { + sumcheck_poly.extend_from_slice([tilde_g.clone(), tilde_eq].as_slice()); + } + + let proof = SumCheck::::prove(&sumcheck_poly, transcript); + + println!("SumCheck proof: {:?}", proof,); + + let a2 = &proof.point[..num_vars]; + + // build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the + // sumcheck's point \tilde eq_i(a2) = eq(a2, point_i) + let mut g_prime_evals = vec![C::Scalar::zero(); 1 << num_vars]; + for (tilde_g, point) in tilde_gs.iter().zip(points.iter()) { + let eq_i_a2 = EqPolynomial::eq_vec(a2, point); + for (j, &tilde_g_eval) in tilde_g.coeffs.iter().enumerate() { + g_prime_evals[j] += tilde_g_eval * eq_i_a2; + } + } + let g_prime = MultiLinearPoly { + coeffs: g_prime_evals, + }; + + let (_g_prime_eval, g_prime_proof) = + hyrax_open(proving_key, &g_prime, a2.to_vec().as_ref()); + + BatchOpening { + sum_check_proof: proof, + f_i_eval_at_point_i: evals.to_vec(), + g_prime_proof, + } + } + + /// Verify the opening of a set of polynomials at a single point. + fn multiple_points_batch_verify( + _params: &Self::Params, + verifying_key: &::VKey, + commitments: &[Self::Commitment], + points: &[Self::EvalPoint], + _values: &[C::Scalar], + opening: &BatchOpening, + transcript: &mut impl Transcript, + ) -> bool { + let k = commitments.len(); + let ell = log2(k) as usize; + let num_var = opening.sum_check_proof.point.len(); + + // challenge point t + let t = transcript.generate_field_elements::(ell); + + // sum check point (a2) + let a2 = &opening.sum_check_proof.point[..num_var]; + + // build g' commitment + // todo: use MSM + let eq_t_list = EqPolynomial::build_eq_x_r(&t); + + // let mut scalars = vec![]; + // let mut bases = vec![]; + + let mut g_prime_commit_elems = vec![C::Curve::default(); commitments[0].0.len()]; + for (i, point) in points.iter().enumerate() { + let eq_i_a2 = EqPolynomial::eq_vec(a2, point); + // scalars.push(eq_i_a2 * eq_t_list[i]); + // bases.push(commitments[i].0); + let scalar = eq_i_a2 * eq_t_list[i]; + for (j, &base) in commitments[i].0.iter().enumerate() { + g_prime_commit_elems[j] += (base * scalar); + } + } + let mut g_prime_commit_affine = vec![C::default(); commitments[0].0.len()]; + C::Curve::batch_normalize(&g_prime_commit_elems, &mut g_prime_commit_affine); + + let g_prime_commit = HyraxCommitment(g_prime_commit_affine); + + // ensure \sum_i eq(t, ) * f_i_evals matches the sum via SumCheck + let mut sum = C::Scalar::zero(); + for (i, &e) in eq_t_list.iter().enumerate().take(k) { + sum += e * opening.f_i_eval_at_point_i[i]; + } + + let subclaim = + SumCheck::::verify(sum, &opening.sum_check_proof, num_var, transcript); + + let tilde_g_eval = subclaim.expected_evaluation; + + // verify commitment + hyrax_verify( + verifying_key, + &g_prime_commit, + a2.to_vec().as_ref(), + tilde_g_eval, + &opening.g_prime_proof, + ) + } } diff --git a/poly_commit/src/kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/pcs_trait_impl.rs index ff296033..c8f168c7 100644 --- a/poly_commit/src/kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/pcs_trait_impl.rs @@ -113,7 +113,7 @@ where E::G1Affine: ExpSerde + Default + CurveAffine, E::G2Affine: ExpSerde + Default + CurveAffine, { - fn batch_open( + fn single_point_batch_open( _params: &Self::Params, proving_key: &::PKey, polys: &[Self::Poly], @@ -124,7 +124,7 @@ where kzg_batch_open(proving_key, polys, x, transcript) } - fn batch_verify( + fn single_point_batch_verify( _params: &Self::Params, verifying_key: &::VKey, commitments: &[Self::Commitment], diff --git a/poly_commit/src/traits.rs b/poly_commit/src/traits.rs index cef83ce0..1c47e4d3 100644 --- a/poly_commit/src/traits.rs +++ b/poly_commit/src/traits.rs @@ -3,6 +3,7 @@ use gkr_engine::{StructuredReferenceString, Transcript}; use rand::RngCore; use serdes::ExpSerde; use std::fmt::Debug; +use sumcheck::IOPProof; /// Standard Polynomial commitment scheme (PCS) trait. pub trait PolynomialCommitmentScheme { @@ -58,11 +59,25 @@ pub trait PolynomialCommitmentScheme { ) -> bool; } +#[derive(Debug, PartialEq, Eq)] +pub struct BatchOpening +where + F: ExtensionField, + PCS: PolynomialCommitmentScheme, +{ + /// A sum check proof proving tilde g's sum + pub(crate) sum_check_proof: IOPProof, + /// f_i(point_i) + pub f_i_eval_at_point_i: Vec, + /// proof for g'(a_2) + pub(crate) g_prime_proof: PCS::Opening, +} + /// Batch opening polynomial commitment scheme trait. /// This trait is implemented for homomorphic polynomial commitment schemes such as Hyrax and KZG -pub trait BatchOpeningPCS: PolynomialCommitmentScheme { +pub trait BatchOpeningPCS: PolynomialCommitmentScheme + Sized { /// Open a set of polynomials at a single point. - fn batch_open( + fn single_point_batch_open( params: &Self::Params, proving_key: &::PKey, polys: &[Self::Poly], @@ -72,7 +87,7 @@ pub trait BatchOpeningPCS: PolynomialCommitmentScheme { ) -> (Vec, Self::Opening); /// Verify the opening of a set of polynomials at a single point. - fn batch_verify( + fn single_point_batch_verify( params: &Self::Params, verifying_key: &::VKey, commitments: &[Self::Commitment], @@ -81,6 +96,32 @@ pub trait BatchOpeningPCS: PolynomialCommitmentScheme { opening: &Self::Opening, transcript: &mut impl Transcript, ) -> bool; + + /// Open a set of polynomials at a multiple points. + /// Requires the length of the polys to be the same as points. + fn multiple_points_batch_open( + params: &Self::Params, + proving_key: &::PKey, + polys: &[Self::Poly], + points: &[Self::EvalPoint], + scratch_pad: &Self::ScratchPad, + transcript: &mut impl Transcript, + ) -> BatchOpening { + unimplemented!() + } + + /// Verify the opening of a set of polynomials at a single point. + fn multiple_points_batch_verify( + params: &Self::Params, + verifying_key: &::VKey, + commitments: &[Self::Commitment], + points: &[Self::EvalPoint], + values: &[F], + opening: &BatchOpening, + transcript: &mut impl Transcript, + ) -> bool { + unimplemented!() + } } pub(crate) trait TensorCodeIOPPCS { diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index 58a9fcd0..297f95e1 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -4,7 +4,7 @@ use gkr_engine::{ ExpanderPCS, ExpanderSingleVarChallenge, FieldEngine, MPIConfig, MPIEngine, StructuredReferenceString, Transcript, }; -use poly_commit::PolynomialCommitmentScheme; +use poly_commit::{BatchOpeningPCS, PolynomialCommitmentScheme}; use polynomials::{MultiLinearPoly, MultilinearExtension}; use rand::thread_rng; @@ -49,7 +49,7 @@ pub fn test_batching() where F: ExtensionField, T: Transcript, - P: PolynomialCommitmentScheme, Poly = MultiLinearPoly>, + P: BatchOpeningPCS, Poly = MultiLinearPoly>, { let mut rng = thread_rng(); @@ -61,6 +61,7 @@ where let (proving_key, verification_key) = srs.into_keys(); + // single point batch opening for num_poly in [1, 2, 10, 100] { let polys = (0..num_poly) .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) @@ -77,7 +78,7 @@ where let mut transcript = T::new(); - let (values, batch_opening) = P::batch_open( + let (values, batch_opening) = P::single_point_batch_open( &num_vars, &proving_key, &polys, @@ -88,7 +89,7 @@ where let mut transcript = T::new(); - assert!(P::batch_verify( + assert!(P::single_point_batch_verify( &num_vars, &verification_key, &commitments, @@ -98,6 +99,56 @@ where &mut transcript )) } + + // multi point batch opening + for num_poly in [2, 10, 100] { + let polys = (0..num_poly) + .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) + .collect::>(); + + let commitments = polys + .iter() + .map(|poly| P::commit(&num_vars, &proving_key, poly, &mut scratch_pad)) + .collect::>(); + + // open all polys at all points + let points = (0..num_poly) + .map(|_| { + (0..num_vars) + .map(|_| F::random_unsafe(&mut rng)) + .collect::>() + }) + .collect::>(); + + let values = polys + .iter() + .zip(points.iter()) + .map(|(poly, point)| poly.evaluate_jolt(point)) + .collect::>(); + + let mut transcript = T::new(); + + let batch_opening = P::multiple_points_batch_open( + &num_vars, + &proving_key, + &polys, + points.as_ref(), + &mut scratch_pad, + &mut transcript, + ); + + let mut transcript = T::new(); + + assert!(P::multiple_points_batch_verify( + &num_vars, + &verification_key, + &commitments, + points.as_ref(), + &values, + &batch_opening, + &mut transcript + )) + } } } diff --git a/sumcheck/src/sumcheck_generic.rs b/sumcheck/src/sumcheck_generic.rs index 5ac2c4f5..eb0ccceb 100644 --- a/sumcheck/src/sumcheck_generic.rs +++ b/sumcheck/src/sumcheck_generic.rs @@ -1,6 +1,7 @@ //! This module implements the SumCheck protocol for verifying the sum of //! evaluations of a set of multi-linear polynomial over the hypercube {0,1}^n. //! This is hardcoded for addition gate for simplicity and efficiency. +// Credit: code adopted from https://github.com/EspressoSystems/hyperplonk/ with modification use arith::Field; use gkr_engine::Transcript; @@ -13,11 +14,13 @@ mod verifier; #[cfg(test)] mod tests; -/// An IOP proof is a collections of messages from prover to verifier at each -/// round through the interactive protocol. -#[derive(Clone, Debug, Default, PartialEq)] +/// An IOP proof is a collections of +/// - messages from prover to verifier at each round through the interactive protocol. +/// - a point that is generated by the transcript for evaluation +#[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct IOPProof { pub proofs: Vec>, + pub point: Vec, } /// A message from the prover to the verifier at a given round @@ -95,6 +98,7 @@ impl SumCheck { } IOPProof { + point: prover_state.challenges, proofs: prover_msgs, } } diff --git a/sumcheck/src/sumcheck_generic/verifier.rs b/sumcheck/src/sumcheck_generic/verifier.rs index 6dc8cc72..f92cdd00 100644 --- a/sumcheck/src/sumcheck_generic/verifier.rs +++ b/sumcheck/src/sumcheck_generic/verifier.rs @@ -6,14 +6,13 @@ use super::{IOPProverMessage, IOPVerifierState, SumCheckSubClaim}; impl IOPVerifierState { /// Initialize the verifier's state. pub fn verifier_init(num_vars: usize) -> Self { - Self { + Self { round: 1, num_vars, finished: false, polynomials_received: Vec::with_capacity(num_vars), challenges: Vec::with_capacity(num_vars), } - } /// Run verifier for the current round, given a prover message. diff --git a/sumcheck/src/utils.rs b/sumcheck/src/utils.rs index 60bcb1ac..43728db1 100644 --- a/sumcheck/src/utils.rs +++ b/sumcheck/src/utils.rs @@ -1,4 +1,4 @@ -use arith::{ExtensionField, SimdField}; +use arith::{ExtensionField, SimdField}; use gkr_engine::{MPIEngine, Transcript}; #[inline(always)] From 9979816bffe6c21370d866bb76c9886524afe02e Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 28 May 2025 16:48:03 -0400 Subject: [PATCH 27/57] wip --- poly_commit/src/hyrax/pcs_trait_impl.rs | 5 ++ poly_commit/tests/common.rs | 78 ++++++++++++------------- sumcheck/src/sumcheck_generic.rs | 4 ++ 3 files changed, 48 insertions(+), 39 deletions(-) diff --git a/poly_commit/src/hyrax/pcs_trait_impl.rs b/poly_commit/src/hyrax/pcs_trait_impl.rs index 26e96fad..4d80cf25 100644 --- a/poly_commit/src/hyrax/pcs_trait_impl.rs +++ b/poly_commit/src/hyrax/pcs_trait_impl.rs @@ -159,6 +159,7 @@ where }); } + // built the virtual polynomial for SumCheck let tilde_eqs: Vec> = points .iter() .map(|point| { @@ -171,6 +172,10 @@ where for (tilde_g, tilde_eq) in tilde_gs.iter().zip(tilde_eqs.into_iter()) { sumcheck_poly.extend_from_slice([tilde_g.clone(), tilde_eq].as_slice()); } + println!("SumCheck poly: {:?}", sumcheck_poly.len()); + for poly in sumcheck_poly.iter() { + println!("Poly: {:?}", poly.coeffs.len()); + } let proof = SumCheck::::prove(&sumcheck_poly, transcript); diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index 297f95e1..09e0438f 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -61,47 +61,47 @@ where let (proving_key, verification_key) = srs.into_keys(); - // single point batch opening - for num_poly in [1, 2, 10, 100] { - let polys = (0..num_poly) - .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) - .collect::>(); - let commitments = polys - .iter() - .map(|poly| P::commit(&num_vars, &proving_key, poly, &mut scratch_pad)) - .collect::>(); - - // open all polys at a single point - let x = (0..num_vars) - .map(|_| F::random_unsafe(&mut rng)) - .collect::>(); - - let mut transcript = T::new(); - - let (values, batch_opening) = P::single_point_batch_open( - &num_vars, - &proving_key, - &polys, - x.as_ref(), - &mut scratch_pad, - &mut transcript, - ); - - let mut transcript = T::new(); - - assert!(P::single_point_batch_verify( - &num_vars, - &verification_key, - &commitments, - x.as_ref(), - &values, - &batch_opening, - &mut transcript - )) - } + // // single point batch opening + // for num_poly in [1, 2, 10, 100] { + // let polys = (0..num_poly) + // .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) + // .collect::>(); + // let commitments = polys + // .iter() + // .map(|poly| P::commit(&num_vars, &proving_key, poly, &mut scratch_pad)) + // .collect::>(); + + // // open all polys at a single point + // let x = (0..num_vars) + // .map(|_| F::random_unsafe(&mut rng)) + // .collect::>(); + + // let mut transcript = T::new(); + + // let (values, batch_opening) = P::single_point_batch_open( + // &num_vars, + // &proving_key, + // &polys, + // x.as_ref(), + // &mut scratch_pad, + // &mut transcript, + // ); + + // let mut transcript = T::new(); + + // assert!(P::single_point_batch_verify( + // &num_vars, + // &verification_key, + // &commitments, + // x.as_ref(), + // &values, + // &batch_opening, + // &mut transcript + // )) + // } // multi point batch opening - for num_poly in [2, 10, 100] { + for num_poly in [2, 4, 8, 16] { let polys = (0..num_poly) .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) .collect::>(); diff --git a/sumcheck/src/sumcheck_generic.rs b/sumcheck/src/sumcheck_generic.rs index eb0ccceb..01a92567 100644 --- a/sumcheck/src/sumcheck_generic.rs +++ b/sumcheck/src/sumcheck_generic.rs @@ -96,6 +96,10 @@ impl SumCheck { prover_msgs.push(prover_msg); challenge = Some(transcript.generate_field_element::()); } + // pushing the last challenge point to the state + if let Some(p) = challenge { + prover_state.challenges.push(p) + }; IOPProof { point: prover_state.challenges, From 1e67e2527210d36f4ac2702bd81f7fccc14bf7c9 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 28 May 2025 21:14:45 -0400 Subject: [PATCH 28/57] wip --- gkr_engine/src/transcript/definition.rs | 4 +- poly_commit/src/hyrax/pcs_trait_impl.rs | 97 +++++++++++++++++++++---- poly_commit/tests/common.rs | 14 +++- 3 files changed, 96 insertions(+), 19 deletions(-) diff --git a/gkr_engine/src/transcript/definition.rs b/gkr_engine/src/transcript/definition.rs index fbc6f0dd..5e376ec1 100644 --- a/gkr_engine/src/transcript/definition.rs +++ b/gkr_engine/src/transcript/definition.rs @@ -55,7 +55,9 @@ pub trait Transcript: Clone + Debug { /// Generate a field element. #[inline(always)] fn generate_field_element(&mut self) -> F { - F::from_uniform_bytes(&self.generate_u8_slice(F::SIZE)) + F::from(self.generate_u8_slice(1)[0] as u32) + + // F::from_uniform_bytes(&self.generate_u8_slice(F::SIZE)) } /// Generate a field element vector. diff --git a/poly_commit/src/hyrax/pcs_trait_impl.rs b/poly_commit/src/hyrax/pcs_trait_impl.rs index 4d80cf25..d981f415 100644 --- a/poly_commit/src/hyrax/pcs_trait_impl.rs +++ b/poly_commit/src/hyrax/pcs_trait_impl.rs @@ -122,6 +122,15 @@ where /// Open a set of polynomials at a multiple points. /// Requires the length of the polys to be the same as points. + /// Steps: + /// 1. get challenge point t from transcript + /// 2. build eq(t,i) for i in [0..k] + /// 3. build \tilde g_i(b) = eq(t, i) * f_i(b) + /// 4. compute \tilde eq_i(b) = eq(b, point_i) + /// 5. run sumcheck on \sum_i=1..k \tilde eq_i * \tilde g_i + /// 6. build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the sumcheck's + /// point + /// 7. open g'(X) at point (a2) fn multiple_points_batch_open( _params: &Self::Params, proving_key: &::PKey, @@ -141,23 +150,26 @@ where .map(|(poly, point)| poly.evaluate_jolt(point)) .collect(); - // challenge point t - let t = transcript.generate_field_elements::(ell); + // // challenge point t + // let t = transcript.generate_field_elements::(ell); - // eq(t, i) for i in [0..k] - let eq_t_i_list = EqPolynomial::build_eq_x_r(&t); + // // eq(t, i) for i in [0..k] + // let eq_t_i = EqPolynomial::build_eq_x_r(&t); + + let eq_t_i = vec![C::Scalar::one(); 1 << ell]; // \tilde g_i(b) = eq(t, i) * f_i(b) let mut tilde_gs = vec![]; for (index, f_i) in polys.iter().enumerate() { let mut tilde_g_eval = vec![C::Scalar::zero(); 1 << num_vars]; for (j, &f_i_eval) in f_i.coeffs.iter().enumerate() { - tilde_g_eval[j] = f_i_eval * eq_t_i_list[index]; + tilde_g_eval[j] = f_i_eval * eq_t_i[index]; } tilde_gs.push(MultiLinearPoly { coeffs: tilde_g_eval, }); } + // println!("tilde_gs: {:?}", tilde_gs); // built the virtual polynomial for SumCheck let tilde_eqs: Vec> = points @@ -178,16 +190,28 @@ where } let proof = SumCheck::::prove(&sumcheck_poly, transcript); - + println!("SumCheck proof: {:?}", proof,); + println!( + "SumCheck sum: {:?}", + SumCheck::::extract_sum(&proof) + ); + let a2 = &proof.point[..num_vars]; + println!("a2: {:?}", a2); + println!("eq_t_i: {:?}", eq_t_i); + // build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the // sumcheck's point \tilde eq_i(a2) = eq(a2, point_i) let mut g_prime_evals = vec![C::Scalar::zero(); 1 << num_vars]; + + // println!("tilde_gs: {:?}", tilde_gs.len()); + // println!("tilde_gs: {:?}", tilde_gs[0]); for (tilde_g, point) in tilde_gs.iter().zip(points.iter()) { let eq_i_a2 = EqPolynomial::eq_vec(a2, point); + println!("eq_i_a2: {:?}", eq_i_a2); for (j, &tilde_g_eval) in tilde_g.coeffs.iter().enumerate() { g_prime_evals[j] += tilde_g_eval * eq_i_a2; } @@ -196,8 +220,34 @@ where coeffs: g_prime_evals, }; - let (_g_prime_eval, g_prime_proof) = - hyrax_open(proving_key, &g_prime, a2.to_vec().as_ref()); + let mut a2_rev = a2.to_vec(); + a2_rev.reverse(); + + // let (_g_prime_eval, g_prime_proof) = hyrax_open(proving_key, &g_prime, a2_rev.as_ref()); //a2.to_vec().as_ref()); + let (_g_prime_eval, g_prime_proof) = hyrax_open(proving_key, &g_prime, a2); //a2.to_vec().as_ref()); + + println!("g(a2) from hyrax: {:?}", _g_prime_eval); + + println!( + "g'(a2): {:?}", + g_prime.evaluate_jolt(a2) + ); + println!("g'(a2_rev): {:?}", g_prime.eval_reverse_order(a2)); + + let mut sumcheck_poly_eval = C::Scalar::zero(); + for p in sumcheck_poly.iter() { + sumcheck_poly_eval += p.evaluate_jolt(a2); + } + + println!("prover sumcheck eval: {:?}", sumcheck_poly_eval); + + let mut sumcheck_poly_eval = C::Scalar::zero(); + for p in sumcheck_poly.iter() { + sumcheck_poly_eval += p.eval_reverse_order(a2); + } + + + println!("prover sumcheck eval rev: {:?}", sumcheck_poly_eval); BatchOpening { sum_check_proof: proof, @@ -207,6 +257,12 @@ where } /// Verify the opening of a set of polynomials at a single point. + /// Steps: + /// 1. get challenge point t from transcript + /// 2. build g' commitment + /// 3. ensure \sum_i eq(a2, point_i) * eq(t, ) * f_i_evals matches the sum via SumCheck + /// verification + /// 4. verify commitment fn multiple_points_batch_verify( _params: &Self::Params, verifying_key: &::VKey, @@ -220,15 +276,21 @@ where let ell = log2(k) as usize; let num_var = opening.sum_check_proof.point.len(); - // challenge point t - let t = transcript.generate_field_elements::(ell); - // sum check point (a2) let a2 = &opening.sum_check_proof.point[..num_var]; + // // challenge point t + // let t = transcript.generate_field_elements::(ell); + + // let eq_t_i = EqPolynomial::build_eq_x_r(&t); + + let eq_t_i = vec![C::Scalar::one(); 1 << ell]; + + println!("a2: {:?}", a2); + println!("eq_t_i: {:?}", eq_t_i); + // build g' commitment // todo: use MSM - let eq_t_list = EqPolynomial::build_eq_x_r(&t); // let mut scalars = vec![]; // let mut bases = vec![]; @@ -236,11 +298,12 @@ where let mut g_prime_commit_elems = vec![C::Curve::default(); commitments[0].0.len()]; for (i, point) in points.iter().enumerate() { let eq_i_a2 = EqPolynomial::eq_vec(a2, point); + println!("eq_i_a2: {:?}", eq_i_a2); // scalars.push(eq_i_a2 * eq_t_list[i]); // bases.push(commitments[i].0); - let scalar = eq_i_a2 * eq_t_list[i]; + let scalar = eq_i_a2 * eq_t_i[i]; for (j, &base) in commitments[i].0.iter().enumerate() { - g_prime_commit_elems[j] += (base * scalar); + g_prime_commit_elems[j] += base * scalar; } } let mut g_prime_commit_affine = vec![C::default(); commitments[0].0.len()]; @@ -250,14 +313,17 @@ where // ensure \sum_i eq(t, ) * f_i_evals matches the sum via SumCheck let mut sum = C::Scalar::zero(); - for (i, &e) in eq_t_list.iter().enumerate().take(k) { + for (i, &e) in eq_t_i.iter().enumerate().take(k) { sum += e * opening.f_i_eval_at_point_i[i]; } let subclaim = SumCheck::::verify(sum, &opening.sum_check_proof, num_var, transcript); + println!("subclaim: {:?}", subclaim); + let tilde_g_eval = subclaim.expected_evaluation; + println!("verifier expected tilde_g_eval: {:?}", tilde_g_eval); // verify commitment hyrax_verify( @@ -265,6 +331,7 @@ where &g_prime_commit, a2.to_vec().as_ref(), tilde_g_eval, + // C::Scalar::from(4916250u32), // this is the expected value of g'(a2) from the sumcheck &opening.g_prime_proof, ) } diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index 09e0438f..11206000 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -103,7 +103,13 @@ where // multi point batch opening for num_poly in [2, 4, 8, 16] { let polys = (0..num_poly) - .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) + .map( + |_| MultiLinearPoly { + coeffs: (0..1 << num_vars) + .map(|i| F::from(num_poly * 10 + i as u32)) + .collect(), + }, // MultiLinearPoly::::random(num_vars, &mut rng) + ) .collect::>(); let commitments = polys @@ -115,7 +121,9 @@ where let points = (0..num_poly) .map(|_| { (0..num_vars) - .map(|_| F::random_unsafe(&mut rng)) + .map( + |_| F::from(1u32), // F::random_unsafe(&mut rng) + ) .collect::>() }) .collect::>(); @@ -123,7 +131,7 @@ where let values = polys .iter() .zip(points.iter()) - .map(|(poly, point)| poly.evaluate_jolt(point)) + .map(|(poly, point)| poly.eval_reverse_order(point)) .collect::>(); let mut transcript = T::new(); From fa5cd00ebd8fedfafc142b70dd7c610d96dbdfbf Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 28 May 2025 21:43:39 -0400 Subject: [PATCH 29/57] degree 2 sumcheck --- poly_commit/src/hyrax/pcs_trait_impl.rs | 14 +++--- sumcheck/src/sumcheck_generic.rs | 45 +++++++++++++++-- sumcheck/src/sumcheck_generic/prover.rs | 51 ++++++++++++------- sumcheck/src/sumcheck_generic/tests.rs | 60 +++++++++++++---------- sumcheck/src/sumcheck_generic/verifier.rs | 22 +++++++-- 5 files changed, 131 insertions(+), 61 deletions(-) diff --git a/poly_commit/src/hyrax/pcs_trait_impl.rs b/poly_commit/src/hyrax/pcs_trait_impl.rs index d981f415..246f9c70 100644 --- a/poly_commit/src/hyrax/pcs_trait_impl.rs +++ b/poly_commit/src/hyrax/pcs_trait_impl.rs @@ -190,7 +190,7 @@ where } let proof = SumCheck::::prove(&sumcheck_poly, transcript); - + println!("SumCheck proof: {:?}", proof,); println!( @@ -223,15 +223,13 @@ where let mut a2_rev = a2.to_vec(); a2_rev.reverse(); - // let (_g_prime_eval, g_prime_proof) = hyrax_open(proving_key, &g_prime, a2_rev.as_ref()); //a2.to_vec().as_ref()); + // let (_g_prime_eval, g_prime_proof) = hyrax_open(proving_key, &g_prime, a2_rev.as_ref()); + // //a2.to_vec().as_ref()); let (_g_prime_eval, g_prime_proof) = hyrax_open(proving_key, &g_prime, a2); //a2.to_vec().as_ref()); println!("g(a2) from hyrax: {:?}", _g_prime_eval); - println!( - "g'(a2): {:?}", - g_prime.evaluate_jolt(a2) - ); + println!("g'(a2): {:?}", g_prime.evaluate_jolt(a2)); println!("g'(a2_rev): {:?}", g_prime.eval_reverse_order(a2)); let mut sumcheck_poly_eval = C::Scalar::zero(); @@ -245,7 +243,6 @@ where for p in sumcheck_poly.iter() { sumcheck_poly_eval += p.eval_reverse_order(a2); } - println!("prover sumcheck eval rev: {:?}", sumcheck_poly_eval); @@ -331,7 +328,8 @@ where &g_prime_commit, a2.to_vec().as_ref(), tilde_g_eval, - // C::Scalar::from(4916250u32), // this is the expected value of g'(a2) from the sumcheck + // C::Scalar::from(4916250u32), // this is the expected value of g'(a2) from the + // sumcheck &opening.g_prime_proof, ) } diff --git a/sumcheck/src/sumcheck_generic.rs b/sumcheck/src/sumcheck_generic.rs index 01a92567..7947d240 100644 --- a/sumcheck/src/sumcheck_generic.rs +++ b/sumcheck/src/sumcheck_generic.rs @@ -14,6 +14,45 @@ mod verifier; #[cfg(test)] mod tests; +#[derive(Clone, Debug, Default, PartialEq, Eq)] +/// A special form of a multi-linear polynomial: f = f0*g0 + f1*g1 + ... +/// where f0, f1, ... and g0, g1, ... are multi-linear polynomials +/// The sumcheck over this polynomial has a degree of 2 +pub struct SumOfProductsPoly { + /// The list of multi-linear polynomials to be summed + pub f_and_g_pairs: Vec<(MultiLinearPoly, MultiLinearPoly)>, +} + +impl SumOfProductsPoly { + /// Create a new SumOfProducts instance + pub fn new() -> Self { + Self { + f_and_g_pairs: vec![], + } + } + + /// Get the number of variables in the polynomial + pub fn num_vars(&self) -> usize { + if self.f_and_g_pairs.is_empty() { + 0 + } else { + self.f_and_g_pairs[0].0.num_vars() + } + } + + pub fn add_pair(&mut self, poly0: MultiLinearPoly, poly1: MultiLinearPoly) { + assert_eq!(poly0.num_vars(), poly1.num_vars()); + self.f_and_g_pairs.push((poly0, poly1)); + } + + pub fn evaluate(&self, point: &[F]) -> F { + self.f_and_g_pairs + .iter() + .map(|(f, g)| f.eval_reverse_order(point) * g.eval_reverse_order(point)) + .sum() + } +} + /// An IOP proof is a collections of /// - messages from prover to verifier at each round through the interactive protocol. /// - a point that is generated by the transcript for evaluation @@ -40,7 +79,7 @@ pub struct IOPProverState { pub(crate) round: usize, /// list of MLE poly // todo: change this to reference - pub mle_list: Vec>, + pub mle_list: SumOfProductsPoly, } /// Prover State of a PolyIOP @@ -81,10 +120,10 @@ impl SumCheck { /// /// The polynomial is represented in the form of a VirtualPolynomial. pub fn prove( - poly_list: &[MultiLinearPoly], + poly_list: &SumOfProductsPoly, transcript: &mut impl Transcript, ) -> IOPProof { - let num_vars = poly_list[0].num_vars(); + let num_vars = poly_list.num_vars(); let mut prover_state = IOPProverState::prover_init(poly_list); let mut challenge = None; diff --git a/sumcheck/src/sumcheck_generic/prover.rs b/sumcheck/src/sumcheck_generic/prover.rs index eac55622..18217f89 100644 --- a/sumcheck/src/sumcheck_generic/prover.rs +++ b/sumcheck/src/sumcheck_generic/prover.rs @@ -1,17 +1,16 @@ use arith::Field; -use polynomials::{MultiLinearPoly, MultilinearExtension}; -use super::{IOPProverMessage, IOPProverState}; +use super::{IOPProverMessage, IOPProverState, SumOfProductsPoly}; impl IOPProverState { /// Initialize the prover state to argue for the sum of the input polynomial /// over {0,1}^`num_vars`. - pub fn prover_init(polynomials: &[MultiLinearPoly]) -> Self { + pub fn prover_init(polynomials: &SumOfProductsPoly) -> Self { Self { - challenges: Vec::with_capacity(polynomials[0].num_vars()), + challenges: Vec::with_capacity(polynomials.num_vars()), round: 0, - init_num_vars: polynomials[0].num_vars(), - mle_list: polynomials.to_vec(), + init_num_vars: polynomials.num_vars(), + mle_list: polynomials.clone(), } } @@ -44,8 +43,9 @@ impl IOPProverState { let r = self.challenges[self.round - 1]; - for mle in self.mle_list.iter_mut() { - mle.fix_top_variable(r); + for (f, g) in self.mle_list.f_and_g_pairs.iter_mut() { + f.fix_top_variable(r); + g.fix_top_variable(r); } } else if self.round > 0 { panic!("verifier message is empty") @@ -53,20 +53,35 @@ impl IOPProverState { self.round += 1; - let len = self.mle_list[0].coeffs.len() / 2; - let mut f_0 = F::zero(); - let mut f_1 = F::zero(); + let len = 1 << (self.mle_list.num_vars() - 1); + let mut h_0 = F::zero(); + let mut h_1 = F::zero(); + let mut h_2 = F::zero(); - for mle in self.mle_list.iter() { - // evaluate the polynomial at the current point - // and sum the evaluations for f_0 and f_1 - let coeffs = mle.coeffs.as_slice(); - f_0 += coeffs[..len].iter().sum::(); - f_1 += coeffs[len..].iter().sum::(); + for (f, g) in self.mle_list.f_and_g_pairs.iter() { + // evaluate the polynomial at 0, 1 and 2 + // and obtain f(0)g(0) and f(1)g(1) and f(2)g(2) + let f_coeffs = f.coeffs.as_slice(); + let g_coeffs = g.coeffs.as_slice(); + + h_0 += f_coeffs[..len].iter().sum::() * g_coeffs[..len].iter().sum::(); + h_1 += f_coeffs[len..].iter().sum::() * g_coeffs[len..].iter().sum::(); + + let f_2 = f_coeffs[..len] + .iter() + .zip(f_coeffs[len..].iter()) + .map(|(a, b)| -*a + b.double()) + .sum::(); + let g2 = g_coeffs[..len] + .iter() + .zip(g_coeffs[len..].iter()) + .map(|(a, b)| -*a + b.double()) + .sum::(); + h_2 += f_2 * g2; } IOPProverMessage { - evaluations: vec![f_0, f_1], + evaluations: vec![h_0, h_1, h_2], } } } diff --git a/sumcheck/src/sumcheck_generic/tests.rs b/sumcheck/src/sumcheck_generic/tests.rs index 640b036e..c65e3c53 100644 --- a/sumcheck/src/sumcheck_generic/tests.rs +++ b/sumcheck/src/sumcheck_generic/tests.rs @@ -3,7 +3,6 @@ use super::*; use arith::Fr; use ark_std::test_rng; use gkr_hashers::Keccak256hasher; -use polynomials::MultilinearExtension; use transcript::BytesHashTranscript; #[test] @@ -12,28 +11,38 @@ fn test_sumcheck_subroutine() { let size = 1 << num_vars; for num_poly in 1..10 { - let mle_list = (0..num_poly) + let f_and_g_pairs = (0..num_poly) .map(|j| { - let coeffs = (1..=size) + let f_coeffs = (1..=size) .map(|i| Fr::from(j * 10 + i as u32)) .collect::>(); - MultiLinearPoly::::new(coeffs) + let f = MultiLinearPoly::::new(f_coeffs); + + let g_coeffs = (1..=size) + .map(|i| Fr::from(j * 100 + i as u32)) + .collect::>(); + let g = MultiLinearPoly::::new(g_coeffs); + + (f, g) }) .collect::>(); + let mle_list = SumOfProductsPoly:: { f_and_g_pairs }; + let asserted_sum = mle_list + .f_and_g_pairs .iter() - .map(|mle| mle.coeffs.iter().sum::()) + .map(|(f, g)| f.coeffs.iter().sum::() * g.coeffs.iter().sum::()) .sum::(); let mut transcript = BytesHashTranscript::::new(); let mut prover = IOPProverState::prover_init(&mle_list); - let mut verifier = IOPVerifierState::verifier_init(prover.mle_list[0].num_vars()); + let mut verifier = IOPVerifierState::verifier_init(prover.mle_list.num_vars()); let mut challenge = None; - for _ in 0..prover.mle_list[0].num_vars() { + for _ in 0..prover.mle_list.num_vars() { let prover_msg = IOPProverState::prove_round_and_update_state(&mut prover, &challenge); @@ -46,17 +55,8 @@ fn test_sumcheck_subroutine() { let subclaim = IOPVerifierState::check_and_generate_subclaim(&verifier, &asserted_sum); - let evals = mle_list - .iter() - .map(|mle| mle.eval_reverse_order(&subclaim.point)) - .sum::(); - - assert!( - evals == subclaim.expected_evaluation, - "wrong subclaim: {:?} != {:?}", - evals, - subclaim.expected_evaluation - ); + let evals = mle_list.evaluate(&subclaim.point); + assert!(evals == subclaim.expected_evaluation, "wrong subclaim"); } } } @@ -69,18 +69,28 @@ fn test_sumcheck_e2e() { let size = 1 << num_vars; for num_poly in 1..10 { - let mle_list = (0..num_poly) + let f_and_g_pairs = (0..num_poly) .map(|_| { - let coeffs = (1..=size) + let f_coeffs = (1..=size) .map(|_| Fr::random_unsafe(&mut rng)) .collect::>(); - MultiLinearPoly::::new(coeffs) + let f = MultiLinearPoly::::new(f_coeffs); + + let g_coeffs = (1..=size) + .map(|_| Fr::random_unsafe(&mut rng)) + .collect::>(); + let g = MultiLinearPoly::::new(g_coeffs); + + (f, g) }) .collect::>(); + let mle_list = SumOfProductsPoly:: { f_and_g_pairs }; + let asserted_sum = mle_list + .f_and_g_pairs .iter() - .map(|mle| mle.coeffs.iter().sum::()) + .map(|(f, g)| f.coeffs.iter().sum::() * g.coeffs.iter().sum::()) .sum::(); // prover @@ -91,11 +101,7 @@ fn test_sumcheck_e2e() { let mut transcript = BytesHashTranscript::::new(); let subclaim = SumCheck::::verify(asserted_sum, &proof, num_vars, &mut transcript); - let evals = mle_list - .iter() - .map(|mle| mle.eval_reverse_order(&subclaim.point)) - .sum::(); - + let evals = mle_list.evaluate(&subclaim.point); assert!(evals == subclaim.expected_evaluation, "wrong subclaim"); } } diff --git a/sumcheck/src/sumcheck_generic/verifier.rs b/sumcheck/src/sumcheck_generic/verifier.rs index f92cdd00..5728c35f 100644 --- a/sumcheck/src/sumcheck_generic/verifier.rs +++ b/sumcheck/src/sumcheck_generic/verifier.rs @@ -77,11 +77,23 @@ impl IOPVerifierState { let evals = &self.polynomials_received[i]; // the univariate polynomial f is received in its extrapolated form, i.e., - // f(0) = evals[0] and f(1) = evals[1]. - // now we want to compute f(r) for the challenge r = self.challenges[i] - // that is - // f(0) + (f(1) - f(0)) * r - expected = evals[0] + (evals[1] - evals[0]) * self.challenges[i]; + // h(0) = evals[0], h(1) = evals[1], h(2) = evals[2] + // that is, suppose h = h_0 + h_1 * x + h_2 * x^2, then + // h(0) = h_0 + // h(1) = h_0 + h_1 + h_2 + // h(2) = h_0 + 2 * h_1 + 4 * h_2 + // therefore + // h_0 = evals[0] + // h_2 = (h(2) + h(0))/2 - h(1) + // h_1 = h(1) - h_0 - h_2 + + let h_0 = evals[0]; + let h_2 = (evals[2] + evals[0]) * F::from(2u32).inv().unwrap() - evals[1]; + let h_1 = evals[1] - h_0 - h_2; + + // now we want to compute h(r) for the challenge r = self.challenges[i] + // h(r) = h_0 + h_1 * r + h_2 * r^2 + expected = h_0 + h_1 * self.challenges[i] + h_2 * self.challenges[i].square(); } SumCheckSubClaim { From 1c99242de3c03bef8ee820025cee968b0db00f30 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 28 May 2025 21:51:39 -0400 Subject: [PATCH 30/57] works now! --- poly_commit/src/hyrax/pcs_trait_impl.rs | 60 +++++++++++++------------ 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/poly_commit/src/hyrax/pcs_trait_impl.rs b/poly_commit/src/hyrax/pcs_trait_impl.rs index 246f9c70..bc3a7891 100644 --- a/poly_commit/src/hyrax/pcs_trait_impl.rs +++ b/poly_commit/src/hyrax/pcs_trait_impl.rs @@ -9,6 +9,7 @@ use halo2curves::{ff::PrimeField, CurveAffine}; use polynomials::{EqPolynomial, MultiLinearPoly, MultilinearExtension}; use serdes::ExpSerde; use sumcheck::SumCheck; +use sumcheck::SumOfProductsPoly; use crate::traits::BatchOpening; use crate::{ @@ -150,13 +151,13 @@ where .map(|(poly, point)| poly.evaluate_jolt(point)) .collect(); - // // challenge point t - // let t = transcript.generate_field_elements::(ell); + // challenge point t + let t = transcript.generate_field_elements::(ell); - // // eq(t, i) for i in [0..k] - // let eq_t_i = EqPolynomial::build_eq_x_r(&t); + // eq(t, i) for i in [0..k] + let eq_t_i = EqPolynomial::build_eq_x_r(&t); - let eq_t_i = vec![C::Scalar::one(); 1 << ell]; + // let eq_t_i = vec![C::Scalar::one(); 1 << ell]; // \tilde g_i(b) = eq(t, i) * f_i(b) let mut tilde_gs = vec![]; @@ -180,14 +181,14 @@ where }) .collect(); - let mut sumcheck_poly = vec![]; + let mut sumcheck_poly = SumOfProductsPoly::new(); for (tilde_g, tilde_eq) in tilde_gs.iter().zip(tilde_eqs.into_iter()) { - sumcheck_poly.extend_from_slice([tilde_g.clone(), tilde_eq].as_slice()); - } - println!("SumCheck poly: {:?}", sumcheck_poly.len()); - for poly in sumcheck_poly.iter() { - println!("Poly: {:?}", poly.coeffs.len()); + sumcheck_poly.add_pair(tilde_g.clone(), tilde_eq); } + // println!("SumCheck poly: {:?}", sumcheck_poly.len()); + // for poly in sumcheck_poly.iter() { + // println!("Poly: {:?}", poly.coeffs.len()); + // } let proof = SumCheck::::prove(&sumcheck_poly, transcript); @@ -225,26 +226,27 @@ where // let (_g_prime_eval, g_prime_proof) = hyrax_open(proving_key, &g_prime, a2_rev.as_ref()); // //a2.to_vec().as_ref()); - let (_g_prime_eval, g_prime_proof) = hyrax_open(proving_key, &g_prime, a2); //a2.to_vec().as_ref()); + let (_g_prime_eval, g_prime_proof) = hyrax_open(proving_key, &g_prime, a2_rev.as_ref()); //a2.to_vec().as_ref()); println!("g(a2) from hyrax: {:?}", _g_prime_eval); println!("g'(a2): {:?}", g_prime.evaluate_jolt(a2)); println!("g'(a2_rev): {:?}", g_prime.eval_reverse_order(a2)); - let mut sumcheck_poly_eval = C::Scalar::zero(); - for p in sumcheck_poly.iter() { - sumcheck_poly_eval += p.evaluate_jolt(a2); - } + // let mut sumcheck_poly_eval = C::Scalar::zero(); + // for p in sumcheck_poly.iter() { + // sumcheck_poly_eval += p.evaluate_jolt(a2); + // } - println!("prover sumcheck eval: {:?}", sumcheck_poly_eval); + println!("prover sumcheck eval: {:?}", sumcheck_poly.evaluate(a2)); + // println!("prover sumcheck eval: {:?}", sumcheck_poly_eval); - let mut sumcheck_poly_eval = C::Scalar::zero(); - for p in sumcheck_poly.iter() { - sumcheck_poly_eval += p.eval_reverse_order(a2); - } + // let mut sumcheck_poly_eval = C::Scalar::zero(); + // for p in sumcheck_poly.iter() { + // sumcheck_poly_eval += p.eval_reverse_order(a2); + // } - println!("prover sumcheck eval rev: {:?}", sumcheck_poly_eval); + // println!("prover sumcheck eval rev: {:?}", sumcheck_poly_eval); BatchOpening { sum_check_proof: proof, @@ -275,13 +277,15 @@ where // sum check point (a2) let a2 = &opening.sum_check_proof.point[..num_var]; + let mut a2_rev = a2.to_vec(); + a2_rev.reverse(); - // // challenge point t - // let t = transcript.generate_field_elements::(ell); + // challenge point t + let t = transcript.generate_field_elements::(ell); - // let eq_t_i = EqPolynomial::build_eq_x_r(&t); + let eq_t_i = EqPolynomial::build_eq_x_r(&t); - let eq_t_i = vec![C::Scalar::one(); 1 << ell]; + // let eq_t_i = vec![C::Scalar::one(); 1 << ell]; println!("a2: {:?}", a2); println!("eq_t_i: {:?}", eq_t_i); @@ -326,10 +330,8 @@ where hyrax_verify( verifying_key, &g_prime_commit, - a2.to_vec().as_ref(), + a2_rev.as_ref(), tilde_g_eval, - // C::Scalar::from(4916250u32), // this is the expected value of g'(a2) from the - // sumcheck &opening.g_prime_proof, ) } From e66e0ba4a8f56f2bb6f9af9b4a8b84be48debfc0 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 28 May 2025 22:08:24 -0400 Subject: [PATCH 31/57] hyrax works properly now --- gkr_engine/src/transcript/definition.rs | 4 +- poly_commit/src/hyrax/pcs_trait_impl.rs | 86 +++++----------------- poly_commit/src/traits.rs | 4 +- poly_commit/tests/common.rs | 96 +++++++++++-------------- 4 files changed, 62 insertions(+), 128 deletions(-) diff --git a/gkr_engine/src/transcript/definition.rs b/gkr_engine/src/transcript/definition.rs index 5e376ec1..fbc6f0dd 100644 --- a/gkr_engine/src/transcript/definition.rs +++ b/gkr_engine/src/transcript/definition.rs @@ -55,9 +55,7 @@ pub trait Transcript: Clone + Debug { /// Generate a field element. #[inline(always)] fn generate_field_element(&mut self) -> F { - F::from(self.generate_u8_slice(1)[0] as u32) - - // F::from_uniform_bytes(&self.generate_u8_slice(F::SIZE)) + F::from_uniform_bytes(&self.generate_u8_slice(F::SIZE)) } /// Generate a field element vector. diff --git a/poly_commit/src/hyrax/pcs_trait_impl.rs b/poly_commit/src/hyrax/pcs_trait_impl.rs index bc3a7891..788c4e39 100644 --- a/poly_commit/src/hyrax/pcs_trait_impl.rs +++ b/poly_commit/src/hyrax/pcs_trait_impl.rs @@ -132,6 +132,10 @@ where /// 6. build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the sumcheck's /// point /// 7. open g'(X) at point (a2) + /// + /// Returns: + /// - the evaluations of the polynomials at their corresponding points + /// - the batch opening proof containing the sumcheck proof and the opening of g'(X) fn multiple_points_batch_open( _params: &Self::Params, proving_key: &::PKey, @@ -139,7 +143,7 @@ where points: &[Self::EvalPoint], _scratch_pad: &Self::ScratchPad, transcript: &mut impl Transcript, - ) -> BatchOpening { + ) -> (Vec, BatchOpening) { let num_vars = polys[0].num_vars(); let k = polys.len(); let ell = log2(k) as usize; @@ -157,8 +161,6 @@ where // eq(t, i) for i in [0..k] let eq_t_i = EqPolynomial::build_eq_x_r(&t); - // let eq_t_i = vec![C::Scalar::one(); 1 << ell]; - // \tilde g_i(b) = eq(t, i) * f_i(b) let mut tilde_gs = vec![]; for (index, f_i) in polys.iter().enumerate() { @@ -170,7 +172,6 @@ where coeffs: tilde_g_eval, }); } - // println!("tilde_gs: {:?}", tilde_gs); // built the virtual polynomial for SumCheck let tilde_eqs: Vec> = points @@ -185,34 +186,19 @@ where for (tilde_g, tilde_eq) in tilde_gs.iter().zip(tilde_eqs.into_iter()) { sumcheck_poly.add_pair(tilde_g.clone(), tilde_eq); } - // println!("SumCheck poly: {:?}", sumcheck_poly.len()); - // for poly in sumcheck_poly.iter() { - // println!("Poly: {:?}", poly.coeffs.len()); - // } let proof = SumCheck::::prove(&sumcheck_poly, transcript); - println!("SumCheck proof: {:?}", proof,); - - println!( - "SumCheck sum: {:?}", - SumCheck::::extract_sum(&proof) - ); - let a2 = &proof.point[..num_vars]; - - println!("a2: {:?}", a2); - println!("eq_t_i: {:?}", eq_t_i); + let mut a2_rev = a2.to_vec(); + a2_rev.reverse(); // build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the // sumcheck's point \tilde eq_i(a2) = eq(a2, point_i) let mut g_prime_evals = vec![C::Scalar::zero(); 1 << num_vars]; - // println!("tilde_gs: {:?}", tilde_gs.len()); - // println!("tilde_gs: {:?}", tilde_gs[0]); for (tilde_g, point) in tilde_gs.iter().zip(points.iter()) { - let eq_i_a2 = EqPolynomial::eq_vec(a2, point); - println!("eq_i_a2: {:?}", eq_i_a2); + let eq_i_a2 = EqPolynomial::eq_vec(a2_rev.as_ref(), point); for (j, &tilde_g_eval) in tilde_g.coeffs.iter().enumerate() { g_prime_evals[j] += tilde_g_eval * eq_i_a2; } @@ -221,38 +207,15 @@ where coeffs: g_prime_evals, }; - let mut a2_rev = a2.to_vec(); - a2_rev.reverse(); - - // let (_g_prime_eval, g_prime_proof) = hyrax_open(proving_key, &g_prime, a2_rev.as_ref()); - // //a2.to_vec().as_ref()); let (_g_prime_eval, g_prime_proof) = hyrax_open(proving_key, &g_prime, a2_rev.as_ref()); //a2.to_vec().as_ref()); + ( + evals, + BatchOpening { + sum_check_proof: proof, - println!("g(a2) from hyrax: {:?}", _g_prime_eval); - - println!("g'(a2): {:?}", g_prime.evaluate_jolt(a2)); - println!("g'(a2_rev): {:?}", g_prime.eval_reverse_order(a2)); - - // let mut sumcheck_poly_eval = C::Scalar::zero(); - // for p in sumcheck_poly.iter() { - // sumcheck_poly_eval += p.evaluate_jolt(a2); - // } - - println!("prover sumcheck eval: {:?}", sumcheck_poly.evaluate(a2)); - // println!("prover sumcheck eval: {:?}", sumcheck_poly_eval); - - // let mut sumcheck_poly_eval = C::Scalar::zero(); - // for p in sumcheck_poly.iter() { - // sumcheck_poly_eval += p.eval_reverse_order(a2); - // } - - // println!("prover sumcheck eval rev: {:?}", sumcheck_poly_eval); - - BatchOpening { - sum_check_proof: proof, - f_i_eval_at_point_i: evals.to_vec(), - g_prime_proof, - } + g_prime_proof, + }, + ) } /// Verify the opening of a set of polynomials at a single point. @@ -267,7 +230,7 @@ where verifying_key: &::VKey, commitments: &[Self::Commitment], points: &[Self::EvalPoint], - _values: &[C::Scalar], + values: &[C::Scalar], opening: &BatchOpening, transcript: &mut impl Transcript, ) -> bool { @@ -285,23 +248,15 @@ where let eq_t_i = EqPolynomial::build_eq_x_r(&t); - // let eq_t_i = vec![C::Scalar::one(); 1 << ell]; - - println!("a2: {:?}", a2); - println!("eq_t_i: {:?}", eq_t_i); - // build g' commitment - // todo: use MSM + // todo: use MSM // let mut scalars = vec![]; // let mut bases = vec![]; let mut g_prime_commit_elems = vec![C::Curve::default(); commitments[0].0.len()]; for (i, point) in points.iter().enumerate() { - let eq_i_a2 = EqPolynomial::eq_vec(a2, point); - println!("eq_i_a2: {:?}", eq_i_a2); - // scalars.push(eq_i_a2 * eq_t_list[i]); - // bases.push(commitments[i].0); + let eq_i_a2 = EqPolynomial::eq_vec(a2_rev.as_ref(), point); let scalar = eq_i_a2 * eq_t_i[i]; for (j, &base) in commitments[i].0.iter().enumerate() { g_prime_commit_elems[j] += base * scalar; @@ -315,16 +270,13 @@ where // ensure \sum_i eq(t, ) * f_i_evals matches the sum via SumCheck let mut sum = C::Scalar::zero(); for (i, &e) in eq_t_i.iter().enumerate().take(k) { - sum += e * opening.f_i_eval_at_point_i[i]; + sum += e * values[i]; } let subclaim = SumCheck::::verify(sum, &opening.sum_check_proof, num_var, transcript); - println!("subclaim: {:?}", subclaim); - let tilde_g_eval = subclaim.expected_evaluation; - println!("verifier expected tilde_g_eval: {:?}", tilde_g_eval); // verify commitment hyrax_verify( diff --git a/poly_commit/src/traits.rs b/poly_commit/src/traits.rs index 1c47e4d3..03731a56 100644 --- a/poly_commit/src/traits.rs +++ b/poly_commit/src/traits.rs @@ -67,8 +67,6 @@ where { /// A sum check proof proving tilde g's sum pub(crate) sum_check_proof: IOPProof, - /// f_i(point_i) - pub f_i_eval_at_point_i: Vec, /// proof for g'(a_2) pub(crate) g_prime_proof: PCS::Opening, } @@ -106,7 +104,7 @@ pub trait BatchOpeningPCS: PolynomialCommitmentScheme + Si points: &[Self::EvalPoint], scratch_pad: &Self::ScratchPad, transcript: &mut impl Transcript, - ) -> BatchOpening { + ) -> (Vec, BatchOpening) { unimplemented!() } diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index 11206000..32895459 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -61,55 +61,49 @@ where let (proving_key, verification_key) = srs.into_keys(); - // // single point batch opening - // for num_poly in [1, 2, 10, 100] { - // let polys = (0..num_poly) - // .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) - // .collect::>(); - // let commitments = polys - // .iter() - // .map(|poly| P::commit(&num_vars, &proving_key, poly, &mut scratch_pad)) - // .collect::>(); - - // // open all polys at a single point - // let x = (0..num_vars) - // .map(|_| F::random_unsafe(&mut rng)) - // .collect::>(); - - // let mut transcript = T::new(); - - // let (values, batch_opening) = P::single_point_batch_open( - // &num_vars, - // &proving_key, - // &polys, - // x.as_ref(), - // &mut scratch_pad, - // &mut transcript, - // ); - - // let mut transcript = T::new(); - - // assert!(P::single_point_batch_verify( - // &num_vars, - // &verification_key, - // &commitments, - // x.as_ref(), - // &values, - // &batch_opening, - // &mut transcript - // )) - // } + // single point batch opening + for num_poly in [1, 2, 10, 100] { + let polys = (0..num_poly) + .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) + .collect::>(); + let commitments = polys + .iter() + .map(|poly| P::commit(&num_vars, &proving_key, poly, &mut scratch_pad)) + .collect::>(); + + // open all polys at a single point + let x = (0..num_vars) + .map(|_| F::random_unsafe(&mut rng)) + .collect::>(); + + let mut transcript = T::new(); + + let (values, batch_opening) = P::single_point_batch_open( + &num_vars, + &proving_key, + &polys, + x.as_ref(), + &mut scratch_pad, + &mut transcript, + ); + + let mut transcript = T::new(); + + assert!(P::single_point_batch_verify( + &num_vars, + &verification_key, + &commitments, + x.as_ref(), + &values, + &batch_opening, + &mut transcript + )) + } // multi point batch opening for num_poly in [2, 4, 8, 16] { let polys = (0..num_poly) - .map( - |_| MultiLinearPoly { - coeffs: (0..1 << num_vars) - .map(|i| F::from(num_poly * 10 + i as u32)) - .collect(), - }, // MultiLinearPoly::::random(num_vars, &mut rng) - ) + .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) .collect::>(); let commitments = polys @@ -121,22 +115,14 @@ where let points = (0..num_poly) .map(|_| { (0..num_vars) - .map( - |_| F::from(1u32), // F::random_unsafe(&mut rng) - ) + .map(|_i| F::random_unsafe(&mut rng)) .collect::>() }) .collect::>(); - let values = polys - .iter() - .zip(points.iter()) - .map(|(poly, point)| poly.eval_reverse_order(point)) - .collect::>(); - let mut transcript = T::new(); - let batch_opening = P::multiple_points_batch_open( + let (values, batch_opening) = P::multiple_points_batch_open( &num_vars, &proving_key, &polys, From 83e8eb4e198d81f692e7d4ac813045c12a66b3e3 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 28 May 2025 22:22:37 -0400 Subject: [PATCH 32/57] kzg works now --- poly_commit/src/kzg/batch.rs | 2 +- poly_commit/src/kzg/hyper_bikzg.rs | 2 +- poly_commit/src/kzg/hyper_bikzg_tests.rs | 2 +- poly_commit/src/kzg/hyper_kzg.rs | 4 +- poly_commit/src/kzg/pcs_trait_impl.rs | 187 ++++++++++++++++++++++- poly_commit/src/kzg/univariate.rs | 8 +- poly_commit/src/traits.rs | 8 +- 7 files changed, 195 insertions(+), 18 deletions(-) diff --git a/poly_commit/src/kzg/batch.rs b/poly_commit/src/kzg/batch.rs index f202feb8..6b2348fc 100644 --- a/poly_commit/src/kzg/batch.rs +++ b/poly_commit/src/kzg/batch.rs @@ -84,7 +84,7 @@ where let mut accumulator = PairingAccumulator::default(); let partial_check = coeff_form_uni_hyperkzg_partial_verify( - verifying_key.clone(), + &verifying_key, merged_commitment.to_affine(), x, merged_eval, diff --git a/poly_commit/src/kzg/hyper_bikzg.rs b/poly_commit/src/kzg/hyper_bikzg.rs index 6260ccd0..65aee351 100644 --- a/poly_commit/src/kzg/hyper_bikzg.rs +++ b/poly_commit/src/kzg/hyper_bikzg.rs @@ -501,7 +501,7 @@ where let hyper_kzg_opening: HyperKZGOpening = hyper_bikzg_opening.into(); let what = coeff_form_uni_hyperkzg_partial_verify( - vk.into(), + &vk.into(), commitment, local_alphas, eval, diff --git a/poly_commit/src/kzg/hyper_bikzg_tests.rs b/poly_commit/src/kzg/hyper_bikzg_tests.rs index 399e743f..b4c3bd2f 100644 --- a/poly_commit/src/kzg/hyper_bikzg_tests.rs +++ b/poly_commit/src/kzg/hyper_bikzg_tests.rs @@ -347,7 +347,7 @@ where let hyper_kzg_opening: HyperKZGOpening = hyper_bikzg_opening.into(); let what = coeff_form_uni_hyperkzg_verify( - vk.into(), + &vk.into(), commitment, local_alphas, eval, diff --git a/poly_commit/src/kzg/hyper_kzg.rs b/poly_commit/src/kzg/hyper_kzg.rs index 9a03f8fb..1946b101 100644 --- a/poly_commit/src/kzg/hyper_kzg.rs +++ b/poly_commit/src/kzg/hyper_kzg.rs @@ -175,7 +175,7 @@ where #[inline(always)] pub fn coeff_form_uni_hyperkzg_verify( - vk: UniKZGVerifierParams, + vk: &UniKZGVerifierParams, comm: E::G1Affine, alphas: &[E::Fr], eval: E::Fr, @@ -206,7 +206,7 @@ where #[inline(always)] pub fn coeff_form_uni_hyperkzg_partial_verify( - vk: UniKZGVerifierParams, + vk: &UniKZGVerifierParams, comm: E::G1Affine, alphas: &[E::Fr], eval: E::Fr, diff --git a/poly_commit/src/kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/pcs_trait_impl.rs index c8f168c7..ae6d0c49 100644 --- a/poly_commit/src/kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/pcs_trait_impl.rs @@ -1,16 +1,25 @@ use std::marker::PhantomData; use arith::ExtensionField; +use arith::Field; +use ark_std::log2; use gkr_engine::{DeferredCheck, StructuredReferenceString, Transcript}; +use halo2curves::group::Curve; +use halo2curves::group::Group; use halo2curves::{ ff::PrimeField, pairing::{Engine, MultiMillerLoop}, CurveAffine, }; -use polynomials::MultiLinearPoly; +use polynomials::{EqPolynomial, MultiLinearPoly, MultilinearExtension}; use serdes::ExpSerde; +use sumcheck::SumCheck; +use sumcheck::SumOfProductsPoly; -use crate::{traits::BatchOpeningPCS, *}; +use crate::{ + traits::{BatchOpening, BatchOpeningPCS}, + *, +}; use kzg::hyper_kzg::*; use super::deferred_pairing::PairingAccumulator; @@ -91,7 +100,7 @@ where let mut accumulator = PairingAccumulator::default(); let partial_check = coeff_form_uni_hyperkzg_partial_verify( - verifying_key.clone(), + &verifying_key, commitment.0, x, v, @@ -144,4 +153,176 @@ where transcript, ) } + + /// Open a set of polynomials at a multiple points. + /// Requires the length of the polys to be the same as points. + /// Steps: + /// 1. get challenge point t from transcript + /// 2. build eq(t,i) for i in [0..k] + /// 3. build \tilde g_i(b) = eq(t, i) * f_i(b) + /// 4. compute \tilde eq_i(b) = eq(b, point_i) + /// 5. run sumcheck on \sum_i=1..k \tilde eq_i * \tilde g_i + /// 6. build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the sumcheck's + /// point + /// 7. open g'(X) at point (a2) + /// + /// Returns: + /// - the evaluations of the polynomials at their corresponding points + /// - the batch opening proof containing the sumcheck proof and the opening of g'(X) + fn multiple_points_batch_open( + _params: &Self::Params, + proving_key: &::PKey, + polys: &[Self::Poly], + points: &[Self::EvalPoint], + _scratch_pad: &Self::ScratchPad, + transcript: &mut impl Transcript, + ) -> (Vec, BatchOpening) { + let num_vars = polys[0].num_vars(); + let k = polys.len(); + let ell = log2(k) as usize; + + // generate evals for each polynomial at its corresponding point + let evals: Vec = polys + .iter() + .zip(points.iter()) + .map(|(poly, point)| poly.evaluate_jolt(point)) + .collect(); + + // challenge point t + let t = transcript.generate_field_elements::(ell); + + // eq(t, i) for i in [0..k] + let eq_t_i = EqPolynomial::build_eq_x_r(&t); + + // \tilde g_i(b) = eq(t, i) * f_i(b) + let mut tilde_gs = vec![]; + for (index, f_i) in polys.iter().enumerate() { + let mut tilde_g_eval = vec![E::Fr::zero(); 1 << num_vars]; + for (j, &f_i_eval) in f_i.coeffs.iter().enumerate() { + tilde_g_eval[j] = f_i_eval * eq_t_i[index]; + } + tilde_gs.push(MultiLinearPoly { + coeffs: tilde_g_eval, + }); + } + + // built the virtual polynomial for SumCheck + let tilde_eqs: Vec> = points + .iter() + .map(|point| { + let eq_b_zi = EqPolynomial::build_eq_x_r(point); + MultiLinearPoly { coeffs: eq_b_zi } + }) + .collect(); + + let mut sumcheck_poly = SumOfProductsPoly::new(); + for (tilde_g, tilde_eq) in tilde_gs.iter().zip(tilde_eqs.into_iter()) { + sumcheck_poly.add_pair(tilde_g.clone(), tilde_eq); + } + + let proof = SumCheck::::prove(&sumcheck_poly, transcript); + + let a2 = &proof.point[..num_vars]; + let mut a2_rev = a2.to_vec(); + a2_rev.reverse(); + + // build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the + // sumcheck's point \tilde eq_i(a2) = eq(a2, point_i) + let mut g_prime_evals = vec![E::Fr::zero(); 1 << num_vars]; + + for (tilde_g, point) in tilde_gs.iter().zip(points.iter()) { + let eq_i_a2 = EqPolynomial::eq_vec(a2_rev.as_ref(), point); + for (j, &tilde_g_eval) in tilde_g.coeffs.iter().enumerate() { + g_prime_evals[j] += tilde_g_eval * eq_i_a2; + } + } + let g_prime = MultiLinearPoly { + coeffs: g_prime_evals, + }; + + let (_g_prime_eval, g_prime_proof) = + coeff_form_uni_hyperkzg_open(proving_key, &g_prime.coeffs, a2_rev.as_ref(), transcript); + ( + evals, + BatchOpening { + sum_check_proof: proof, + g_prime_proof, + }, + ) + } + + /// Verify the opening of a set of polynomials at a single point. + /// Steps: + /// 1. get challenge point t from transcript + /// 2. build g' commitment + /// 3. ensure \sum_i eq(a2, point_i) * eq(t, ) * f_i_evals matches the sum via SumCheck + /// verification + /// 4. verify commitment + fn multiple_points_batch_verify( + _params: &Self::Params, + verifying_key: &::VKey, + commitments: &[Self::Commitment], + points: &[Self::EvalPoint], + values: &[E::Fr], + opening: &BatchOpening, + transcript: &mut impl Transcript, + ) -> bool { + let k = commitments.len(); + let ell = log2(k) as usize; + let num_var = opening.sum_check_proof.point.len(); + + // sum check point (a2) + let a2 = &opening.sum_check_proof.point[..num_var]; + let mut a2_rev = a2.to_vec(); + a2_rev.reverse(); + + // challenge point t + let t = transcript.generate_field_elements::(ell); + + let eq_t_i = EqPolynomial::build_eq_x_r(&t); + + // build g' commitment + + // todo: use MSM + // let mut scalars = vec![]; + // let mut bases = vec![]; + + let mut g_prime_commit_elems = E::G1::identity(); + for (i, point) in points.iter().enumerate() { + let eq_i_a2 = EqPolynomial::eq_vec(a2_rev.as_ref(), point); + let scalar = eq_i_a2 * eq_t_i[i]; + + g_prime_commit_elems += commitments[i].0 * scalar; + } + + let g_prime_commit = g_prime_commit_elems.to_affine(); + + // ensure \sum_i eq(t, ) * f_i_evals matches the sum via SumCheck + let mut sum = E::Fr::zero(); + for (i, &e) in eq_t_i.iter().enumerate().take(k) { + sum += e * values[i]; + } + + let subclaim = + SumCheck::::verify(sum, &opening.sum_check_proof, num_var, transcript); + + let tilde_g_eval = subclaim.expected_evaluation; + + // verify commitment + coeff_form_uni_hyperkzg_verify( + verifying_key, + g_prime_commit, + a2_rev.as_ref(), + tilde_g_eval, + &opening.g_prime_proof, + transcript, + ) + // hyrax_verify( + // verifying_key, + // &g_prime_commit, + // a2_rev.as_ref(), + // tilde_g_eval, + // &opening.g_prime_proof, + // ) + } } diff --git a/poly_commit/src/kzg/univariate.rs b/poly_commit/src/kzg/univariate.rs index 05c57190..8906944b 100644 --- a/poly_commit/src/kzg/univariate.rs +++ b/poly_commit/src/kzg/univariate.rs @@ -92,7 +92,7 @@ where #[inline(always)] #[cfg(test)] pub(crate) fn coeff_form_uni_kzg_verify( - vk: UniKZGVerifierParams, + vk: &UniKZGVerifierParams, comm: E::G1Affine, alpha: E::Fr, eval: E::Fr, @@ -111,7 +111,7 @@ where #[inline(always)] pub(crate) fn coeff_form_uni_kzg_partial_verify( - vk: UniKZGVerifierParams, + vk: &UniKZGVerifierParams, comm: E::G1Affine, alpha: E::Fr, eval: E::Fr, @@ -162,7 +162,7 @@ mod tests { let (actual_eval, opening) = coeff_form_uni_kzg_open_eval(&srs, &poly, alpha); assert_eq!(actual_eval, eval); - assert!(coeff_form_uni_kzg_verify(vk, com, alpha, eval, opening)) + assert!(coeff_form_uni_kzg_verify(&vk, com, alpha, eval, opening)) } #[test] @@ -179,6 +179,6 @@ mod tests { let (actual_eval, opening) = coeff_form_uni_kzg_open_eval(&srs, &poly, alpha); assert_eq!(actual_eval, eval); - assert!(coeff_form_uni_kzg_verify(vk, com, alpha, eval, opening)) + assert!(coeff_form_uni_kzg_verify(&vk, com, alpha, eval, opening)) } } diff --git a/poly_commit/src/traits.rs b/poly_commit/src/traits.rs index 03731a56..58a94434 100644 --- a/poly_commit/src/traits.rs +++ b/poly_commit/src/traits.rs @@ -104,9 +104,7 @@ pub trait BatchOpeningPCS: PolynomialCommitmentScheme + Si points: &[Self::EvalPoint], scratch_pad: &Self::ScratchPad, transcript: &mut impl Transcript, - ) -> (Vec, BatchOpening) { - unimplemented!() - } + ) -> (Vec, BatchOpening); /// Verify the opening of a set of polynomials at a single point. fn multiple_points_batch_verify( @@ -117,9 +115,7 @@ pub trait BatchOpeningPCS: PolynomialCommitmentScheme + Si values: &[F], opening: &BatchOpening, transcript: &mut impl Transcript, - ) -> bool { - unimplemented!() - } + ) -> bool; } pub(crate) trait TensorCodeIOPPCS { From ff83111a3556b49f7790740570a109307b37018a Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 28 May 2025 22:58:26 -0400 Subject: [PATCH 33/57] fix ci --- poly_commit/benches/pcs_all.rs | 15 ++++++--------- poly_commit/src/kzg/batch.rs | 2 +- poly_commit/src/kzg/pcs_trait_impl.rs | 2 +- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/poly_commit/benches/pcs_all.rs b/poly_commit/benches/pcs_all.rs index 8e3fc0d0..bb708639 100644 --- a/poly_commit/benches/pcs_all.rs +++ b/poly_commit/benches/pcs_all.rs @@ -5,7 +5,9 @@ use gkr_engine::StructuredReferenceString; use gkr_engine::{root_println, MPIConfig, MPIEngine, Transcript}; use gkr_hashers::{Keccak256hasher, SHA256hasher}; use halo2curves::bn256::{Bn256, G1Affine}; -use poly_commit::{HyperKZGPCS, HyraxPCS, OrionBaseFieldPCS, PolynomialCommitmentScheme}; +use poly_commit::{ + BatchOpeningPCS, HyperKZGPCS, HyraxPCS, OrionBaseFieldPCS, PolynomialCommitmentScheme, +}; use polynomials::MultiLinearPoly; use rand::RngCore; use serdes::ExpSerde; @@ -203,12 +205,7 @@ fn pcs_bench>( fn bench_batch_open(mpi_config: &MPIConfig, num_vars: usize, num_poly: usize) where F: Field + ExtensionField, - PCS: PolynomialCommitmentScheme< - F, - Params = usize, - EvalPoint = Vec, - Poly = MultiLinearPoly, - >, + PCS: BatchOpeningPCS, Poly = MultiLinearPoly>, { let mut rng = test_rng(); @@ -237,7 +234,7 @@ where format!("{} batch open {} polys ", PCS::NAME, num_poly).as_ref(), mpi_config.is_root(), ); - let (values, batch_opening) = PCS::batch_open( + let (values, batch_opening) = PCS::single_point_batch_open( &num_vars, &proving_key, &polys, @@ -258,7 +255,7 @@ where format!("{} batch verify {} polys ", PCS::NAME, num_poly).as_ref(), mpi_config.is_root(), ); - assert!(PCS::batch_verify( + assert!(PCS::single_point_batch_verify( &num_vars, &verification_key, &commitments, diff --git a/poly_commit/src/kzg/batch.rs b/poly_commit/src/kzg/batch.rs index 6b2348fc..1fb3ed42 100644 --- a/poly_commit/src/kzg/batch.rs +++ b/poly_commit/src/kzg/batch.rs @@ -84,7 +84,7 @@ where let mut accumulator = PairingAccumulator::default(); let partial_check = coeff_form_uni_hyperkzg_partial_verify( - &verifying_key, + verifying_key, merged_commitment.to_affine(), x, merged_eval, diff --git a/poly_commit/src/kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/pcs_trait_impl.rs index ae6d0c49..454524ba 100644 --- a/poly_commit/src/kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/pcs_trait_impl.rs @@ -100,7 +100,7 @@ where let mut accumulator = PairingAccumulator::default(); let partial_check = coeff_form_uni_hyperkzg_partial_verify( - &verifying_key, + verifying_key, commitment.0, x, v, From accad15a3b57672a41a96fec9fe08d98ec737a0e Mon Sep 17 00:00:00 2001 From: zhenfei Date: Thu, 29 May 2025 08:51:50 -0400 Subject: [PATCH 34/57] remove pairing accumulator --- gkr/src/verifier/snark.rs | 83 ++--------- gkr_engine/src/poly_commit/definition.rs | 56 -------- poly_commit/src/hyrax/expander_api.rs | 6 +- poly_commit/src/kzg.rs | 3 - poly_commit/src/kzg/batch.rs | 17 +-- poly_commit/src/kzg/bivariate.rs | 70 +++------- poly_commit/src/kzg/deferred_pairing.rs | 57 -------- poly_commit/src/kzg/expander_api.rs | 9 +- poly_commit/src/kzg/hyper_bikzg.rs | 44 +----- poly_commit/src/kzg/hyper_kzg.rs | 39 +----- poly_commit/src/kzg/pcs_trait_impl.rs | 20 +-- poly_commit/src/kzg/univariate.rs | 37 ++--- poly_commit/src/orion/expander_api.rs | 5 +- poly_commit/src/raw.rs | 5 +- poly_commit/tests/test_kzg.rs | 168 +++++++++++------------ sumcheck/src/sumcheck_generic.rs | 2 +- 16 files changed, 134 insertions(+), 487 deletions(-) delete mode 100644 poly_commit/src/kzg/deferred_pairing.rs diff --git a/gkr/src/verifier/snark.rs b/gkr/src/verifier/snark.rs index 673926ee..ebdfaa36 100644 --- a/gkr/src/verifier/snark.rs +++ b/gkr/src/verifier/snark.rs @@ -7,8 +7,8 @@ use std::{ use super::gkr_square::sumcheck_verify_gkr_square_layer; use circuit::Circuit; use gkr_engine::{ - DeferredCheck, ExpanderPCS, ExpanderSingleVarChallenge, FieldEngine, GKREngine, GKRScheme, - MPIConfig, MPIEngine, Proof, StructuredReferenceString, Transcript, + ExpanderPCS, ExpanderSingleVarChallenge, FieldEngine, GKREngine, GKRScheme, MPIConfig, + MPIEngine, Proof, StructuredReferenceString, Transcript, }; use rayon::iter::{ IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator, @@ -267,10 +267,9 @@ impl Verifier { claim_y: &Option<::ChallengeField>, transcript: &mut impl Transcript, mut proof_reader: impl Read, - accmulator: &mut >::Accumulator, ) -> bool { let timer = Timer::new("post_gkr", true); - let mut verified = self.get_pcs_opening_from_proof_and_partial_verify( + let mut verified = self.get_pcs_opening_from_proof_and_verify( pcs_params, pcs_verification_key, commitment, @@ -278,11 +277,10 @@ impl Verifier { claim_x, transcript, &mut proof_reader, - accmulator, ); if let Some(challenge_y) = challenge_y { - verified &= self.get_pcs_opening_from_proof_and_partial_verify( + verified &= self.get_pcs_opening_from_proof_and_verify( pcs_params, pcs_verification_key, commitment, @@ -290,7 +288,6 @@ impl Verifier { claim_y.as_ref().unwrap(), transcript, &mut proof_reader, - accmulator, ); } @@ -301,7 +298,7 @@ impl Verifier { /// Paritially verify the proof. /// Conduct the whole procedure except for pairing, if any. #[allow(clippy::too_many_arguments)] - pub fn partial_verify( + pub fn verify( &self, circuit: &mut Circuit, public_input: &[::SimdCircuitField], @@ -309,7 +306,6 @@ impl Verifier { pcs_params: &>::Params, pcs_verification_key: &<>::SRS as StructuredReferenceString>::VKey, proof: &Proof, - accumulator: &mut >::Accumulator, ) -> bool { let timer = Timer::new("snark verify", true); @@ -338,7 +334,6 @@ impl Verifier { &claim_y, &mut transcript, &mut cursor, - accumulator, ); timer.stop(); @@ -346,38 +341,7 @@ impl Verifier { verified } - /// Verify the GKR proof := { GKR_IOP proof, PCS proof} - pub fn verify( - &self, - circuit: &mut Circuit, - public_input: &[::SimdCircuitField], - claimed_v: &::ChallengeField, - pcs_params: &>::Params, - pcs_verification_key: &<>::SRS as StructuredReferenceString>::VKey, - proof: &Proof, - ) -> bool { - let mut accumulator = - >::Accumulator::default( - ); - - let partial_check = self.partial_verify( - circuit, - public_input, - claimed_v, - pcs_params, - pcs_verification_key, - proof, - &mut accumulator, - ); - let final_check = accumulator.final_check(); - - partial_check && final_check - } - - /// Paritially verify the proof. - /// Conduct the whole procedure except for pairing, if any. - #[allow(clippy::too_many_arguments)] - pub fn par_partial_verify( + pub fn par_verify( &self, circuit: &mut Circuit, public_input: &[::SimdCircuitField], @@ -385,7 +349,6 @@ impl Verifier { pcs_params: &>::Params, pcs_verification_key: &<>::SRS as StructuredReferenceString>::VKey, proof: &Proof, - accumulator: &mut >::Accumulator, ) -> bool { let timer = Timer::new("snark verify", true); @@ -414,44 +377,16 @@ impl Verifier { &claim_y, &mut transcript, &mut cursor, - accumulator, ); timer.stop(); verified } - - /// Verify the GKR proof with parallel GKR. - pub fn par_verify( - &self, - circuit: &mut Circuit, - public_input: &[::SimdCircuitField], - claimed_v: &::ChallengeField, - pcs_params: &>::Params, - pcs_verification_key: &<>::SRS as StructuredReferenceString>::VKey, - proof: &Proof, - ) -> bool { - let mut accumulator = - >::Accumulator::default( - ); - let partial_check = self.par_partial_verify( - circuit, - public_input, - claimed_v, - pcs_params, - pcs_verification_key, - proof, - &mut accumulator, - ); - let final_check = accumulator.final_check(); - - partial_check && final_check - } } impl Verifier { #[allow(clippy::too_many_arguments)] - fn get_pcs_opening_from_proof_and_partial_verify( + fn get_pcs_opening_from_proof_and_verify( &self, pcs_params: &>::Params, pcs_verification_key: &<>::SRS as StructuredReferenceString>::VKey, @@ -460,7 +395,6 @@ impl Verifier { v: &::ChallengeField, transcript: &mut impl Transcript, proof_reader: impl Read, - accumulator: &mut >::Accumulator, ) -> bool { let opening = >::Opening::deserialize_from( proof_reader, @@ -468,7 +402,7 @@ impl Verifier { .unwrap(); transcript.lock_proof(); - let verified = Cfg::PCSConfig::partial_verify( + let verified = Cfg::PCSConfig::verify( pcs_params, pcs_verification_key, commitment, @@ -476,7 +410,6 @@ impl Verifier { *v, transcript, &opening, - accumulator, ); transcript.unlock_proof(); diff --git a/gkr_engine/src/poly_commit/definition.rs b/gkr_engine/src/poly_commit/definition.rs index c1efd132..53296dad 100644 --- a/gkr_engine/src/poly_commit/definition.rs +++ b/gkr_engine/src/poly_commit/definition.rs @@ -20,24 +20,6 @@ pub trait PCSParams: Clone + Debug + Default + Send + Sync + 'static { fn num_vars(&self) -> usize; } -pub trait DeferredCheck { - /// Data type to be accumulated - type AccumulatedValues; - - /// Add a new pairing check to the accumulator - fn accumulate(&mut self, _accumulated_values: &Self::AccumulatedValues) {} - - /// Check if all pairings are valid - fn final_check(&self) -> bool { - true - } -} - -// Empty implementation for the case where no pairing checks are needed -impl DeferredCheck for () { - type AccumulatedValues = (); -} - impl PCSParams for usize { fn num_vars(&self) -> usize { *self @@ -56,9 +38,6 @@ pub trait ExpanderPCS { type Commitment: Clone + Debug + Default + ExpSerde + Send + Sync; type Opening: Clone + Debug + Default + ExpSerde + Send + Sync; - /// An accumulator to be used for deferred batch verification for KZG. - type Accumulator: Clone + Debug + Default + DeferredCheck; - /// Generate a random structured reference string (SRS) for testing purposes. /// Each process should return the SRS share used for its committing and opening. /// @@ -136,43 +115,8 @@ pub trait ExpanderPCS { v: F::ChallengeField, transcript: &mut impl Transcript, opening: &Self::Opening, - ) -> bool { - let mut accumulator = Self::Accumulator::default(); - - let partial_check = Self::partial_verify( - params, - verifying_key, - commitment, - x, - v, - transcript, - opening, - &mut accumulator, - ); - let final_check = accumulator.final_check(); - - partial_check && final_check - } - - /// Partially verify the opening of a polynomial at a point. - /// Deffer some of the checks to the batch verification via accumulator. - #[allow(clippy::too_many_arguments)] - fn partial_verify( - params: &Self::Params, - verifying_key: &::VKey, - commitment: &Self::Commitment, - x: &ExpanderSingleVarChallenge, - v: F::ChallengeField, - transcript: &mut impl Transcript, - opening: &Self::Opening, - accumulator: &mut Self::Accumulator, ) -> bool; - /// Perform the finally batch verification for the accumulated opening proofs. - fn batch_deferred_verification(accumulator: &mut Self::Accumulator) -> bool { - accumulator.final_check() - } - /// Open a set of polynomials at a point. fn batch_open( _params: &Self::Params, diff --git a/poly_commit/src/hyrax/expander_api.rs b/poly_commit/src/hyrax/expander_api.rs index fff6348c..b6297fa3 100644 --- a/poly_commit/src/hyrax/expander_api.rs +++ b/poly_commit/src/hyrax/expander_api.rs @@ -38,8 +38,6 @@ where type Opening = HyraxOpening; type SRS = PedersenParams; - type Accumulator = (); - fn gen_params(n_input_vars: usize, _world_size: usize) -> Self::Params { n_input_vars } @@ -115,7 +113,7 @@ where HyraxOpening(combined_coeffs).into() } - fn partial_verify( + fn verify( _params: &Self::Params, verifying_key: &::VKey, commitment: &Self::Commitment, @@ -123,7 +121,6 @@ where evals: ::ChallengeField, _transcript: &mut impl Transcript, opening: &Self::Opening, - _accumulator: &mut Self::Accumulator, ) -> bool { if x.r_mpi.is_empty() { return hyrax_verify(verifying_key, commitment, &x.local_xs(), evals, opening); @@ -148,6 +145,7 @@ where == RefMultiLinearPoly::from_ref(&opening.0) .evaluate_with_buffer(&local_vars[..pedersen_vars], &mut scratch) } + /// Open a set of polynomials at a point. fn batch_open( _params: &Self::Params, diff --git a/poly_commit/src/kzg.rs b/poly_commit/src/kzg.rs index cd00c886..fdb9f959 100644 --- a/poly_commit/src/kzg.rs +++ b/poly_commit/src/kzg.rs @@ -29,8 +29,5 @@ pub use pcs_trait_impl::HyperKZGPCS; mod expander_api; -mod deferred_pairing; -pub use deferred_pairing::PairingAccumulator; - mod batch; pub use batch::{kzg_batch_open, kzg_batch_verify}; diff --git a/poly_commit/src/kzg/batch.rs b/poly_commit/src/kzg/batch.rs index 1fb3ed42..53f30e3d 100644 --- a/poly_commit/src/kzg/batch.rs +++ b/poly_commit/src/kzg/batch.rs @@ -1,13 +1,13 @@ use arith::{ExtensionField, Field}; -use gkr_engine::{DeferredCheck, Transcript}; +use gkr_engine::Transcript; use halo2curves::group::Group; use halo2curves::{group::Curve, msm::multiexp_serial, pairing::MultiMillerLoop, CurveAffine}; use polynomials::MultiLinearPoly; use serdes::ExpSerde; use super::{ - coeff_form_uni_hyperkzg_open, coeff_form_uni_hyperkzg_partial_verify, powers_series, - CoefFormUniKZGSRS, HyperKZGOpening, PairingAccumulator, UniKZGVerifierParams, + coeff_form_uni_hyperkzg_open, coeff_form_uni_hyperkzg_verify, powers_series, CoefFormUniKZGSRS, + HyperKZGOpening, UniKZGVerifierParams, }; pub fn kzg_batch_open( @@ -81,19 +81,12 @@ where .zip(rlcs.iter()) .fold(E::Fr::zero(), |acc, (e, r)| acc + (*e * r)); - let mut accumulator = PairingAccumulator::default(); - - let partial_check = coeff_form_uni_hyperkzg_partial_verify( + coeff_form_uni_hyperkzg_verify( verifying_key, merged_commitment.to_affine(), x, merged_eval, opening, transcript, - &mut accumulator, - ); - - let pairing_check = accumulator.final_check(); - - pairing_check && partial_check + ) } diff --git a/poly_commit/src/kzg/bivariate.rs b/poly_commit/src/kzg/bivariate.rs index d280af77..ea08667b 100644 --- a/poly_commit/src/kzg/bivariate.rs +++ b/poly_commit/src/kzg/bivariate.rs @@ -1,9 +1,8 @@ -use gkr_engine::DeferredCheck; use halo2curves::{ ff::Field, group::{prime::PrimeCurveAffine, Curve, Group}, msm, - pairing::MultiMillerLoop, + pairing::{MillerLoopResult, MultiMillerLoop}, CurveAffine, }; use itertools::izip; @@ -11,8 +10,6 @@ use serdes::ExpSerde; use crate::*; -use super::deferred_pairing::PairingAccumulator; - #[inline(always)] pub fn generate_coef_form_bi_kzg_local_srs_for_testing( local_length: usize, @@ -113,34 +110,6 @@ pub fn coeff_form_bi_kzg_verify( eval: E::Fr, opening: BiKZGProof, ) -> bool -where - E::G1Affine: CurveAffine + ExpSerde, - E::G2Affine: CurveAffine + ExpSerde, -{ - let mut pairing_accumulator = PairingAccumulator::default(); - let partial_check = coeff_form_bi_kzg_partial_verify( - vk, - comm, - alpha, - beta, - eval, - opening, - &mut pairing_accumulator, - ); - let pairing_check = pairing_accumulator.final_check(); - partial_check && pairing_check -} - -#[inline(always)] -pub fn coeff_form_bi_kzg_partial_verify( - vk: BiKZGVerifierParam, - comm: E::G1Affine, - alpha: E::Fr, - beta: E::Fr, - eval: E::Fr, - opening: BiKZGProof, - pairing_accumulator: &mut PairingAccumulator, -) -> bool where E::G1Affine: CurveAffine + ExpSerde, E::G2Affine: CurveAffine + ExpSerde, @@ -149,25 +118,24 @@ where let g2_alpha: E::G2 = E::G2Affine::generator() * alpha; let g2_beta: E::G2 = E::G2Affine::generator() * beta; - pairing_accumulator.accumulate(&( - opening.quotient_x.to_curve(), - (vk.tau_x_g2.to_curve() - g2_alpha), - )); - - pairing_accumulator.accumulate(&( - opening.quotient_y.to_curve(), - (vk.tau_y_g2.to_curve() - g2_beta), - )); - - pairing_accumulator.accumulate(&((g1_eval - comm), E::G2::generator())); - - true + let gt_result = E::multi_miller_loop(&[ + ( + &opening.quotient_x, + &(vk.tau_x_g2.to_curve() - g2_alpha).to_affine().into(), + ), + ( + &opening.quotient_y, + &(vk.tau_y_g2.to_curve() - g2_beta).to_affine().into(), + ), + (&(g1_eval - comm).into(), &E::G2Affine::generator().into()), + ]); + + gt_result.final_exponentiation().is_identity().into() } #[cfg(test)] mod tests { use ark_std::test_rng; - use gkr_engine::DeferredCheck; use halo2curves::{ bn256::{Bn256, Fr, G1Affine, G1}, ff::Field, @@ -175,7 +143,7 @@ mod tests { }; use itertools::izip; - use crate::{kzg::deferred_pairing::PairingAccumulator, *}; + use crate::*; #[test] fn test_coefficient_form_bivariate_kzg_e2e() { @@ -217,17 +185,13 @@ mod tests { let vk: BiKZGVerifierParam = From::from(&party_srs[0]); - let mut pairing_accumulator = PairingAccumulator::default(); - coeff_form_bi_kzg_partial_verify( + assert!(coeff_form_bi_kzg_verify( vk, global_commitment, alpha, beta, final_eval, final_opening, - &mut pairing_accumulator, - ); - - assert!(pairing_accumulator.final_check()); + )); } } diff --git a/poly_commit/src/kzg/deferred_pairing.rs b/poly_commit/src/kzg/deferred_pairing.rs deleted file mode 100644 index 89fe42ae..00000000 --- a/poly_commit/src/kzg/deferred_pairing.rs +++ /dev/null @@ -1,57 +0,0 @@ -use gkr_engine::DeferredCheck; -use halo2curves::group::prime::PrimeCurveAffine; -use halo2curves::group::Curve; -use halo2curves::{ - group::Group, - pairing::{Engine, MillerLoopResult, MultiMillerLoop}, -}; - -/// Deferred pairing checks -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct PairingAccumulator { - pub g1s: Vec, - pub g2s: Vec, -} - -impl Default for PairingAccumulator -where - E: Engine, -{ - fn default() -> Self { - Self { - g1s: Vec::new(), - g2s: Vec::new(), - } - } -} - -impl DeferredCheck for PairingAccumulator { - type AccumulatedValues = (E::G1, E::G2); - - fn accumulate(&mut self, accumulated_values: &(E::G1, E::G2)) { - self.g1s.push(accumulated_values.0); - self.g2s.push(accumulated_values.1); - } - - fn final_check(&self) -> bool { - if self.g1s.is_empty() || self.g2s.is_empty() { - return true; - } - - let mut g1_affines = vec![::G1Affine::identity(); self.g1s.len()]; - E::G1::batch_normalize(&self.g1s, &mut g1_affines); - - let mut g2_affines = vec![::G2Affine::identity(); self.g2s.len()]; - E::G2::batch_normalize(&self.g2s, &mut g2_affines); - let g2_prepared: Vec = - g2_affines.iter().map(|&g2| g2.into()).collect::>(); - - let g1g2_pairs = g1_affines - .iter() - .zip(g2_prepared.iter()) - .collect::>(); - - let gt_result = E::multi_miller_loop(g1g2_pairs.as_slice()); - gt_result.final_exponentiation().is_identity().into() - } -} diff --git a/poly_commit/src/kzg/expander_api.rs b/poly_commit/src/kzg/expander_api.rs index 77f8d904..3189182a 100644 --- a/poly_commit/src/kzg/expander_api.rs +++ b/poly_commit/src/kzg/expander_api.rs @@ -20,8 +20,6 @@ use crate::{ *, }; -use super::deferred_pairing::PairingAccumulator; - impl ExpanderPCS for HyperKZGPCS where G: FieldEngine, @@ -39,7 +37,6 @@ where type Params = usize; type SRS = CoefFormBiKZGLocalSRS; type ScratchPad = (); - type Accumulator = PairingAccumulator; fn init_scratch_pad(_params: &Self::Params, _mpi_engine: &impl MPIEngine) -> Self::ScratchPad {} @@ -137,7 +134,7 @@ where ) } - fn partial_verify( + fn verify( _params: &Self::Params, verifying_key: &::VKey, commitment: &Self::Commitment, @@ -145,7 +142,6 @@ where v: ::ChallengeField, transcript: &mut impl Transcript, opening: &Self::Opening, - accumulator: &mut Self::Accumulator, ) -> bool { if x.rz.len() < Self::MINIMUM_SUPPORTED_NUM_VARS { let x = lift_expander_challenge_to_n_vars(x, Self::MINIMUM_SUPPORTED_NUM_VARS); @@ -160,7 +156,7 @@ where ); }; - coeff_form_hyper_bikzg_partial_verify( + coeff_form_hyper_bikzg_verify( verifying_key, &x.local_xs(), &x.r_mpi, @@ -168,7 +164,6 @@ where commitment.0, opening, transcript, - accumulator, ) } diff --git a/poly_commit/src/kzg/hyper_bikzg.rs b/poly_commit/src/kzg/hyper_bikzg.rs index 65aee351..11706dc5 100644 --- a/poly_commit/src/kzg/hyper_bikzg.rs +++ b/poly_commit/src/kzg/hyper_bikzg.rs @@ -4,7 +4,7 @@ use std::{io::Cursor, iter}; use arith::ExtensionField; -use gkr_engine::{DeferredCheck, MPIEngine, Transcript}; +use gkr_engine::{MPIEngine, Transcript}; use halo2curves::{ ff::Field, group::{prime::PrimeCurveAffine, Curve, Group, GroupEncoding}, @@ -18,8 +18,6 @@ use transcript::{transcript_root_broadcast, transcript_verifier_sync}; use crate::*; -use super::deferred_pairing::PairingAccumulator; - pub fn coeff_form_hyper_bikzg_open( srs: &CoefFormBiKZGLocalSRS, mpi_engine: &impl MPIEngine, @@ -454,40 +452,6 @@ pub fn coeff_form_hyper_bikzg_verify( opening: &HyperBiKZGOpening, fs_transcript: &mut T, ) -> bool -where - E: MultiMillerLoop, - T: Transcript, - E::G1Affine: CurveAffine + ExpSerde, - E::G2Affine: CurveAffine + ExpSerde, - E::Fr: ExtensionField, -{ - let mut pairing_accumulator = PairingAccumulator::default(); - let partial_check = coeff_form_hyper_bikzg_partial_verify( - vk, - local_alphas, - mpi_alphas, - eval, - commitment, - opening, - fs_transcript, - &mut pairing_accumulator, - ); - let pairing_check = pairing_accumulator.final_check(); - - partial_check && pairing_check -} - -#[allow(clippy::too_many_arguments)] -pub fn coeff_form_hyper_bikzg_partial_verify( - vk: &BiKZGVerifierParam, - local_alphas: &[E::Fr], - mpi_alphas: &[E::Fr], - eval: E::Fr, - commitment: E::G1Affine, - opening: &HyperBiKZGOpening, - fs_transcript: &mut T, - pairing_accumulator: &mut PairingAccumulator, -) -> bool where E: MultiMillerLoop, T: Transcript, @@ -500,14 +464,13 @@ where let hyper_bikzg_opening = opening.clone(); let hyper_kzg_opening: HyperKZGOpening = hyper_bikzg_opening.into(); - let what = coeff_form_uni_hyperkzg_partial_verify( + let what = coeff_form_uni_hyperkzg_verify( &vk.into(), commitment, local_alphas, eval, &hyper_kzg_opening, fs_transcript, - pairing_accumulator, ); return what; @@ -676,13 +639,12 @@ where quotient_y: opening.quotient_delta_y_commitment, }; - coeff_form_bi_kzg_partial_verify( + coeff_form_bi_kzg_verify( vk.clone(), com_r.to_affine(), delta_x, delta_y, degree_2_final_eval, final_opening, - pairing_accumulator, ) } diff --git a/poly_commit/src/kzg/hyper_kzg.rs b/poly_commit/src/kzg/hyper_kzg.rs index 1946b101..51fcd426 100644 --- a/poly_commit/src/kzg/hyper_kzg.rs +++ b/poly_commit/src/kzg/hyper_kzg.rs @@ -1,7 +1,7 @@ use std::iter; use arith::ExtensionField; -use gkr_engine::{DeferredCheck, Transcript}; +use gkr_engine::Transcript; use halo2curves::{ ff::Field, group::{prime::PrimeCurveAffine, GroupEncoding}, @@ -13,8 +13,6 @@ use serdes::ExpSerde; use crate::*; -use super::deferred_pairing::PairingAccumulator; - #[inline(always)] pub(crate) fn coeff_form_hyperkzg_local_poly_oracles( srs: &CoefFormUniKZGSRS, @@ -182,38 +180,6 @@ pub fn coeff_form_uni_hyperkzg_verify( opening: &HyperKZGOpening, fs_transcript: &mut T, ) -> bool -where - E: MultiMillerLoop, - E::G1Affine: CurveAffine + ExpSerde, - E::G2Affine: ExpSerde, - E::Fr: ExtensionField + ExpSerde, - T: Transcript, -{ - let mut pairing_accumulator = PairingAccumulator::default(); - let partial_check = coeff_form_uni_hyperkzg_partial_verify( - vk, - comm, - alphas, - eval, - opening, - fs_transcript, - &mut pairing_accumulator, - ); - let pairing_check = pairing_accumulator.final_check(); - - partial_check && pairing_check -} - -#[inline(always)] -pub fn coeff_form_uni_hyperkzg_partial_verify( - vk: &UniKZGVerifierParams, - comm: E::G1Affine, - alphas: &[E::Fr], - eval: E::Fr, - opening: &HyperKZGOpening, - fs_transcript: &mut T, - pairing_accumulator: &mut PairingAccumulator, -) -> bool where E: MultiMillerLoop, E::G1Affine: CurveAffine + ExpSerde, @@ -261,13 +227,12 @@ where let lagrange_eval = lagrange_degree2[0] + lagrange_degree2[1] * tau + lagrange_degree2[2] * tau * tau; - coeff_form_uni_kzg_partial_verify( + coeff_form_uni_kzg_verify( vk, (commitment_agg_g1 - opening.beta_x_commitment.to_curve() * q_weight).into(), tau, lagrange_eval, opening.quotient_delta_x_commitment, - pairing_accumulator, ); true diff --git a/poly_commit/src/kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/pcs_trait_impl.rs index 454524ba..3c6b24e1 100644 --- a/poly_commit/src/kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/pcs_trait_impl.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use arith::ExtensionField; use arith::Field; use ark_std::log2; -use gkr_engine::{DeferredCheck, StructuredReferenceString, Transcript}; +use gkr_engine::{StructuredReferenceString, Transcript}; use halo2curves::group::Curve; use halo2curves::group::Group; use halo2curves::{ @@ -22,8 +22,6 @@ use crate::{ }; use kzg::hyper_kzg::*; -use super::deferred_pairing::PairingAccumulator; - pub struct HyperKZGPCS where E: Engine, @@ -97,21 +95,7 @@ where opening: &Self::Opening, transcript: &mut impl Transcript, ) -> bool { - let mut accumulator = PairingAccumulator::default(); - - let partial_check = coeff_form_uni_hyperkzg_partial_verify( - verifying_key, - commitment.0, - x, - v, - opening, - transcript, - &mut accumulator, - ); - - let pairing_check = accumulator.final_check(); - - pairing_check && partial_check + coeff_form_uni_hyperkzg_verify(verifying_key, commitment.0, x, v, opening, transcript) } } diff --git a/poly_commit/src/kzg/univariate.rs b/poly_commit/src/kzg/univariate.rs index 8906944b..5d8a6d7a 100644 --- a/poly_commit/src/kzg/univariate.rs +++ b/poly_commit/src/kzg/univariate.rs @@ -1,9 +1,8 @@ -use gkr_engine::DeferredCheck; use halo2curves::{ ff::Field, group::{prime::PrimeCurveAffine, Curve, Group}, msm, - pairing::MultiMillerLoop, + pairing::{MillerLoopResult, MultiMillerLoop}, CurveAffine, }; use itertools::izip; @@ -11,8 +10,6 @@ use serdes::ExpSerde; use crate::*; -use super::deferred_pairing::PairingAccumulator; - #[inline(always)] pub(crate) fn generate_coef_form_uni_kzg_srs_for_testing( length: usize, @@ -90,7 +87,6 @@ where } #[inline(always)] -#[cfg(test)] pub(crate) fn coeff_form_uni_kzg_verify( vk: &UniKZGVerifierParams, comm: E::G1Affine, @@ -98,26 +94,6 @@ pub(crate) fn coeff_form_uni_kzg_verify( eval: E::Fr, opening: E::G1Affine, ) -> bool -where - E::G1Affine: CurveAffine, - E::G2Affine: ExpSerde, -{ - let mut pairing_accumulator = PairingAccumulator::default(); - coeff_form_uni_kzg_partial_verify(vk, comm, alpha, eval, opening, &mut pairing_accumulator); - let pairing_check = pairing_accumulator.final_check(); - - pairing_check -} - -#[inline(always)] -pub(crate) fn coeff_form_uni_kzg_partial_verify( - vk: &UniKZGVerifierParams, - comm: E::G1Affine, - alpha: E::Fr, - eval: E::Fr, - opening: E::G1Affine, - pairing_accumulator: &mut PairingAccumulator, -) -> bool where E::G1Affine: CurveAffine, E::G2Affine: ExpSerde, @@ -125,10 +101,15 @@ where let g1_eval: E::G1Affine = (E::G1Affine::generator() * eval).into(); let g2_alpha: E::G2 = E::G2Affine::generator() * alpha; - pairing_accumulator.accumulate(&(opening.to_curve(), (vk.tau_g2.to_curve() - g2_alpha))); - pairing_accumulator.accumulate(&(g1_eval - comm, E::G2::generator())); + let gt_result = E::multi_miller_loop(&[ + ( + &opening, + &(vk.tau_g2.to_curve() - g2_alpha).to_affine().into(), + ), + (&(g1_eval - comm).into(), &E::G2Affine::generator().into()), + ]); - true + gt_result.final_exponentiation().is_identity().into() } #[cfg(test)] diff --git a/poly_commit/src/orion/expander_api.rs b/poly_commit/src/orion/expander_api.rs index 1b3c0801..28c7ece8 100644 --- a/poly_commit/src/orion/expander_api.rs +++ b/poly_commit/src/orion/expander_api.rs @@ -38,8 +38,6 @@ where type Opening = OrionProof; type SRS = OrionSRS; - type Accumulator = (); - /// NOTE(HS): this is the number of variables for local polynomial w.r.t. SIMD field elements. fn gen_params(n_input_vars: usize, world_size: usize) -> Self::Params { let num_vars_each_core = n_input_vars + C::SimdCircuitField::PACK_SIZE.ilog2() as usize; @@ -162,7 +160,7 @@ where ) } - fn partial_verify( + fn verify( params: &Self::Params, verifying_key: &::VKey, commitment: &Self::Commitment, @@ -171,7 +169,6 @@ where transcript: &mut impl Transcript, /* add transcript here to allow * interactive arguments */ opening: &Self::Opening, - _accumulator: &mut Self::Accumulator, ) -> bool { if eval_point.num_vars() < *params { let eval_point = lift_expander_challenge_to_n_vars(eval_point, *params); diff --git a/poly_commit/src/raw.rs b/poly_commit/src/raw.rs index ce26f89c..2d2e99cf 100644 --- a/poly_commit/src/raw.rs +++ b/poly_commit/src/raw.rs @@ -136,8 +136,6 @@ impl ExpanderPCS for RawExpanderGKR { type Opening = (); - type Accumulator = (); - fn gen_srs_for_testing( _params: &Self::Params, _mpi_engine: &impl MPIEngine, @@ -194,7 +192,7 @@ impl ExpanderPCS for RawExpanderGKR { Some(()) } - fn partial_verify( + fn verify( _params: &Self::Params, _verifying_key: &::VKey, commitment: &Self::Commitment, @@ -202,7 +200,6 @@ impl ExpanderPCS for RawExpanderGKR { v: C::ChallengeField, _transcript: &mut impl Transcript, _opening: &Self::Opening, - _accumulator: &mut Self::Accumulator, ) -> bool { let v_target = C::single_core_eval_circuit_vals_at_expander_challenge(&commitment.evals, challenge); diff --git a/poly_commit/tests/test_kzg.rs b/poly_commit/tests/test_kzg.rs index 074d0230..fbedf430 100644 --- a/poly_commit/tests/test_kzg.rs +++ b/poly_commit/tests/test_kzg.rs @@ -3,13 +3,12 @@ mod common; use arith::{Field, Fr}; use ark_std::test_rng; use gkr_engine::{ - BN254Config, DeferredCheck, ExpanderSingleVarChallenge, FieldEngine, MPIConfig, MPIEngine, - Transcript, + BN254Config, ExpanderSingleVarChallenge, FieldEngine, MPIConfig, MPIEngine, Transcript, }; use gkr_engine::{ExpanderPCS, StructuredReferenceString}; use gkr_hashers::Keccak256hasher; use halo2curves::bn256::Bn256; -use poly_commit::{HyperKZGPCS, PairingAccumulator}; +use poly_commit::HyperKZGPCS; use polynomials::{MultiLinearPoly, MultilinearExtension}; use transcript::BytesHashTranscript; @@ -91,90 +90,85 @@ fn test_hyper_bikzg_for_expander_gkr() { MPIConfig::finalize() } -#[test] -fn test_hyper_bikzg_batch_verification() { - let mut rng = test_rng(); - let mpi_config = MPIConfig::prover_new(); - - for num_vars in 2..=15 { - let srs = as ExpanderPCS>::gen_srs_for_testing( - &num_vars, - &mpi_config, - &mut rng, - ); - let (proving_key, verification_key) = srs.into_keys(); - - let transcript = BytesHashTranscript::::new(); - let mut scratch_pad = - as ExpanderPCS>::init_scratch_pad( - &num_vars, - &mpi_config, - ); - let mut pairing_accumulator = PairingAccumulator::::default(); - - let polys = (0..3).map(|_| MultiLinearPoly::::random(num_vars, &mut rng)); - - for poly in polys { - let mut rng = test_rng(); - let challenge_point_1 = ExpanderSingleVarChallenge:: { - r_mpi: Vec::new(), - r_simd: Vec::new(), - rz: (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(), - }; - let challenge_point_2 = ExpanderSingleVarChallenge:: { - r_mpi: Vec::new(), - r_simd: Vec::new(), - rz: (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(), - }; - let commitment = as ExpanderPCS>::commit( - &num_vars, - &mpi_config, - &proving_key, - &poly, - &mut scratch_pad, - ) - .unwrap(); - - for c in [challenge_point_1, challenge_point_2] { - // open - let mut local_transcript = transcript.clone(); - let opening = as ExpanderPCS>::open( - &num_vars, - &mpi_config, - &proving_key, - &poly, - &c, - &mut local_transcript, - &mut scratch_pad, - ) - .unwrap(); - - // partial verify - let mut local_transcript = transcript.clone(); - let v = BN254Config::single_core_eval_circuit_vals_at_expander_challenge( - &poly.hypercube_basis_ref(), - &c, - ); - - let partial_verify = - as ExpanderPCS>::partial_verify( - &num_vars, - &verification_key, - &commitment, - &c, - v, - &mut local_transcript, - &opening, - &mut pairing_accumulator, - ); - - assert!(partial_verify); - } - } - // finalize the pairing check - assert!(pairing_accumulator.final_check()); - } -} +// #[test] +// fn test_hyper_bikzg_batch_verification() { +// let mut rng = test_rng(); +// let mpi_config = MPIConfig::prover_new(); + +// for num_vars in 2..=15 { +// let srs = as ExpanderPCS>::gen_srs_for_testing( +// &num_vars, +// &mpi_config, +// &mut rng, +// ); +// let (proving_key, verification_key) = srs.into_keys(); + +// let transcript = BytesHashTranscript::::new(); +// let mut scratch_pad = +// as ExpanderPCS>::init_scratch_pad( +// &num_vars, +// &mpi_config, +// ); + +// let polys = (0..3).map(|_| MultiLinearPoly::::random(num_vars, &mut rng)); + +// for poly in polys { +// let mut rng = test_rng(); +// let challenge_point_1 = ExpanderSingleVarChallenge:: { +// r_mpi: Vec::new(), +// r_simd: Vec::new(), +// rz: (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(), +// }; +// let challenge_point_2 = ExpanderSingleVarChallenge:: { +// r_mpi: Vec::new(), +// r_simd: Vec::new(), +// rz: (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(), +// }; +// let commitment = as ExpanderPCS>::commit( +// &num_vars, +// &mpi_config, +// &proving_key, +// &poly, +// &mut scratch_pad, +// ) +// .unwrap(); + +// for c in [challenge_point_1, challenge_point_2] { +// // open +// let mut local_transcript = transcript.clone(); +// let opening = as ExpanderPCS>::open( +// &num_vars, +// &mpi_config, +// &proving_key, +// &poly, +// &c, +// &mut local_transcript, +// &mut scratch_pad, +// ) +// .unwrap(); + +// // partial verify +// let mut local_transcript = transcript.clone(); +// let v = BN254Config::single_core_eval_circuit_vals_at_expander_challenge( +// &poly.hypercube_basis_ref(), +// &c, +// ); + +// assert!( +// as ExpanderPCS>::verify( +// &num_vars, +// &verification_key, +// &commitment, +// &c, +// v, +// &mut local_transcript, +// &opening, +// ) +// ); +// } +// } +// } +// } #[test] fn test_kzg_batch_open() { diff --git a/sumcheck/src/sumcheck_generic.rs b/sumcheck/src/sumcheck_generic.rs index 7947d240..71d9942e 100644 --- a/sumcheck/src/sumcheck_generic.rs +++ b/sumcheck/src/sumcheck_generic.rs @@ -1,6 +1,6 @@ //! This module implements the SumCheck protocol for verifying the sum of //! evaluations of a set of multi-linear polynomial over the hypercube {0,1}^n. -//! This is hardcoded for addition gate for simplicity and efficiency. +//! This is hardcoded for sum of product of MLEs for simplicity and efficiency. // Credit: code adopted from https://github.com/EspressoSystems/hyperplonk/ with modification use arith::Field; From 9b2aba889cc0d2ab9e09407a849003d0c1dc26eb Mon Sep 17 00:00:00 2001 From: zhenfei Date: Thu, 29 May 2025 09:52:09 -0400 Subject: [PATCH 35/57] clean up --- gkr/src/verifier/snark.rs | 1 - poly_commit/src/hyrax/pcs_trait_impl.rs | 3 +- poly_commit/tests/test_kzg.rs | 80 ------------------------- 3 files changed, 2 insertions(+), 82 deletions(-) diff --git a/gkr/src/verifier/snark.rs b/gkr/src/verifier/snark.rs index ebdfaa36..c0f086f2 100644 --- a/gkr/src/verifier/snark.rs +++ b/gkr/src/verifier/snark.rs @@ -252,7 +252,6 @@ impl Verifier { } /// Verify the PCS opening against the commitment and the claim from GKR. - /// Defer the pairing check to accumulator if any. #[inline(always)] #[allow(clippy::too_many_arguments)] #[allow(clippy::type_complexity)] diff --git a/poly_commit/src/hyrax/pcs_trait_impl.rs b/poly_commit/src/hyrax/pcs_trait_impl.rs index 788c4e39..7fe8b3ca 100644 --- a/poly_commit/src/hyrax/pcs_trait_impl.rs +++ b/poly_commit/src/hyrax/pcs_trait_impl.rs @@ -6,7 +6,8 @@ use ark_std::log2; use gkr_engine::{StructuredReferenceString, Transcript}; use halo2curves::group::Curve; use halo2curves::{ff::PrimeField, CurveAffine}; -use polynomials::{EqPolynomial, MultiLinearPoly, MultilinearExtension}; +use polynomials::MultilinearExtension; +use polynomials::{EqPolynomial, MultiLinearPoly}; use serdes::ExpSerde; use sumcheck::SumCheck; use sumcheck::SumOfProductsPoly; diff --git a/poly_commit/tests/test_kzg.rs b/poly_commit/tests/test_kzg.rs index fbedf430..e7ef02c2 100644 --- a/poly_commit/tests/test_kzg.rs +++ b/poly_commit/tests/test_kzg.rs @@ -90,86 +90,6 @@ fn test_hyper_bikzg_for_expander_gkr() { MPIConfig::finalize() } -// #[test] -// fn test_hyper_bikzg_batch_verification() { -// let mut rng = test_rng(); -// let mpi_config = MPIConfig::prover_new(); - -// for num_vars in 2..=15 { -// let srs = as ExpanderPCS>::gen_srs_for_testing( -// &num_vars, -// &mpi_config, -// &mut rng, -// ); -// let (proving_key, verification_key) = srs.into_keys(); - -// let transcript = BytesHashTranscript::::new(); -// let mut scratch_pad = -// as ExpanderPCS>::init_scratch_pad( -// &num_vars, -// &mpi_config, -// ); - -// let polys = (0..3).map(|_| MultiLinearPoly::::random(num_vars, &mut rng)); - -// for poly in polys { -// let mut rng = test_rng(); -// let challenge_point_1 = ExpanderSingleVarChallenge:: { -// r_mpi: Vec::new(), -// r_simd: Vec::new(), -// rz: (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(), -// }; -// let challenge_point_2 = ExpanderSingleVarChallenge:: { -// r_mpi: Vec::new(), -// r_simd: Vec::new(), -// rz: (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(), -// }; -// let commitment = as ExpanderPCS>::commit( -// &num_vars, -// &mpi_config, -// &proving_key, -// &poly, -// &mut scratch_pad, -// ) -// .unwrap(); - -// for c in [challenge_point_1, challenge_point_2] { -// // open -// let mut local_transcript = transcript.clone(); -// let opening = as ExpanderPCS>::open( -// &num_vars, -// &mpi_config, -// &proving_key, -// &poly, -// &c, -// &mut local_transcript, -// &mut scratch_pad, -// ) -// .unwrap(); - -// // partial verify -// let mut local_transcript = transcript.clone(); -// let v = BN254Config::single_core_eval_circuit_vals_at_expander_challenge( -// &poly.hypercube_basis_ref(), -// &c, -// ); - -// assert!( -// as ExpanderPCS>::verify( -// &num_vars, -// &verification_key, -// &commitment, -// &c, -// v, -// &mut local_transcript, -// &opening, -// ) -// ); -// } -// } -// } -// } - #[test] fn test_kzg_batch_open() { common::test_batching::, HyperKZGPCS>(); From fb3f5d6728933f053d25f932859d543b6944827b Mon Sep 17 00:00:00 2001 From: zhenfei Date: Thu, 29 May 2025 13:23:18 -0400 Subject: [PATCH 36/57] Update test_kzg.rs --- poly_commit/tests/test_kzg.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/poly_commit/tests/test_kzg.rs b/poly_commit/tests/test_kzg.rs index e7ef02c2..326355d0 100644 --- a/poly_commit/tests/test_kzg.rs +++ b/poly_commit/tests/test_kzg.rs @@ -2,14 +2,12 @@ mod common; use arith::{Field, Fr}; use ark_std::test_rng; -use gkr_engine::{ - BN254Config, ExpanderSingleVarChallenge, FieldEngine, MPIConfig, MPIEngine, Transcript, -}; -use gkr_engine::{ExpanderPCS, StructuredReferenceString}; +use gkr_engine::ExpanderPCS; +use gkr_engine::{BN254Config, ExpanderSingleVarChallenge, MPIConfig, MPIEngine, Transcript}; use gkr_hashers::Keccak256hasher; use halo2curves::bn256::Bn256; use poly_commit::HyperKZGPCS; -use polynomials::{MultiLinearPoly, MultilinearExtension}; +use polynomials::MultiLinearPoly; use transcript::BytesHashTranscript; const TEST_REPETITION: usize = 3; From 425eb5dc5f676ae90b616214d95bd50de6bde3dd Mon Sep 17 00:00:00 2001 From: zhenfei Date: Thu, 29 May 2025 18:39:11 -0400 Subject: [PATCH 37/57] refactor hyrax --- poly_commit/src/batching.rs | 140 +++++++++++++++++++++ poly_commit/src/hyrax/expander_api.rs | 63 ++++++---- poly_commit/src/hyrax/hyrax_impl.rs | 92 ++++++++++++++ poly_commit/src/hyrax/pcs_trait_impl.rs | 156 ++---------------------- poly_commit/src/kzg/expander_api.rs | 2 + poly_commit/src/kzg/pcs_trait_impl.rs | 135 ++++---------------- poly_commit/src/lib.rs | 2 + poly_commit/src/orion/expander_api.rs | 1 + poly_commit/src/raw.rs | 2 + poly_commit/src/traits.rs | 2 +- poly_commit/tests/common.rs | 24 ++-- poly_commit/tests/test_hyrax.rs | 10 +- 12 files changed, 334 insertions(+), 295 deletions(-) create mode 100644 poly_commit/src/batching.rs diff --git a/poly_commit/src/batching.rs b/poly_commit/src/batching.rs new file mode 100644 index 00000000..63b6f796 --- /dev/null +++ b/poly_commit/src/batching.rs @@ -0,0 +1,140 @@ +//! Multi-points batch opening +use arith::{ExtensionField, Field}; +use ark_std::log2; +use gkr_engine::Transcript; +use halo2curves::group::Curve; +use halo2curves::{ff::PrimeField, CurveAffine}; +use polynomials::MultiLinearPoly; +use polynomials::{EqPolynomial, MultilinearExtension}; +use serdes::ExpSerde; +use sumcheck::{IOPProof, SumCheck, SumOfProductsPoly}; + +/// Merge a list of polynomials and its corresponding points into a single polynomial +/// Returns +/// - the new point for evaluation +/// - the new polynomial that is merged via sumcheck +/// - the proof of the sumcheck +pub fn prover_merge_points( + polys: &[MultiLinearPoly], + points: &[Vec], + transcript: &mut impl Transcript, +) -> ( + Vec, + MultiLinearPoly, + IOPProof, +) +where + C: CurveAffine + ExpSerde, + C::Scalar: ExtensionField + PrimeField, + C::ScalarExt: ExtensionField + PrimeField, +{ + let num_vars = polys[0].num_vars(); + let k = polys.len(); + let ell = log2(k) as usize; + + // challenge point t + let t = transcript.generate_field_elements::(ell); + + // eq(t, i) for i in [0..k] + let eq_t_i = EqPolynomial::build_eq_x_r(&t); + + // \tilde g_i(b) = eq(t, i) * f_i(b) + let mut tilde_gs = vec![]; + for (index, f_i) in polys.iter().enumerate() { + let mut tilde_g_eval = vec![C::Scalar::zero(); 1 << num_vars]; + for (j, &f_i_eval) in f_i.coeffs.iter().enumerate() { + tilde_g_eval[j] = f_i_eval * eq_t_i[index]; + } + tilde_gs.push(MultiLinearPoly { + coeffs: tilde_g_eval, + }); + } + + // built the virtual polynomial for SumCheck + let tilde_eqs: Vec> = points + .iter() + .map(|point| { + let eq_b_zi = EqPolynomial::build_eq_x_r(point); + MultiLinearPoly { coeffs: eq_b_zi } + }) + .collect(); + + let mut sumcheck_poly = SumOfProductsPoly::new(); + for (tilde_g, tilde_eq) in tilde_gs.iter().zip(tilde_eqs.into_iter()) { + sumcheck_poly.add_pair(tilde_g.clone(), tilde_eq); + } + + let proof = SumCheck::::prove(&sumcheck_poly, transcript); + + let a2 = proof.export_point_to_expander(); + + // build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the + // sumcheck's point \tilde eq_i(a2) = eq(a2, point_i) + let mut g_prime_evals = vec![C::Scalar::zero(); 1 << num_vars]; + + for (tilde_g, point) in tilde_gs.iter().zip(points.iter()) { + let eq_i_a2 = EqPolynomial::eq_vec(a2.as_ref(), point); + for (j, &tilde_g_eval) in tilde_g.coeffs.iter().enumerate() { + g_prime_evals[j] += tilde_g_eval * eq_i_a2; + } + } + let g_prime = MultiLinearPoly { + coeffs: g_prime_evals, + }; + + (a2, g_prime, proof) +} + +pub fn verifier_merge_points( + commitments: &[impl AsRef<[C]>], + points: &[Vec], + values: &[C::Scalar], + sumcheck_proof: &IOPProof, + transcript: &mut impl Transcript, +) -> (C::Scalar, Vec) +where + C: CurveAffine + ExpSerde, + C::Scalar: ExtensionField + PrimeField, + C::ScalarExt: ExtensionField + PrimeField, +{ + let k = commitments.len(); + let ell = log2(k) as usize; + let num_var = sumcheck_proof.point.len(); + + // sum check point (a2) + let a2 = sumcheck_proof.export_point_to_expander(); + + // challenge point t + let t = transcript.generate_field_elements::(ell); + + let eq_t_i = EqPolynomial::build_eq_x_r(&t); + + // build g' commitment + + // todo: use MSM + // let mut scalars = vec![]; + // let mut bases = vec![]; + + let mut g_prime_commit_elems = vec![C::Curve::default(); commitments[0].as_ref().len()]; + for (i, point) in points.iter().enumerate() { + let eq_i_a2 = EqPolynomial::eq_vec(a2.as_ref(), point); + let scalar = eq_i_a2 * eq_t_i[i]; + for (j, &base) in commitments[i].as_ref().iter().enumerate() { + g_prime_commit_elems[j] += base * scalar; + } + } + let mut g_prime_commit_affine = vec![C::default(); commitments[0].as_ref().len()]; + C::Curve::batch_normalize(&g_prime_commit_elems, &mut g_prime_commit_affine); + + // ensure \sum_i eq(t, ) * f_i_evals matches the sum via SumCheck + let mut sum = C::Scalar::zero(); + for (i, &e) in eq_t_i.iter().enumerate().take(k) { + sum += e * values[i]; + } + + let subclaim = SumCheck::::verify(sum, &sumcheck_proof, num_var, transcript); + + let tilde_g_eval = subclaim.expected_evaluation; + + (tilde_g_eval, g_prime_commit_affine) +} diff --git a/poly_commit/src/hyrax/expander_api.rs b/poly_commit/src/hyrax/expander_api.rs index b6297fa3..0383180a 100644 --- a/poly_commit/src/hyrax/expander_api.rs +++ b/poly_commit/src/hyrax/expander_api.rs @@ -5,8 +5,8 @@ use gkr_engine::{ }; use halo2curves::{ff::PrimeField, msm, CurveAffine}; use polynomials::{ - EqPolynomial, MultilinearExtension, MutRefMultiLinearPoly, MutableMultilinearExtension, - RefMultiLinearPoly, + EqPolynomial, MultiLinearPoly, MultilinearExtension, MutRefMultiLinearPoly, + MutableMultilinearExtension, RefMultiLinearPoly, }; use serdes::ExpSerde; @@ -15,10 +15,13 @@ use crate::{ hyrax_impl::{hyrax_commit, hyrax_open, hyrax_setup, hyrax_verify}, pedersen::pedersen_commit, }, + traits::BatchOpening, HyraxCommitment, HyraxOpening, HyraxPCS, PedersenParams, }; -use super::hyrax_impl::{hyrax_batch_open, hyrax_batch_verify}; +use super::hyrax_impl::{ + hyrax_multi_points_batch_open_internal, hyrax_multi_points_batch_verify_internal, +}; impl ExpanderPCS for HyraxPCS where @@ -38,6 +41,8 @@ where type Opening = HyraxOpening; type SRS = PedersenParams; + type BatchOpening = BatchOpening; + fn gen_params(n_input_vars: usize, _world_size: usize) -> Self::Params { n_input_vars } @@ -146,39 +151,55 @@ where .evaluate_with_buffer(&local_vars[..pedersen_vars], &mut scratch) } - /// Open a set of polynomials at a point. - fn batch_open( + /// Open a set of polynomials at a set of points. + fn multi_points_batch_open( _params: &Self::Params, - _mpi_engine: &impl MPIEngine, + mpi_engine: &impl MPIEngine, proving_key: &::PKey, - mle_poly_list: &[impl MultilinearExtension], - eval_point: &ExpanderSingleVarChallenge, + mle_poly_list: &[MultiLinearPoly], + eval_points: &[ExpanderSingleVarChallenge], _scratch_pad: &Self::ScratchPad, transcript: &mut impl Transcript, - ) -> (Vec, Self::Opening) { - hyrax_batch_open( - proving_key, - mle_poly_list, - &eval_point.local_xs(), - transcript, - ) + ) -> (Vec, Self::BatchOpening) { + if mpi_engine.is_single_process() || mpi_engine.is_root() { + let points = eval_points.iter().map(|x| x.local_xs()).collect::>(); + + return hyrax_multi_points_batch_open_internal( + proving_key, + mle_poly_list, + &points, + transcript, + ); + } else { + // todo: handle this case? + panic!("Hyrax PCS does not support multi-points batch opening in non-root processes"); + } } - fn batch_verify( + /// Verify the opening of a set of polynomials at a set of points. + fn multi_points_batch_verify( _params: &Self::Params, verifying_key: &::VKey, commitments: &[Self::Commitment], - x: &ExpanderSingleVarChallenge, + x: &[ExpanderSingleVarChallenge], evals: &[::ChallengeField], - opening: &Self::Opening, + batch_opening: &Self::BatchOpening, transcript: &mut impl Transcript, ) -> bool { - hyrax_batch_verify( + for x_i in x { + assert!( + x_i.r_mpi.is_empty(), + "Hyrax PCS does not support multi-points batch verification with MPI challenges" + ); + } + let points = x.iter().map(|x| x.local_xs()).collect::>(); + + hyrax_multi_points_batch_verify_internal( verifying_key, commitments, - &x.local_xs(), + &points, evals, - opening, + batch_opening, transcript, ) } diff --git a/poly_commit/src/hyrax/hyrax_impl.rs b/poly_commit/src/hyrax/hyrax_impl.rs index e6d56f9e..7ccdb56a 100644 --- a/poly_commit/src/hyrax/hyrax_impl.rs +++ b/poly_commit/src/hyrax/hyrax_impl.rs @@ -1,12 +1,15 @@ use arith::{ExtensionField, Field}; use gkr_engine::Transcript; use halo2curves::{ff::PrimeField, msm, CurveAffine}; +use polynomials::MultiLinearPoly; use polynomials::{ EqPolynomial, MultilinearExtension, MutRefMultiLinearPoly, MutableMultilinearExtension, RefMultiLinearPoly, }; use serdes::ExpSerde; +use crate::batching::{prover_merge_points, verifier_merge_points}; +use crate::traits::BatchOpening; use crate::{ hyrax::{ pedersen::{pedersen_commit, pedersen_setup}, @@ -15,6 +18,8 @@ use crate::{ powers_series, }; +use super::HyraxPCS; + pub(crate) fn hyrax_setup( local_vars: usize, mpi_vars: usize, @@ -245,3 +250,90 @@ where fn scale(base: &[F], scalar: &F) -> Vec { base.iter().map(|x| *x * scalar).collect() } + +/// Open a set of polynomials at a multiple points. +/// Requires the length of the polys to be the same as points. +/// Steps: +/// 1. get challenge point t from transcript +/// 2. build eq(t,i) for i in [0..k] +/// 3. build \tilde g_i(b) = eq(t, i) * f_i(b) +/// 4. compute \tilde eq_i(b) = eq(b, point_i) +/// 5. run sumcheck on \sum_i=1..k \tilde eq_i * \tilde g_i +/// 6. build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the sumcheck's point +/// 7. open g'(X) at point (a2) +/// +/// Returns: +/// - the evaluations of the polynomials at their corresponding points +/// - the batch opening proof containing the sumcheck proof and the opening of g'(X) +pub(crate) fn hyrax_multi_points_batch_open_internal( + proving_key: &PedersenParams, + polys: &[MultiLinearPoly], + points: &[Vec], + transcript: &mut impl Transcript, +) -> (Vec, BatchOpening>) +where + C: CurveAffine + ExpSerde, + C::Scalar: ExtensionField + PrimeField, + C::ScalarExt: ExtensionField + PrimeField, +{ + // generate evals for each polynomial at its corresponding point + let evals: Vec = polys + .iter() + .zip(points.iter()) + .map(|(poly, point)| poly.evaluate_jolt(point)) + .collect(); + + let (new_point, g_prime, proof) = prover_merge_points::(polys, points, transcript); + + let (_g_prime_eval, g_prime_proof) = hyrax_open(proving_key, &g_prime, &new_point); + ( + evals, + BatchOpening { + sum_check_proof: proof, + g_prime_proof, + }, + ) +} + +/// Verify the opening of a set of polynomials at a single point. +/// Steps: +/// 1. get challenge point t from transcript +/// 2. build g' commitment +/// 3. ensure \sum_i eq(a2, point_i) * eq(t, ) * f_i_evals matches the sum via SumCheck +/// verification +/// 4. verify commitment +pub(crate) fn hyrax_multi_points_batch_verify_internal( + verifying_key: &PedersenParams, + commitments: &[HyraxCommitment], + points: &[Vec], + values: &[C::Scalar], + batch_opening: &BatchOpening>, + transcript: &mut impl Transcript, +) -> bool +where + C: CurveAffine + ExpSerde, + C::Scalar: ExtensionField + PrimeField, + C::ScalarExt: ExtensionField + PrimeField, +{ + let a2 = batch_opening.sum_check_proof.export_point_to_expander(); + + let commitments = commitments.iter().map(|c| c.0.clone()).collect::>(); + + let (tilde_g_eval, g_prime_commit) = verifier_merge_points( + &commitments, + points, + values, + &batch_opening.sum_check_proof, + transcript, + ); + let g_prime_commit = HyraxCommitment(g_prime_commit); + + // verify commitment + hyrax_verify( + verifying_key, + &g_prime_commit, + a2.as_ref(), + tilde_g_eval, + &batch_opening.g_prime_proof, + ) +} diff --git a/poly_commit/src/hyrax/pcs_trait_impl.rs b/poly_commit/src/hyrax/pcs_trait_impl.rs index 7fe8b3ca..498ef0ae 100644 --- a/poly_commit/src/hyrax/pcs_trait_impl.rs +++ b/poly_commit/src/hyrax/pcs_trait_impl.rs @@ -1,16 +1,10 @@ use std::marker::PhantomData; use arith::ExtensionField; -use arith::Field; -use ark_std::log2; use gkr_engine::{StructuredReferenceString, Transcript}; -use halo2curves::group::Curve; use halo2curves::{ff::PrimeField, CurveAffine}; -use polynomials::MultilinearExtension; -use polynomials::{EqPolynomial, MultiLinearPoly}; +use polynomials::MultiLinearPoly; use serdes::ExpSerde; -use sumcheck::SumCheck; -use sumcheck::SumOfProductsPoly; use crate::traits::BatchOpening; use crate::{ @@ -19,6 +13,8 @@ use crate::{ HyraxCommitment, HyraxOpening, PedersenParams, PolynomialCommitmentScheme, }; +use super::hyrax_impl::hyrax_multi_points_batch_open_internal; +use super::hyrax_impl::hyrax_multi_points_batch_verify_internal; use super::hyrax_impl::{hyrax_batch_open, hyrax_batch_verify}; pub struct HyraxPCS @@ -124,15 +120,6 @@ where /// Open a set of polynomials at a multiple points. /// Requires the length of the polys to be the same as points. - /// Steps: - /// 1. get challenge point t from transcript - /// 2. build eq(t,i) for i in [0..k] - /// 3. build \tilde g_i(b) = eq(t, i) * f_i(b) - /// 4. compute \tilde eq_i(b) = eq(b, point_i) - /// 5. run sumcheck on \sum_i=1..k \tilde eq_i * \tilde g_i - /// 6. build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the sumcheck's - /// point - /// 7. open g'(X) at point (a2) /// /// Returns: /// - the evaluations of the polynomials at their corresponding points @@ -145,147 +132,26 @@ where _scratch_pad: &Self::ScratchPad, transcript: &mut impl Transcript, ) -> (Vec, BatchOpening) { - let num_vars = polys[0].num_vars(); - let k = polys.len(); - let ell = log2(k) as usize; - - // generate evals for each polynomial at its corresponding point - let evals: Vec = polys - .iter() - .zip(points.iter()) - .map(|(poly, point)| poly.evaluate_jolt(point)) - .collect(); - - // challenge point t - let t = transcript.generate_field_elements::(ell); - - // eq(t, i) for i in [0..k] - let eq_t_i = EqPolynomial::build_eq_x_r(&t); - - // \tilde g_i(b) = eq(t, i) * f_i(b) - let mut tilde_gs = vec![]; - for (index, f_i) in polys.iter().enumerate() { - let mut tilde_g_eval = vec![C::Scalar::zero(); 1 << num_vars]; - for (j, &f_i_eval) in f_i.coeffs.iter().enumerate() { - tilde_g_eval[j] = f_i_eval * eq_t_i[index]; - } - tilde_gs.push(MultiLinearPoly { - coeffs: tilde_g_eval, - }); - } - - // built the virtual polynomial for SumCheck - let tilde_eqs: Vec> = points - .iter() - .map(|point| { - let eq_b_zi = EqPolynomial::build_eq_x_r(point); - MultiLinearPoly { coeffs: eq_b_zi } - }) - .collect(); - - let mut sumcheck_poly = SumOfProductsPoly::new(); - for (tilde_g, tilde_eq) in tilde_gs.iter().zip(tilde_eqs.into_iter()) { - sumcheck_poly.add_pair(tilde_g.clone(), tilde_eq); - } - - let proof = SumCheck::::prove(&sumcheck_poly, transcript); - - let a2 = &proof.point[..num_vars]; - let mut a2_rev = a2.to_vec(); - a2_rev.reverse(); - - // build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the - // sumcheck's point \tilde eq_i(a2) = eq(a2, point_i) - let mut g_prime_evals = vec![C::Scalar::zero(); 1 << num_vars]; - - for (tilde_g, point) in tilde_gs.iter().zip(points.iter()) { - let eq_i_a2 = EqPolynomial::eq_vec(a2_rev.as_ref(), point); - for (j, &tilde_g_eval) in tilde_g.coeffs.iter().enumerate() { - g_prime_evals[j] += tilde_g_eval * eq_i_a2; - } - } - let g_prime = MultiLinearPoly { - coeffs: g_prime_evals, - }; - - let (_g_prime_eval, g_prime_proof) = hyrax_open(proving_key, &g_prime, a2_rev.as_ref()); //a2.to_vec().as_ref()); - ( - evals, - BatchOpening { - sum_check_proof: proof, - - g_prime_proof, - }, - ) + hyrax_multi_points_batch_open_internal(proving_key, polys, points, transcript) } /// Verify the opening of a set of polynomials at a single point. - /// Steps: - /// 1. get challenge point t from transcript - /// 2. build g' commitment - /// 3. ensure \sum_i eq(a2, point_i) * eq(t, ) * f_i_evals matches the sum via SumCheck - /// verification - /// 4. verify commitment fn multiple_points_batch_verify( _params: &Self::Params, verifying_key: &::VKey, commitments: &[Self::Commitment], points: &[Self::EvalPoint], values: &[C::Scalar], - opening: &BatchOpening, + batch_opening: &BatchOpening, transcript: &mut impl Transcript, ) -> bool { - let k = commitments.len(); - let ell = log2(k) as usize; - let num_var = opening.sum_check_proof.point.len(); - - // sum check point (a2) - let a2 = &opening.sum_check_proof.point[..num_var]; - let mut a2_rev = a2.to_vec(); - a2_rev.reverse(); - - // challenge point t - let t = transcript.generate_field_elements::(ell); - - let eq_t_i = EqPolynomial::build_eq_x_r(&t); - - // build g' commitment - - // todo: use MSM - // let mut scalars = vec![]; - // let mut bases = vec![]; - - let mut g_prime_commit_elems = vec![C::Curve::default(); commitments[0].0.len()]; - for (i, point) in points.iter().enumerate() { - let eq_i_a2 = EqPolynomial::eq_vec(a2_rev.as_ref(), point); - let scalar = eq_i_a2 * eq_t_i[i]; - for (j, &base) in commitments[i].0.iter().enumerate() { - g_prime_commit_elems[j] += base * scalar; - } - } - let mut g_prime_commit_affine = vec![C::default(); commitments[0].0.len()]; - C::Curve::batch_normalize(&g_prime_commit_elems, &mut g_prime_commit_affine); - - let g_prime_commit = HyraxCommitment(g_prime_commit_affine); - - // ensure \sum_i eq(t, ) * f_i_evals matches the sum via SumCheck - let mut sum = C::Scalar::zero(); - for (i, &e) in eq_t_i.iter().enumerate().take(k) { - sum += e * values[i]; - } - - let subclaim = - SumCheck::::verify(sum, &opening.sum_check_proof, num_var, transcript); - - let tilde_g_eval = subclaim.expected_evaluation; - - // verify commitment - hyrax_verify( + hyrax_multi_points_batch_verify_internal( verifying_key, - &g_prime_commit, - a2_rev.as_ref(), - tilde_g_eval, - &opening.g_prime_proof, + commitments, + points, + values, + &batch_opening, + transcript, ) } } diff --git a/poly_commit/src/kzg/expander_api.rs b/poly_commit/src/kzg/expander_api.rs index 3189182a..61a8637f 100644 --- a/poly_commit/src/kzg/expander_api.rs +++ b/poly_commit/src/kzg/expander_api.rs @@ -1,3 +1,4 @@ +use crate::traits::BatchOpening; use arith::ExtensionField; use gkr_engine::{ ExpanderPCS, ExpanderSingleVarChallenge, FieldEngine, MPIEngine, PolynomialCommitmentType, @@ -37,6 +38,7 @@ where type Params = usize; type SRS = CoefFormBiKZGLocalSRS; type ScratchPad = (); + type BatchOpening = BatchOpening; fn init_scratch_pad(_params: &Self::Params, _mpi_engine: &impl MPIEngine) -> Self::ScratchPad {} diff --git a/poly_commit/src/kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/pcs_trait_impl.rs index 3c6b24e1..2a1702c4 100644 --- a/poly_commit/src/kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/pcs_trait_impl.rs @@ -1,21 +1,17 @@ use std::marker::PhantomData; use arith::ExtensionField; -use arith::Field; -use ark_std::log2; use gkr_engine::{StructuredReferenceString, Transcript}; -use halo2curves::group::Curve; -use halo2curves::group::Group; use halo2curves::{ ff::PrimeField, pairing::{Engine, MultiMillerLoop}, CurveAffine, }; -use polynomials::{EqPolynomial, MultiLinearPoly, MultilinearExtension}; +use polynomials::MultiLinearPoly; use serdes::ExpSerde; -use sumcheck::SumCheck; -use sumcheck::SumOfProductsPoly; +use crate::batching::prover_merge_points; +use crate::batching::verifier_merge_points; use crate::{ traits::{BatchOpening, BatchOpeningPCS}, *, @@ -161,10 +157,6 @@ where _scratch_pad: &Self::ScratchPad, transcript: &mut impl Transcript, ) -> (Vec, BatchOpening) { - let num_vars = polys[0].num_vars(); - let k = polys.len(); - let ell = log2(k) as usize; - // generate evals for each polynomial at its corresponding point let evals: Vec = polys .iter() @@ -172,60 +164,11 @@ where .map(|(poly, point)| poly.evaluate_jolt(point)) .collect(); - // challenge point t - let t = transcript.generate_field_elements::(ell); - - // eq(t, i) for i in [0..k] - let eq_t_i = EqPolynomial::build_eq_x_r(&t); - - // \tilde g_i(b) = eq(t, i) * f_i(b) - let mut tilde_gs = vec![]; - for (index, f_i) in polys.iter().enumerate() { - let mut tilde_g_eval = vec![E::Fr::zero(); 1 << num_vars]; - for (j, &f_i_eval) in f_i.coeffs.iter().enumerate() { - tilde_g_eval[j] = f_i_eval * eq_t_i[index]; - } - tilde_gs.push(MultiLinearPoly { - coeffs: tilde_g_eval, - }); - } - - // built the virtual polynomial for SumCheck - let tilde_eqs: Vec> = points - .iter() - .map(|point| { - let eq_b_zi = EqPolynomial::build_eq_x_r(point); - MultiLinearPoly { coeffs: eq_b_zi } - }) - .collect(); - - let mut sumcheck_poly = SumOfProductsPoly::new(); - for (tilde_g, tilde_eq) in tilde_gs.iter().zip(tilde_eqs.into_iter()) { - sumcheck_poly.add_pair(tilde_g.clone(), tilde_eq); - } - - let proof = SumCheck::::prove(&sumcheck_poly, transcript); - - let a2 = &proof.point[..num_vars]; - let mut a2_rev = a2.to_vec(); - a2_rev.reverse(); - - // build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the - // sumcheck's point \tilde eq_i(a2) = eq(a2, point_i) - let mut g_prime_evals = vec![E::Fr::zero(); 1 << num_vars]; - - for (tilde_g, point) in tilde_gs.iter().zip(points.iter()) { - let eq_i_a2 = EqPolynomial::eq_vec(a2_rev.as_ref(), point); - for (j, &tilde_g_eval) in tilde_g.coeffs.iter().enumerate() { - g_prime_evals[j] += tilde_g_eval * eq_i_a2; - } - } - let g_prime = MultiLinearPoly { - coeffs: g_prime_evals, - }; + let (new_point, g_prime, proof) = + prover_merge_points::(polys, points, transcript); let (_g_prime_eval, g_prime_proof) = - coeff_form_uni_hyperkzg_open(proving_key, &g_prime.coeffs, a2_rev.as_ref(), transcript); + coeff_form_uni_hyperkzg_open(proving_key, &g_prime.coeffs, &new_point, transcript); ( evals, BatchOpening { @@ -248,65 +191,33 @@ where commitments: &[Self::Commitment], points: &[Self::EvalPoint], values: &[E::Fr], - opening: &BatchOpening, + batch_opening: &BatchOpening, transcript: &mut impl Transcript, ) -> bool { - let k = commitments.len(); - let ell = log2(k) as usize; - let num_var = opening.sum_check_proof.point.len(); - // sum check point (a2) - let a2 = &opening.sum_check_proof.point[..num_var]; - let mut a2_rev = a2.to_vec(); - a2_rev.reverse(); + let a2 = batch_opening.sum_check_proof.export_point_to_expander(); - // challenge point t - let t = transcript.generate_field_elements::(ell); - - let eq_t_i = EqPolynomial::build_eq_x_r(&t); - - // build g' commitment - - // todo: use MSM - // let mut scalars = vec![]; - // let mut bases = vec![]; - - let mut g_prime_commit_elems = E::G1::identity(); - for (i, point) in points.iter().enumerate() { - let eq_i_a2 = EqPolynomial::eq_vec(a2_rev.as_ref(), point); - let scalar = eq_i_a2 * eq_t_i[i]; - - g_prime_commit_elems += commitments[i].0 * scalar; - } - - let g_prime_commit = g_prime_commit_elems.to_affine(); - - // ensure \sum_i eq(t, ) * f_i_evals matches the sum via SumCheck - let mut sum = E::Fr::zero(); - for (i, &e) in eq_t_i.iter().enumerate().take(k) { - sum += e * values[i]; - } - - let subclaim = - SumCheck::::verify(sum, &opening.sum_check_proof, num_var, transcript); - - let tilde_g_eval = subclaim.expected_evaluation; + let commitments = commitments + .iter() + .map(|c| vec![c.0.clone()]) + .collect::>(); + + let (tilde_g_eval, g_prime_commit) = verifier_merge_points::( + &commitments, + points, + values, + &batch_opening.sum_check_proof, + transcript, + ); // verify commitment coeff_form_uni_hyperkzg_verify( verifying_key, - g_prime_commit, - a2_rev.as_ref(), + g_prime_commit[0], + a2.as_ref(), tilde_g_eval, - &opening.g_prime_proof, + &batch_opening.g_prime_proof, transcript, ) - // hyrax_verify( - // verifying_key, - // &g_prime_commit, - // a2_rev.as_ref(), - // tilde_g_eval, - // &opening.g_prime_proof, - // ) } } diff --git a/poly_commit/src/lib.rs b/poly_commit/src/lib.rs index 2d131d8f..b0bc946d 100644 --- a/poly_commit/src/lib.rs +++ b/poly_commit/src/lib.rs @@ -19,3 +19,5 @@ pub use hyrax::*; pub mod kzg; pub use kzg::*; + +pub mod batching; diff --git a/poly_commit/src/orion/expander_api.rs b/poly_commit/src/orion/expander_api.rs index 28c7ece8..1f30aa6b 100644 --- a/poly_commit/src/orion/expander_api.rs +++ b/poly_commit/src/orion/expander_api.rs @@ -36,6 +36,7 @@ where type Commitment = OrionCommitment; type Opening = OrionProof; + type BatchOpening = (); type SRS = OrionSRS; /// NOTE(HS): this is the number of variables for local polynomial w.r.t. SIMD field elements. diff --git a/poly_commit/src/raw.rs b/poly_commit/src/raw.rs index 2d2e99cf..d0750d0b 100644 --- a/poly_commit/src/raw.rs +++ b/poly_commit/src/raw.rs @@ -136,6 +136,8 @@ impl ExpanderPCS for RawExpanderGKR { type Opening = (); + type BatchOpening = (); + fn gen_srs_for_testing( _params: &Self::Params, _mpi_engine: &impl MPIEngine, diff --git a/poly_commit/src/traits.rs b/poly_commit/src/traits.rs index 58a94434..dc068458 100644 --- a/poly_commit/src/traits.rs +++ b/poly_commit/src/traits.rs @@ -59,7 +59,7 @@ pub trait PolynomialCommitmentScheme { ) -> bool; } -#[derive(Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Default, ExpSerde)] pub struct BatchOpening where F: ExtensionField, diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index 32895459..acae655f 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -238,33 +238,35 @@ where .collect::>(); // open all polys at a single point - let challenge_point = ExpanderSingleVarChallenge:: { - r_mpi: Vec::new(), - r_simd: Vec::new(), - rz: (0..num_vars) - .map(|_| C::ChallengeField::random_unsafe(&mut rng)) - .collect(), - }; + let challenge_points = (0..num_poly) + .map(|_| ExpanderSingleVarChallenge:: { + r_mpi: Vec::new(), + r_simd: Vec::new(), + rz: (0..num_vars) + .map(|_| C::ChallengeField::random_unsafe(&mut rng)) + .collect(), + }) + .collect::>(); let mut transcript = T::new(); - let (eval_list, opening) = P::batch_open( + let (eval_list, opening) = P::multi_points_batch_open( &num_vars, &mpi_config, &proving_key, &polys, - &challenge_point, + &challenge_points, &mut scratch_pad, &mut transcript, ); let mut transcript = T::new(); - assert!(P::batch_verify( + assert!(P::multi_points_batch_verify( &num_vars, &verification_key, &commitments, - &challenge_point, + &challenge_points, &eval_list, &opening, &mut transcript, diff --git a/poly_commit/tests/test_hyrax.rs b/poly_commit/tests/test_hyrax.rs index 63b5f22c..13d81f44 100644 --- a/poly_commit/tests/test_hyrax.rs +++ b/poly_commit/tests/test_hyrax.rs @@ -85,9 +85,9 @@ fn test_hyrax_for_expander_gkr() { #[test] fn test_hyrax_batch_open() { common::test_batching::, HyraxPCS>(); - common::test_batching_for_expander_gkr::< - BN254Config, - BytesHashTranscript, - HyraxPCS, - >(); + // common::test_batching_for_expander_gkr::< + // BN254Config, + // BytesHashTranscript, + // HyraxPCS, + // >(); } From c38d5b31f6c8e7962d6d6cf92d574870501b23c6 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Thu, 29 May 2025 18:41:50 -0400 Subject: [PATCH 38/57] fix --- gkr_engine/src/poly_commit/definition.rs | 21 +++++++++++---------- sumcheck/src/sumcheck_generic.rs | 11 ++++++++++- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/gkr_engine/src/poly_commit/definition.rs b/gkr_engine/src/poly_commit/definition.rs index 53296dad..dafd586f 100644 --- a/gkr_engine/src/poly_commit/definition.rs +++ b/gkr_engine/src/poly_commit/definition.rs @@ -1,5 +1,5 @@ use arith::Field; -use polynomials::MultilinearExtension; +use polynomials::{MultiLinearPoly, MultilinearExtension}; use rand::RngCore; use serdes::ExpSerde; use std::{fmt::Debug, str::FromStr}; @@ -37,6 +37,7 @@ pub trait ExpanderPCS { type SRS: Clone + Debug + Default + ExpSerde + StructuredReferenceString + Send + Sync; type Commitment: Clone + Debug + Default + ExpSerde + Send + Sync; type Opening: Clone + Debug + Default + ExpSerde + Send + Sync; + type BatchOpening: ExpSerde + Send + Sync; /// Generate a random structured reference string (SRS) for testing purposes. /// Each process should return the SRS share used for its committing and opening. @@ -117,27 +118,27 @@ pub trait ExpanderPCS { opening: &Self::Opening, ) -> bool; - /// Open a set of polynomials at a point. - fn batch_open( + /// Open a set of polynomials at a set of points. + fn multi_points_batch_open( _params: &Self::Params, _mpi_engine: &impl MPIEngine, _proving_key: &::PKey, - _polys: &[impl MultilinearExtension], - _x: &ExpanderSingleVarChallenge, + _polys: &[MultiLinearPoly], + _x: &[ExpanderSingleVarChallenge], _scratch_pad: &Self::ScratchPad, _transcript: &mut impl Transcript, - ) -> (Vec, Self::Opening) { + ) -> (Vec, Self::BatchOpening) { unimplemented!("Batch opening is not implemented for this PCS type") } - /// Verify the opening of a set of polynomials at a point. - fn batch_verify( + /// Verify the opening of a set of polynomials at a set of points. + fn multi_points_batch_verify( _params: &Self::Params, _verifying_key: &::VKey, _commitments: &[Self::Commitment], - _x: &ExpanderSingleVarChallenge, + _x: &[ExpanderSingleVarChallenge], _evals: &[F::ChallengeField], - _opening: &Self::Opening, + _opening: &Self::BatchOpening, _transcript: &mut impl Transcript, ) -> bool { unimplemented!("Batch verify is not implemented for this PCS type") diff --git a/sumcheck/src/sumcheck_generic.rs b/sumcheck/src/sumcheck_generic.rs index 71d9942e..f42c6c00 100644 --- a/sumcheck/src/sumcheck_generic.rs +++ b/sumcheck/src/sumcheck_generic.rs @@ -56,12 +56,21 @@ impl SumOfProductsPoly { /// An IOP proof is a collections of /// - messages from prover to verifier at each round through the interactive protocol. /// - a point that is generated by the transcript for evaluation -#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Debug, Default, PartialEq, Eq, ExpSerde)] pub struct IOPProof { pub proofs: Vec>, pub point: Vec, } +impl IOPProof { + /// The endianness of SumCheck is reversed c.f. the rest of expander. + pub fn export_point_to_expander(&self) -> Vec { + let mut point = self.point.clone(); + point.reverse(); + point + } +} + /// A message from the prover to the verifier at a given round /// is a list of evaluations. #[derive(Clone, Debug, Default, PartialEq, Eq, ExpSerde)] From 9c44e62bcfe38059bfe63929dc09a223ac5398a2 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Thu, 29 May 2025 19:00:31 -0400 Subject: [PATCH 39/57] fix clippy --- poly_commit/src/batching.rs | 3 ++- poly_commit/src/hyrax/expander_api.rs | 7 +------ poly_commit/src/hyrax/hyrax_impl.rs | 1 + poly_commit/src/hyrax/pcs_trait_impl.rs | 2 +- poly_commit/src/kzg/pcs_trait_impl.rs | 5 +---- 5 files changed, 6 insertions(+), 12 deletions(-) diff --git a/poly_commit/src/batching.rs b/poly_commit/src/batching.rs index 63b6f796..f7dc09af 100644 --- a/poly_commit/src/batching.rs +++ b/poly_commit/src/batching.rs @@ -14,6 +14,7 @@ use sumcheck::{IOPProof, SumCheck, SumOfProductsPoly}; /// - the new point for evaluation /// - the new polynomial that is merged via sumcheck /// - the proof of the sumcheck +#[allow(clippy::type_complexity)] pub fn prover_merge_points( polys: &[MultiLinearPoly], points: &[Vec], @@ -132,7 +133,7 @@ where sum += e * values[i]; } - let subclaim = SumCheck::::verify(sum, &sumcheck_proof, num_var, transcript); + let subclaim = SumCheck::::verify(sum, sumcheck_proof, num_var, transcript); let tilde_g_eval = subclaim.expected_evaluation; diff --git a/poly_commit/src/hyrax/expander_api.rs b/poly_commit/src/hyrax/expander_api.rs index 0383180a..528f9498 100644 --- a/poly_commit/src/hyrax/expander_api.rs +++ b/poly_commit/src/hyrax/expander_api.rs @@ -164,12 +164,7 @@ where if mpi_engine.is_single_process() || mpi_engine.is_root() { let points = eval_points.iter().map(|x| x.local_xs()).collect::>(); - return hyrax_multi_points_batch_open_internal( - proving_key, - mle_poly_list, - &points, - transcript, - ); + hyrax_multi_points_batch_open_internal(proving_key, mle_poly_list, &points, transcript) } else { // todo: handle this case? panic!("Hyrax PCS does not support multi-points batch opening in non-root processes"); diff --git a/poly_commit/src/hyrax/hyrax_impl.rs b/poly_commit/src/hyrax/hyrax_impl.rs index 7ccdb56a..b36192e2 100644 --- a/poly_commit/src/hyrax/hyrax_impl.rs +++ b/poly_commit/src/hyrax/hyrax_impl.rs @@ -265,6 +265,7 @@ fn scale(base: &[F], scalar: &F) -> Vec { /// Returns: /// - the evaluations of the polynomials at their corresponding points /// - the batch opening proof containing the sumcheck proof and the opening of g'(X) +#[allow(clippy::type_complexity)] pub(crate) fn hyrax_multi_points_batch_open_internal( proving_key: &PedersenParams, polys: &[MultiLinearPoly], diff --git a/poly_commit/src/hyrax/pcs_trait_impl.rs b/poly_commit/src/hyrax/pcs_trait_impl.rs index 498ef0ae..0b98bd6c 100644 --- a/poly_commit/src/hyrax/pcs_trait_impl.rs +++ b/poly_commit/src/hyrax/pcs_trait_impl.rs @@ -150,7 +150,7 @@ where commitments, points, values, - &batch_opening, + batch_opening, transcript, ) } diff --git a/poly_commit/src/kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/pcs_trait_impl.rs index 2a1702c4..81b90c8a 100644 --- a/poly_commit/src/kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/pcs_trait_impl.rs @@ -197,10 +197,7 @@ where // sum check point (a2) let a2 = batch_opening.sum_check_proof.export_point_to_expander(); - let commitments = commitments - .iter() - .map(|c| vec![c.0.clone()]) - .collect::>(); + let commitments = commitments.iter().map(|c| vec![c.0]).collect::>(); let (tilde_g_eval, g_prime_commit) = verifier_merge_points::( &commitments, From 428567be8156d83704b53ac4f4133bfb4c18d699 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Fri, 30 May 2025 15:14:23 -0400 Subject: [PATCH 40/57] refactoring kzg --- config_macros/src/lib.rs | 2 +- config_macros/tests/macro_expansion.rs | 2 +- gkr/src/gkr_configs.rs | 2 +- gkr/src/tests/gkr_correctness.rs | 2 +- poly_commit/benches/kzg.rs | 12 +++---- poly_commit/benches/pcs_all.rs | 10 +++--- poly_commit/src/bi_kzg.rs | 33 +++++++++++++++++++ poly_commit/src/{kzg => bi_kzg}/batch.rs | 0 poly_commit/src/{kzg => bi_kzg}/bivariate.rs | 0 .../src/{kzg => bi_kzg}/expander_api.rs | 4 +-- .../src/{kzg => bi_kzg}/hyper_bikzg.rs | 0 .../src/{kzg => bi_kzg}/hyper_bikzg_tests.rs | 0 poly_commit/src/{kzg => bi_kzg}/hyper_kzg.rs | 0 .../src/{kzg => bi_kzg}/hyper_kzg_structs.rs | 0 .../src/{kzg => bi_kzg}/kzg_structs.rs | 0 .../src/{kzg => bi_kzg}/pcs_trait_impl.rs | 12 +++---- poly_commit/src/{kzg => bi_kzg}/serde.rs | 0 poly_commit/src/{kzg => bi_kzg}/univariate.rs | 0 poly_commit/src/{kzg => bi_kzg}/utils.rs | 0 poly_commit/src/kzg.rs | 2 +- poly_commit/src/lib.rs | 4 +-- poly_commit/tests/test_kzg.rs | 10 +++--- 22 files changed, 64 insertions(+), 31 deletions(-) create mode 100644 poly_commit/src/bi_kzg.rs rename poly_commit/src/{kzg => bi_kzg}/batch.rs (100%) rename poly_commit/src/{kzg => bi_kzg}/bivariate.rs (100%) rename poly_commit/src/{kzg => bi_kzg}/expander_api.rs (98%) rename poly_commit/src/{kzg => bi_kzg}/hyper_bikzg.rs (100%) rename poly_commit/src/{kzg => bi_kzg}/hyper_bikzg_tests.rs (100%) rename poly_commit/src/{kzg => bi_kzg}/hyper_kzg.rs (100%) rename poly_commit/src/{kzg => bi_kzg}/hyper_kzg_structs.rs (100%) rename poly_commit/src/{kzg => bi_kzg}/kzg_structs.rs (100%) rename poly_commit/src/{kzg => bi_kzg}/pcs_trait_impl.rs (96%) rename poly_commit/src/{kzg => bi_kzg}/serde.rs (100%) rename poly_commit/src/{kzg => bi_kzg}/univariate.rs (100%) rename poly_commit/src/{kzg => bi_kzg}/utils.rs (100%) diff --git a/config_macros/src/lib.rs b/config_macros/src/lib.rs index ca48ac6e..2fbda4b2 100644 --- a/config_macros/src/lib.rs +++ b/config_macros/src/lib.rs @@ -111,7 +111,7 @@ fn parse_polynomial_commitment_type( format!("RawExpanderGKR::<{field_config}>").to_owned(), ), ("Hyrax", "BN254") => ("Hyrax".to_string(), "HyraxPCS::".to_string()), - ("KZG", "BN254") => ("KZG".to_owned(), "HyperKZGPCS::".to_string()), + ("KZG", "BN254") => ("KZG".to_owned(), "HyperBiKZGPCS::".to_string()), ("Orion", "GF2Ext128") => ( "Orion".to_owned(), format!("OrionPCSForGKR::<{field_config}, GF2x128>").to_owned(), diff --git a/config_macros/tests/macro_expansion.rs b/config_macros/tests/macro_expansion.rs index d5e50467..26714091 100644 --- a/config_macros/tests/macro_expansion.rs +++ b/config_macros/tests/macro_expansion.rs @@ -9,7 +9,7 @@ use gkr_engine::{ use gkr_hashers::{Keccak256hasher, MiMC5FiatShamirHasher, PoseidonFiatShamirHasher, SHA256hasher}; use halo2curves::bn256::Bn256; use mersenne31::M31x16; -use poly_commit::{HyperKZGPCS, OrionPCSForGKR, RawExpanderGKR}; +use poly_commit::{HyperBiKZGPCS, OrionPCSForGKR, RawExpanderGKR}; use transcript::BytesHashTranscript; fn print_type_name() { diff --git a/gkr/src/gkr_configs.rs b/gkr/src/gkr_configs.rs index aded11c5..76111887 100644 --- a/gkr/src/gkr_configs.rs +++ b/gkr/src/gkr_configs.rs @@ -8,7 +8,7 @@ use gkr_hashers::{MiMC5FiatShamirHasher, PoseidonFiatShamirHasher, SHA256hasher} use goldilocks::Goldilocksx8; use halo2curves::bn256::{Bn256, G1Affine}; use mersenne31::M31x16; -use poly_commit::{raw::RawExpanderGKR, HyperKZGPCS, HyraxPCS, OrionPCSForGKR}; +use poly_commit::{raw::RawExpanderGKR, HyperBiKZGPCS, HyraxPCS, OrionPCSForGKR}; use transcript::BytesHashTranscript; // ============== M31 ============== diff --git a/gkr/src/tests/gkr_correctness.rs b/gkr/src/tests/gkr_correctness.rs index 32a19920..1a5bae52 100644 --- a/gkr/src/tests/gkr_correctness.rs +++ b/gkr/src/tests/gkr_correctness.rs @@ -16,7 +16,7 @@ use gkr_hashers::{Keccak256hasher, MiMC5FiatShamirHasher, PoseidonFiatShamirHash use halo2curves::bn256::{Bn256, G1Affine}; use mersenne31::M31x16; use poly_commit::{ - expander_pcs_init_testing_only, HyperKZGPCS, HyraxPCS, OrionPCSForGKR, RawExpanderGKR, + expander_pcs_init_testing_only, HyperBiKZGPCS, HyraxPCS, OrionPCSForGKR, RawExpanderGKR, }; use rand::Rng; use serdes::ExpSerde; diff --git a/poly_commit/benches/kzg.rs b/poly_commit/benches/kzg.rs index 78013134..7483df1e 100644 --- a/poly_commit/benches/kzg.rs +++ b/poly_commit/benches/kzg.rs @@ -6,7 +6,7 @@ use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; use gkr_engine::Transcript; use gkr_hashers::Keccak256hasher; use halo2curves::bn256::Bn256; -use poly_commit::{HyperKZGPCS, PolynomialCommitmentScheme}; +use poly_commit::{HyperBiKZGPCS, PolynomialCommitmentScheme}; use polynomials::MultiLinearPoly; use transcript::BytesHashTranscript; @@ -23,14 +23,14 @@ fn hyperkzg_committing_benchmark_helper( for num_vars in lowest_num_vars..=highest_num_vars { let poly = MultiLinearPoly::::random(num_vars, &mut rng); - let (srs, _) = HyperKZGPCS::::gen_srs_for_testing(&num_vars, &mut rng); + let (srs, _) = HyperBiKZGPCS::::gen_srs_for_testing(&num_vars, &mut rng); group .bench_function( BenchmarkId::new(format!("{num_vars} variables"), num_vars), |b| { b.iter(|| { - _ = black_box(HyperKZGPCS::::commit( + _ = black_box(HyperBiKZGPCS::::commit( &num_vars, &srs, &poly, @@ -61,17 +61,17 @@ fn hyperkzg_opening_benchmark_helper( for num_vars in lowest_num_vars..=highest_num_vars { let poly = MultiLinearPoly::::random(num_vars, &mut rng); - let (srs, _) = HyperKZGPCS::::gen_srs_for_testing(&num_vars, &mut rng); + let (srs, _) = HyperBiKZGPCS::::gen_srs_for_testing(&num_vars, &mut rng); let eval_point: Vec<_> = (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(); - let _ = HyperKZGPCS::::commit(&num_vars, &srs, &poly, &mut scratch_pad); + let _ = HyperBiKZGPCS::::commit(&num_vars, &srs, &poly, &mut scratch_pad); group .bench_function( BenchmarkId::new(format!("{num_vars} variables"), num_vars), |b| { b.iter(|| { - _ = black_box(HyperKZGPCS::::open( + _ = black_box(HyperBiKZGPCS::::open( &num_vars, &srs, &poly, diff --git a/poly_commit/benches/pcs_all.rs b/poly_commit/benches/pcs_all.rs index bb708639..d6698fad 100644 --- a/poly_commit/benches/pcs_all.rs +++ b/poly_commit/benches/pcs_all.rs @@ -6,7 +6,7 @@ use gkr_engine::{root_println, MPIConfig, MPIEngine, Transcript}; use gkr_hashers::{Keccak256hasher, SHA256hasher}; use halo2curves::bn256::{Bn256, G1Affine}; use poly_commit::{ - BatchOpeningPCS, HyperKZGPCS, HyraxPCS, OrionBaseFieldPCS, PolynomialCommitmentScheme, + BatchOpeningPCS, HyperBiKZGPCS, HyraxPCS, OrionBaseFieldPCS, PolynomialCommitmentScheme, }; use polynomials::MultiLinearPoly; use rand::RngCore; @@ -97,12 +97,12 @@ fn bench_hyrax(mpi_config: &MPIConfig, num_vars: usize) { fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { // full scalar let mut rng = test_rng(); - let (srs, _) = HyperKZGPCS::::gen_srs_for_testing(&num_vars, &mut rng); + let (srs, _) = HyperBiKZGPCS::::gen_srs_for_testing(&num_vars, &mut rng); let poly = MultiLinearPoly::::random(num_vars, &mut rng); let eval_point: Vec<_> = (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(); - pcs_bench::>( + pcs_bench::>( mpi_config, &num_vars, &srs, @@ -116,7 +116,7 @@ fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { .map(|_| Fr::from(rng.next_u32())) .collect::>(); let poly = MultiLinearPoly::::new(input); - pcs_bench::>( + pcs_bench::>( mpi_config, &num_vars, &srs, @@ -126,7 +126,7 @@ fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { ); // batch open - bench_batch_open::>(mpi_config, num_vars, NUM_POLY_BATCH_OPEN); + bench_batch_open::>(mpi_config, num_vars, NUM_POLY_BATCH_OPEN); } fn pcs_bench>( diff --git a/poly_commit/src/bi_kzg.rs b/poly_commit/src/bi_kzg.rs new file mode 100644 index 00000000..722c904f --- /dev/null +++ b/poly_commit/src/bi_kzg.rs @@ -0,0 +1,33 @@ +mod utils; +pub(crate) use utils::*; + +mod serde; + +mod kzg_structs; +pub use kzg_structs::*; + +mod univariate; +pub use univariate::*; + +mod bivariate; +pub use bivariate::*; + +mod hyper_kzg_structs; +pub use hyper_kzg_structs::*; + +mod hyper_kzg; +pub use hyper_kzg::*; + +mod hyper_bikzg; +pub use hyper_bikzg::*; + +#[cfg(test)] +mod hyper_bikzg_tests; + +mod pcs_trait_impl; +pub use pcs_trait_impl::HyperBiKZGPCS; + +mod expander_api; + +mod batch; +pub use batch::{kzg_batch_open, kzg_batch_verify}; diff --git a/poly_commit/src/kzg/batch.rs b/poly_commit/src/bi_kzg/batch.rs similarity index 100% rename from poly_commit/src/kzg/batch.rs rename to poly_commit/src/bi_kzg/batch.rs diff --git a/poly_commit/src/kzg/bivariate.rs b/poly_commit/src/bi_kzg/bivariate.rs similarity index 100% rename from poly_commit/src/kzg/bivariate.rs rename to poly_commit/src/bi_kzg/bivariate.rs diff --git a/poly_commit/src/kzg/expander_api.rs b/poly_commit/src/bi_kzg/expander_api.rs similarity index 98% rename from poly_commit/src/kzg/expander_api.rs rename to poly_commit/src/bi_kzg/expander_api.rs index 61a8637f..38730b26 100644 --- a/poly_commit/src/kzg/expander_api.rs +++ b/poly_commit/src/bi_kzg/expander_api.rs @@ -21,7 +21,7 @@ use crate::{ *, }; -impl ExpanderPCS for HyperKZGPCS +impl ExpanderPCS for HyperBiKZGPCS where G: FieldEngine, E: Engine + MultiMillerLoop, @@ -29,7 +29,7 @@ where E::G1Affine: ExpSerde + Default + CurveAffine, E::G2Affine: ExpSerde + Default + CurveAffine, { - const NAME: &'static str = "HyperKZGPCSForExpander"; + const NAME: &'static str = "HyperBiKZGPCSForExpander"; const PCS_TYPE: PolynomialCommitmentType = PolynomialCommitmentType::KZG; diff --git a/poly_commit/src/kzg/hyper_bikzg.rs b/poly_commit/src/bi_kzg/hyper_bikzg.rs similarity index 100% rename from poly_commit/src/kzg/hyper_bikzg.rs rename to poly_commit/src/bi_kzg/hyper_bikzg.rs diff --git a/poly_commit/src/kzg/hyper_bikzg_tests.rs b/poly_commit/src/bi_kzg/hyper_bikzg_tests.rs similarity index 100% rename from poly_commit/src/kzg/hyper_bikzg_tests.rs rename to poly_commit/src/bi_kzg/hyper_bikzg_tests.rs diff --git a/poly_commit/src/kzg/hyper_kzg.rs b/poly_commit/src/bi_kzg/hyper_kzg.rs similarity index 100% rename from poly_commit/src/kzg/hyper_kzg.rs rename to poly_commit/src/bi_kzg/hyper_kzg.rs diff --git a/poly_commit/src/kzg/hyper_kzg_structs.rs b/poly_commit/src/bi_kzg/hyper_kzg_structs.rs similarity index 100% rename from poly_commit/src/kzg/hyper_kzg_structs.rs rename to poly_commit/src/bi_kzg/hyper_kzg_structs.rs diff --git a/poly_commit/src/kzg/kzg_structs.rs b/poly_commit/src/bi_kzg/kzg_structs.rs similarity index 100% rename from poly_commit/src/kzg/kzg_structs.rs rename to poly_commit/src/bi_kzg/kzg_structs.rs diff --git a/poly_commit/src/kzg/pcs_trait_impl.rs b/poly_commit/src/bi_kzg/pcs_trait_impl.rs similarity index 96% rename from poly_commit/src/kzg/pcs_trait_impl.rs rename to poly_commit/src/bi_kzg/pcs_trait_impl.rs index 81b90c8a..da9b7522 100644 --- a/poly_commit/src/kzg/pcs_trait_impl.rs +++ b/poly_commit/src/bi_kzg/pcs_trait_impl.rs @@ -16,9 +16,9 @@ use crate::{ traits::{BatchOpening, BatchOpeningPCS}, *, }; -use kzg::hyper_kzg::*; +use bi_kzg::hyper_kzg::*; -pub struct HyperKZGPCS +pub struct HyperBiKZGPCS where E: Engine, E::Fr: ExtensionField, @@ -26,7 +26,7 @@ where _marker_e: PhantomData, } -impl HyperKZGPCS +impl HyperBiKZGPCS where E: Engine, E::Fr: ExtensionField, @@ -34,14 +34,14 @@ where pub const MINIMUM_SUPPORTED_NUM_VARS: usize = 2; } -impl PolynomialCommitmentScheme for HyperKZGPCS +impl PolynomialCommitmentScheme for HyperBiKZGPCS where E: Engine + MultiMillerLoop, E::Fr: ExtensionField + PrimeField, E::G1Affine: ExpSerde + Default + CurveAffine, E::G2Affine: ExpSerde + Default + CurveAffine, { - const NAME: &'static str = "HyperKZGPCS"; + const NAME: &'static str = "HyperBiKZGPCS"; type Params = usize; type Poly = MultiLinearPoly; @@ -95,7 +95,7 @@ where } } -impl BatchOpeningPCS for HyperKZGPCS +impl BatchOpeningPCS for HyperBiKZGPCS where E: Engine + MultiMillerLoop, E::Fr: ExtensionField + PrimeField, diff --git a/poly_commit/src/kzg/serde.rs b/poly_commit/src/bi_kzg/serde.rs similarity index 100% rename from poly_commit/src/kzg/serde.rs rename to poly_commit/src/bi_kzg/serde.rs diff --git a/poly_commit/src/kzg/univariate.rs b/poly_commit/src/bi_kzg/univariate.rs similarity index 100% rename from poly_commit/src/kzg/univariate.rs rename to poly_commit/src/bi_kzg/univariate.rs diff --git a/poly_commit/src/kzg/utils.rs b/poly_commit/src/bi_kzg/utils.rs similarity index 100% rename from poly_commit/src/kzg/utils.rs rename to poly_commit/src/bi_kzg/utils.rs diff --git a/poly_commit/src/kzg.rs b/poly_commit/src/kzg.rs index fdb9f959..722c904f 100644 --- a/poly_commit/src/kzg.rs +++ b/poly_commit/src/kzg.rs @@ -25,7 +25,7 @@ pub use hyper_bikzg::*; mod hyper_bikzg_tests; mod pcs_trait_impl; -pub use pcs_trait_impl::HyperKZGPCS; +pub use pcs_trait_impl::HyperBiKZGPCS; mod expander_api; diff --git a/poly_commit/src/lib.rs b/poly_commit/src/lib.rs index b0bc946d..3adf2d08 100644 --- a/poly_commit/src/lib.rs +++ b/poly_commit/src/lib.rs @@ -17,7 +17,7 @@ pub use orion::*; pub mod hyrax; pub use hyrax::*; -pub mod kzg; -pub use kzg::*; +pub mod bi_kzg; +pub use bi_kzg::*; pub mod batching; diff --git a/poly_commit/tests/test_kzg.rs b/poly_commit/tests/test_kzg.rs index 326355d0..92b36df5 100644 --- a/poly_commit/tests/test_kzg.rs +++ b/poly_commit/tests/test_kzg.rs @@ -6,7 +6,7 @@ use gkr_engine::ExpanderPCS; use gkr_engine::{BN254Config, ExpanderSingleVarChallenge, MPIConfig, MPIEngine, Transcript}; use gkr_hashers::Keccak256hasher; use halo2curves::bn256::Bn256; -use poly_commit::HyperKZGPCS; +use poly_commit::HyperBiKZGPCS; use polynomials::MultiLinearPoly; use transcript::BytesHashTranscript; @@ -21,7 +21,7 @@ fn test_hyperkzg_pcs_generics(num_vars_start: usize, num_vars_end: usize) { .collect(); let poly = MultiLinearPoly::::random(num_vars, &mut rng); - common::test_pcs::, HyperKZGPCS>( + common::test_pcs::, HyperBiKZGPCS>( &num_vars, &poly, &xs, ); }) @@ -61,14 +61,14 @@ fn test_hyper_bikzg_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_ dbg!(local_poly.get_num_vars(), local_poly.coeffs[0]); - let params = as ExpanderPCS>::gen_params( + let params = as ExpanderPCS>::gen_params( num_vars_in_each_poly, mpi_config_ref.world_size(), ); common::test_pcs_for_expander_gkr::< BN254Config, BytesHashTranscript, - HyperKZGPCS, + HyperBiKZGPCS, >( ¶ms, mpi_config_ref, @@ -90,7 +90,7 @@ fn test_hyper_bikzg_for_expander_gkr() { #[test] fn test_kzg_batch_open() { - common::test_batching::, HyperKZGPCS>(); + common::test_batching::, HyperBiKZGPCS>(); // common::test_batching_for_expander_gkr::< // BN254Config, // BytesHashTranscript, From c9faa9d77bbfe3d55307fee6e3f30259816de13d Mon Sep 17 00:00:00 2001 From: zhenfei Date: Fri, 30 May 2025 15:26:01 -0400 Subject: [PATCH 41/57] wip --- poly_commit/src/kzg.rs | 37 ++--------- poly_commit/src/{ => kzg}/bi_kzg.rs | 4 +- poly_commit/src/{ => kzg}/bi_kzg/batch.rs | 5 +- poly_commit/src/{ => kzg}/bi_kzg/bivariate.rs | 0 .../src/{ => kzg}/bi_kzg/expander_api.rs | 0 .../src/{ => kzg}/bi_kzg/hyper_bikzg.rs | 0 .../src/{ => kzg}/bi_kzg/hyper_bikzg_tests.rs | 0 poly_commit/src/{ => kzg}/bi_kzg/hyper_kzg.rs | 0 .../src/{ => kzg}/bi_kzg/hyper_kzg_structs.rs | 0 .../src/{ => kzg}/bi_kzg/pcs_trait_impl.rs | 1 - poly_commit/src/{ => kzg}/bi_kzg/serde.rs | 0 .../kzg_structs.rs => kzg/bi_kzg/structs.rs} | 56 +---------------- .../src/{ => kzg}/bi_kzg/univariate.rs | 0 poly_commit/src/{ => kzg}/bi_kzg/utils.rs | 0 poly_commit/src/kzg/structs.rs | 1 + poly_commit/src/kzg/uni_kzg.rs | 2 + poly_commit/src/kzg/uni_kzg/structs.rs | 62 +++++++++++++++++++ poly_commit/src/lib.rs | 4 +- 18 files changed, 81 insertions(+), 91 deletions(-) rename poly_commit/src/{ => kzg}/bi_kzg.rs (91%) rename poly_commit/src/{ => kzg}/bi_kzg/batch.rs (96%) rename poly_commit/src/{ => kzg}/bi_kzg/bivariate.rs (100%) rename poly_commit/src/{ => kzg}/bi_kzg/expander_api.rs (100%) rename poly_commit/src/{ => kzg}/bi_kzg/hyper_bikzg.rs (100%) rename poly_commit/src/{ => kzg}/bi_kzg/hyper_bikzg_tests.rs (100%) rename poly_commit/src/{ => kzg}/bi_kzg/hyper_kzg.rs (100%) rename poly_commit/src/{ => kzg}/bi_kzg/hyper_kzg_structs.rs (100%) rename poly_commit/src/{ => kzg}/bi_kzg/pcs_trait_impl.rs (99%) rename poly_commit/src/{ => kzg}/bi_kzg/serde.rs (100%) rename poly_commit/src/{bi_kzg/kzg_structs.rs => kzg/bi_kzg/structs.rs} (58%) rename poly_commit/src/{ => kzg}/bi_kzg/univariate.rs (100%) rename poly_commit/src/{ => kzg}/bi_kzg/utils.rs (100%) create mode 100644 poly_commit/src/kzg/structs.rs create mode 100644 poly_commit/src/kzg/uni_kzg.rs create mode 100644 poly_commit/src/kzg/uni_kzg/structs.rs diff --git a/poly_commit/src/kzg.rs b/poly_commit/src/kzg.rs index 722c904f..f29cf309 100644 --- a/poly_commit/src/kzg.rs +++ b/poly_commit/src/kzg.rs @@ -1,33 +1,8 @@ -mod utils; -pub(crate) use utils::*; +mod uni_kzg; +pub use uni_kzg::*; -mod serde; +mod bi_kzg; +pub use bi_kzg::*; -mod kzg_structs; -pub use kzg_structs::*; - -mod univariate; -pub use univariate::*; - -mod bivariate; -pub use bivariate::*; - -mod hyper_kzg_structs; -pub use hyper_kzg_structs::*; - -mod hyper_kzg; -pub use hyper_kzg::*; - -mod hyper_bikzg; -pub use hyper_bikzg::*; - -#[cfg(test)] -mod hyper_bikzg_tests; - -mod pcs_trait_impl; -pub use pcs_trait_impl::HyperBiKZGPCS; - -mod expander_api; - -mod batch; -pub use batch::{kzg_batch_open, kzg_batch_verify}; +mod structs; +pub use structs::*; diff --git a/poly_commit/src/bi_kzg.rs b/poly_commit/src/kzg/bi_kzg.rs similarity index 91% rename from poly_commit/src/bi_kzg.rs rename to poly_commit/src/kzg/bi_kzg.rs index 722c904f..26f5d723 100644 --- a/poly_commit/src/bi_kzg.rs +++ b/poly_commit/src/kzg/bi_kzg.rs @@ -3,8 +3,8 @@ pub(crate) use utils::*; mod serde; -mod kzg_structs; -pub use kzg_structs::*; +mod structs; +pub use structs::*; mod univariate; pub use univariate::*; diff --git a/poly_commit/src/bi_kzg/batch.rs b/poly_commit/src/kzg/bi_kzg/batch.rs similarity index 96% rename from poly_commit/src/bi_kzg/batch.rs rename to poly_commit/src/kzg/bi_kzg/batch.rs index 53f30e3d..6bde9aec 100644 --- a/poly_commit/src/bi_kzg/batch.rs +++ b/poly_commit/src/kzg/bi_kzg/batch.rs @@ -5,9 +5,10 @@ use halo2curves::{group::Curve, msm::multiexp_serial, pairing::MultiMillerLoop, use polynomials::MultiLinearPoly; use serdes::ExpSerde; +use crate::{CoefFormUniKZGSRS, UniKZGVerifierParams}; + use super::{ - coeff_form_uni_hyperkzg_open, coeff_form_uni_hyperkzg_verify, powers_series, CoefFormUniKZGSRS, - HyperKZGOpening, UniKZGVerifierParams, + coeff_form_uni_hyperkzg_open, coeff_form_uni_hyperkzg_verify, powers_series, HyperKZGOpening, }; pub fn kzg_batch_open( diff --git a/poly_commit/src/bi_kzg/bivariate.rs b/poly_commit/src/kzg/bi_kzg/bivariate.rs similarity index 100% rename from poly_commit/src/bi_kzg/bivariate.rs rename to poly_commit/src/kzg/bi_kzg/bivariate.rs diff --git a/poly_commit/src/bi_kzg/expander_api.rs b/poly_commit/src/kzg/bi_kzg/expander_api.rs similarity index 100% rename from poly_commit/src/bi_kzg/expander_api.rs rename to poly_commit/src/kzg/bi_kzg/expander_api.rs diff --git a/poly_commit/src/bi_kzg/hyper_bikzg.rs b/poly_commit/src/kzg/bi_kzg/hyper_bikzg.rs similarity index 100% rename from poly_commit/src/bi_kzg/hyper_bikzg.rs rename to poly_commit/src/kzg/bi_kzg/hyper_bikzg.rs diff --git a/poly_commit/src/bi_kzg/hyper_bikzg_tests.rs b/poly_commit/src/kzg/bi_kzg/hyper_bikzg_tests.rs similarity index 100% rename from poly_commit/src/bi_kzg/hyper_bikzg_tests.rs rename to poly_commit/src/kzg/bi_kzg/hyper_bikzg_tests.rs diff --git a/poly_commit/src/bi_kzg/hyper_kzg.rs b/poly_commit/src/kzg/bi_kzg/hyper_kzg.rs similarity index 100% rename from poly_commit/src/bi_kzg/hyper_kzg.rs rename to poly_commit/src/kzg/bi_kzg/hyper_kzg.rs diff --git a/poly_commit/src/bi_kzg/hyper_kzg_structs.rs b/poly_commit/src/kzg/bi_kzg/hyper_kzg_structs.rs similarity index 100% rename from poly_commit/src/bi_kzg/hyper_kzg_structs.rs rename to poly_commit/src/kzg/bi_kzg/hyper_kzg_structs.rs diff --git a/poly_commit/src/bi_kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs similarity index 99% rename from poly_commit/src/bi_kzg/pcs_trait_impl.rs rename to poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs index da9b7522..3c1d215f 100644 --- a/poly_commit/src/bi_kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs @@ -16,7 +16,6 @@ use crate::{ traits::{BatchOpening, BatchOpeningPCS}, *, }; -use bi_kzg::hyper_kzg::*; pub struct HyperBiKZGPCS where diff --git a/poly_commit/src/bi_kzg/serde.rs b/poly_commit/src/kzg/bi_kzg/serde.rs similarity index 100% rename from poly_commit/src/bi_kzg/serde.rs rename to poly_commit/src/kzg/bi_kzg/serde.rs diff --git a/poly_commit/src/bi_kzg/kzg_structs.rs b/poly_commit/src/kzg/bi_kzg/structs.rs similarity index 58% rename from poly_commit/src/bi_kzg/kzg_structs.rs rename to poly_commit/src/kzg/bi_kzg/structs.rs index 15348427..72bed455 100644 --- a/poly_commit/src/bi_kzg/kzg_structs.rs +++ b/poly_commit/src/kzg/bi_kzg/structs.rs @@ -3,64 +3,14 @@ use gkr_engine::StructuredReferenceString; use halo2curves::{pairing::Engine, CurveAffine}; use serdes::ExpSerde; +use crate::{CoefFormUniKZGSRS, UniKZGVerifierParams}; + #[derive(Clone, Copy, Debug, PartialEq, Eq, Derivative)] #[derivative(Default(bound = ""))] -pub struct KZGCommitment(pub E::G1Affine) +pub struct BiKZGCommitment(pub E::G1Affine) where E::G1Affine: CurveAffine; -/// Structured reference string for univariate KZG polynomial commitment scheme. -/// The univariate polynomial here is of coefficient form. -#[derive(Clone, Debug, PartialEq, Eq, Derivative, ExpSerde)] -#[derivative(Default(bound = ""))] -pub struct CoefFormUniKZGSRS -where - E::G1Affine: ExpSerde, - E::G2Affine: CurveAffine + ExpSerde, -{ - /// power of \tau times the generators of G1, yielding - /// \tau^i over G1 with i ranging in \[ 0, 2^n - 1 \] - pub powers_of_tau: Vec, - /// \tau over G2 - pub tau_g2: E::G2Affine, -} - -impl StructuredReferenceString for CoefFormUniKZGSRS -where - ::G1Affine: ExpSerde + CurveAffine, - ::G2Affine: ExpSerde + CurveAffine, -{ - type PKey = CoefFormUniKZGSRS; - type VKey = UniKZGVerifierParams; - - fn into_keys(self) -> (Self::PKey, Self::VKey) { - let vk: Self::VKey = From::from(&self); - (self, vk) - } -} - -/// Univariate KZG PCS verifier's params. -#[derive(Copy, Clone, Debug, PartialEq, Eq, ExpSerde)] -pub struct UniKZGVerifierParams -where - E::G2Affine: ExpSerde, -{ - /// \tau over G2 - pub tau_g2: E::G2Affine, -} - -impl From<&CoefFormUniKZGSRS> for UniKZGVerifierParams -where - E::G1Affine: ExpSerde, - E::G2Affine: CurveAffine + ExpSerde, -{ - fn from(value: &CoefFormUniKZGSRS) -> Self { - Self { - tau_g2: value.tau_g2, - } - } -} - #[derive(Clone, Debug, PartialEq, Eq, Derivative, ExpSerde)] #[derivative(Default(bound = ""))] pub struct CoefFormBiKZGLocalSRS diff --git a/poly_commit/src/bi_kzg/univariate.rs b/poly_commit/src/kzg/bi_kzg/univariate.rs similarity index 100% rename from poly_commit/src/bi_kzg/univariate.rs rename to poly_commit/src/kzg/bi_kzg/univariate.rs diff --git a/poly_commit/src/bi_kzg/utils.rs b/poly_commit/src/kzg/bi_kzg/utils.rs similarity index 100% rename from poly_commit/src/bi_kzg/utils.rs rename to poly_commit/src/kzg/bi_kzg/utils.rs diff --git a/poly_commit/src/kzg/structs.rs b/poly_commit/src/kzg/structs.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/poly_commit/src/kzg/structs.rs @@ -0,0 +1 @@ + diff --git a/poly_commit/src/kzg/uni_kzg.rs b/poly_commit/src/kzg/uni_kzg.rs new file mode 100644 index 00000000..7a536efe --- /dev/null +++ b/poly_commit/src/kzg/uni_kzg.rs @@ -0,0 +1,2 @@ +mod structs; +pub use structs::*; diff --git a/poly_commit/src/kzg/uni_kzg/structs.rs b/poly_commit/src/kzg/uni_kzg/structs.rs new file mode 100644 index 00000000..81c6e015 --- /dev/null +++ b/poly_commit/src/kzg/uni_kzg/structs.rs @@ -0,0 +1,62 @@ +use derivative::Derivative; +use gkr_engine::StructuredReferenceString; +use halo2curves::{pairing::Engine, CurveAffine}; +use serdes::ExpSerde; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Derivative)] +#[derivative(Default(bound = ""))] +pub struct KZGCommitment(pub E::G1Affine) +where + E::G1Affine: CurveAffine; + +/// Structured reference string for univariate KZG polynomial commitment scheme. +/// The univariate polynomial here is of coefficient form. +#[derive(Clone, Debug, PartialEq, Eq, Derivative, ExpSerde)] +#[derivative(Default(bound = ""))] +pub struct CoefFormUniKZGSRS +where + E::G1Affine: ExpSerde, + E::G2Affine: CurveAffine + ExpSerde, +{ + /// power of \tau times the generators of G1, yielding + /// \tau^i over G1 with i ranging in \[ 0, 2^n - 1 \] + pub powers_of_tau: Vec, + /// \tau over G2 + pub tau_g2: E::G2Affine, +} + +impl StructuredReferenceString for CoefFormUniKZGSRS +where + ::G1Affine: ExpSerde + CurveAffine, + ::G2Affine: ExpSerde + CurveAffine, +{ + type PKey = CoefFormUniKZGSRS; + type VKey = UniKZGVerifierParams; + + fn into_keys(self) -> (Self::PKey, Self::VKey) { + let vk: Self::VKey = From::from(&self); + (self, vk) + } +} + +/// Univariate KZG PCS verifier's params. +#[derive(Copy, Clone, Debug, PartialEq, Eq, ExpSerde)] +pub struct UniKZGVerifierParams +where + E::G2Affine: ExpSerde, +{ + /// \tau over G2 + pub tau_g2: E::G2Affine, +} + +impl From<&CoefFormUniKZGSRS> for UniKZGVerifierParams +where + E::G1Affine: ExpSerde, + E::G2Affine: CurveAffine + ExpSerde, +{ + fn from(value: &CoefFormUniKZGSRS) -> Self { + Self { + tau_g2: value.tau_g2, + } + } +} diff --git a/poly_commit/src/lib.rs b/poly_commit/src/lib.rs index 3adf2d08..b0bc946d 100644 --- a/poly_commit/src/lib.rs +++ b/poly_commit/src/lib.rs @@ -17,7 +17,7 @@ pub use orion::*; pub mod hyrax; pub use hyrax::*; -pub mod bi_kzg; -pub use bi_kzg::*; +pub mod kzg; +pub use kzg::*; pub mod batching; From 4be7c38ee5900b78b9afc51c0d49c1f23eb3b1c0 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Fri, 30 May 2025 16:02:08 -0400 Subject: [PATCH 42/57] wip --- poly_commit/src/kzg.rs | 3 + poly_commit/src/kzg/bi_kzg.rs | 22 +- poly_commit/src/kzg/bi_kzg/expander_api.rs | 5 +- poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs | 368 +++++++++--------- poly_commit/src/kzg/bi_kzg/serde.rs | 18 - .../bi_kzg/{structs.rs => structs_bi_kzg.rs} | 16 +- .../src/kzg/bi_kzg/structs_hyper_bi_kzg.rs | 61 +++ poly_commit/src/kzg/uni_kzg.rs | 22 +- .../src/kzg/{bi_kzg => uni_kzg}/batch.rs | 11 +- poly_commit/src/kzg/uni_kzg/expander_api.rs | 213 ++++++++++ .../src/kzg/{bi_kzg => uni_kzg}/hyper_kzg.rs | 0 poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs | 211 ++++++++++ .../structs_hyper_kzg.rs} | 51 --- .../uni_kzg/{structs.rs => structs_kzg.rs} | 16 +- .../src/kzg/{bi_kzg => uni_kzg}/univariate.rs | 0 poly_commit/src/kzg/{bi_kzg => }/utils.rs | 0 poly_commit/tests/test_bi_kzg.rs | 99 +++++ .../tests/{test_kzg.rs => test_uni_kzg.rs} | 18 +- 18 files changed, 841 insertions(+), 293 deletions(-) delete mode 100644 poly_commit/src/kzg/bi_kzg/serde.rs rename poly_commit/src/kzg/bi_kzg/{structs.rs => structs_bi_kzg.rs} (82%) create mode 100644 poly_commit/src/kzg/bi_kzg/structs_hyper_bi_kzg.rs rename poly_commit/src/kzg/{bi_kzg => uni_kzg}/batch.rs (94%) create mode 100644 poly_commit/src/kzg/uni_kzg/expander_api.rs rename poly_commit/src/kzg/{bi_kzg => uni_kzg}/hyper_kzg.rs (100%) create mode 100644 poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs rename poly_commit/src/kzg/{bi_kzg/hyper_kzg_structs.rs => uni_kzg/structs_hyper_kzg.rs} (86%) rename poly_commit/src/kzg/uni_kzg/{structs.rs => structs_kzg.rs} (79%) rename poly_commit/src/kzg/{bi_kzg => uni_kzg}/univariate.rs (100%) rename poly_commit/src/kzg/{bi_kzg => }/utils.rs (100%) create mode 100644 poly_commit/tests/test_bi_kzg.rs rename poly_commit/tests/{test_kzg.rs => test_uni_kzg.rs} (85%) diff --git a/poly_commit/src/kzg.rs b/poly_commit/src/kzg.rs index f29cf309..964defe6 100644 --- a/poly_commit/src/kzg.rs +++ b/poly_commit/src/kzg.rs @@ -6,3 +6,6 @@ pub use bi_kzg::*; mod structs; pub use structs::*; + +mod utils; +pub use utils::*; diff --git a/poly_commit/src/kzg/bi_kzg.rs b/poly_commit/src/kzg/bi_kzg.rs index 26f5d723..c08c75d8 100644 --- a/poly_commit/src/kzg/bi_kzg.rs +++ b/poly_commit/src/kzg/bi_kzg.rs @@ -1,23 +1,12 @@ -mod utils; -pub(crate) use utils::*; +mod structs_bi_kzg; +pub use structs_bi_kzg::*; -mod serde; - -mod structs; -pub use structs::*; - -mod univariate; -pub use univariate::*; +mod structs_hyper_bi_kzg; +pub use structs_hyper_bi_kzg::*; mod bivariate; pub use bivariate::*; -mod hyper_kzg_structs; -pub use hyper_kzg_structs::*; - -mod hyper_kzg; -pub use hyper_kzg::*; - mod hyper_bikzg; pub use hyper_bikzg::*; @@ -28,6 +17,3 @@ mod pcs_trait_impl; pub use pcs_trait_impl::HyperBiKZGPCS; mod expander_api; - -mod batch; -pub use batch::{kzg_batch_open, kzg_batch_verify}; diff --git a/poly_commit/src/kzg/bi_kzg/expander_api.rs b/poly_commit/src/kzg/bi_kzg/expander_api.rs index 38730b26..0d6dcf9d 100644 --- a/poly_commit/src/kzg/bi_kzg/expander_api.rs +++ b/poly_commit/src/kzg/bi_kzg/expander_api.rs @@ -1,4 +1,3 @@ -use crate::traits::BatchOpening; use arith::ExtensionField; use gkr_engine::{ ExpanderPCS, ExpanderSingleVarChallenge, FieldEngine, MPIEngine, PolynomialCommitmentType, @@ -29,7 +28,7 @@ where E::G1Affine: ExpSerde + Default + CurveAffine, E::G2Affine: ExpSerde + Default + CurveAffine, { - const NAME: &'static str = "HyperBiKZGPCSForExpander"; + const NAME: &'static str = "HyperBiKZGForExpander"; const PCS_TYPE: PolynomialCommitmentType = PolynomialCommitmentType::KZG; @@ -38,7 +37,7 @@ where type Params = usize; type SRS = CoefFormBiKZGLocalSRS; type ScratchPad = (); - type BatchOpening = BatchOpening; + type BatchOpening = (); fn init_scratch_pad(_params: &Self::Params, _mpi_engine: &impl MPIEngine) -> Self::ScratchPad {} diff --git a/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs index 3c1d215f..e058b302 100644 --- a/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs @@ -33,187 +33,187 @@ where pub const MINIMUM_SUPPORTED_NUM_VARS: usize = 2; } -impl PolynomialCommitmentScheme for HyperBiKZGPCS -where - E: Engine + MultiMillerLoop, - E::Fr: ExtensionField + PrimeField, - E::G1Affine: ExpSerde + Default + CurveAffine, - E::G2Affine: ExpSerde + Default + CurveAffine, -{ - const NAME: &'static str = "HyperBiKZGPCS"; - - type Params = usize; - type Poly = MultiLinearPoly; - type EvalPoint = Vec; - type ScratchPad = (); - - type SRS = CoefFormUniKZGSRS; - type Commitment = KZGCommitment; - type Opening = HyperKZGOpening; - - fn init_scratch_pad(_params: &Self::Params) -> Self::ScratchPad {} - - fn gen_srs_for_testing(params: &Self::Params, rng: impl rand::RngCore) -> (Self::SRS, usize) { - let local_num_vars = if *params == 0 { 1 } else { *params }; - - let length = 1 << local_num_vars; - let srs = generate_coef_form_uni_kzg_srs_for_testing(length, rng); - (srs, local_num_vars) - } - - fn commit( - _params: &Self::Params, - proving_key: &::PKey, - poly: &Self::Poly, - _scratch_pad: &mut Self::ScratchPad, - ) -> Self::Commitment { - KZGCommitment(coeff_form_uni_kzg_commit(proving_key, &poly.coeffs)) - } - - fn open( - _params: &Self::Params, - proving_key: &::PKey, - poly: &Self::Poly, - x: &Self::EvalPoint, - _scratch_pad: &Self::ScratchPad, - transcript: &mut impl Transcript, - ) -> (E::Fr, Self::Opening) { - coeff_form_uni_hyperkzg_open(proving_key, &poly.coeffs, x, transcript) - } - - fn verify( - _params: &Self::Params, - verifying_key: &::VKey, - commitment: &Self::Commitment, - x: &Self::EvalPoint, - v: E::Fr, - opening: &Self::Opening, - transcript: &mut impl Transcript, - ) -> bool { - coeff_form_uni_hyperkzg_verify(verifying_key, commitment.0, x, v, opening, transcript) - } -} - -impl BatchOpeningPCS for HyperBiKZGPCS -where - E: Engine + MultiMillerLoop, - E::Fr: ExtensionField + PrimeField, - E::G1Affine: ExpSerde + Default + CurveAffine, - E::G2Affine: ExpSerde + Default + CurveAffine, -{ - fn single_point_batch_open( - _params: &Self::Params, - proving_key: &::PKey, - polys: &[Self::Poly], - x: &Self::EvalPoint, - _scratch_pad: &Self::ScratchPad, - transcript: &mut impl Transcript, - ) -> (Vec, Self::Opening) { - kzg_batch_open(proving_key, polys, x, transcript) - } - - fn single_point_batch_verify( - _params: &Self::Params, - verifying_key: &::VKey, - commitments: &[Self::Commitment], - x: &Self::EvalPoint, - evals: &[E::Fr], - opening: &Self::Opening, - transcript: &mut impl Transcript, - ) -> bool { - let commitment_unwrapped = commitments.iter().map(|c| c.0).collect::>(); - - kzg_batch_verify( - verifying_key, - &commitment_unwrapped, - x, - evals, - opening, - transcript, - ) - } - - /// Open a set of polynomials at a multiple points. - /// Requires the length of the polys to be the same as points. - /// Steps: - /// 1. get challenge point t from transcript - /// 2. build eq(t,i) for i in [0..k] - /// 3. build \tilde g_i(b) = eq(t, i) * f_i(b) - /// 4. compute \tilde eq_i(b) = eq(b, point_i) - /// 5. run sumcheck on \sum_i=1..k \tilde eq_i * \tilde g_i - /// 6. build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the sumcheck's - /// point - /// 7. open g'(X) at point (a2) - /// - /// Returns: - /// - the evaluations of the polynomials at their corresponding points - /// - the batch opening proof containing the sumcheck proof and the opening of g'(X) - fn multiple_points_batch_open( - _params: &Self::Params, - proving_key: &::PKey, - polys: &[Self::Poly], - points: &[Self::EvalPoint], - _scratch_pad: &Self::ScratchPad, - transcript: &mut impl Transcript, - ) -> (Vec, BatchOpening) { - // generate evals for each polynomial at its corresponding point - let evals: Vec = polys - .iter() - .zip(points.iter()) - .map(|(poly, point)| poly.evaluate_jolt(point)) - .collect(); - - let (new_point, g_prime, proof) = - prover_merge_points::(polys, points, transcript); - - let (_g_prime_eval, g_prime_proof) = - coeff_form_uni_hyperkzg_open(proving_key, &g_prime.coeffs, &new_point, transcript); - ( - evals, - BatchOpening { - sum_check_proof: proof, - g_prime_proof, - }, - ) - } - - /// Verify the opening of a set of polynomials at a single point. - /// Steps: - /// 1. get challenge point t from transcript - /// 2. build g' commitment - /// 3. ensure \sum_i eq(a2, point_i) * eq(t, ) * f_i_evals matches the sum via SumCheck - /// verification - /// 4. verify commitment - fn multiple_points_batch_verify( - _params: &Self::Params, - verifying_key: &::VKey, - commitments: &[Self::Commitment], - points: &[Self::EvalPoint], - values: &[E::Fr], - batch_opening: &BatchOpening, - transcript: &mut impl Transcript, - ) -> bool { - // sum check point (a2) - let a2 = batch_opening.sum_check_proof.export_point_to_expander(); - - let commitments = commitments.iter().map(|c| vec![c.0]).collect::>(); - - let (tilde_g_eval, g_prime_commit) = verifier_merge_points::( - &commitments, - points, - values, - &batch_opening.sum_check_proof, - transcript, - ); - - // verify commitment - coeff_form_uni_hyperkzg_verify( - verifying_key, - g_prime_commit[0], - a2.as_ref(), - tilde_g_eval, - &batch_opening.g_prime_proof, - transcript, - ) - } -} +// impl PolynomialCommitmentScheme for HyperBiKZGPCS +// where +// E: Engine + MultiMillerLoop, +// E::Fr: ExtensionField + PrimeField, +// E::G1Affine: ExpSerde + Default + CurveAffine, +// E::G2Affine: ExpSerde + Default + CurveAffine, +// { +// const NAME: &'static str = "HyperBiKZGPCS"; + +// type Params = usize; +// type Poly = MultiLinearPoly; +// type EvalPoint = Vec; +// type ScratchPad = (); + +// type SRS = CoefFormUniKZGSRS; +// type Commitment = KZGCommitment; +// type Opening = HyperKZGOpening; + +// fn init_scratch_pad(_params: &Self::Params) -> Self::ScratchPad {} + +// fn gen_srs_for_testing(params: &Self::Params, rng: impl rand::RngCore) -> (Self::SRS, usize) +// { let local_num_vars = if *params == 0 { 1 } else { *params }; + +// let length = 1 << local_num_vars; +// let srs = generate_coef_form_uni_kzg_srs_for_testing(length, rng); +// (srs, local_num_vars) +// } + +// fn commit( +// _params: &Self::Params, +// proving_key: &::PKey, +// poly: &Self::Poly, +// _scratch_pad: &mut Self::ScratchPad, +// ) -> Self::Commitment { +// KZGCommitment(coeff_form_uni_kzg_commit(proving_key, &poly.coeffs)) +// } + +// fn open( +// _params: &Self::Params, +// proving_key: &::PKey, +// poly: &Self::Poly, +// x: &Self::EvalPoint, +// _scratch_pad: &Self::ScratchPad, +// transcript: &mut impl Transcript, +// ) -> (E::Fr, Self::Opening) { +// coeff_form_uni_hyperkzg_open(proving_key, &poly.coeffs, x, transcript) +// } + +// fn verify( +// _params: &Self::Params, +// verifying_key: &::VKey, +// commitment: &Self::Commitment, +// x: &Self::EvalPoint, +// v: E::Fr, +// opening: &Self::Opening, +// transcript: &mut impl Transcript, +// ) -> bool { +// coeff_form_uni_hyperkzg_verify(verifying_key, commitment.0, x, v, opening, transcript) +// } +// } + +// impl BatchOpeningPCS for HyperBiKZGPCS +// where +// E: Engine + MultiMillerLoop, +// E::Fr: ExtensionField + PrimeField, +// E::G1Affine: ExpSerde + Default + CurveAffine, +// E::G2Affine: ExpSerde + Default + CurveAffine, +// { +// fn single_point_batch_open( +// _params: &Self::Params, +// proving_key: &::PKey, +// polys: &[Self::Poly], +// x: &Self::EvalPoint, +// _scratch_pad: &Self::ScratchPad, +// transcript: &mut impl Transcript, +// ) -> (Vec, Self::Opening) { +// kzg_single_point_batch_open(proving_key, polys, x, transcript) +// } + +// fn single_point_batch_verify( +// _params: &Self::Params, +// verifying_key: &::VKey, +// commitments: &[Self::Commitment], +// x: &Self::EvalPoint, +// evals: &[E::Fr], +// opening: &Self::Opening, +// transcript: &mut impl Transcript, +// ) -> bool { +// let commitment_unwrapped = commitments.iter().map(|c| c.0).collect::>(); + +// kzg_single_point_batch_verify( +// verifying_key, +// &commitment_unwrapped, +// x, +// evals, +// opening, +// transcript, +// ) +// } + +// /// Open a set of polynomials at a multiple points. +// /// Requires the length of the polys to be the same as points. +// /// Steps: +// /// 1. get challenge point t from transcript +// /// 2. build eq(t,i) for i in [0..k] +// /// 3. build \tilde g_i(b) = eq(t, i) * f_i(b) +// /// 4. compute \tilde eq_i(b) = eq(b, point_i) +// /// 5. run sumcheck on \sum_i=1..k \tilde eq_i * \tilde g_i +// /// 6. build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the sumcheck's +// /// point +// /// 7. open g'(X) at point (a2) +// /// +// /// Returns: +// /// - the evaluations of the polynomials at their corresponding points +// /// - the batch opening proof containing the sumcheck proof and the opening of g'(X) +// fn multiple_points_batch_open( +// _params: &Self::Params, +// proving_key: &::PKey, +// polys: &[Self::Poly], +// points: &[Self::EvalPoint], +// _scratch_pad: &Self::ScratchPad, +// transcript: &mut impl Transcript, +// ) -> (Vec, BatchOpening) { +// // generate evals for each polynomial at its corresponding point +// let evals: Vec = polys +// .iter() +// .zip(points.iter()) +// .map(|(poly, point)| poly.evaluate_jolt(point)) +// .collect(); + +// let (new_point, g_prime, proof) = +// prover_merge_points::(polys, points, transcript); + +// let (_g_prime_eval, g_prime_proof) = +// coeff_form_uni_hyperkzg_open(proving_key, &g_prime.coeffs, &new_point, transcript); +// ( +// evals, +// BatchOpening { +// sum_check_proof: proof, +// g_prime_proof, +// }, +// ) +// } + +// /// Verify the opening of a set of polynomials at a single point. +// /// Steps: +// /// 1. get challenge point t from transcript +// /// 2. build g' commitment +// /// 3. ensure \sum_i eq(a2, point_i) * eq(t, ) * f_i_evals matches the sum via SumCheck +// /// verification +// /// 4. verify commitment +// fn multiple_points_batch_verify( +// _params: &Self::Params, +// verifying_key: &::VKey, +// commitments: &[Self::Commitment], +// points: &[Self::EvalPoint], +// values: &[E::Fr], +// batch_opening: &BatchOpening, +// transcript: &mut impl Transcript, +// ) -> bool { +// // sum check point (a2) +// let a2 = batch_opening.sum_check_proof.export_point_to_expander(); + +// let commitments = commitments.iter().map(|c| vec![c.0]).collect::>(); + +// let (tilde_g_eval, g_prime_commit) = verifier_merge_points::( +// &commitments, +// points, +// values, +// &batch_opening.sum_check_proof, +// transcript, +// ); + +// // verify commitment +// coeff_form_uni_hyperkzg_verify( +// verifying_key, +// g_prime_commit[0], +// a2.as_ref(), +// tilde_g_eval, +// &batch_opening.g_prime_proof, +// transcript, +// ) +// } +// } diff --git a/poly_commit/src/kzg/bi_kzg/serde.rs b/poly_commit/src/kzg/bi_kzg/serde.rs deleted file mode 100644 index 438fb5c5..00000000 --- a/poly_commit/src/kzg/bi_kzg/serde.rs +++ /dev/null @@ -1,18 +0,0 @@ -use halo2curves::{pairing::Engine, CurveAffine}; -use serdes::{ExpSerde, SerdeResult}; - -use crate::*; - -// Derive macros does not work for associated types -impl ExpSerde for KZGCommitment -where - E::G1Affine: ExpSerde + CurveAffine, -{ - fn serialize_into(&self, writer: W) -> SerdeResult<()> { - self.0.serialize_into(writer) - } - - fn deserialize_from(reader: R) -> SerdeResult { - Ok(Self(::deserialize_from(reader)?)) - } -} diff --git a/poly_commit/src/kzg/bi_kzg/structs.rs b/poly_commit/src/kzg/bi_kzg/structs_bi_kzg.rs similarity index 82% rename from poly_commit/src/kzg/bi_kzg/structs.rs rename to poly_commit/src/kzg/bi_kzg/structs_bi_kzg.rs index 72bed455..161a2461 100644 --- a/poly_commit/src/kzg/bi_kzg/structs.rs +++ b/poly_commit/src/kzg/bi_kzg/structs_bi_kzg.rs @@ -1,7 +1,7 @@ use derivative::Derivative; use gkr_engine::StructuredReferenceString; use halo2curves::{pairing::Engine, CurveAffine}; -use serdes::ExpSerde; +use serdes::{ExpSerde, SerdeResult}; use crate::{CoefFormUniKZGSRS, UniKZGVerifierParams}; @@ -11,6 +11,20 @@ pub struct BiKZGCommitment(pub E::G1Affine) where E::G1Affine: CurveAffine; +// Derive macros does not work for associated types +impl ExpSerde for BiKZGCommitment +where + E::G1Affine: ExpSerde + CurveAffine, +{ + fn serialize_into(&self, writer: W) -> SerdeResult<()> { + self.0.serialize_into(writer) + } + + fn deserialize_from(reader: R) -> SerdeResult { + Ok(Self(::deserialize_from(reader)?)) + } +} + #[derive(Clone, Debug, PartialEq, Eq, Derivative, ExpSerde)] #[derivative(Default(bound = ""))] pub struct CoefFormBiKZGLocalSRS diff --git a/poly_commit/src/kzg/bi_kzg/structs_hyper_bi_kzg.rs b/poly_commit/src/kzg/bi_kzg/structs_hyper_bi_kzg.rs new file mode 100644 index 00000000..11faf453 --- /dev/null +++ b/poly_commit/src/kzg/bi_kzg/structs_hyper_bi_kzg.rs @@ -0,0 +1,61 @@ +use std::ops::{Index, IndexMut}; + +use arith::ExtensionField; +use derivative::Derivative; +use gkr_engine::Transcript; +use halo2curves::{ff::Field, pairing::Engine}; +use itertools::izip; +use serdes::ExpSerde; + +use crate::*; + +#[derive(Debug, Clone, Derivative, ExpSerde)] +#[derivative(Default(bound = ""))] +pub struct HyperBiKZGOpening +where + E::Fr: ExpSerde, + E::G1Affine: Default + ExpSerde, +{ + pub folded_oracle_commitments: Vec, + + pub aggregated_evals: HyperKZGAggregatedEvals, + pub leader_evals: HyperKZGExportedLocalEvals, + + pub beta_x_commitment: E::G1Affine, + pub beta_y_commitment: E::G1Affine, + + pub quotient_delta_x_commitment: E::G1Affine, + pub quotient_delta_y_commitment: E::G1Affine, +} + +impl From> for HyperKZGOpening +where + E::Fr: ExpSerde, + E::G1Affine: Default + ExpSerde, +{ + fn from(value: HyperBiKZGOpening) -> Self { + Self { + folded_oracle_commitments: value.folded_oracle_commitments, + evals_at_x: value.leader_evals, + beta_x_commitment: value.beta_x_commitment, + quotient_delta_x_commitment: value.quotient_delta_x_commitment, + } + } +} + +impl From> for HyperBiKZGOpening +where + E::Fr: ExpSerde, + E::G1Affine: Default + ExpSerde, +{ + fn from(value: HyperKZGOpening) -> Self { + Self { + folded_oracle_commitments: value.folded_oracle_commitments, + leader_evals: value.evals_at_x, + beta_x_commitment: value.beta_x_commitment, + quotient_delta_x_commitment: value.quotient_delta_x_commitment, + + ..Default::default() + } + } +} diff --git a/poly_commit/src/kzg/uni_kzg.rs b/poly_commit/src/kzg/uni_kzg.rs index 7a536efe..6efc34ed 100644 --- a/poly_commit/src/kzg/uni_kzg.rs +++ b/poly_commit/src/kzg/uni_kzg.rs @@ -1,2 +1,20 @@ -mod structs; -pub use structs::*; +mod structs_kzg; +pub use structs_kzg::*; + +mod structs_hyper_kzg; +pub use structs_hyper_kzg::*; + +mod hyper_kzg; +pub use hyper_kzg::*; + +mod univariate; +pub use univariate::*; + +mod pcs_trait_impl; +pub use pcs_trait_impl::*; + +mod expander_api; +pub use expander_api::*; + +mod batch; +pub use batch::{kzg_single_point_batch_open, kzg_single_point_batch_verify}; diff --git a/poly_commit/src/kzg/bi_kzg/batch.rs b/poly_commit/src/kzg/uni_kzg/batch.rs similarity index 94% rename from poly_commit/src/kzg/bi_kzg/batch.rs rename to poly_commit/src/kzg/uni_kzg/batch.rs index 6bde9aec..3d980e43 100644 --- a/poly_commit/src/kzg/bi_kzg/batch.rs +++ b/poly_commit/src/kzg/uni_kzg/batch.rs @@ -5,13 +5,12 @@ use halo2curves::{group::Curve, msm::multiexp_serial, pairing::MultiMillerLoop, use polynomials::MultiLinearPoly; use serdes::ExpSerde; -use crate::{CoefFormUniKZGSRS, UniKZGVerifierParams}; - -use super::{ - coeff_form_uni_hyperkzg_open, coeff_form_uni_hyperkzg_verify, powers_series, HyperKZGOpening, +use crate::{ + coeff_form_uni_hyperkzg_open, coeff_form_uni_hyperkzg_verify, powers_series, CoefFormUniKZGSRS, + HyperKZGOpening, UniKZGVerifierParams, }; -pub fn kzg_batch_open( +pub fn kzg_single_point_batch_open( proving_key: &CoefFormUniKZGSRS, polys: &[MultiLinearPoly], x: &[E::Fr], @@ -55,7 +54,7 @@ where (evals, open) } -pub fn kzg_batch_verify( +pub fn kzg_single_point_batch_verify( verifying_key: &UniKZGVerifierParams, commitments: &[E::G1Affine], x: &[E::Fr], diff --git a/poly_commit/src/kzg/uni_kzg/expander_api.rs b/poly_commit/src/kzg/uni_kzg/expander_api.rs new file mode 100644 index 00000000..ff885db1 --- /dev/null +++ b/poly_commit/src/kzg/uni_kzg/expander_api.rs @@ -0,0 +1,213 @@ +use arith::ExtensionField; +use gkr_engine::{ + ExpanderPCS, ExpanderSingleVarChallenge, FieldEngine, MPIEngine, PolynomialCommitmentType, + StructuredReferenceString, Transcript, +}; +use halo2curves::{ + ff::PrimeField, + group::prime::PrimeCurveAffine, + pairing::{Engine, MultiMillerLoop}, + CurveAffine, +}; +use polynomials::MultilinearExtension; +use serdes::ExpSerde; + +use crate::{ + traits::BatchOpening, utils::{ + lift_expander_challenge_to_n_vars, lift_poly_and_expander_challenge_to_n_vars, + lift_poly_to_n_vars, + }, * +}; + +impl ExpanderPCS for HyperUniKZGPCS +where + G: FieldEngine, + E: Engine + MultiMillerLoop, + E::Fr: ExtensionField + PrimeField, + E::G1Affine: ExpSerde + Default + CurveAffine, + E::G2Affine: ExpSerde + Default + CurveAffine, +{ + const NAME: &'static str = "HyperUniKZGForExpander"; + + const PCS_TYPE: PolynomialCommitmentType = PolynomialCommitmentType::KZG; + + type Commitment = KZGCommitment; + type Opening = HyperBiKZGOpening; + type Params = usize; + type SRS = CoefFormBiKZGLocalSRS; + type ScratchPad = (); + type BatchOpening = BatchOpening; + + fn init_scratch_pad(_params: &Self::Params, _mpi_engine: &impl MPIEngine) -> Self::ScratchPad {} + + fn gen_params(n_input_vars: usize, _world_size: usize) -> Self::Params { + n_input_vars + } + + fn gen_srs_for_testing( + params: &Self::Params, + mpi_engine: &impl MPIEngine, + rng: impl rand::RngCore, + ) -> Self::SRS { + todo!() + // let local_num_vars = *params; + + // let x_degree_po2 = 1 << local_num_vars; + // let y_degree_po2 = mpi_engine.world_size(); + // let rank = mpi_engine.world_rank(); + + // generate_coef_form_bi_kzg_local_srs_for_testing(x_degree_po2, y_degree_po2, rank, rng) + } + + fn commit( + _params: &Self::Params, + mpi_engine: &impl MPIEngine, + proving_key: &::PKey, + poly: &impl polynomials::MultilinearExtension, + _scratch_pad: &mut Self::ScratchPad, + ) -> Option { + todo!() + + // // The minimum supported number of variables is 1. + // // If the polynomial has no variables, we lift it to a polynomial with 1 variable. + // if poly.num_vars() < Self::MINIMUM_SUPPORTED_NUM_VARS { + // let poly = lift_poly_to_n_vars(poly, Self::MINIMUM_SUPPORTED_NUM_VARS); + // return >::commit( + // _params, + // mpi_engine, + // proving_key, + // &poly, + // _scratch_pad, + // ); + // }; + + // let local_commitment = + // coeff_form_uni_kzg_commit(&proving_key.tau_x_srs, poly.hypercube_basis_ref()); + + // if mpi_engine.is_single_process() { + // return KZGCommitment(local_commitment).into(); + // } + + // let local_g1 = local_commitment.to_curve(); + // let mut root_gathering_commits: Vec = vec![local_g1; mpi_engine.world_size()]; + // mpi_engine.gather_vec(&[local_g1], &mut root_gathering_commits); + + // if !mpi_engine.is_root() { + // return None; + // } + + // let final_commit = root_gathering_commits.iter().sum::().into(); + + // KZGCommitment(final_commit).into() + } + + fn open( + _params: &Self::Params, + mpi_engine: &impl MPIEngine, + proving_key: &::PKey, + poly: &impl MultilinearExtension, + x: &ExpanderSingleVarChallenge, + transcript: &mut impl Transcript, + _scratch_pad: &Self::ScratchPad, + ) -> Option { + // if poly.num_vars() < Self::MINIMUM_SUPPORTED_NUM_VARS { + // let (poly, x) = lift_poly_and_expander_challenge_to_n_vars( + // poly, + // x, + // Self::MINIMUM_SUPPORTED_NUM_VARS, + // ); + // return >::open( + // _params, + // mpi_engine, + // proving_key, + // &poly, + // &x, + // transcript, + // _scratch_pad, + // ); + // }; + + // coeff_form_hyper_bikzg_open( + // proving_key, + // mpi_engine, + // poly, + // &x.local_xs(), + // &x.r_mpi, + // transcript, + // ) + todo!() + + } + + fn verify( + _params: &Self::Params, + verifying_key: &::VKey, + commitment: &Self::Commitment, + x: &ExpanderSingleVarChallenge, + v: ::ChallengeField, + transcript: &mut impl Transcript, + opening: &Self::Opening, + ) -> bool { + todo!() + // if x.rz.len() < Self::MINIMUM_SUPPORTED_NUM_VARS { + // let x = lift_expander_challenge_to_n_vars(x, Self::MINIMUM_SUPPORTED_NUM_VARS); + // return >::verify( + // _params, + // verifying_key, + // commitment, + // &x, + // v, + // transcript, + // opening, + // ); + // }; + + // coeff_form_hyper_bikzg_verify( + // verifying_key, + // &x.local_xs(), + // &x.r_mpi, + // v, + // commitment.0, + // opening, + // transcript, + // ) + } + + // /// Open a set of polynomials at a point. + // fn batch_open( + // _params: &Self::Params, + // _mpi_engine: &impl MPIEngine, + // proving_key: &::PKey, + // mle_poly_list: &[impl MultilinearExtension], + // eval_point: &ExpanderSingleVarChallenge, + // _scratch_pad: &Self::ScratchPad, + // transcript: &mut impl Transcript, + // ) -> (Vec, Self::Opening) { + // let (eval, open) = kzg_batch_open( + // proving_key, + // mle_poly_list, + // &eval_point.local_xs(), + // transcript, + // ); + // (eval, open.into()) + // } + + // fn batch_verify( + // _params: &Self::Params, + // verifying_key: &::VKey, + // commitments: &[Self::Commitment], + // x: &ExpanderSingleVarChallenge, + // evals: &[::ChallengeField], + // opening: &Self::Opening, + // transcript: &mut impl Transcript, + // ) -> bool { + // kzg_batch_verify( + // verifying_key, + // commitments, + // &x.local_xs(), + // evals, + // opening, + // transcript, + // ) + // } +} diff --git a/poly_commit/src/kzg/bi_kzg/hyper_kzg.rs b/poly_commit/src/kzg/uni_kzg/hyper_kzg.rs similarity index 100% rename from poly_commit/src/kzg/bi_kzg/hyper_kzg.rs rename to poly_commit/src/kzg/uni_kzg/hyper_kzg.rs diff --git a/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs new file mode 100644 index 00000000..08d6b3a7 --- /dev/null +++ b/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs @@ -0,0 +1,211 @@ +use std::marker::PhantomData; + +use arith::ExtensionField; +use gkr_engine::{StructuredReferenceString, Transcript}; +use halo2curves::{ + ff::PrimeField, + pairing::{Engine, MultiMillerLoop}, + CurveAffine, +}; +use polynomials::MultiLinearPoly; +use serdes::ExpSerde; + +use crate::batching::prover_merge_points; +use crate::batching::verifier_merge_points; +use crate::{ + traits::{BatchOpening, BatchOpeningPCS}, + *, +}; + +pub struct HyperUniKZGPCS +where + E: Engine, + E::Fr: ExtensionField, +{ + _marker_e: PhantomData, +} + +impl PolynomialCommitmentScheme for HyperUniKZGPCS +where + E: Engine + MultiMillerLoop, + E::Fr: ExtensionField + PrimeField, + E::G1Affine: ExpSerde + Default + CurveAffine, + E::G2Affine: ExpSerde + Default + CurveAffine, +{ + const NAME: &'static str = "HyperUniKZGPCS"; + + type Params = usize; + type Poly = MultiLinearPoly; + type EvalPoint = Vec; + type ScratchPad = (); + + type SRS = CoefFormUniKZGSRS; + type Commitment = KZGCommitment; + type Opening = HyperKZGOpening; + + fn init_scratch_pad(_params: &Self::Params) -> Self::ScratchPad {} + + fn gen_srs_for_testing(params: &Self::Params, rng: impl rand::RngCore) -> (Self::SRS, usize) { + let local_num_vars = if *params == 0 { 1 } else { *params }; + + let length = 1 << local_num_vars; + let srs = generate_coef_form_uni_kzg_srs_for_testing(length, rng); + (srs, local_num_vars) + } + + fn commit( + _params: &Self::Params, + proving_key: &::PKey, + poly: &Self::Poly, + _scratch_pad: &mut Self::ScratchPad, + ) -> Self::Commitment { + KZGCommitment(coeff_form_uni_kzg_commit(proving_key, &poly.coeffs)) + } + + fn open( + _params: &Self::Params, + proving_key: &::PKey, + poly: &Self::Poly, + x: &Self::EvalPoint, + _scratch_pad: &Self::ScratchPad, + transcript: &mut impl Transcript, + ) -> (E::Fr, Self::Opening) { + coeff_form_uni_hyperkzg_open(proving_key, &poly.coeffs, x, transcript) + } + + fn verify( + _params: &Self::Params, + verifying_key: &::VKey, + commitment: &Self::Commitment, + x: &Self::EvalPoint, + v: E::Fr, + opening: &Self::Opening, + transcript: &mut impl Transcript, + ) -> bool { + coeff_form_uni_hyperkzg_verify(verifying_key, commitment.0, x, v, opening, transcript) + } +} + +impl BatchOpeningPCS for HyperUniKZGPCS +where + E: Engine + MultiMillerLoop, + E::Fr: ExtensionField + PrimeField, + E::G1Affine: ExpSerde + Default + CurveAffine, + E::G2Affine: ExpSerde + Default + CurveAffine, +{ + fn single_point_batch_open( + _params: &Self::Params, + proving_key: &::PKey, + polys: &[Self::Poly], + x: &Self::EvalPoint, + _scratch_pad: &Self::ScratchPad, + transcript: &mut impl Transcript, + ) -> (Vec, Self::Opening) { + kzg_single_point_batch_open(proving_key, polys, x, transcript) + } + + fn single_point_batch_verify( + _params: &Self::Params, + verifying_key: &::VKey, + commitments: &[Self::Commitment], + x: &Self::EvalPoint, + evals: &[E::Fr], + opening: &Self::Opening, + transcript: &mut impl Transcript, + ) -> bool { + let commitment_unwrapped = commitments.iter().map(|c| c.0).collect::>(); + + kzg_single_point_batch_verify( + verifying_key, + &commitment_unwrapped, + x, + evals, + opening, + transcript, + ) + } + + /// Open a set of polynomials at a multiple points. + /// Requires the length of the polys to be the same as points. + /// Steps: + /// 1. get challenge point t from transcript + /// 2. build eq(t,i) for i in [0..k] + /// 3. build \tilde g_i(b) = eq(t, i) * f_i(b) + /// 4. compute \tilde eq_i(b) = eq(b, point_i) + /// 5. run sumcheck on \sum_i=1..k \tilde eq_i * \tilde g_i + /// 6. build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the sumcheck's + /// point + /// 7. open g'(X) at point (a2) + /// + /// Returns: + /// - the evaluations of the polynomials at their corresponding points + /// - the batch opening proof containing the sumcheck proof and the opening of g'(X) + fn multiple_points_batch_open( + _params: &Self::Params, + proving_key: &::PKey, + polys: &[Self::Poly], + points: &[Self::EvalPoint], + _scratch_pad: &Self::ScratchPad, + transcript: &mut impl Transcript, + ) -> (Vec, BatchOpening) { + // generate evals for each polynomial at its corresponding point + let evals: Vec = polys + .iter() + .zip(points.iter()) + .map(|(poly, point)| poly.evaluate_jolt(point)) + .collect(); + + let (new_point, g_prime, proof) = + prover_merge_points::(polys, points, transcript); + + let (_g_prime_eval, g_prime_proof) = + coeff_form_uni_hyperkzg_open(proving_key, &g_prime.coeffs, &new_point, transcript); + ( + evals, + BatchOpening { + sum_check_proof: proof, + g_prime_proof, + }, + ) + } + + /// Verify the opening of a set of polynomials at a single point. + /// Steps: + /// 1. get challenge point t from transcript + /// 2. build g' commitment + /// 3. ensure \sum_i eq(a2, point_i) * eq(t, ) * f_i_evals matches the sum via SumCheck + /// verification + /// 4. verify commitment + fn multiple_points_batch_verify( + _params: &Self::Params, + verifying_key: &::VKey, + commitments: &[Self::Commitment], + points: &[Self::EvalPoint], + values: &[E::Fr], + batch_opening: &BatchOpening, + transcript: &mut impl Transcript, + ) -> bool { + // sum check point (a2) + let a2 = batch_opening.sum_check_proof.export_point_to_expander(); + + let commitments = commitments.iter().map(|c| vec![c.0]).collect::>(); + + let (tilde_g_eval, g_prime_commit) = verifier_merge_points::( + &commitments, + points, + values, + &batch_opening.sum_check_proof, + transcript, + ); + + // verify commitment + coeff_form_uni_hyperkzg_verify( + verifying_key, + g_prime_commit[0], + a2.as_ref(), + tilde_g_eval, + &batch_opening.g_prime_proof, + transcript, + ) + } +} diff --git a/poly_commit/src/kzg/bi_kzg/hyper_kzg_structs.rs b/poly_commit/src/kzg/uni_kzg/structs_hyper_kzg.rs similarity index 86% rename from poly_commit/src/kzg/bi_kzg/hyper_kzg_structs.rs rename to poly_commit/src/kzg/uni_kzg/structs_hyper_kzg.rs index 055f8ad5..5d02a5ae 100644 --- a/poly_commit/src/kzg/bi_kzg/hyper_kzg_structs.rs +++ b/poly_commit/src/kzg/uni_kzg/structs_hyper_kzg.rs @@ -280,54 +280,3 @@ where self.neg_beta_y_evals.append_to_transcript(fs_transcript); } } - -#[derive(Debug, Clone, Derivative, ExpSerde)] -#[derivative(Default(bound = ""))] -pub struct HyperBiKZGOpening -where - E::Fr: ExpSerde, - E::G1Affine: Default + ExpSerde, -{ - pub folded_oracle_commitments: Vec, - - pub aggregated_evals: HyperKZGAggregatedEvals, - pub leader_evals: HyperKZGExportedLocalEvals, - - pub beta_x_commitment: E::G1Affine, - pub beta_y_commitment: E::G1Affine, - - pub quotient_delta_x_commitment: E::G1Affine, - pub quotient_delta_y_commitment: E::G1Affine, -} - -impl From> for HyperKZGOpening -where - E::Fr: ExpSerde, - E::G1Affine: Default + ExpSerde, -{ - fn from(value: HyperBiKZGOpening) -> Self { - Self { - folded_oracle_commitments: value.folded_oracle_commitments, - evals_at_x: value.leader_evals, - beta_x_commitment: value.beta_x_commitment, - quotient_delta_x_commitment: value.quotient_delta_x_commitment, - } - } -} - -impl From> for HyperBiKZGOpening -where - E::Fr: ExpSerde, - E::G1Affine: Default + ExpSerde, -{ - fn from(value: HyperKZGOpening) -> Self { - Self { - folded_oracle_commitments: value.folded_oracle_commitments, - leader_evals: value.evals_at_x, - beta_x_commitment: value.beta_x_commitment, - quotient_delta_x_commitment: value.quotient_delta_x_commitment, - - ..Default::default() - } - } -} diff --git a/poly_commit/src/kzg/uni_kzg/structs.rs b/poly_commit/src/kzg/uni_kzg/structs_kzg.rs similarity index 79% rename from poly_commit/src/kzg/uni_kzg/structs.rs rename to poly_commit/src/kzg/uni_kzg/structs_kzg.rs index 81c6e015..c05dec71 100644 --- a/poly_commit/src/kzg/uni_kzg/structs.rs +++ b/poly_commit/src/kzg/uni_kzg/structs_kzg.rs @@ -1,7 +1,7 @@ use derivative::Derivative; use gkr_engine::StructuredReferenceString; use halo2curves::{pairing::Engine, CurveAffine}; -use serdes::ExpSerde; +use serdes::{ExpSerde, SerdeResult}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Derivative)] #[derivative(Default(bound = ""))] @@ -9,6 +9,20 @@ pub struct KZGCommitment(pub E::G1Affine) where E::G1Affine: CurveAffine; +// Derive macros does not work for associated types +impl ExpSerde for KZGCommitment +where + E::G1Affine: ExpSerde + CurveAffine, +{ + fn serialize_into(&self, writer: W) -> SerdeResult<()> { + self.0.serialize_into(writer) + } + + fn deserialize_from(reader: R) -> SerdeResult { + Ok(Self(::deserialize_from(reader)?)) + } +} + /// Structured reference string for univariate KZG polynomial commitment scheme. /// The univariate polynomial here is of coefficient form. #[derive(Clone, Debug, PartialEq, Eq, Derivative, ExpSerde)] diff --git a/poly_commit/src/kzg/bi_kzg/univariate.rs b/poly_commit/src/kzg/uni_kzg/univariate.rs similarity index 100% rename from poly_commit/src/kzg/bi_kzg/univariate.rs rename to poly_commit/src/kzg/uni_kzg/univariate.rs diff --git a/poly_commit/src/kzg/bi_kzg/utils.rs b/poly_commit/src/kzg/utils.rs similarity index 100% rename from poly_commit/src/kzg/bi_kzg/utils.rs rename to poly_commit/src/kzg/utils.rs diff --git a/poly_commit/tests/test_bi_kzg.rs b/poly_commit/tests/test_bi_kzg.rs new file mode 100644 index 00000000..a7773c53 --- /dev/null +++ b/poly_commit/tests/test_bi_kzg.rs @@ -0,0 +1,99 @@ +mod common; + +use arith::{Field, Fr}; +use ark_std::test_rng; +use gkr_engine::ExpanderPCS; +use gkr_engine::{BN254Config, ExpanderSingleVarChallenge, MPIConfig, MPIEngine, Transcript}; +use gkr_hashers::Keccak256hasher; +use halo2curves::bn256::Bn256; +use poly_commit::{HyperBiKZGPCS, }; +use polynomials::MultiLinearPoly; +use transcript::BytesHashTranscript; + +const TEST_REPETITION: usize = 3; + +// fn test_hyperkzg_pcs_generics(num_vars_start: usize, num_vars_end: usize) { +// let mut rng = test_rng(); + +// (num_vars_start..=num_vars_end).for_each(|num_vars| { +// let xs: Vec<_> = (0..TEST_REPETITION) +// .map(|_| -> Vec { (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect() }) +// .collect(); +// let poly = MultiLinearPoly::::random(num_vars, &mut rng); + +// common::test_pcs::, HyperBiKZGPCS>( +// &num_vars, &poly, &xs, +// ); +// }) +// } + +// #[test] +// fn test_hyperkzg_pcs_full_e2e() { +// test_hyperkzg_pcs_generics(2, 15) +// } + +fn test_hyper_bikzg_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_num_vars: usize) { + let mut rng = test_rng(); + + // NOTE BN254 GKR SIMD pack size = 1, num vars in SIMD is 0 + let num_vars_in_mpi = mpi_config_ref.world_size().ilog2() as usize; + let num_vars_in_each_poly = total_num_vars - num_vars_in_mpi; + + let global_poly = MultiLinearPoly::::random(total_num_vars, &mut rng); + let challenge_point = ExpanderSingleVarChallenge:: { + r_mpi: (0..num_vars_in_mpi) + .map(|_| Fr::random_unsafe(&mut rng)) + .collect(), + r_simd: Vec::new(), + rz: (0..num_vars_in_each_poly) + .map(|_| Fr::random_unsafe(&mut rng)) + .collect(), + }; + + let mut transcript = BytesHashTranscript::::new(); + + // NOTE separate polynomial into different pieces by mpi rank + let poly_vars_stride = (1 << global_poly.get_num_vars()) / mpi_config_ref.world_size(); + let poly_coeff_starts = mpi_config_ref.world_rank() * poly_vars_stride; + let poly_coeff_ends = poly_coeff_starts + poly_vars_stride; + let local_poly = + MultiLinearPoly::new(global_poly.coeffs[poly_coeff_starts..poly_coeff_ends].to_vec()); + + dbg!(local_poly.get_num_vars(), local_poly.coeffs[0]); + + let params = as ExpanderPCS>::gen_params( + num_vars_in_each_poly, + mpi_config_ref.world_size(), + ); + common::test_pcs_for_expander_gkr::< + BN254Config, + BytesHashTranscript, + HyperBiKZGPCS, + >( + ¶ms, + mpi_config_ref, + &mut transcript, + &local_poly, + &[challenge_point], + ); +} + +#[test] +fn test_hyper_bikzg_for_expander_gkr() { + let mpi_config = MPIConfig::prover_new(); + + test_hyper_bikzg_for_expander_gkr_generics(&mpi_config, 1); + test_hyper_bikzg_for_expander_gkr_generics(&mpi_config, 15); + + MPIConfig::finalize() +} + +// #[test] +// fn test_kzg_batch_open() { +// common::test_batching::, HyperBiKZGPCS>(); +// // common::test_batching_for_expander_gkr::< +// // BN254Config, +// // BytesHashTranscript, +// // HyraxPCS, +// // >(); +// } diff --git a/poly_commit/tests/test_kzg.rs b/poly_commit/tests/test_uni_kzg.rs similarity index 85% rename from poly_commit/tests/test_kzg.rs rename to poly_commit/tests/test_uni_kzg.rs index 92b36df5..625c424e 100644 --- a/poly_commit/tests/test_kzg.rs +++ b/poly_commit/tests/test_uni_kzg.rs @@ -6,7 +6,7 @@ use gkr_engine::ExpanderPCS; use gkr_engine::{BN254Config, ExpanderSingleVarChallenge, MPIConfig, MPIEngine, Transcript}; use gkr_hashers::Keccak256hasher; use halo2curves::bn256::Bn256; -use poly_commit::HyperBiKZGPCS; +use poly_commit::HyperUniKZGPCS; use polynomials::MultiLinearPoly; use transcript::BytesHashTranscript; @@ -21,7 +21,7 @@ fn test_hyperkzg_pcs_generics(num_vars_start: usize, num_vars_end: usize) { .collect(); let poly = MultiLinearPoly::::random(num_vars, &mut rng); - common::test_pcs::, HyperBiKZGPCS>( + common::test_pcs::, HyperUniKZGPCS>( &num_vars, &poly, &xs, ); }) @@ -32,7 +32,7 @@ fn test_hyperkzg_pcs_full_e2e() { test_hyperkzg_pcs_generics(2, 15) } -fn test_hyper_bikzg_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_num_vars: usize) { +fn test_hyper_unikzg_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_num_vars: usize) { let mut rng = test_rng(); // NOTE BN254 GKR SIMD pack size = 1, num vars in SIMD is 0 @@ -61,14 +61,14 @@ fn test_hyper_bikzg_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_ dbg!(local_poly.get_num_vars(), local_poly.coeffs[0]); - let params = as ExpanderPCS>::gen_params( + let params = as ExpanderPCS>::gen_params( num_vars_in_each_poly, mpi_config_ref.world_size(), ); common::test_pcs_for_expander_gkr::< BN254Config, BytesHashTranscript, - HyperBiKZGPCS, + HyperUniKZGPCS, >( ¶ms, mpi_config_ref, @@ -79,18 +79,18 @@ fn test_hyper_bikzg_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_ } #[test] -fn test_hyper_bikzg_for_expander_gkr() { +fn test_hyper_unikzg_for_expander_gkr() { let mpi_config = MPIConfig::prover_new(); - test_hyper_bikzg_for_expander_gkr_generics(&mpi_config, 1); - test_hyper_bikzg_for_expander_gkr_generics(&mpi_config, 15); + test_hyper_unikzg_for_expander_gkr_generics(&mpi_config, 1); + test_hyper_unikzg_for_expander_gkr_generics(&mpi_config, 15); MPIConfig::finalize() } #[test] fn test_kzg_batch_open() { - common::test_batching::, HyperBiKZGPCS>(); + common::test_batching::, HyperUniKZGPCS>(); // common::test_batching_for_expander_gkr::< // BN254Config, // BytesHashTranscript, From 7dde99cda2d224e7d1e053fb2d30c60e55922b3f Mon Sep 17 00:00:00 2001 From: zhenfei Date: Fri, 30 May 2025 16:08:50 -0400 Subject: [PATCH 43/57] wip --- poly_commit/src/kzg/bi_kzg/hyper_bikzg.rs | 2 +- poly_commit/src/kzg/bi_kzg/hyper_bikzg_tests.rs | 2 +- poly_commit/src/kzg/bi_kzg/structs_hyper_bi_kzg.rs | 6 +++--- poly_commit/src/kzg/uni_kzg/batch.rs | 6 +++--- poly_commit/src/kzg/uni_kzg/expander_api.rs | 11 ++++++++--- poly_commit/src/kzg/uni_kzg/hyper_kzg.rs | 6 +++--- poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs | 2 +- poly_commit/src/kzg/uni_kzg/structs_hyper_kzg.rs | 2 +- 8 files changed, 21 insertions(+), 16 deletions(-) diff --git a/poly_commit/src/kzg/bi_kzg/hyper_bikzg.rs b/poly_commit/src/kzg/bi_kzg/hyper_bikzg.rs index 11706dc5..099260c9 100644 --- a/poly_commit/src/kzg/bi_kzg/hyper_bikzg.rs +++ b/poly_commit/src/kzg/bi_kzg/hyper_bikzg.rs @@ -462,7 +462,7 @@ where // NOTE(HS) deteriorate to vanilla HyperKZG verify if mpi_alphas is empty if mpi_alphas.is_empty() { let hyper_bikzg_opening = opening.clone(); - let hyper_kzg_opening: HyperKZGOpening = hyper_bikzg_opening.into(); + let hyper_kzg_opening: HyperUniKZGOpening = hyper_bikzg_opening.into(); let what = coeff_form_uni_hyperkzg_verify( &vk.into(), diff --git a/poly_commit/src/kzg/bi_kzg/hyper_bikzg_tests.rs b/poly_commit/src/kzg/bi_kzg/hyper_bikzg_tests.rs index b4c3bd2f..35d327a5 100644 --- a/poly_commit/src/kzg/bi_kzg/hyper_bikzg_tests.rs +++ b/poly_commit/src/kzg/bi_kzg/hyper_bikzg_tests.rs @@ -344,7 +344,7 @@ where // NOTE(HS) deteriorate to vanilla HyperKZG verify if mpi_alphas is empty if mpi_alphas.is_empty() { let hyper_bikzg_opening = opening.clone(); - let hyper_kzg_opening: HyperKZGOpening = hyper_bikzg_opening.into(); + let hyper_kzg_opening: HyperUniKZGOpening = hyper_bikzg_opening.into(); let what = coeff_form_uni_hyperkzg_verify( &vk.into(), diff --git a/poly_commit/src/kzg/bi_kzg/structs_hyper_bi_kzg.rs b/poly_commit/src/kzg/bi_kzg/structs_hyper_bi_kzg.rs index 11faf453..bae3ace4 100644 --- a/poly_commit/src/kzg/bi_kzg/structs_hyper_bi_kzg.rs +++ b/poly_commit/src/kzg/bi_kzg/structs_hyper_bi_kzg.rs @@ -28,7 +28,7 @@ where pub quotient_delta_y_commitment: E::G1Affine, } -impl From> for HyperKZGOpening +impl From> for HyperUniKZGOpening where E::Fr: ExpSerde, E::G1Affine: Default + ExpSerde, @@ -43,12 +43,12 @@ where } } -impl From> for HyperBiKZGOpening +impl From> for HyperBiKZGOpening where E::Fr: ExpSerde, E::G1Affine: Default + ExpSerde, { - fn from(value: HyperKZGOpening) -> Self { + fn from(value: HyperUniKZGOpening) -> Self { Self { folded_oracle_commitments: value.folded_oracle_commitments, leader_evals: value.evals_at_x, diff --git a/poly_commit/src/kzg/uni_kzg/batch.rs b/poly_commit/src/kzg/uni_kzg/batch.rs index 3d980e43..1f8d884f 100644 --- a/poly_commit/src/kzg/uni_kzg/batch.rs +++ b/poly_commit/src/kzg/uni_kzg/batch.rs @@ -7,7 +7,7 @@ use serdes::ExpSerde; use crate::{ coeff_form_uni_hyperkzg_open, coeff_form_uni_hyperkzg_verify, powers_series, CoefFormUniKZGSRS, - HyperKZGOpening, UniKZGVerifierParams, + HyperUniKZGOpening, UniKZGVerifierParams, }; pub fn kzg_single_point_batch_open( @@ -15,7 +15,7 @@ pub fn kzg_single_point_batch_open( polys: &[MultiLinearPoly], x: &[E::Fr], transcript: &mut impl Transcript, -) -> (Vec, HyperKZGOpening) +) -> (Vec, HyperUniKZGOpening) where E: MultiMillerLoop, E::G1Affine: CurveAffine + ExpSerde, @@ -59,7 +59,7 @@ pub fn kzg_single_point_batch_verify( commitments: &[E::G1Affine], x: &[E::Fr], evals: &[E::Fr], - opening: &HyperKZGOpening, + opening: &HyperUniKZGOpening, transcript: &mut impl Transcript, ) -> bool where diff --git a/poly_commit/src/kzg/uni_kzg/expander_api.rs b/poly_commit/src/kzg/uni_kzg/expander_api.rs index ff885db1..bdf28ea7 100644 --- a/poly_commit/src/kzg/uni_kzg/expander_api.rs +++ b/poly_commit/src/kzg/uni_kzg/expander_api.rs @@ -32,9 +32,9 @@ where const PCS_TYPE: PolynomialCommitmentType = PolynomialCommitmentType::KZG; type Commitment = KZGCommitment; - type Opening = HyperBiKZGOpening; + type Opening = HyperUniKZGOpening; type Params = usize; - type SRS = CoefFormBiKZGLocalSRS; + type SRS = CoefFormUniKZGSRS; type ScratchPad = (); type BatchOpening = BatchOpening; @@ -49,7 +49,12 @@ where mpi_engine: &impl MPIEngine, rng: impl rand::RngCore, ) -> Self::SRS { - todo!() + // todo!() + let local_num_vars = *params; + + let x_degree_po2 = 1 << local_num_vars; + generate_coef_form_uni_kzg_srs_for_testing(x_degree_po2, rng) + // let local_num_vars = *params; // let x_degree_po2 = 1 << local_num_vars; diff --git a/poly_commit/src/kzg/uni_kzg/hyper_kzg.rs b/poly_commit/src/kzg/uni_kzg/hyper_kzg.rs index 51fcd426..869e6169 100644 --- a/poly_commit/src/kzg/uni_kzg/hyper_kzg.rs +++ b/poly_commit/src/kzg/uni_kzg/hyper_kzg.rs @@ -111,7 +111,7 @@ pub fn coeff_form_uni_hyperkzg_open( coeffs: &[E::Fr], alphas: &[E::Fr], fs_transcript: &mut T, -) -> (E::Fr, HyperKZGOpening) +) -> (E::Fr, HyperUniKZGOpening) where E: MultiMillerLoop, E::G1Affine: CurveAffine + ExpSerde, @@ -162,7 +162,7 @@ where ( local_evals.multilinear_final_eval(), - HyperKZGOpening { + HyperUniKZGOpening { folded_oracle_commitments, evals_at_x: local_evals.into(), beta_x_commitment, @@ -177,7 +177,7 @@ pub fn coeff_form_uni_hyperkzg_verify( comm: E::G1Affine, alphas: &[E::Fr], eval: E::Fr, - opening: &HyperKZGOpening, + opening: &HyperUniKZGOpening, fs_transcript: &mut T, ) -> bool where diff --git a/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs index 08d6b3a7..fc8132ab 100644 --- a/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs @@ -41,7 +41,7 @@ where type SRS = CoefFormUniKZGSRS; type Commitment = KZGCommitment; - type Opening = HyperKZGOpening; + type Opening = HyperUniKZGOpening; fn init_scratch_pad(_params: &Self::Params) -> Self::ScratchPad {} diff --git a/poly_commit/src/kzg/uni_kzg/structs_hyper_kzg.rs b/poly_commit/src/kzg/uni_kzg/structs_hyper_kzg.rs index 5d02a5ae..79dce771 100644 --- a/poly_commit/src/kzg/uni_kzg/structs_hyper_kzg.rs +++ b/poly_commit/src/kzg/uni_kzg/structs_hyper_kzg.rs @@ -53,7 +53,7 @@ where #[derive(Clone, Debug, Derivative, ExpSerde)] #[derivative(Default(bound = ""))] -pub struct HyperKZGOpening +pub struct HyperUniKZGOpening where E::Fr: ExpSerde, E::G1Affine: Default + ExpSerde, From ebdb4e0ad89fb82553922969491ba49c5b042011 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Fri, 30 May 2025 17:57:53 -0400 Subject: [PATCH 44/57] refactor bikzg and unikzg --- poly_commit/src/kzg.rs | 5 +- poly_commit/src/kzg/bi_kzg/expander_api.rs | 44 +-- poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs | 278 ++++++------------ .../src/kzg/bi_kzg/structs_hyper_bi_kzg.rs | 7 +- poly_commit/src/kzg/structs.rs | 1 - poly_commit/src/kzg/uni_kzg.rs | 2 - poly_commit/src/kzg/uni_kzg/batch.rs | 4 +- poly_commit/src/kzg/uni_kzg/expander_api.rs | 214 +++++--------- poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs | 6 +- poly_commit/src/kzg/uni_kzg/structs_kzg.rs | 4 +- poly_commit/tests/common.rs | 1 + poly_commit/tests/test_bi_kzg.rs | 34 +-- poly_commit/tests/test_uni_kzg.rs | 10 +- 13 files changed, 194 insertions(+), 416 deletions(-) delete mode 100644 poly_commit/src/kzg/structs.rs diff --git a/poly_commit/src/kzg.rs b/poly_commit/src/kzg.rs index 964defe6..0e9c9798 100644 --- a/poly_commit/src/kzg.rs +++ b/poly_commit/src/kzg.rs @@ -4,8 +4,5 @@ pub use uni_kzg::*; mod bi_kzg; pub use bi_kzg::*; -mod structs; -pub use structs::*; - mod utils; -pub use utils::*; +pub(crate) use utils::*; diff --git a/poly_commit/src/kzg/bi_kzg/expander_api.rs b/poly_commit/src/kzg/bi_kzg/expander_api.rs index 0d6dcf9d..9df36c59 100644 --- a/poly_commit/src/kzg/bi_kzg/expander_api.rs +++ b/poly_commit/src/kzg/bi_kzg/expander_api.rs @@ -32,7 +32,7 @@ where const PCS_TYPE: PolynomialCommitmentType = PolynomialCommitmentType::KZG; - type Commitment = KZGCommitment; + type Commitment = BiKZGCommitment; type Opening = HyperBiKZGOpening; type Params = usize; type SRS = CoefFormBiKZGLocalSRS; @@ -83,7 +83,7 @@ where coeff_form_uni_kzg_commit(&proving_key.tau_x_srs, poly.hypercube_basis_ref()); if mpi_engine.is_single_process() { - return KZGCommitment(local_commitment).into(); + return BiKZGCommitment(local_commitment).into(); } let local_g1 = local_commitment.to_curve(); @@ -96,7 +96,7 @@ where let final_commit = root_gathering_commits.iter().sum::().into(); - KZGCommitment(final_commit).into() + BiKZGCommitment(final_commit).into() } fn open( @@ -167,42 +167,4 @@ where transcript, ) } - - // /// Open a set of polynomials at a point. - // fn batch_open( - // _params: &Self::Params, - // _mpi_engine: &impl MPIEngine, - // proving_key: &::PKey, - // mle_poly_list: &[impl MultilinearExtension], - // eval_point: &ExpanderSingleVarChallenge, - // _scratch_pad: &Self::ScratchPad, - // transcript: &mut impl Transcript, - // ) -> (Vec, Self::Opening) { - // let (eval, open) = kzg_batch_open( - // proving_key, - // mle_poly_list, - // &eval_point.local_xs(), - // transcript, - // ); - // (eval, open.into()) - // } - - // fn batch_verify( - // _params: &Self::Params, - // verifying_key: &::VKey, - // commitments: &[Self::Commitment], - // x: &ExpanderSingleVarChallenge, - // evals: &[::ChallengeField], - // opening: &Self::Opening, - // transcript: &mut impl Transcript, - // ) -> bool { - // kzg_batch_verify( - // verifying_key, - // commitments, - // &x.local_xs(), - // evals, - // opening, - // transcript, - // ) - // } } diff --git a/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs index e058b302..e7ca1f62 100644 --- a/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs @@ -7,14 +7,17 @@ use halo2curves::{ pairing::{Engine, MultiMillerLoop}, CurveAffine, }; -use polynomials::MultiLinearPoly; +use polynomials::{MultiLinearPoly, MultilinearExtension}; use serdes::ExpSerde; -use crate::batching::prover_merge_points; -use crate::batching::verifier_merge_points; use crate::{ - traits::{BatchOpening, BatchOpeningPCS}, - *, + coeff_form_uni_hyperkzg_open, coeff_form_uni_hyperkzg_verify, coeff_form_uni_kzg_commit, + HyperUniKZGOpening, PolynomialCommitmentScheme, +}; + +use super::{ + generate_coef_form_bi_kzg_local_srs_for_testing, BiKZGCommitment, CoefFormBiKZGLocalSRS, + HyperBiKZGOpening, }; pub struct HyperBiKZGPCS @@ -33,187 +36,84 @@ where pub const MINIMUM_SUPPORTED_NUM_VARS: usize = 2; } -// impl PolynomialCommitmentScheme for HyperBiKZGPCS -// where -// E: Engine + MultiMillerLoop, -// E::Fr: ExtensionField + PrimeField, -// E::G1Affine: ExpSerde + Default + CurveAffine, -// E::G2Affine: ExpSerde + Default + CurveAffine, -// { -// const NAME: &'static str = "HyperBiKZGPCS"; - -// type Params = usize; -// type Poly = MultiLinearPoly; -// type EvalPoint = Vec; -// type ScratchPad = (); - -// type SRS = CoefFormUniKZGSRS; -// type Commitment = KZGCommitment; -// type Opening = HyperKZGOpening; - -// fn init_scratch_pad(_params: &Self::Params) -> Self::ScratchPad {} - -// fn gen_srs_for_testing(params: &Self::Params, rng: impl rand::RngCore) -> (Self::SRS, usize) -// { let local_num_vars = if *params == 0 { 1 } else { *params }; - -// let length = 1 << local_num_vars; -// let srs = generate_coef_form_uni_kzg_srs_for_testing(length, rng); -// (srs, local_num_vars) -// } - -// fn commit( -// _params: &Self::Params, -// proving_key: &::PKey, -// poly: &Self::Poly, -// _scratch_pad: &mut Self::ScratchPad, -// ) -> Self::Commitment { -// KZGCommitment(coeff_form_uni_kzg_commit(proving_key, &poly.coeffs)) -// } - -// fn open( -// _params: &Self::Params, -// proving_key: &::PKey, -// poly: &Self::Poly, -// x: &Self::EvalPoint, -// _scratch_pad: &Self::ScratchPad, -// transcript: &mut impl Transcript, -// ) -> (E::Fr, Self::Opening) { -// coeff_form_uni_hyperkzg_open(proving_key, &poly.coeffs, x, transcript) -// } - -// fn verify( -// _params: &Self::Params, -// verifying_key: &::VKey, -// commitment: &Self::Commitment, -// x: &Self::EvalPoint, -// v: E::Fr, -// opening: &Self::Opening, -// transcript: &mut impl Transcript, -// ) -> bool { -// coeff_form_uni_hyperkzg_verify(verifying_key, commitment.0, x, v, opening, transcript) -// } -// } - -// impl BatchOpeningPCS for HyperBiKZGPCS -// where -// E: Engine + MultiMillerLoop, -// E::Fr: ExtensionField + PrimeField, -// E::G1Affine: ExpSerde + Default + CurveAffine, -// E::G2Affine: ExpSerde + Default + CurveAffine, -// { -// fn single_point_batch_open( -// _params: &Self::Params, -// proving_key: &::PKey, -// polys: &[Self::Poly], -// x: &Self::EvalPoint, -// _scratch_pad: &Self::ScratchPad, -// transcript: &mut impl Transcript, -// ) -> (Vec, Self::Opening) { -// kzg_single_point_batch_open(proving_key, polys, x, transcript) -// } - -// fn single_point_batch_verify( -// _params: &Self::Params, -// verifying_key: &::VKey, -// commitments: &[Self::Commitment], -// x: &Self::EvalPoint, -// evals: &[E::Fr], -// opening: &Self::Opening, -// transcript: &mut impl Transcript, -// ) -> bool { -// let commitment_unwrapped = commitments.iter().map(|c| c.0).collect::>(); - -// kzg_single_point_batch_verify( -// verifying_key, -// &commitment_unwrapped, -// x, -// evals, -// opening, -// transcript, -// ) -// } - -// /// Open a set of polynomials at a multiple points. -// /// Requires the length of the polys to be the same as points. -// /// Steps: -// /// 1. get challenge point t from transcript -// /// 2. build eq(t,i) for i in [0..k] -// /// 3. build \tilde g_i(b) = eq(t, i) * f_i(b) -// /// 4. compute \tilde eq_i(b) = eq(b, point_i) -// /// 5. run sumcheck on \sum_i=1..k \tilde eq_i * \tilde g_i -// /// 6. build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the sumcheck's -// /// point -// /// 7. open g'(X) at point (a2) -// /// -// /// Returns: -// /// - the evaluations of the polynomials at their corresponding points -// /// - the batch opening proof containing the sumcheck proof and the opening of g'(X) -// fn multiple_points_batch_open( -// _params: &Self::Params, -// proving_key: &::PKey, -// polys: &[Self::Poly], -// points: &[Self::EvalPoint], -// _scratch_pad: &Self::ScratchPad, -// transcript: &mut impl Transcript, -// ) -> (Vec, BatchOpening) { -// // generate evals for each polynomial at its corresponding point -// let evals: Vec = polys -// .iter() -// .zip(points.iter()) -// .map(|(poly, point)| poly.evaluate_jolt(point)) -// .collect(); - -// let (new_point, g_prime, proof) = -// prover_merge_points::(polys, points, transcript); - -// let (_g_prime_eval, g_prime_proof) = -// coeff_form_uni_hyperkzg_open(proving_key, &g_prime.coeffs, &new_point, transcript); -// ( -// evals, -// BatchOpening { -// sum_check_proof: proof, -// g_prime_proof, -// }, -// ) -// } - -// /// Verify the opening of a set of polynomials at a single point. -// /// Steps: -// /// 1. get challenge point t from transcript -// /// 2. build g' commitment -// /// 3. ensure \sum_i eq(a2, point_i) * eq(t, ) * f_i_evals matches the sum via SumCheck -// /// verification -// /// 4. verify commitment -// fn multiple_points_batch_verify( -// _params: &Self::Params, -// verifying_key: &::VKey, -// commitments: &[Self::Commitment], -// points: &[Self::EvalPoint], -// values: &[E::Fr], -// batch_opening: &BatchOpening, -// transcript: &mut impl Transcript, -// ) -> bool { -// // sum check point (a2) -// let a2 = batch_opening.sum_check_proof.export_point_to_expander(); - -// let commitments = commitments.iter().map(|c| vec![c.0]).collect::>(); - -// let (tilde_g_eval, g_prime_commit) = verifier_merge_points::( -// &commitments, -// points, -// values, -// &batch_opening.sum_check_proof, -// transcript, -// ); - -// // verify commitment -// coeff_form_uni_hyperkzg_verify( -// verifying_key, -// g_prime_commit[0], -// a2.as_ref(), -// tilde_g_eval, -// &batch_opening.g_prime_proof, -// transcript, -// ) -// } -// } +impl PolynomialCommitmentScheme for HyperBiKZGPCS +where + E: Engine + MultiMillerLoop, + E::Fr: ExtensionField + PrimeField, + E::G1Affine: ExpSerde + Default + CurveAffine, + E::G2Affine: ExpSerde + Default + CurveAffine, +{ + const NAME: &'static str = "HyperBiKZGPCS"; + + type Params = usize; + type Poly = MultiLinearPoly; + type EvalPoint = Vec; + type ScratchPad = (); + + type SRS = CoefFormBiKZGLocalSRS; + type Commitment = BiKZGCommitment; + type Opening = HyperBiKZGOpening; + + fn init_scratch_pad(_params: &Self::Params) -> Self::ScratchPad {} + + fn gen_srs_for_testing(params: &Self::Params, rng: impl rand::RngCore) -> (Self::SRS, usize) { + let local_num_vars = if *params == 0 { 1 } else { *params }; + + let length = 1 << local_num_vars; + let srs = generate_coef_form_bi_kzg_local_srs_for_testing(length, 1, 0, rng); + (srs, local_num_vars) + } + + fn commit( + _params: &Self::Params, + proving_key: &::PKey, + poly: &Self::Poly, + _scratch_pad: &mut Self::ScratchPad, + ) -> Self::Commitment { + let local_commitment = + coeff_form_uni_kzg_commit(&proving_key.tau_x_srs, poly.hypercube_basis_ref()); + + BiKZGCommitment(local_commitment).into() + } + + fn open( + _params: &Self::Params, + proving_key: &::PKey, + poly: &Self::Poly, + x: &Self::EvalPoint, + _scratch_pad: &Self::ScratchPad, + transcript: &mut impl Transcript, + ) -> (E::Fr, Self::Opening) { + let (eval, hyperkzg_opening) = coeff_form_uni_hyperkzg_open( + &proving_key.tau_x_srs, + poly.hypercube_basis_ref(), + x, + transcript, + ); + + let hyper_bikzg_opening: HyperBiKZGOpening = hyperkzg_opening.into(); + (eval, hyper_bikzg_opening) + } + + fn verify( + _params: &Self::Params, + verifying_key: &::VKey, + commitment: &Self::Commitment, + x: &Self::EvalPoint, + v: E::Fr, + opening: &Self::Opening, + transcript: &mut impl Transcript, + ) -> bool { + let hyper_bikzg_opening = opening.clone(); + let hyper_kzg_opening: HyperUniKZGOpening = hyper_bikzg_opening.into(); + + coeff_form_uni_hyperkzg_verify( + &verifying_key.into(), + commitment.0, + x, + v, + &hyper_kzg_opening, + transcript, + ) + } +} diff --git a/poly_commit/src/kzg/bi_kzg/structs_hyper_bi_kzg.rs b/poly_commit/src/kzg/bi_kzg/structs_hyper_bi_kzg.rs index bae3ace4..a16c84eb 100644 --- a/poly_commit/src/kzg/bi_kzg/structs_hyper_bi_kzg.rs +++ b/poly_commit/src/kzg/bi_kzg/structs_hyper_bi_kzg.rs @@ -1,10 +1,5 @@ -use std::ops::{Index, IndexMut}; - -use arith::ExtensionField; use derivative::Derivative; -use gkr_engine::Transcript; -use halo2curves::{ff::Field, pairing::Engine}; -use itertools::izip; +use halo2curves::pairing::Engine; use serdes::ExpSerde; use crate::*; diff --git a/poly_commit/src/kzg/structs.rs b/poly_commit/src/kzg/structs.rs deleted file mode 100644 index 8b137891..00000000 --- a/poly_commit/src/kzg/structs.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/poly_commit/src/kzg/uni_kzg.rs b/poly_commit/src/kzg/uni_kzg.rs index 6efc34ed..a19e0674 100644 --- a/poly_commit/src/kzg/uni_kzg.rs +++ b/poly_commit/src/kzg/uni_kzg.rs @@ -14,7 +14,5 @@ mod pcs_trait_impl; pub use pcs_trait_impl::*; mod expander_api; -pub use expander_api::*; mod batch; -pub use batch::{kzg_single_point_batch_open, kzg_single_point_batch_verify}; diff --git a/poly_commit/src/kzg/uni_kzg/batch.rs b/poly_commit/src/kzg/uni_kzg/batch.rs index 1f8d884f..709fb348 100644 --- a/poly_commit/src/kzg/uni_kzg/batch.rs +++ b/poly_commit/src/kzg/uni_kzg/batch.rs @@ -10,7 +10,7 @@ use crate::{ HyperUniKZGOpening, UniKZGVerifierParams, }; -pub fn kzg_single_point_batch_open( +pub(crate) fn kzg_single_point_batch_open( proving_key: &CoefFormUniKZGSRS, polys: &[MultiLinearPoly], x: &[E::Fr], @@ -54,7 +54,7 @@ where (evals, open) } -pub fn kzg_single_point_batch_verify( +pub(crate) fn kzg_single_point_batch_verify( verifying_key: &UniKZGVerifierParams, commitments: &[E::G1Affine], x: &[E::Fr], diff --git a/poly_commit/src/kzg/uni_kzg/expander_api.rs b/poly_commit/src/kzg/uni_kzg/expander_api.rs index bdf28ea7..a0e82e7a 100644 --- a/poly_commit/src/kzg/uni_kzg/expander_api.rs +++ b/poly_commit/src/kzg/uni_kzg/expander_api.rs @@ -5,19 +5,13 @@ use gkr_engine::{ }; use halo2curves::{ ff::PrimeField, - group::prime::PrimeCurveAffine, pairing::{Engine, MultiMillerLoop}, CurveAffine, }; -use polynomials::MultilinearExtension; +use polynomials::{MultiLinearPoly, MultilinearExtension}; use serdes::ExpSerde; -use crate::{ - traits::BatchOpening, utils::{ - lift_expander_challenge_to_n_vars, lift_poly_and_expander_challenge_to_n_vars, - lift_poly_to_n_vars, - }, * -}; +use crate::{traits::BatchOpening, *}; impl ExpanderPCS for HyperUniKZGPCS where @@ -31,7 +25,7 @@ where const PCS_TYPE: PolynomialCommitmentType = PolynomialCommitmentType::KZG; - type Commitment = KZGCommitment; + type Commitment = UniKZGCommitment; type Opening = HyperUniKZGOpening; type Params = usize; type SRS = CoefFormUniKZGSRS; @@ -41,107 +35,46 @@ where fn init_scratch_pad(_params: &Self::Params, _mpi_engine: &impl MPIEngine) -> Self::ScratchPad {} fn gen_params(n_input_vars: usize, _world_size: usize) -> Self::Params { - n_input_vars + n_input_vars } fn gen_srs_for_testing( params: &Self::Params, - mpi_engine: &impl MPIEngine, + _mpi_engine: &impl MPIEngine, rng: impl rand::RngCore, ) -> Self::SRS { - // todo!() - let local_num_vars = *params; - - let x_degree_po2 = 1 << local_num_vars; - generate_coef_form_uni_kzg_srs_for_testing(x_degree_po2, rng) - - // let local_num_vars = *params; - - // let x_degree_po2 = 1 << local_num_vars; - // let y_degree_po2 = mpi_engine.world_size(); - // let rank = mpi_engine.world_rank(); - - // generate_coef_form_bi_kzg_local_srs_for_testing(x_degree_po2, y_degree_po2, rank, rng) + let size = 1 << *params; + generate_coef_form_uni_kzg_srs_for_testing(size, rng) } fn commit( _params: &Self::Params, - mpi_engine: &impl MPIEngine, + _mpi_engine: &impl MPIEngine, proving_key: &::PKey, poly: &impl polynomials::MultilinearExtension, _scratch_pad: &mut Self::ScratchPad, ) -> Option { - todo!() - - // // The minimum supported number of variables is 1. - // // If the polynomial has no variables, we lift it to a polynomial with 1 variable. - // if poly.num_vars() < Self::MINIMUM_SUPPORTED_NUM_VARS { - // let poly = lift_poly_to_n_vars(poly, Self::MINIMUM_SUPPORTED_NUM_VARS); - // return >::commit( - // _params, - // mpi_engine, - // proving_key, - // &poly, - // _scratch_pad, - // ); - // }; - - // let local_commitment = - // coeff_form_uni_kzg_commit(&proving_key.tau_x_srs, poly.hypercube_basis_ref()); - - // if mpi_engine.is_single_process() { - // return KZGCommitment(local_commitment).into(); - // } - - // let local_g1 = local_commitment.to_curve(); - // let mut root_gathering_commits: Vec = vec![local_g1; mpi_engine.world_size()]; - // mpi_engine.gather_vec(&[local_g1], &mut root_gathering_commits); - - // if !mpi_engine.is_root() { - // return None; - // } - - // let final_commit = root_gathering_commits.iter().sum::().into(); - - // KZGCommitment(final_commit).into() + let commitment = coeff_form_uni_kzg_commit(&proving_key, poly.hypercube_basis_ref()); + Some(UniKZGCommitment(commitment)) } fn open( _params: &Self::Params, - mpi_engine: &impl MPIEngine, + _mpi_engine: &impl MPIEngine, proving_key: &::PKey, poly: &impl MultilinearExtension, x: &ExpanderSingleVarChallenge, transcript: &mut impl Transcript, _scratch_pad: &Self::ScratchPad, ) -> Option { - // if poly.num_vars() < Self::MINIMUM_SUPPORTED_NUM_VARS { - // let (poly, x) = lift_poly_and_expander_challenge_to_n_vars( - // poly, - // x, - // Self::MINIMUM_SUPPORTED_NUM_VARS, - // ); - // return >::open( - // _params, - // mpi_engine, - // proving_key, - // &poly, - // &x, - // transcript, - // _scratch_pad, - // ); - // }; - - // coeff_form_hyper_bikzg_open( - // proving_key, - // mpi_engine, - // poly, - // &x.local_xs(), - // &x.r_mpi, - // transcript, - // ) - todo!() - + let (_eval, open) = coeff_form_uni_hyperkzg_open( + proving_key, + &poly.hypercube_basis_ref(), + &x.local_xs(), + transcript, + ); + + Some(open) } fn verify( @@ -153,66 +86,57 @@ where transcript: &mut impl Transcript, opening: &Self::Opening, ) -> bool { - todo!() - // if x.rz.len() < Self::MINIMUM_SUPPORTED_NUM_VARS { - // let x = lift_expander_challenge_to_n_vars(x, Self::MINIMUM_SUPPORTED_NUM_VARS); - // return >::verify( - // _params, - // verifying_key, - // commitment, - // &x, - // v, - // transcript, - // opening, - // ); - // }; - - // coeff_form_hyper_bikzg_verify( - // verifying_key, - // &x.local_xs(), - // &x.r_mpi, - // v, - // commitment.0, - // opening, - // transcript, - // ) + coeff_form_uni_hyperkzg_verify( + verifying_key, + commitment.0, + &x.local_xs(), + v, + opening, + transcript, + ) } - // /// Open a set of polynomials at a point. - // fn batch_open( - // _params: &Self::Params, - // _mpi_engine: &impl MPIEngine, - // proving_key: &::PKey, - // mle_poly_list: &[impl MultilinearExtension], - // eval_point: &ExpanderSingleVarChallenge, - // _scratch_pad: &Self::ScratchPad, - // transcript: &mut impl Transcript, - // ) -> (Vec, Self::Opening) { - // let (eval, open) = kzg_batch_open( - // proving_key, - // mle_poly_list, - // &eval_point.local_xs(), - // transcript, - // ); - // (eval, open.into()) - // } + /// Open a set of polynomials at a point. + fn multi_points_batch_open( + params: &Self::Params, + _mpi_engine: &impl MPIEngine, + proving_key: &::PKey, + polys: &[MultiLinearPoly], + x: &[ExpanderSingleVarChallenge], + scratch_pad: &Self::ScratchPad, + transcript: &mut impl Transcript, + ) -> (Vec, Self::BatchOpening) { + let points: Vec> = x.iter().map(|p| p.local_xs()).collect(); + + >::multiple_points_batch_open( + params, + proving_key, + polys, + points.as_ref(), + scratch_pad, + transcript, + ) + } - // fn batch_verify( - // _params: &Self::Params, - // verifying_key: &::VKey, - // commitments: &[Self::Commitment], - // x: &ExpanderSingleVarChallenge, - // evals: &[::ChallengeField], - // opening: &Self::Opening, - // transcript: &mut impl Transcript, - // ) -> bool { - // kzg_batch_verify( - // verifying_key, - // commitments, - // &x.local_xs(), - // evals, - // opening, - // transcript, - // ) - // } + fn multi_points_batch_verify( + params: &Self::Params, + verifying_key: &::VKey, + commitments: &[Self::Commitment], + x: &[ExpanderSingleVarChallenge], + evals: &[E::Fr], + batch_opening: &Self::BatchOpening, + transcript: &mut impl Transcript, + ) -> bool { + let points: Vec> = x.iter().map(|p| p.local_xs()).collect(); + + >::multiple_points_batch_verify( + params, + verifying_key, + commitments, + points.as_ref(), + evals, + batch_opening, + transcript, + ) + } } diff --git a/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs index fc8132ab..72b18b35 100644 --- a/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs @@ -17,6 +17,8 @@ use crate::{ *, }; +use super::batch::{kzg_single_point_batch_open, kzg_single_point_batch_verify}; + pub struct HyperUniKZGPCS where E: Engine, @@ -40,7 +42,7 @@ where type ScratchPad = (); type SRS = CoefFormUniKZGSRS; - type Commitment = KZGCommitment; + type Commitment = UniKZGCommitment; type Opening = HyperUniKZGOpening; fn init_scratch_pad(_params: &Self::Params) -> Self::ScratchPad {} @@ -59,7 +61,7 @@ where poly: &Self::Poly, _scratch_pad: &mut Self::ScratchPad, ) -> Self::Commitment { - KZGCommitment(coeff_form_uni_kzg_commit(proving_key, &poly.coeffs)) + UniKZGCommitment(coeff_form_uni_kzg_commit(proving_key, &poly.coeffs)) } fn open( diff --git a/poly_commit/src/kzg/uni_kzg/structs_kzg.rs b/poly_commit/src/kzg/uni_kzg/structs_kzg.rs index c05dec71..5ba06574 100644 --- a/poly_commit/src/kzg/uni_kzg/structs_kzg.rs +++ b/poly_commit/src/kzg/uni_kzg/structs_kzg.rs @@ -5,12 +5,12 @@ use serdes::{ExpSerde, SerdeResult}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Derivative)] #[derivative(Default(bound = ""))] -pub struct KZGCommitment(pub E::G1Affine) +pub struct UniKZGCommitment(pub E::G1Affine) where E::G1Affine: CurveAffine; // Derive macros does not work for associated types -impl ExpSerde for KZGCommitment +impl ExpSerde for UniKZGCommitment where E::G1Affine: ExpSerde + CurveAffine, { diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index acae655f..b80acbd6 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -8,6 +8,7 @@ use poly_commit::{BatchOpeningPCS, PolynomialCommitmentScheme}; use polynomials::{MultiLinearPoly, MultilinearExtension}; use rand::thread_rng; +#[allow(dead_code)] pub fn test_pcs>( params: &P::Params, poly: &P::Poly, diff --git a/poly_commit/tests/test_bi_kzg.rs b/poly_commit/tests/test_bi_kzg.rs index a7773c53..4b2a5787 100644 --- a/poly_commit/tests/test_bi_kzg.rs +++ b/poly_commit/tests/test_bi_kzg.rs @@ -6,31 +6,31 @@ use gkr_engine::ExpanderPCS; use gkr_engine::{BN254Config, ExpanderSingleVarChallenge, MPIConfig, MPIEngine, Transcript}; use gkr_hashers::Keccak256hasher; use halo2curves::bn256::Bn256; -use poly_commit::{HyperBiKZGPCS, }; +use poly_commit::HyperBiKZGPCS; use polynomials::MultiLinearPoly; use transcript::BytesHashTranscript; const TEST_REPETITION: usize = 3; -// fn test_hyperkzg_pcs_generics(num_vars_start: usize, num_vars_end: usize) { -// let mut rng = test_rng(); +fn test_hyperkzg_pcs_generics(num_vars_start: usize, num_vars_end: usize) { + let mut rng = test_rng(); -// (num_vars_start..=num_vars_end).for_each(|num_vars| { -// let xs: Vec<_> = (0..TEST_REPETITION) -// .map(|_| -> Vec { (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect() }) -// .collect(); -// let poly = MultiLinearPoly::::random(num_vars, &mut rng); + (num_vars_start..=num_vars_end).for_each(|num_vars| { + let xs: Vec<_> = (0..TEST_REPETITION) + .map(|_| -> Vec { (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect() }) + .collect(); + let poly = MultiLinearPoly::::random(num_vars, &mut rng); -// common::test_pcs::, HyperBiKZGPCS>( -// &num_vars, &poly, &xs, -// ); -// }) -// } + common::test_pcs::, HyperBiKZGPCS>( + &num_vars, &poly, &xs, + ); + }) +} -// #[test] -// fn test_hyperkzg_pcs_full_e2e() { -// test_hyperkzg_pcs_generics(2, 15) -// } +#[test] +fn test_hyperkzg_pcs_full_e2e() { + test_hyperkzg_pcs_generics(2, 15) +} fn test_hyper_bikzg_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_num_vars: usize) { let mut rng = test_rng(); diff --git a/poly_commit/tests/test_uni_kzg.rs b/poly_commit/tests/test_uni_kzg.rs index 625c424e..0c5f38cd 100644 --- a/poly_commit/tests/test_uni_kzg.rs +++ b/poly_commit/tests/test_uni_kzg.rs @@ -91,9 +91,9 @@ fn test_hyper_unikzg_for_expander_gkr() { #[test] fn test_kzg_batch_open() { common::test_batching::, HyperUniKZGPCS>(); - // common::test_batching_for_expander_gkr::< - // BN254Config, - // BytesHashTranscript, - // HyraxPCS, - // >(); + common::test_batching_for_expander_gkr::< + BN254Config, + BytesHashTranscript, + HyperUniKZGPCS, + >(); } From 8257bf5df727ed6a6c02db3a97e6c96ac19cef95 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Fri, 30 May 2025 18:31:10 -0400 Subject: [PATCH 45/57] performance tuning --- poly_commit/benches/pcs_all.rs | 32 ++++++++------- poly_commit/src/batching.rs | 47 +++++++++++++++++------ poly_commit/src/kzg/uni_kzg/univariate.rs | 12 +----- 3 files changed, 56 insertions(+), 35 deletions(-) diff --git a/poly_commit/benches/pcs_all.rs b/poly_commit/benches/pcs_all.rs index d6698fad..7b7c6f44 100644 --- a/poly_commit/benches/pcs_all.rs +++ b/poly_commit/benches/pcs_all.rs @@ -6,7 +6,7 @@ use gkr_engine::{root_println, MPIConfig, MPIEngine, Transcript}; use gkr_hashers::{Keccak256hasher, SHA256hasher}; use halo2curves::bn256::{Bn256, G1Affine}; use poly_commit::{ - BatchOpeningPCS, HyperBiKZGPCS, HyraxPCS, OrionBaseFieldPCS, PolynomialCommitmentScheme, + BatchOpeningPCS, HyperUniKZGPCS, HyraxPCS, OrionBaseFieldPCS, PolynomialCommitmentScheme, }; use polynomials::MultiLinearPoly; use rand::RngCore; @@ -97,12 +97,12 @@ fn bench_hyrax(mpi_config: &MPIConfig, num_vars: usize) { fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { // full scalar let mut rng = test_rng(); - let (srs, _) = HyperBiKZGPCS::::gen_srs_for_testing(&num_vars, &mut rng); + let (srs, _) = HyperUniKZGPCS::::gen_srs_for_testing(&num_vars, &mut rng); let poly = MultiLinearPoly::::random(num_vars, &mut rng); let eval_point: Vec<_> = (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(); - pcs_bench::>( + pcs_bench::>( mpi_config, &num_vars, &srs, @@ -116,7 +116,7 @@ fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { .map(|_| Fr::from(rng.next_u32())) .collect::>(); let poly = MultiLinearPoly::::new(input); - pcs_bench::>( + pcs_bench::>( mpi_config, &num_vars, &srs, @@ -126,7 +126,7 @@ fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { ); // batch open - bench_batch_open::>(mpi_config, num_vars, NUM_POLY_BATCH_OPEN); + bench_batch_open::>(mpi_config, num_vars, NUM_POLY_BATCH_OPEN); } fn pcs_bench>( @@ -216,6 +216,15 @@ where let polys = (0..num_poly) .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) .collect::>(); + + let points = (0..num_poly) + .map(|_| { + (0..num_vars) + .map(|_| F::random_unsafe(&mut rng)) + .collect::>() + }) + .collect::>(); + let commitments = polys .iter() .map(|poly| PCS::commit(&num_vars, &proving_key, poly, &mut scratch_pad)) @@ -224,21 +233,16 @@ where commitments.serialize_into(&mut buf).unwrap(); let com_size = buf.len(); - // open all polys at a single point - let x = (0..num_vars) - .map(|_| F::random_unsafe(&mut rng)) - .collect::>(); - let mut transcript = BytesHashTranscript::::new(); let timer = Timer::new( format!("{} batch open {} polys ", PCS::NAME, num_poly).as_ref(), mpi_config.is_root(), ); - let (values, batch_opening) = PCS::single_point_batch_open( + let (values, batch_opening) = PCS::multiple_points_batch_open( &num_vars, &proving_key, &polys, - &x, + &points, &mut scratch_pad, &mut transcript, ); @@ -255,11 +259,11 @@ where format!("{} batch verify {} polys ", PCS::NAME, num_poly).as_ref(), mpi_config.is_root(), ); - assert!(PCS::single_point_batch_verify( + assert!(PCS::multiple_points_batch_verify( &num_vars, &verification_key, &commitments, - &x, + &points, &values, &batch_opening, &mut transcript diff --git a/poly_commit/src/batching.rs b/poly_commit/src/batching.rs index f7dc09af..79bf175f 100644 --- a/poly_commit/src/batching.rs +++ b/poly_commit/src/batching.rs @@ -3,6 +3,7 @@ use arith::{ExtensionField, Field}; use ark_std::log2; use gkr_engine::Transcript; use halo2curves::group::Curve; +use halo2curves::msm::best_multiexp; use halo2curves::{ff::PrimeField, CurveAffine}; use polynomials::MultiLinearPoly; use polynomials::{EqPolynomial, MultilinearExtension}; @@ -111,19 +112,23 @@ where let eq_t_i = EqPolynomial::build_eq_x_r(&t); // build g' commitment + let bases = commitments.iter().map(|c| c.as_ref()).collect::>(); + let bases_transposed = transpose::(&bases); - // todo: use MSM - // let mut scalars = vec![]; - // let mut bases = vec![]; + let scalars = points + .iter() + .enumerate() + .map(|(i, p)| { + let eq_i_a2 = EqPolynomial::eq_vec(a2.as_ref(), p); + eq_i_a2 * eq_t_i[i] + }) + .collect::>(); + + let g_prime_commit_elems = bases_transposed + .iter() + .map(|base| best_multiexp(&scalars, base)) + .collect::>(); - let mut g_prime_commit_elems = vec![C::Curve::default(); commitments[0].as_ref().len()]; - for (i, point) in points.iter().enumerate() { - let eq_i_a2 = EqPolynomial::eq_vec(a2.as_ref(), point); - let scalar = eq_i_a2 * eq_t_i[i]; - for (j, &base) in commitments[i].as_ref().iter().enumerate() { - g_prime_commit_elems[j] += base * scalar; - } - } let mut g_prime_commit_affine = vec![C::default(); commitments[0].as_ref().len()]; C::Curve::batch_normalize(&g_prime_commit_elems, &mut g_prime_commit_affine); @@ -139,3 +144,23 @@ where (tilde_g_eval, g_prime_commit_affine) } + +#[inline] +fn transpose(m: &[&[C]]) -> Vec> { + if m.is_empty() || m[0].is_empty() { + return Vec::new(); + } + + let rows = m.len(); + let cols = m[0].len(); + + let mut transposed = vec![Vec::with_capacity(rows); cols]; + + for i in 0..rows { + for j in 0..cols { + transposed[j].push(m[i][j]); + } + } + + transposed +} diff --git a/poly_commit/src/kzg/uni_kzg/univariate.rs b/poly_commit/src/kzg/uni_kzg/univariate.rs index 5d8a6d7a..7b26c8fd 100644 --- a/poly_commit/src/kzg/uni_kzg/univariate.rs +++ b/poly_commit/src/kzg/uni_kzg/univariate.rs @@ -55,11 +55,7 @@ where { assert!(srs.powers_of_tau.len() >= coeffs.len()); - let mut com = E::G1::generator() * E::Fr::ZERO; - // let timer = ::utils::timer::Timer::new(format!("kzg commit msm {}", coeffs.len()).as_ref(), - // true); - msm::multiexp_serial(coeffs, &srs.powers_of_tau[..coeffs.len()], &mut com); - // timer.stop(); + let com = msm::best_multiexp(coeffs, &srs.powers_of_tau[..coeffs.len()]); com.into() } @@ -77,11 +73,7 @@ where assert!(srs.powers_of_tau.len() >= coeffs.len()); let (div, eval) = univariate_degree_one_quotient(coeffs, alpha); - let mut opening = E::G1::generator() * E::Fr::ZERO; - - // let timer = ::utils::timer::Timer::new(format!("kzg open msm {}", div.len()).as_ref(), true); - msm::multiexp_serial(&div, &srs.powers_of_tau[..div.len()], &mut opening); - // timer.stop(); + let opening = msm::best_multiexp(&div, &srs.powers_of_tau[..div.len()]); (eval, opening.into()) } From 9ec57e5f43214d95e27a0fd766f52868085d8440 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Fri, 30 May 2025 19:13:53 -0400 Subject: [PATCH 46/57] mirco benches --- Cargo.lock | 2 + poly_commit/Cargo.toml | 12 ++- poly_commit/src/batching.rs | 77 ++++++++++----- poly_commit/src/hyrax/hyrax_impl.rs | 12 +++ poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs | 2 +- poly_commit/src/kzg/uni_kzg/expander_api.rs | 4 +- poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs | 15 ++- poly_commit/tests/test_bi_kzg.rs | 24 ++--- poly_commit/tests/test_uni_kzg.rs | 4 +- sumcheck/Cargo.toml | 1 + sumcheck/src/sumcheck_generic/prover.rs | 93 ++++++++++++++----- 11 files changed, 171 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9d5d8390..86096626 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1754,6 +1754,7 @@ dependencies = [ "mersenne31", "polynomials", "rand", + "rayon", "serdes", "sumcheck", "thiserror", @@ -2170,6 +2171,7 @@ dependencies = [ "gkr_hashers", "log", "polynomials", + "rayon", "serdes", "transcript", "utils", diff --git a/poly_commit/Cargo.toml b/poly_commit/Cargo.toml index 8655622a..9404942e 100644 --- a/poly_commit/Cargo.toml +++ b/poly_commit/Cargo.toml @@ -14,14 +14,15 @@ tree = { path = "../tree" } utils = { path = "../utils" } sumcheck = { path = "../sumcheck" } -rand.workspace = true ethnum.workspace = true ark-std.workspace = true -thiserror.workspace = true -itertools.workspace = true derivative.workspace = true -transpose.workspace = true halo2curves.workspace = true +itertools.workspace = true +rand.workspace = true +rayon.workspace = true +transpose.workspace = true +thiserror.workspace = true [dev-dependencies] gf2_128 = { path = "../arith/gf2_128" } @@ -49,5 +50,6 @@ name = "pcs_all" harness = false [features] -default = [ "profile" ] +default = [ ] +# default = [ "profile" ] profile = [ "utils/profile" ] \ No newline at end of file diff --git a/poly_commit/src/batching.rs b/poly_commit/src/batching.rs index 79bf175f..48705b3b 100644 --- a/poly_commit/src/batching.rs +++ b/poly_commit/src/batching.rs @@ -1,4 +1,5 @@ //! Multi-points batch opening +//! Uses Rayon to parallelize the computation. use arith::{ExtensionField, Field}; use ark_std::log2; use gkr_engine::Transcript; @@ -7,8 +8,12 @@ use halo2curves::msm::best_multiexp; use halo2curves::{ff::PrimeField, CurveAffine}; use polynomials::MultiLinearPoly; use polynomials::{EqPolynomial, MultilinearExtension}; +use rayon::iter::{ + IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, ParallelIterator, +}; use serdes::ExpSerde; use sumcheck::{IOPProof, SumCheck, SumOfProductsPoly}; +use utils::timer::Timer; /// Merge a list of polynomials and its corresponding points into a single polynomial /// Returns @@ -41,49 +46,79 @@ where let eq_t_i = EqPolynomial::build_eq_x_r(&t); // \tilde g_i(b) = eq(t, i) * f_i(b) - let mut tilde_gs = vec![]; - for (index, f_i) in polys.iter().enumerate() { - let mut tilde_g_eval = vec![C::Scalar::zero(); 1 << num_vars]; - for (j, &f_i_eval) in f_i.coeffs.iter().enumerate() { - tilde_g_eval[j] = f_i_eval * eq_t_i[index]; - } - tilde_gs.push(MultiLinearPoly { - coeffs: tilde_g_eval, - }); - } + let timer = Timer::new("Building tilde g_i(b)", true); + + let tilde_gs = polys + .par_iter() + .enumerate() + .map(|(index, f_i)| { + let mut tilde_g_eval = vec![C::Scalar::zero(); 1 << num_vars]; + for (j, &f_i_eval) in f_i.coeffs.iter().enumerate() { + tilde_g_eval[j] = f_i_eval * eq_t_i[index]; + } + + MultiLinearPoly { + coeffs: tilde_g_eval, + } + }) + .collect::>(); + timer.stop(); // built the virtual polynomial for SumCheck + let timer = Timer::new("Building tilde eqs", true); let tilde_eqs: Vec> = points - .iter() + .par_iter() .map(|point| { let eq_b_zi = EqPolynomial::build_eq_x_r(point); MultiLinearPoly { coeffs: eq_b_zi } }) .collect(); + timer.stop(); + let timer = Timer::new("Sumcheck merging points", true); let mut sumcheck_poly = SumOfProductsPoly::new(); for (tilde_g, tilde_eq) in tilde_gs.iter().zip(tilde_eqs.into_iter()) { sumcheck_poly.add_pair(tilde_g.clone(), tilde_eq); } - let proof = SumCheck::::prove(&sumcheck_poly, transcript); + timer.stop(); let a2 = proof.export_point_to_expander(); // build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the // sumcheck's point \tilde eq_i(a2) = eq(a2, point_i) - let mut g_prime_evals = vec![C::Scalar::zero(); 1 << num_vars]; + let timer = Timer::new("Building g'(X)", true); + let g_prime_evals: Vec = (0..(1 << num_vars)) + .into_par_iter() + .map(|j| { + tilde_gs + .par_iter() + .zip(points.par_iter()) + .map(|(tilde_g, point)| { + let eq_i_a2 = EqPolynomial::eq_vec(a2.as_ref(), point); + + tilde_g.coeffs[j] * eq_i_a2 + }) + .sum() + }) + .collect(); - for (tilde_g, point) in tilde_gs.iter().zip(points.iter()) { - let eq_i_a2 = EqPolynomial::eq_vec(a2.as_ref(), point); - for (j, &tilde_g_eval) in tilde_g.coeffs.iter().enumerate() { - g_prime_evals[j] += tilde_g_eval * eq_i_a2; - } - } let g_prime = MultiLinearPoly { coeffs: g_prime_evals, }; + // let mut g_prime_evals = vec![C::Scalar::zero(); 1 << num_vars]; + + // for (tilde_g, point) in tilde_gs.iter().zip(points.iter()) { + // let eq_i_a2 = EqPolynomial::eq_vec(a2.as_ref(), point); + // for (j, &tilde_g_eval) in tilde_g.coeffs.iter().enumerate() { + // g_prime_evals[j] += tilde_g_eval * eq_i_a2; + // } + // } + // let g_prime = MultiLinearPoly { + // coeffs: g_prime_evals, + // }; + timer.stop(); (a2, g_prime, proof) } @@ -156,9 +191,9 @@ fn transpose(m: &[&[C]]) -> Vec> { let mut transposed = vec![Vec::with_capacity(rows); cols]; - for i in 0..rows { + for row in m.iter() { for j in 0..cols { - transposed[j].push(m[i][j]); + transposed[j].push(row[j]); } } diff --git a/poly_commit/src/hyrax/hyrax_impl.rs b/poly_commit/src/hyrax/hyrax_impl.rs index b36192e2..e10f530b 100644 --- a/poly_commit/src/hyrax/hyrax_impl.rs +++ b/poly_commit/src/hyrax/hyrax_impl.rs @@ -7,6 +7,7 @@ use polynomials::{ RefMultiLinearPoly, }; use serdes::ExpSerde; +use utils::timer::Timer; use crate::batching::{prover_merge_points, verifier_merge_points}; use crate::traits::BatchOpening; @@ -277,16 +278,27 @@ where C::Scalar: ExtensionField + PrimeField, C::ScalarExt: ExtensionField + PrimeField, { + let timer = Timer::new("batch_opening", true); // generate evals for each polynomial at its corresponding point + let eval_timer = Timer::new("eval all polys", true); let evals: Vec = polys .iter() .zip(points.iter()) .map(|(poly, point)| poly.evaluate_jolt(point)) .collect(); + eval_timer.stop(); + let merger_timer = Timer::new("merging points", true); let (new_point, g_prime, proof) = prover_merge_points::(polys, points, transcript); + merger_timer.stop(); + // open g'(X) at point (a2) + // g_prime is a MultiLinearPoly, so we can use the hyrax_open function + let pcs_timer = Timer::new("hyrax_open", true); let (_g_prime_eval, g_prime_proof) = hyrax_open(proving_key, &g_prime, &new_point); + pcs_timer.stop(); + + timer.stop(); ( evals, BatchOpening { diff --git a/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs index e7ca1f62..86b39ff4 100644 --- a/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs @@ -73,7 +73,7 @@ where let local_commitment = coeff_form_uni_kzg_commit(&proving_key.tau_x_srs, poly.hypercube_basis_ref()); - BiKZGCommitment(local_commitment).into() + BiKZGCommitment(local_commitment) } fn open( diff --git a/poly_commit/src/kzg/uni_kzg/expander_api.rs b/poly_commit/src/kzg/uni_kzg/expander_api.rs index a0e82e7a..0cf78160 100644 --- a/poly_commit/src/kzg/uni_kzg/expander_api.rs +++ b/poly_commit/src/kzg/uni_kzg/expander_api.rs @@ -54,7 +54,7 @@ where poly: &impl polynomials::MultilinearExtension, _scratch_pad: &mut Self::ScratchPad, ) -> Option { - let commitment = coeff_form_uni_kzg_commit(&proving_key, poly.hypercube_basis_ref()); + let commitment = coeff_form_uni_kzg_commit(proving_key, poly.hypercube_basis_ref()); Some(UniKZGCommitment(commitment)) } @@ -69,7 +69,7 @@ where ) -> Option { let (_eval, open) = coeff_form_uni_hyperkzg_open( proving_key, - &poly.hypercube_basis_ref(), + poly.hypercube_basis_ref(), &x.local_xs(), transcript, ); diff --git a/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs index 72b18b35..d8a003e3 100644 --- a/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs @@ -1,5 +1,6 @@ use std::marker::PhantomData; +use ::utils::timer::Timer; use arith::ExtensionField; use gkr_engine::{StructuredReferenceString, Transcript}; use halo2curves::{ @@ -8,6 +9,7 @@ use halo2curves::{ CurveAffine, }; use polynomials::MultiLinearPoly; +use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use serdes::ExpSerde; use crate::batching::prover_merge_points; @@ -150,18 +152,27 @@ where _scratch_pad: &Self::ScratchPad, transcript: &mut impl Transcript, ) -> (Vec, BatchOpening) { + let timer = Timer::new("batch_opening", true); // generate evals for each polynomial at its corresponding point + let eval_timer = Timer::new("eval all polys", true); let evals: Vec = polys - .iter() - .zip(points.iter()) + .par_iter() + .zip_eq(points.par_iter()) .map(|(poly, point)| poly.evaluate_jolt(point)) .collect(); + eval_timer.stop(); + let merger_timer = Timer::new("merging points", true); let (new_point, g_prime, proof) = prover_merge_points::(polys, points, transcript); + merger_timer.stop(); + let pcs_timer = Timer::new("kzg_open", true); let (_g_prime_eval, g_prime_proof) = coeff_form_uni_hyperkzg_open(proving_key, &g_prime.coeffs, &new_point, transcript); + pcs_timer.stop(); + + timer.stop(); ( evals, BatchOpening { diff --git a/poly_commit/tests/test_bi_kzg.rs b/poly_commit/tests/test_bi_kzg.rs index 4b2a5787..47286391 100644 --- a/poly_commit/tests/test_bi_kzg.rs +++ b/poly_commit/tests/test_bi_kzg.rs @@ -12,7 +12,7 @@ use transcript::BytesHashTranscript; const TEST_REPETITION: usize = 3; -fn test_hyperkzg_pcs_generics(num_vars_start: usize, num_vars_end: usize) { +fn test_hyper_bi_kzg_pcs_generics(num_vars_start: usize, num_vars_end: usize) { let mut rng = test_rng(); (num_vars_start..=num_vars_end).for_each(|num_vars| { @@ -28,11 +28,11 @@ fn test_hyperkzg_pcs_generics(num_vars_start: usize, num_vars_end: usize) { } #[test] -fn test_hyperkzg_pcs_full_e2e() { - test_hyperkzg_pcs_generics(2, 15) +fn test_hyper_bi_kzg_pcs_full_e2e() { + test_hyper_bi_kzg_pcs_generics(2, 15) } -fn test_hyper_bikzg_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_num_vars: usize) { +fn test_hyper_bi_kzg_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_num_vars: usize) { let mut rng = test_rng(); // NOTE BN254 GKR SIMD pack size = 1, num vars in SIMD is 0 @@ -79,21 +79,11 @@ fn test_hyper_bikzg_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_ } #[test] -fn test_hyper_bikzg_for_expander_gkr() { +fn test_hyper_bi_kzg_for_expander_gkr() { let mpi_config = MPIConfig::prover_new(); - test_hyper_bikzg_for_expander_gkr_generics(&mpi_config, 1); - test_hyper_bikzg_for_expander_gkr_generics(&mpi_config, 15); + test_hyper_bi_kzg_for_expander_gkr_generics(&mpi_config, 1); + test_hyper_bi_kzg_for_expander_gkr_generics(&mpi_config, 15); MPIConfig::finalize() } - -// #[test] -// fn test_kzg_batch_open() { -// common::test_batching::, HyperBiKZGPCS>(); -// // common::test_batching_for_expander_gkr::< -// // BN254Config, -// // BytesHashTranscript, -// // HyraxPCS, -// // >(); -// } diff --git a/poly_commit/tests/test_uni_kzg.rs b/poly_commit/tests/test_uni_kzg.rs index 0c5f38cd..a8d9df83 100644 --- a/poly_commit/tests/test_uni_kzg.rs +++ b/poly_commit/tests/test_uni_kzg.rs @@ -28,7 +28,7 @@ fn test_hyperkzg_pcs_generics(num_vars_start: usize, num_vars_end: usize) { } #[test] -fn test_hyperkzg_pcs_full_e2e() { +fn test_hyper_uni_kzg_pcs_full_e2e() { test_hyperkzg_pcs_generics(2, 15) } @@ -89,7 +89,7 @@ fn test_hyper_unikzg_for_expander_gkr() { } #[test] -fn test_kzg_batch_open() { +fn test_uni_kzg_batch_open() { common::test_batching::, HyperUniKZGPCS>(); common::test_batching_for_expander_gkr::< BN254Config, diff --git a/sumcheck/Cargo.toml b/sumcheck/Cargo.toml index 86445469..815e9ee6 100644 --- a/sumcheck/Cargo.toml +++ b/sumcheck/Cargo.toml @@ -15,6 +15,7 @@ utils = { path = "../utils" } env_logger.workspace = true log.workspace = true +rayon.workspace = true [dev-dependencies] ark-std.workspace = true diff --git a/sumcheck/src/sumcheck_generic/prover.rs b/sumcheck/src/sumcheck_generic/prover.rs index 18217f89..edb7121e 100644 --- a/sumcheck/src/sumcheck_generic/prover.rs +++ b/sumcheck/src/sumcheck_generic/prover.rs @@ -1,4 +1,5 @@ use arith::Field; +use rayon::iter::{IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator}; use super::{IOPProverMessage, IOPProverState, SumOfProductsPoly}; @@ -43,10 +44,14 @@ impl IOPProverState { let r = self.challenges[self.round - 1]; - for (f, g) in self.mle_list.f_and_g_pairs.iter_mut() { - f.fix_top_variable(r); - g.fix_top_variable(r); - } + self.mle_list + .f_and_g_pairs + .par_iter_mut() + .for_each(|(f, g)| { + // fix the top variable of f and g to r + f.fix_top_variable(r); + g.fix_top_variable(r); + }); } else if self.round > 0 { panic!("verifier message is empty") } @@ -58,27 +63,65 @@ impl IOPProverState { let mut h_1 = F::zero(); let mut h_2 = F::zero(); - for (f, g) in self.mle_list.f_and_g_pairs.iter() { - // evaluate the polynomial at 0, 1 and 2 - // and obtain f(0)g(0) and f(1)g(1) and f(2)g(2) - let f_coeffs = f.coeffs.as_slice(); - let g_coeffs = g.coeffs.as_slice(); - - h_0 += f_coeffs[..len].iter().sum::() * g_coeffs[..len].iter().sum::(); - h_1 += f_coeffs[len..].iter().sum::() * g_coeffs[len..].iter().sum::(); - - let f_2 = f_coeffs[..len] - .iter() - .zip(f_coeffs[len..].iter()) - .map(|(a, b)| -*a + b.double()) - .sum::(); - let g2 = g_coeffs[..len] - .iter() - .zip(g_coeffs[len..].iter()) - .map(|(a, b)| -*a + b.double()) - .sum::(); - h_2 += f_2 * g2; - } + // The following commented code is a sequential version of the computation + // + // for (f, g) in self.mle_list.f_and_g_pairs.iter() { + // // evaluate the polynomial at 0, 1 and 2 + // // and obtain f(0)g(0) and f(1)g(1) and f(2)g(2) + // let f_coeffs = f.coeffs.as_slice(); + // let g_coeffs = g.coeffs.as_slice(); + + // h_0 += f_coeffs[..len].iter().sum::() * g_coeffs[..len].iter().sum::(); + // h_1 += f_coeffs[len..].iter().sum::() * g_coeffs[len..].iter().sum::(); + + // let f_2 = f_coeffs[..len] + // .iter() + // .zip(f_coeffs[len..].iter()) + // .map(|(a, b)| -*a + b.double()) + // .sum::(); + // let g2 = g_coeffs[..len] + // .iter() + // .zip(g_coeffs[len..].iter()) + // .map(|(a, b)| -*a + b.double()) + // .sum::(); + // h_2 += f_2 * g2; + // } + + self.mle_list + .f_and_g_pairs + .par_iter() + .map(|(f, g)| { + // evaluate the polynomial at 0, 1 and 2 + // and obtain f(0)g(0) and f(1)g(1) and f(2)g(2) + let f_coeffs = f.coeffs.as_slice(); + let g_coeffs = g.coeffs.as_slice(); + + let h_0_local = + f_coeffs[..len].iter().sum::() * g_coeffs[..len].iter().sum::(); + let h_1_local = + f_coeffs[len..].iter().sum::() * g_coeffs[len..].iter().sum::(); + + let f_2 = f_coeffs[..len] + .iter() + .zip(f_coeffs[len..].iter()) + .map(|(a, b)| -*a + b.double()) + .sum::(); + let g2 = g_coeffs[..len] + .iter() + .zip(g_coeffs[len..].iter()) + .map(|(a, b)| -*a + b.double()) + .sum::(); + + let h_2_local = f_2 * g2; + (h_0_local, h_1_local, h_2_local) + }) + .collect::>() + .iter() + .for_each(|(h_0_local, h_1_local, h_2_local)| { + h_0 += h_0_local; + h_1 += h_1_local; + h_2 += h_2_local; + }); IOPProverMessage { evaluations: vec![h_0, h_1, h_2], From f72e2eb0985dc461192615a38683c280bbe48076 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Fri, 30 May 2025 19:20:50 -0400 Subject: [PATCH 47/57] performance tuning --- poly_commit/src/batching.rs | 41 +++++++++++-------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/poly_commit/src/batching.rs b/poly_commit/src/batching.rs index 48705b3b..20e8d442 100644 --- a/poly_commit/src/batching.rs +++ b/poly_commit/src/batching.rs @@ -8,9 +8,7 @@ use halo2curves::msm::best_multiexp; use halo2curves::{ff::PrimeField, CurveAffine}; use polynomials::MultiLinearPoly; use polynomials::{EqPolynomial, MultilinearExtension}; -use rayon::iter::{ - IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, ParallelIterator, -}; +use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use serdes::ExpSerde; use sumcheck::{IOPProof, SumCheck, SumOfProductsPoly}; use utils::timer::Timer; @@ -88,36 +86,21 @@ where // build g'(X) = \sum_i=1..k \tilde eq_i(a2) * \tilde g_i(X) where (a2) is the // sumcheck's point \tilde eq_i(a2) = eq(a2, point_i) let timer = Timer::new("Building g'(X)", true); - let g_prime_evals: Vec = (0..(1 << num_vars)) - .into_par_iter() - .map(|j| { - tilde_gs - .par_iter() - .zip(points.par_iter()) - .map(|(tilde_g, point)| { - let eq_i_a2 = EqPolynomial::eq_vec(a2.as_ref(), point); - - tilde_g.coeffs[j] * eq_i_a2 - }) - .sum() - }) - .collect(); + let mut g_prime_evals = vec![C::Scalar::zero(); 1 << num_vars]; + let eq_i_a2_polys = points + .par_iter() + .map(|point| EqPolynomial::eq_vec(a2.as_ref(), point)) + .collect::>(); + + for (tilde_g, eq_i_a2) in tilde_gs.iter().zip(eq_i_a2_polys.iter()) { + for (j, &tilde_g_eval) in tilde_g.coeffs.iter().enumerate() { + g_prime_evals[j] += tilde_g_eval * eq_i_a2; + } + } let g_prime = MultiLinearPoly { coeffs: g_prime_evals, }; - - // let mut g_prime_evals = vec![C::Scalar::zero(); 1 << num_vars]; - - // for (tilde_g, point) in tilde_gs.iter().zip(points.iter()) { - // let eq_i_a2 = EqPolynomial::eq_vec(a2.as_ref(), point); - // for (j, &tilde_g_eval) in tilde_g.coeffs.iter().enumerate() { - // g_prime_evals[j] += tilde_g_eval * eq_i_a2; - // } - // } - // let g_prime = MultiLinearPoly { - // coeffs: g_prime_evals, - // }; timer.stop(); (a2, g_prime, proof) } From a8ede0fa2e29d5b9d40b6660c46d63d040550cd6 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Fri, 30 May 2025 19:28:10 -0400 Subject: [PATCH 48/57] performance tuning --- poly_commit/src/hyrax/hyrax_impl.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/poly_commit/src/hyrax/hyrax_impl.rs b/poly_commit/src/hyrax/hyrax_impl.rs index e10f530b..baf71043 100644 --- a/poly_commit/src/hyrax/hyrax_impl.rs +++ b/poly_commit/src/hyrax/hyrax_impl.rs @@ -6,6 +6,7 @@ use polynomials::{ EqPolynomial, MultilinearExtension, MutRefMultiLinearPoly, MutableMultilinearExtension, RefMultiLinearPoly, }; +use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use serdes::ExpSerde; use utils::timer::Timer; @@ -282,8 +283,8 @@ where // generate evals for each polynomial at its corresponding point let eval_timer = Timer::new("eval all polys", true); let evals: Vec = polys - .iter() - .zip(points.iter()) + .par_iter() + .zip_eq(points.par_iter()) .map(|(poly, point)| poly.evaluate_jolt(point)) .collect(); eval_timer.stop(); From b74ed0ff451bc16d0aa2070d6661fbc312b19c04 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 3 Jun 2025 15:22:09 -0400 Subject: [PATCH 49/57] fix after merge --- poly_commit/src/hyrax/pcs_trait_impl.rs | 3 ++- poly_commit/src/kzg/uni_kzg/expander_api.rs | 2 +- poly_commit/tests/common.rs | 6 ++++-- poly_commit/tests/test_uni_kzg.rs | 7 ++++--- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/poly_commit/src/hyrax/pcs_trait_impl.rs b/poly_commit/src/hyrax/pcs_trait_impl.rs index b8b7351b..af80ffeb 100644 --- a/poly_commit/src/hyrax/pcs_trait_impl.rs +++ b/poly_commit/src/hyrax/pcs_trait_impl.rs @@ -85,9 +85,10 @@ where impl BatchOpeningPCS for HyraxPCS where - C: CurveAffine + ExpSerde, + C: CurveAffine + ExpSerde + UncompressedEncoding, C::Scalar: ExtensionField + PrimeField, C::ScalarExt: ExtensionField + PrimeField, + C::Base: PrimeField, { fn single_point_batch_open( _params: &Self::Params, diff --git a/poly_commit/src/kzg/uni_kzg/expander_api.rs b/poly_commit/src/kzg/uni_kzg/expander_api.rs index 0cf78160..fb7466a2 100644 --- a/poly_commit/src/kzg/uni_kzg/expander_api.rs +++ b/poly_commit/src/kzg/uni_kzg/expander_api.rs @@ -38,7 +38,7 @@ where n_input_vars } - fn gen_srs_for_testing( + fn gen_srs( params: &Self::Params, _mpi_engine: &impl MPIEngine, rng: impl rand::RngCore, diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index a85b30e0..ac246d32 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -220,10 +220,12 @@ where P: ExpanderPCS, { let mut rng = test_rng(); - let mpi_config = MPIConfig::prover_new(); + let universe = MPIConfig::init().unwrap(); + let world = universe.world(); + let mpi_config = MPIConfig::prover_new(Some(&universe), Some(&world)); for num_vars in 2..10 { // NOTE(HS) we assume that the polynomials we pass in are of sufficient length. - let srs = P::gen_srs_for_testing(&num_vars, &mpi_config, &mut rng); + let srs = P::gen_srs(&num_vars, &mpi_config, &mut rng); let (proving_key, verification_key) = srs.into_keys(); let mut scratch_pad = P::init_scratch_pad(&num_vars, &mpi_config); diff --git a/poly_commit/tests/test_uni_kzg.rs b/poly_commit/tests/test_uni_kzg.rs index a8d9df83..a1dfe5e5 100644 --- a/poly_commit/tests/test_uni_kzg.rs +++ b/poly_commit/tests/test_uni_kzg.rs @@ -75,17 +75,18 @@ fn test_hyper_unikzg_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total &mut transcript, &local_poly, &[challenge_point], + None, ); } #[test] fn test_hyper_unikzg_for_expander_gkr() { - let mpi_config = MPIConfig::prover_new(); + let universe = MPIConfig::init().unwrap(); + let world = universe.world(); + let mpi_config = MPIConfig::prover_new(Some(&universe), Some(&world)); test_hyper_unikzg_for_expander_gkr_generics(&mpi_config, 1); test_hyper_unikzg_for_expander_gkr_generics(&mpi_config, 15); - - MPIConfig::finalize() } #[test] From 1f0d4e667aba00d1e4a9b23a12e5febb2f2bf6ea Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 3 Jun 2025 15:24:58 -0400 Subject: [PATCH 50/57] fix tests --- poly_commit/tests/common.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index ac246d32..c285e9f1 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -220,9 +220,7 @@ where P: ExpanderPCS, { let mut rng = test_rng(); - let universe = MPIConfig::init().unwrap(); - let world = universe.world(); - let mpi_config = MPIConfig::prover_new(Some(&universe), Some(&world)); + let mpi_config = MPIConfig::prover_new(None, None); for num_vars in 2..10 { // NOTE(HS) we assume that the polynomials we pass in are of sufficient length. let srs = P::gen_srs(&num_vars, &mpi_config, &mut rng); From f1e9dc7c716019002ca0c2e8996788c771f45177 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Wed, 4 Jun 2025 06:55:51 -0400 Subject: [PATCH 51/57] batch with variable length polys --- poly_commit/src/batching.rs | 107 +++++++++++++++++++++++++--- poly_commit/src/hyrax/hyrax_impl.rs | 30 +++++++- poly_commit/tests/common.rs | 63 +++++++++++++++- poly_commit/tests/test_hyrax.rs | 12 ++-- 4 files changed, 191 insertions(+), 21 deletions(-) diff --git a/poly_commit/src/batching.rs b/poly_commit/src/batching.rs index 20e8d442..8c351aaa 100644 --- a/poly_commit/src/batching.rs +++ b/poly_commit/src/batching.rs @@ -33,8 +33,11 @@ where C::Scalar: ExtensionField + PrimeField, C::ScalarExt: ExtensionField + PrimeField, { - let num_vars = polys[0].num_vars(); - let k = polys.len(); + // Ensure that all polynomials have the same number of variables + let (padded_polys, padded_points) = pad_polynomials_and_points::(polys, points); + + let num_vars = padded_polys[0].num_vars(); + let k = padded_polys.len(); let ell = log2(k) as usize; // challenge point t @@ -46,7 +49,7 @@ where // \tilde g_i(b) = eq(t, i) * f_i(b) let timer = Timer::new("Building tilde g_i(b)", true); - let tilde_gs = polys + let tilde_gs = padded_polys .par_iter() .enumerate() .map(|(index, f_i)| { @@ -64,7 +67,7 @@ where // built the virtual polynomial for SumCheck let timer = Timer::new("Building tilde eqs", true); - let tilde_eqs: Vec> = points + let tilde_eqs: Vec> = padded_points .par_iter() .map(|point| { let eq_b_zi = EqPolynomial::build_eq_x_r(point); @@ -88,7 +91,7 @@ where let timer = Timer::new("Building g'(X)", true); let mut g_prime_evals = vec![C::Scalar::zero(); 1 << num_vars]; - let eq_i_a2_polys = points + let eq_i_a2_polys = padded_points .par_iter() .map(|point| EqPolynomial::eq_vec(a2.as_ref(), point)) .collect::>(); @@ -117,9 +120,15 @@ where C::Scalar: ExtensionField + PrimeField, C::ScalarExt: ExtensionField + PrimeField, { - let k = commitments.len(); + let (padded_commitments, padded_points) = pad_commitments_and_points::(commitments, points); + + let k = padded_commitments.len(); let ell = log2(k) as usize; let num_var = sumcheck_proof.point.len(); + assert!( + num_var == padded_points[0].len(), + "Number of variables in sumcheck proof must match the number of variables in points" + ); // sum check point (a2) let a2 = sumcheck_proof.export_point_to_expander(); @@ -130,10 +139,13 @@ where let eq_t_i = EqPolynomial::build_eq_x_r(&t); // build g' commitment - let bases = commitments.iter().map(|c| c.as_ref()).collect::>(); + let bases = padded_commitments + .iter() + .map(|c| c.as_ref()) + .collect::>(); let bases_transposed = transpose::(&bases); - let scalars = points + let scalars = padded_points .iter() .enumerate() .map(|(i, p)| { @@ -147,7 +159,7 @@ where .map(|base| best_multiexp(&scalars, base)) .collect::>(); - let mut g_prime_commit_affine = vec![C::default(); commitments[0].as_ref().len()]; + let mut g_prime_commit_affine = vec![C::default(); padded_commitments[0].len()]; C::Curve::batch_normalize(&g_prime_commit_elems, &mut g_prime_commit_affine); // ensure \sum_i eq(t, ) * f_i_evals matches the sum via SumCheck @@ -182,3 +194,80 @@ fn transpose(m: &[&[C]]) -> Vec> { transposed } + +#[inline] +#[allow(clippy::type_complexity)] +fn pad_polynomials_and_points( + polys: &[MultiLinearPoly], + points: &[Vec], +) -> (Vec>, Vec>) +where + C: CurveAffine + ExpSerde, + C::Scalar: ExtensionField + PrimeField, + C::ScalarExt: ExtensionField + PrimeField, +{ + let max_size = polys + .iter() + .map(|p| p.hypercube_basis_ref().len()) + .max() + .unwrap_or(0); + let max_num_vars = log2(max_size) as usize; + let padded_polys = polys + .iter() + .map(|poly| { + let mut coeffs = poly.coeffs.clone(); + coeffs.resize(max_size, C::Scalar::zero()); + MultiLinearPoly { coeffs } + }) + .collect::>(); + let padded_points = points + .iter() + .map(|point| { + let mut padded_point = point.clone(); + padded_point.resize(max_num_vars, C::Scalar::zero()); + padded_point + }) + .collect::>(); + + (padded_polys, padded_points) +} + +#[inline] +// Each commitment is a vector of curve points +// This generalizes both KZG and Hyrax commitments +fn pad_commitments_and_points( + commitments: &[impl AsRef<[C]>], + points: &[Vec], +) -> (Vec>, Vec>) +where + C: CurveAffine + ExpSerde, + C::Scalar: ExtensionField + PrimeField, + C::ScalarExt: ExtensionField + PrimeField, +{ + let max_num_vars = points.iter().map(|p| p.len()).max().unwrap_or(0); + let max_commit_size = commitments + .iter() + .map(|c| c.as_ref().len()) + .max() + .unwrap_or(0); + + let padded_points = points + .iter() + .map(|point| { + let mut padded_point = point.clone(); + padded_point.resize(max_num_vars, C::Scalar::zero()); + padded_point + }) + .collect::>(); + + let padded_commitments = commitments + .iter() + .map(|commitment| { + let mut padded_commitment = commitment.as_ref().to_vec(); + padded_commitment.resize(max_commit_size, C::identity()); + padded_commitment + }) + .collect::>(); + + (padded_commitments, padded_points) +} diff --git a/poly_commit/src/hyrax/hyrax_impl.rs b/poly_commit/src/hyrax/hyrax_impl.rs index 9ca2889c..06039489 100644 --- a/poly_commit/src/hyrax/hyrax_impl.rs +++ b/poly_commit/src/hyrax/hyrax_impl.rs @@ -112,6 +112,21 @@ where C::ScalarExt: ExtensionField + PrimeField, C::Base: PrimeField, { + if mle_poly.hypercube_basis_ref().len() < params.msm_len() { + // usually the params should be smaller than mle_poly as we rearrange the polynomial as a + // matrix, and the params are the number of columns. + // + // However, in the batch opening cases, it is possible that some of the polynomials are in + // fact much smaller; whereas the params are determined according to the maximum + // polynomial size of the batch. + + let mut scalars = mle_poly.hypercube_basis(); + scalars.resize(params.msm_len(), C::Scalar::zero()); + let commitment = pedersen_commit(params, scalars.as_ref()); + + return HyraxCommitment(vec![commitment]); + } + let commitments: Vec = mle_poly .hypercube_basis_ref() .chunks(params.msm_len()) @@ -165,13 +180,22 @@ where let eq_combination: Vec = EqPolynomial::build_eq_x_r(&eval_point[pedersen_vars..]); let row_comm = msm::best_multiexp(&eq_combination, &comm.0); - if pedersen_commit(params, &proof.0) != row_comm.into() { + let pedersen_commitment = pedersen_commit(params, &proof.0); + + if pedersen_commitment != row_comm.into() { + eprintln!("pedersen commitment not match",); return false; } let mut scratch = vec![C::Scalar::default(); proof.0.len()]; - eval == RefMultiLinearPoly::from_ref(&proof.0) - .evaluate_with_buffer(&eval_point[..pedersen_vars], &mut scratch) + let res = eval + == RefMultiLinearPoly::from_ref(&proof.0) + .evaluate_with_buffer(&eval_point[..pedersen_vars], &mut scratch); + if !res { + eprintln!("evaluation does not match"); + } + + res } // batch open a set of mle_polys at the same point diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index c285e9f1..1b2e5911 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -55,7 +55,6 @@ where let mut rng = thread_rng(); for num_vars in 2..10 { - // NOTE(HS) we assume that the polynomials we pass in are of sufficient length. let (srs, _) = P::gen_srs_for_testing(&num_vars, &mut rng); let mut scratch_pad = P::init_scratch_pad(&num_vars); @@ -101,8 +100,9 @@ where )) } - // multi point batch opening - for num_poly in [2, 4, 8, 16] { + // edga case: multi point batch opening with 1 poly + { + let num_poly = 1; let polys = (0..num_poly) .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) .collect::>(); @@ -144,6 +144,63 @@ where &mut transcript )) } + + // multi point batch opening with multiple polys and various lengths + for num_poly in [1, 2, 4, 8, 16] { + println!( + "Testing multi point batch opening with {} vars and {} polys", + num_vars, num_poly + ); + let mut polys = (0..num_poly) + .map(|_| MultiLinearPoly::::random(num_vars, &mut rng)) + .collect::>(); + // polynomial with a fixed number of variables + polys.push(MultiLinearPoly::::random(2, &mut rng)); + // polynomial with one less variable than the others + polys.push(MultiLinearPoly::::random(num_vars - 1, &mut rng)); + let commitments = polys + .iter() + .map(|poly| P::commit(&num_vars, &proving_key, poly, &mut scratch_pad)) + .collect::>(); + + // open all polys at all points + let mut points = (0..num_poly) + .map(|_| { + (0..num_vars) + .map(|_i| F::random_unsafe(&mut rng)) + .collect::>() + }) + .collect::>(); + points.push(vec![F::random_unsafe(&mut rng), F::random_unsafe(&mut rng)]); + points.push( + (0..num_vars - 1) + .map(|_i| F::random_unsafe(&mut rng)) + .collect::>(), + ); + + let mut transcript = T::new(); + + let (values, batch_opening) = P::multiple_points_batch_open( + &num_vars, + &proving_key, + &polys, + points.as_ref(), + &mut scratch_pad, + &mut transcript, + ); + + let mut transcript = T::new(); + + assert!(P::multiple_points_batch_verify( + &num_vars, + &verification_key, + &commitments, + points.as_ref(), + &values, + &batch_opening, + &mut transcript + )) + } } } diff --git a/poly_commit/tests/test_hyrax.rs b/poly_commit/tests/test_hyrax.rs index 30559a65..e85aed69 100644 --- a/poly_commit/tests/test_hyrax.rs +++ b/poly_commit/tests/test_hyrax.rs @@ -28,7 +28,7 @@ fn test_hyrax_pcs_generics(num_vars_start: usize, num_vars_end: usize) { #[test] fn test_hyrax_pcs_e2e() { - test_hyrax_pcs_generics(3, 17) + test_hyrax_pcs_generics(1, 17) } fn test_hyrax_for_expander_gkr_generics(mpi_config_ref: &MPIConfig, total_num_vars: usize) { @@ -85,9 +85,9 @@ fn test_hyrax_for_expander_gkr() { #[test] fn test_hyrax_batch_open() { common::test_batching::, HyraxPCS>(); - // common::test_batching_for_expander_gkr::< - // BN254Config, - // BytesHashTranscript, - // HyraxPCS, - // >(); + common::test_batching_for_expander_gkr::< + BN254Config, + BytesHashTranscript, + HyraxPCS, + >(); } From 22022d842244694a117b6c1707e2b63d6047fe3d Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 10 Jun 2025 16:53:13 -0400 Subject: [PATCH 52/57] zz/whir api --- Cargo.lock | 436 +++++++++++++++++- Cargo.toml | 25 +- arith/goldilocks/Cargo.toml | 2 + arith/goldilocks/src/goldilocks.rs | 33 ++ arith/goldilocks/src/goldilocks_ext.rs | 38 ++ arith/goldilocks/src/tests.rs | 32 ++ poly_commit/Cargo.toml | 4 + poly_commit/src/hyrax/pcs_trait_impl.rs | 3 +- poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs | 3 +- poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs | 3 +- poly_commit/src/lib.rs | 3 + poly_commit/src/orion/pcs_trait_impl.rs | 6 +- poly_commit/src/raw.rs | 3 +- poly_commit/src/traits.rs | 9 +- poly_commit/src/whir.rs | 162 +++++++ poly_commit/tests/common.rs | 1 + poly_commit/tests/test_whir.rs | 110 +++++ serdes/Cargo.toml | 5 +- serdes/src/serdes.rs | 15 + 19 files changed, 858 insertions(+), 35 deletions(-) create mode 100644 poly_commit/src/whir.rs create mode 100644 poly_commit/tests/test_whir.rs diff --git a/Cargo.lock b/Cargo.lock index 86096626..21010183 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,18 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -26,6 +38,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -112,14 +130,181 @@ dependencies = [ "tynm", ] +[[package]] +name = "ark-crypto-primitives" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0c292754729c8a190e50414fd1a37093c786c709899f29c9f7daccecfa855e" +dependencies = [ + "ahash", + "ark-crypto-primitives-macros", + "ark-ec", + "ark-ff", + "ark-relations", + "ark-serialize", + "ark-snark", + "ark-std", + "blake2", + "derivative", + "digest", + "fnv", + "hashbrown 0.14.5", + "merlin", + "rayon", + "sha2", +] + +[[package]] +name = "ark-crypto-primitives-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e89fe77d1f0f4fe5b96dfc940923d88d17b6a773808124f21e764dfb063c6a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "educe", + "fnv", + "hashbrown 0.15.2", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "arrayvec", + "digest", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "rayon", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.100", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff", + "ark-serialize", + "ark-std", + "educe", + "fnv", + "hashbrown 0.15.2", + "rayon", +] + +[[package]] +name = "ark-relations" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" +dependencies = [ + "ark-ff", + "ark-std", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "arrayvec", + "digest", + "num-bigint", + "rayon", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "ark-snark" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d368e2848c2d4c129ce7679a7d0d2d612b6a274d3ea6a13bad4445d61b381b88" +dependencies = [ + "ark-ff", + "ark-relations", + "ark-serialize", + "ark-std", +] + [[package]] name = "ark-std" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" dependencies = [ "num-traits", "rand", + "rayon", ] [[package]] @@ -264,6 +449,19 @@ dependencies = [ "constant_time_eq", ] +[[package]] +name = "blake3" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -289,6 +487,12 @@ version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +[[package]] +name = "bytemuck" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" + [[package]] name = "byteorder" version = "1.5.0" @@ -388,7 +592,7 @@ dependencies = [ "poly_commit", "rand", "serdes", - "thiserror", + "thiserror 1.0.69", "transcript", ] @@ -582,7 +786,7 @@ dependencies = [ "rand", "serdes", "sumcheck", - "thiserror", + "thiserror 1.0.69", "transcript", ] @@ -647,6 +851,18 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "either" version = "1.15.0" @@ -662,6 +878,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "env_filter" version = "0.1.3" @@ -816,7 +1052,7 @@ dependencies = [ "rand", "raw-cpuid", "serdes", - "thiserror", + "thiserror 1.0.69", "tynm", ] @@ -868,7 +1104,7 @@ dependencies = [ "serdes", "sha2", "sumcheck", - "thiserror", + "thiserror 1.0.69", "transcript", "utils", ] @@ -889,7 +1125,7 @@ dependencies = [ "polynomials", "rand", "serdes", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -914,11 +1150,13 @@ name = "goldilocks" version = "0.1.0" dependencies = [ "arith", + "ark-ff", "ark-std", "criterion", "ethnum", "rand", "serdes", + "whir", ] [[package]] @@ -985,11 +1223,23 @@ dependencies = [ "unroll", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "allocator-api2", +] + [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", +] [[package]] name = "headers" @@ -1027,6 +1277,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "home" version = "0.5.11" @@ -1275,7 +1531,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", ] [[package]] @@ -1322,6 +1578,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -1362,6 +1627,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1446,6 +1720,18 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core", + "zeroize", +] + [[package]] name = "mersenne31" version = "0.1.0" @@ -1461,7 +1747,7 @@ dependencies = [ "rand", "raw-cpuid", "serdes", - "thiserror", + "thiserror 1.0.69", "tynm", ] @@ -1519,7 +1805,7 @@ dependencies = [ "mpi-sys", "once_cell", "smallvec", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1756,13 +2042,16 @@ dependencies = [ "rand", "rayon", "serdes", + "spongefish", + "spongefish-pow", "sumcheck", - "thiserror", + "thiserror 1.0.69", "transcript", "transpose", "tree", "tynm", "utils", + "whir", ] [[package]] @@ -2043,7 +2332,8 @@ dependencies = [ "halo2curves", "rand", "serdes_derive", - "thiserror", + "thiserror 1.0.69", + "whir", ] [[package]] @@ -2077,6 +2367,16 @@ dependencies = [ "digest", ] +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + [[package]] name = "shell-words" version = "1.1.0" @@ -2129,6 +2429,34 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spongefish" +version = "0.2.0" +source = "git+https://github.com/arkworks-rs/spongefish#bf02b09d4c2de0cb5a4ca233c95b1ef812694a50" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "digest", + "hex", + "keccak", + "rand", + "zeroize", +] + +[[package]] +name = "spongefish-pow" +version = "0.1.0" +source = "git+https://github.com/arkworks-rs/spongefish#bf02b09d4c2de0cb5a4ca233c95b1ef812694a50" +dependencies = [ + "blake3", + "bytemuck", + "keccak", + "rand", + "rayon", + "spongefish", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -2222,7 +2550,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] @@ -2236,6 +2573,17 @@ dependencies = [ "syn 2.0.100", ] +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "tiny-keccak" version = "2.0.2" @@ -2343,6 +2691,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", ] [[package]] @@ -2402,7 +2760,7 @@ dependencies = [ "log", "rand", "sha1", - "thiserror", + "thiserror 1.0.69", "url", "utf-8", ] @@ -2486,6 +2844,12 @@ dependencies = [ "colored", ] +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "version_check" version = "0.9.5" @@ -2626,6 +2990,30 @@ dependencies = [ "rustix", ] +[[package]] +name = "whir" +version = "0.1.0" +source = "git+https://github.com/zhenfeizhang/whir#9d7a97b169542f8d0787db482ee58f7b9b660848" +dependencies = [ + "ark-crypto-primitives", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "blake3", + "clap", + "hex", + "itertools 0.14.0", + "rand", + "rayon", + "serde", + "serde_json", + "sha3", + "spongefish", + "spongefish-pow", + "thiserror 2.0.12", +] + [[package]] name = "winapi-util" version = "0.1.9" @@ -2862,6 +3250,26 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "zerovec" version = "0.10.4" diff --git a/Cargo.toml b/Cargo.toml index 829df8fd..07ca6252 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,35 +25,42 @@ members = [ resolver = "2" [workspace.dependencies] -ark-std = "0.4" -ark-bn254 = "0.4.0" -ark-ec = "0.4.0" -ark-ff = { version = "0.4" } +ark-std = { version = "0.5", features = ["std"] } +ark-bn254 = "0.5.0" +ark-ec = "0.5.0" +ark-ff = { version = "0.5", features = ["asm", "std"] } + bytes = "1.6.0" chrono = "0.4.38" clap = { version = "4.1", features = ["derive"] } cfg-if = "1.0" criterion = { version = "0.5", features = ["html_reports"] } +derivative = "2.2.0" env_logger = "0.11.3" +ethnum = "1.5.0" halo2curves = { git = "https://github.com/PolyhedraZK/halo2curves", default-features = false, features = [ "bits", ] } syn = "2.0" # For parsing Rust code +spongefish = { git = "https://github.com/arkworks-rs/spongefish", features = [ + "arkworks-algebra", +] } +spongefish-pow = { git = "https://github.com/arkworks-rs/spongefish" } quote = "1.0" # For generating code proc-macro2 = "1.0" # For working with tokens itertools = "0.13" log = "0.4" mpi = "0.8.0" rand = "0.8.5" +rand_chacha = "0.3.1" raw-cpuid = "11.1.0" rayon = "1.10" sha2 = "0.10.8" +thiserror = "1.0.63" tiny-keccak = { version = "2.0.2", features = [ "sha3", "keccak" ] } tokio = { version = "1.38.0", features = ["full"] } +transpose = "0.2.3" tynm = { version = "0.1.6", default-features = false } warp = "0.3.7" -thiserror = "1.0.63" -ethnum = "1.5.0" -rand_chacha = "0.3.1" -derivative = "2.2.0" -transpose = "0.2.3" +# whir = { git = "https://github.com/WizardOfMenlo/whir", rev = "9d7a97b169542f8d0787db482ee58f7b9b660848" } + whir = { git = "https://github.com/zhenfeizhang/whir" } \ No newline at end of file diff --git a/arith/goldilocks/Cargo.toml b/arith/goldilocks/Cargo.toml index 7583e059..b223d82b 100644 --- a/arith/goldilocks/Cargo.toml +++ b/arith/goldilocks/Cargo.toml @@ -7,9 +7,11 @@ edition = "2021" arith = { path = ".." } serdes = { path = "../../serdes" } +ark-ff.workspace = true ark-std.workspace = true ethnum.workspace = true rand.workspace = true +whir.workspace = true [[bench]] name = "goldilocks" diff --git a/arith/goldilocks/src/goldilocks.rs b/arith/goldilocks/src/goldilocks.rs index d6b3c0ac..47adf7e2 100644 --- a/arith/goldilocks/src/goldilocks.rs +++ b/arith/goldilocks/src/goldilocks.rs @@ -5,9 +5,11 @@ use std::{ }; use arith::{field_common, FFTField, Field, SimdField}; +use ark_ff::{BigInteger64, PrimeField}; use ethnum::U256; use rand::RngCore; use serdes::{ExpSerde, SerdeResult}; +use whir::crypto::fields::Field64; use crate::goldilocks::p2_instructions::{assume, branch_hint, reduce128, try_inverse_u64}; @@ -603,3 +605,34 @@ pub(crate) mod p2_instructions { // ) // } } + +impl From for Goldilocks { + #[inline(always)] + fn from(x: Field64) -> Self { + Goldilocks { + v: x.into_bigint().0[0], + } + } +} + +impl From<&Field64> for Goldilocks { + #[inline(always)] + fn from(x: &Field64) -> Self { + Goldilocks { + v: x.into_bigint().0[0], + } + } +} + +impl From for Field64 { + #[inline(always)] + fn from(x: Goldilocks) -> Self { + Field64::from_bigint(BigInteger64::new([x.v])).unwrap() + } +} +impl From<&Goldilocks> for Field64 { + #[inline(always)] + fn from(x: &Goldilocks) -> Self { + Field64::from_bigint(BigInteger64::new([x.v])).unwrap() + } +} diff --git a/arith/goldilocks/src/goldilocks_ext.rs b/arith/goldilocks/src/goldilocks_ext.rs index e4140c84..52ac7676 100644 --- a/arith/goldilocks/src/goldilocks_ext.rs +++ b/arith/goldilocks/src/goldilocks_ext.rs @@ -7,6 +7,7 @@ use arith::{field_common, ExtensionField, FFTField, Field, SimdField}; use ethnum::U256; use rand::RngCore; use serdes::ExpSerde; +use whir::crypto::fields::Field64_2; use crate::{ goldilocks::{mod_reduce_u64, Goldilocks}, @@ -412,3 +413,40 @@ impl Mul for GoldilocksExt2 { } } } + +impl From for GoldilocksExt2 { + #[inline(always)] + fn from(x: Field64_2) -> Self { + GoldilocksExt2 { + v: [x.c0.into(), x.c1.into()], + } + } +} + +impl From<&Field64_2> for GoldilocksExt2 { + #[inline(always)] + fn from(x: &Field64_2) -> Self { + GoldilocksExt2 { + v: [x.c0.into(), x.c1.into()], + } + } +} + +impl From for Field64_2 { + #[inline(always)] + fn from(x: GoldilocksExt2) -> Self { + Field64_2 { + c0: x.v[0].into(), + c1: x.v[1].into(), + } + } +} +impl From<&GoldilocksExt2> for Field64_2 { + #[inline(always)] + fn from(x: &GoldilocksExt2) -> Self { + Field64_2 { + c0: x.v[0].into(), + c1: x.v[1].into(), + } + } +} diff --git a/arith/goldilocks/src/tests.rs b/arith/goldilocks/src/tests.rs index a229cf6a..f2ff0b96 100644 --- a/arith/goldilocks/src/tests.rs +++ b/arith/goldilocks/src/tests.rs @@ -7,6 +7,7 @@ use ark_std::test_rng; use ethnum::U256; use rand::thread_rng; use serdes::ExpSerde; +use whir::crypto::fields::{Field64, Field64_2}; use crate::{ goldilocks::mod_reduce_u64, Goldilocks, GoldilocksExt2, GoldilocksExt2x8, Goldilocksx8, @@ -239,3 +240,34 @@ fn test_edge_cases() { let x = GoldilocksExt2::X; assert_eq!(x * x, GoldilocksExt2::from(Goldilocks::from(7u32))); } + +#[test] +fn convert_from_and_to_arkworks() { + let mut rng = thread_rng(); + + let one = Goldilocks::one(); + let ark_one = Field64::from(1u32); + + assert_eq!(one, Goldilocks::from(ark_one)); + assert_eq!(Field64::from(one), ark_one); + + for _ in 0..100 { + let x = Goldilocks::random_unsafe(&mut rng); + let ark_x = Field64::from(x); + assert_eq!(x, Goldilocks::from(ark_x)); + assert_eq!(Field64::from(x), ark_x); + } + + let one = GoldilocksExt2::one(); + let ark_one = Field64_2::from(1u32); + + assert_eq!(one, GoldilocksExt2::from(ark_one)); + assert_eq!(Field64_2::from(one), ark_one); + + for _ in 0..100 { + let x = GoldilocksExt2::random_unsafe(&mut rng); + let ark_x = Field64_2::from(x); + assert_eq!(x, GoldilocksExt2::from(ark_x)); + assert_eq!(Field64_2::from(x), ark_x); + } +} diff --git a/poly_commit/Cargo.toml b/poly_commit/Cargo.toml index 9404942e..c75c4627 100644 --- a/poly_commit/Cargo.toml +++ b/poly_commit/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" arith = { path = "../arith" } gf2 = { path = "../arith/gf2" } gkr_engine = { path = "../gkr_engine" } +goldilocks = { path = "../arith/goldilocks" } polynomials = { path = "../arith/polynomials"} serdes = { path = "../serdes" } transcript = { path = "../transcript" } @@ -21,8 +22,11 @@ halo2curves.workspace = true itertools.workspace = true rand.workspace = true rayon.workspace = true +spongefish.workspace = true +spongefish-pow.workspace = true transpose.workspace = true thiserror.workspace = true +whir.workspace = true [dev-dependencies] gf2_128 = { path = "../arith/gf2_128" } diff --git a/poly_commit/src/hyrax/pcs_trait_impl.rs b/poly_commit/src/hyrax/pcs_trait_impl.rs index af80ffeb..31b45a9f 100644 --- a/poly_commit/src/hyrax/pcs_trait_impl.rs +++ b/poly_commit/src/hyrax/pcs_trait_impl.rs @@ -61,10 +61,11 @@ where fn open( _params: &Self::Params, + _commitment: &Self::Commitment, proving_key: &::PKey, poly: &Self::Poly, x: &Self::EvalPoint, - _scratch_pad: &Self::ScratchPad, + _scratch_pad: &mut Self::ScratchPad, _transcript: &mut impl Transcript, ) -> (C::Scalar, Self::Opening) { hyrax_open(proving_key, poly, x) diff --git a/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs index 86b39ff4..16d997a3 100644 --- a/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/bi_kzg/pcs_trait_impl.rs @@ -78,10 +78,11 @@ where fn open( _params: &Self::Params, + _commitment: &Self::Commitment, proving_key: &::PKey, poly: &Self::Poly, x: &Self::EvalPoint, - _scratch_pad: &Self::ScratchPad, + _scratch_pad: &mut Self::ScratchPad, transcript: &mut impl Transcript, ) -> (E::Fr, Self::Opening) { let (eval, hyperkzg_opening) = coeff_form_uni_hyperkzg_open( diff --git a/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs b/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs index d8a003e3..132e6828 100644 --- a/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs +++ b/poly_commit/src/kzg/uni_kzg/pcs_trait_impl.rs @@ -68,10 +68,11 @@ where fn open( _params: &Self::Params, + _commitment: &Self::Commitment, proving_key: &::PKey, poly: &Self::Poly, x: &Self::EvalPoint, - _scratch_pad: &Self::ScratchPad, + _scratch_pad: &mut Self::ScratchPad, transcript: &mut impl Transcript, ) -> (E::Fr, Self::Opening) { coeff_form_uni_hyperkzg_open(proving_key, &poly.coeffs, x, transcript) diff --git a/poly_commit/src/lib.rs b/poly_commit/src/lib.rs index b0bc946d..b3415b79 100644 --- a/poly_commit/src/lib.rs +++ b/poly_commit/src/lib.rs @@ -21,3 +21,6 @@ pub mod kzg; pub use kzg::*; pub mod batching; + +pub mod whir; +pub use whir::*; diff --git a/poly_commit/src/orion/pcs_trait_impl.rs b/poly_commit/src/orion/pcs_trait_impl.rs index bae848e5..0ab74bb7 100644 --- a/poly_commit/src/orion/pcs_trait_impl.rs +++ b/poly_commit/src/orion/pcs_trait_impl.rs @@ -96,10 +96,11 @@ where fn open( params: &Self::Params, + _commitment: &Self::Commitment, pk: &::PKey, poly: &Self::Poly, x: &Self::EvalPoint, - scratch_pad: &Self::ScratchPad, + scratch_pad: &mut Self::ScratchPad, transcript: &mut impl Transcript, ) -> (EvalF, Self::Opening) { assert_eq!(*params, pk.num_vars); @@ -197,10 +198,11 @@ where fn open( params: &Self::Params, + _commitment: &Self::Commitment, proving_key: &::PKey, poly: &Self::Poly, x: &Self::EvalPoint, - scratch_pad: &Self::ScratchPad, + scratch_pad: &mut Self::ScratchPad, transcript: &mut impl Transcript, ) -> (EvalF, Self::Opening) { assert_eq!(*params, proving_key.num_vars); diff --git a/poly_commit/src/raw.rs b/poly_commit/src/raw.rs index 8973bb49..a07145e7 100644 --- a/poly_commit/src/raw.rs +++ b/poly_commit/src/raw.rs @@ -87,10 +87,11 @@ impl PolynomialCommitmentScheme for RawMultiLinearPCS { fn open( params: &Self::Params, + _commitment: &Self::Commitment, _proving_key: &::PKey, poly: &Self::Poly, x: &Self::EvalPoint, - _scratch_pad: &Self::ScratchPad, + _scratch_pad: &mut Self::ScratchPad, _transcript: &mut impl Transcript, ) -> (F, Self::Opening) { assert!(x.len() == *params); diff --git a/poly_commit/src/traits.rs b/poly_commit/src/traits.rs index dc068458..78493e82 100644 --- a/poly_commit/src/traits.rs +++ b/poly_commit/src/traits.rs @@ -9,13 +9,13 @@ use sumcheck::IOPProof; pub trait PolynomialCommitmentScheme { const NAME: &'static str; - type Params: Clone + Debug + Default; + type Params: Clone + Debug; type Poly: Clone + Debug + Default; type EvalPoint: Clone + Debug + Default; - type ScratchPad: Clone + Debug + Default + ExpSerde; + type ScratchPad: Debug; type SRS: Clone + Debug + Default + ExpSerde + StructuredReferenceString; - type Commitment: Clone + Debug + Default + ExpSerde; + type Commitment; type Opening: Clone + Debug + Default + ExpSerde; /// Generate a random structured reference string (SRS) for testing purposes. @@ -40,10 +40,11 @@ pub trait PolynomialCommitmentScheme { /// Open the polynomial at a point. fn open( params: &Self::Params, + commitment: &Self::Commitment, proving_key: &::PKey, poly: &Self::Poly, x: &Self::EvalPoint, - scratch_pad: &Self::ScratchPad, + scratch_pad: &mut Self::ScratchPad, transcript: &mut impl Transcript, ) -> (F, Self::Opening); diff --git a/poly_commit/src/whir.rs b/poly_commit/src/whir.rs new file mode 100644 index 00000000..745a3db5 --- /dev/null +++ b/poly_commit/src/whir.rs @@ -0,0 +1,162 @@ +use arith::FFTField; +use ark_std::log2; +use gkr_engine::{StructuredReferenceString, Transcript}; +use goldilocks::{Goldilocks, GoldilocksExt2}; +use polynomials::MultiLinearPoly; +use spongefish::{DomainSeparator, ProverState}; +use spongefish_pow::keccak::KeccakPoW; +use whir::{ + crypto::{ + fields::{Field64, Field64_2}, + merkle_tree::keccak::{KeccakCompress, KeccakMerkleTreeParams}, + }, + poly_utils::{coeffs::CoefficientList, evals::EvaluationsList, multilinear::MultilinearPoint}, + whir::{ + committer::{CommitmentReader, CommitmentWriter}, + domainsep::WhirDomainSeparator, + parameters::WhirConfig, + prover::Prover, + statement::{Statement, Weights}, + verifier::Verifier, + }, +}; + +use crate::PolynomialCommitmentScheme; + +/// Whir Polynomial Commitment Scheme over Goldilocks field. +// Note: Hard coded to Goldilocks field. +pub struct WhirPCS; + +pub type WhirCommitment = + whir::whir::committer::Witness>; +pub type WhirParam = WhirConfig, KeccakPoW>; + +impl PolynomialCommitmentScheme for WhirPCS { + const NAME: &'static str = "WhirPCS"; + + type Params = WhirParam; + type Poly = MultiLinearPoly; + type EvalPoint = Vec; + type ScratchPad = ProverState; + + type SRS = (); + type Commitment = WhirCommitment; //Vec; //WhirCommitment; + type Opening = Vec; //Goldilocks; + + fn init_scratch_pad(params: &Self::Params) -> Self::ScratchPad { + // todo: session identifier can be sampled from transcript? + let domainsep = DomainSeparator::new("🌪️") + .commit_statement(¶ms) + .add_whir_proof(¶ms); + + domainsep.to_prover_state() + } + + fn gen_srs_for_testing(_params: &Self::Params, _rng: impl rand::RngCore) -> (Self::SRS, usize) { + ((), 0) + } + + fn commit( + params: &Self::Params, + _proving_key: &Self::SRS, + poly: &Self::Poly, + prover_state: &mut Self::ScratchPad, + ) -> Self::Commitment { + let whir_poly = CoefficientList::new( + poly.coeffs + .iter() + .map(|&coeff| Field64::from(coeff)) + .collect::>(), + ); + + let committer = CommitmentWriter::new(params.clone()); + + let witness = committer.commit(prover_state, whir_poly.clone()).unwrap(); + + witness + } + + fn open( + params: &Self::Params, + commitment: &Self::Commitment, + proving_key: &::PKey, + poly: &Self::Poly, + x: &Self::EvalPoint, + prover_state: &mut Self::ScratchPad, + _transcript: &mut impl gkr_engine::Transcript, + ) -> (GoldilocksExt2, Self::Opening) { + // todo: avoid cloning commitment if possible + let witness = (*commitment).clone(); + + let num_variables = log2(poly.coeffs.len()) as usize; + let mut statement = Statement::::new(num_variables); + + let whir_poly = CoefficientList::new( + poly.coeffs + .iter() + .map(|&coeff| Field64::from(coeff)) + .collect::>(), + ); + + let point = MultilinearPoint( + x.iter() + .map(|&coord| Field64_2::from(coord)) + .collect::>(), + ); + + let eval = whir_poly.evaluate_at_extension(&point); + let weights = Weights::evaluation(point.clone()); + statement.add_constraint(weights, eval); + + let prover = Prover(params.clone()); + prover + .prove(prover_state, statement.clone(), witness) + .unwrap(); + + (eval.into(), prover_state.narg_string().to_vec()) + } + + fn verify( + params: &Self::Params, + verifying_key: &::VKey, + commitment: &Self::Commitment, + x: &Self::EvalPoint, + eval: GoldilocksExt2, + opening: &Self::Opening, + transcript: &mut impl Transcript, + ) -> bool { + let num_variables = x.len(); + let mut statement = Statement::::new(num_variables); + + let point = MultilinearPoint( + x.iter() + .map(|&coord| Field64_2::from(coord)) + .collect::>(), + ); + let weights = Weights::evaluation(point.clone()); + statement.add_constraint(weights, eval.into()); + + let commitment_reader = CommitmentReader::new(¶ms); + let verifier = Verifier::new(¶ms); + + let domainsep = DomainSeparator::new("🌪️") + .commit_statement(¶ms) + .add_whir_proof(¶ms); + + let mut verifier_state = domainsep.to_verifier_state(opening); + let parsed_commitment = commitment_reader + .parse_commitment(&mut verifier_state) + .unwrap(); + + let (point, constraint) = + match verifier.verify(&mut verifier_state, &parsed_commitment, &statement) { + Ok((p, c)) => (p, c), + Err(_) => return false, + }; + + println!("WhirPCS: Verifying point: {:?}", point); + println!("WhirPCS: Verifying constraint: {:?}", constraint); + + true + } +} diff --git a/poly_commit/tests/common.rs b/poly_commit/tests/common.rs index 1b2e5911..7f5af6a7 100644 --- a/poly_commit/tests/common.rs +++ b/poly_commit/tests/common.rs @@ -27,6 +27,7 @@ pub fn test_pcs>( + params: &P::Params, + poly: &P::Poly, + xs: &[P::EvalPoint], +) { + let mut rng = thread_rng(); + // NOTE(HS) we assume that the polynomials we pass in are of sufficient length. + let (srs, _) = P::gen_srs_for_testing(params, &mut rng); + let (proving_key, verification_key) = srs.into_keys(); + let mut transcript = T::new(); + let mut scratch_pad = P::init_scratch_pad(params); + + println!("scratch_pad: {:?}", scratch_pad); + + let commitment = P::commit(params, &proving_key, poly, &mut scratch_pad); + + println!("scratch_pad: {:?}", scratch_pad); + + for x in xs { + let mut transcript_cloned = transcript.clone(); + let (v, opening) = P::open( + params, + &commitment, + &proving_key, + poly, + x, + &mut scratch_pad, + &mut transcript, + ); + assert!(P::verify( + params, + &verification_key, + &commitment, + x, + v, + &opening, + &mut transcript_cloned + )); + } +} + +fn test_whir_pcs_generics(num_vars_start: usize, num_vars_end: usize) { + let mut rng = test_rng(); + + (num_vars_start..=num_vars_end).for_each(|num_vars| { + let xs: Vec<_> = (0..TEST_REPETITION) + .map(|_| -> Vec { + (0..num_vars) + .map(|_| GoldilocksExt2::random_unsafe(&mut rng)) + .collect() + }) + .collect(); + let poly = MultiLinearPoly::::random(num_vars, &mut rng); + + let (leaf_hash_params, two_to_one_params) = + default_config::, KeccakCompress>(&mut rng); + + let mv_params = MultivariateParameters::::new(num_vars); + + let whir_params = ProtocolParameters::, KeccakPoW> { + initial_statement: true, + security_level: 100, + pow_bits: 0, + folding_factor: FoldingFactor::ConstantFromSecondRound(4, 2), + leaf_hash_params, + two_to_one_params, + soundness_type: SoundnessType::ConjectureList, + _pow_parameters: Default::default(), + starting_log_inv_rate: 1, + }; + + let params = WhirConfig::, KeccakPoW>::new( + mv_params, + whir_params, + ); + + test_whir_pcs::, WhirPCS>( + ¶ms, &poly, &xs, + ); + }) +} + +#[test] +fn test_whir_pcs_full_e2e() { + test_whir_pcs_generics(10, 15) +} diff --git a/serdes/Cargo.toml b/serdes/Cargo.toml index a37a4e63..aaaee240 100644 --- a/serdes/Cargo.toml +++ b/serdes/Cargo.toml @@ -4,9 +4,10 @@ version = "0.1.0" edition = "2021" [dependencies] -thiserror.workspace = true -halo2curves.workspace = true ethnum.workspace = true +halo2curves.workspace = true +thiserror.workspace = true +whir.workspace = true serdes_derive = { path = "../serdes_derive" } diff --git a/serdes/src/serdes.rs b/serdes/src/serdes.rs index 26d61a4c..70117732 100644 --- a/serdes/src/serdes.rs +++ b/serdes/src/serdes.rs @@ -7,8 +7,13 @@ use std::{ use ethnum::U256; use halo2curves::{ bn256::{Fr, G1Affine, G2Affine}, + ff::Field, group::GroupEncoding, }; +use whir::{ + crypto::{fields::Field64, merkle_tree::keccak::KeccakMerkleTreeParams}, + whir::committer::Witness, +}; use crate::{exp_serde_for_generic_slices, exp_serde_for_number, SerdeError, SerdeResult}; @@ -208,3 +213,13 @@ impl ExpSerde for String { String::from_utf8(buf).map_err(|_| SerdeError::DeserializeError) } } + +impl ExpSerde for Witness> { + fn serialize_into(&self, mut writer: W) -> SerdeResult<()> { + todo!() + } + + fn deserialize_from(mut reader: R) -> SerdeResult { + todo!() + } +} From 834595f61032a5685d4c02e852f0a1af8a47bf48 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 10 Jun 2025 17:21:27 -0400 Subject: [PATCH 53/57] fix bug with scratch pad --- Cargo.lock | 488 ++++++++++++++++++--------------- poly_commit/tests/test_whir.rs | 62 ++--- 2 files changed, 295 insertions(+), 255 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 21010183..1ca50452 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "ahash" @@ -67,9 +67,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -82,36 +82,36 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", - "once_cell", + "once_cell_polyfill", "windows-sys 0.59.0", ] @@ -162,7 +162,7 @@ checksum = "e7e89fe77d1f0f4fe5b96dfc940923d88d17b6a773808124f21e764dfb063c6a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -178,7 +178,7 @@ dependencies = [ "ark-std", "educe", "fnv", - "hashbrown 0.15.2", + "hashbrown 0.15.4", "itertools 0.13.0", "num-bigint", "num-integer", @@ -215,7 +215,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -228,7 +228,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -243,7 +243,7 @@ dependencies = [ "ark-std", "educe", "fnv", - "hashbrown 0.15.2", + "hashbrown 0.15.4", "rayon", ] @@ -281,7 +281,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -339,9 +339,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.74" +version = "0.3.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" dependencies = [ "addr2line", "cfg-if", @@ -349,7 +349,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -407,15 +407,15 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.100", + "syn 2.0.102", "which", ] [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "bitvec" @@ -483,9 +483,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "bytemuck" @@ -513,9 +513,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.19" +version = "1.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" dependencies = [ "shlex", ] @@ -531,15 +531,15 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -609,9 +609,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.37" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" dependencies = [ "clap_builder", "clap_derive", @@ -619,9 +619,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.37" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" dependencies = [ "anstream", "anstyle", @@ -631,27 +631,27 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "colored" @@ -677,7 +677,7 @@ dependencies = [ "poly_commit", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", "transcript", ] @@ -848,7 +848,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -860,7 +860,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -895,7 +895,7 @@ checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -929,9 +929,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys 0.59.0", @@ -939,9 +939,9 @@ dependencies = [ [[package]] name = "ethnum" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0939f82868b77ef93ce3c3c3daf2b3c526b456741da5a1a4559e590965b6026b" +checksum = "ca81e6b4777c89fd810c25a4be2b1bd93ea034fbe58e6a75216a34c6b82c539b" [[package]] name = "ff" @@ -1234,9 +1234,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "allocator-api2", ] @@ -1273,9 +1273,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" +checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" [[package]] name = "hex" @@ -1387,21 +1387,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -1410,31 +1411,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -1442,67 +1423,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - [[package]] name = "idna" version = "1.0.3" @@ -1516,9 +1484,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -1531,7 +1499,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.4", ] [[package]] @@ -1595,9 +1563,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.10" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a064218214dc6a10fbae5ec5fa888d80c45d611aba169222fc272072bf7aef6" +checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" dependencies = [ "jiff-static", "log", @@ -1608,13 +1576,13 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.10" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "199b7932d97e325aff3a7030e141eafe7f2c6268e1d1b24859b753a627f45254" +checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -1678,12 +1646,12 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets", + "windows-targets 0.53.0", ] [[package]] @@ -1694,15 +1662,15 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -1775,22 +1743,22 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "wasi", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1890,6 +1858,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "oorandom" version = "11.1.5" @@ -1907,9 +1881,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -1917,15 +1891,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1972,7 +1946,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -2069,9 +2043,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portable-atomic-util" @@ -2082,6 +2056,15 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -2093,12 +2076,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" +checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" dependencies = [ "proc-macro2", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -2186,9 +2169,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ "bitflags", ] @@ -2224,9 +2207,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" [[package]] name = "rustc-hash" @@ -2249,9 +2232,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" @@ -2297,7 +2280,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -2342,7 +2325,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -2358,9 +2341,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -2409,15 +2392,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -2518,9 +2501,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462" dependencies = [ "proc-macro2", "quote", @@ -2529,13 +2512,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -2570,7 +2553,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -2581,7 +2564,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -2595,9 +2578,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -2615,9 +2598,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.44.2" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", @@ -2639,7 +2622,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -2656,9 +2639,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -2686,9 +2669,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", "valuable", @@ -2819,12 +2802,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -2906,9 +2883,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasm-bindgen" @@ -2932,7 +2909,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", "wasm-bindgen-shared", ] @@ -2954,7 +2931,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2993,7 +2970,7 @@ dependencies = [ [[package]] name = "whir" version = "0.1.0" -source = "git+https://github.com/zhenfeizhang/whir#9d7a97b169542f8d0787db482ee58f7b9b660848" +source = "git+https://github.com/zhenfeizhang/whir#5ff2703372c761462a2e45fb392b67667d7c027d" dependencies = [ "ark-crypto-primitives", "ark-ff", @@ -3025,9 +3002,9 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.61.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", @@ -3044,7 +3021,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -3055,7 +3032,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -3066,18 +3043,18 @@ checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" [[package]] name = "windows-result" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -3088,7 +3065,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3097,7 +3074,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -3106,14 +3083,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -3122,42 +3115,84 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -3165,16 +3200,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "write16" -version = "1.0.0" +name = "windows_x86_64_msvc" +version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wyz" @@ -3187,9 +3222,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -3199,34 +3234,34 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] [[package]] @@ -3246,7 +3281,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", "synstructure", ] @@ -3267,14 +3302,25 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", +] + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", ] [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -3283,11 +3329,11 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.102", ] diff --git a/poly_commit/tests/test_whir.rs b/poly_commit/tests/test_whir.rs index 5c5ea97b..67987cc4 100644 --- a/poly_commit/tests/test_whir.rs +++ b/poly_commit/tests/test_whir.rs @@ -22,10 +22,10 @@ use whir::{ const TEST_REPETITION: usize = 3; -pub fn test_whir_pcs>( +fn test_whir_pcs_helper>( params: &P::Params, poly: &P::Poly, - xs: &[P::EvalPoint], + x: &P::EvalPoint, ) { let mut rng = thread_rng(); // NOTE(HS) we assume that the polynomials we pass in are of sufficient length. @@ -39,40 +39,34 @@ pub fn test_whir_pcs = (0..TEST_REPETITION) - .map(|_| -> Vec { - (0..num_vars) - .map(|_| GoldilocksExt2::random_unsafe(&mut rng)) - .collect() - }) + let point = (0..num_vars) + .map(|_| GoldilocksExt2::random_unsafe(&mut rng)) .collect(); let poly = MultiLinearPoly::::random(num_vars, &mut rng); @@ -98,13 +92,13 @@ fn test_whir_pcs_generics(num_vars_start: usize, num_vars_end: usize) { whir_params, ); - test_whir_pcs::, WhirPCS>( - ¶ms, &poly, &xs, + test_whir_pcs_helper::, WhirPCS>( + ¶ms, &poly, &point, ); }) } #[test] fn test_whir_pcs_full_e2e() { - test_whir_pcs_generics(10, 15) + test_whir_pcs(10, 15) } From 9035ab890b069c363882a5b23178ed0c943ed934 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Thu, 12 Jun 2025 18:22:54 -0400 Subject: [PATCH 54/57] clean up --- poly_commit/src/whir.rs | 36 ++++++++++++++++------------------ poly_commit/tests/test_whir.rs | 8 +------- serdes/src/serdes.rs | 15 -------------- 3 files changed, 18 insertions(+), 41 deletions(-) diff --git a/poly_commit/src/whir.rs b/poly_commit/src/whir.rs index 745a3db5..4353f3a1 100644 --- a/poly_commit/src/whir.rs +++ b/poly_commit/src/whir.rs @@ -1,4 +1,3 @@ -use arith::FFTField; use ark_std::log2; use gkr_engine::{StructuredReferenceString, Transcript}; use goldilocks::{Goldilocks, GoldilocksExt2}; @@ -8,9 +7,9 @@ use spongefish_pow::keccak::KeccakPoW; use whir::{ crypto::{ fields::{Field64, Field64_2}, - merkle_tree::keccak::{KeccakCompress, KeccakMerkleTreeParams}, + merkle_tree::keccak::KeccakMerkleTreeParams, }, - poly_utils::{coeffs::CoefficientList, evals::EvaluationsList, multilinear::MultilinearPoint}, + poly_utils::{coeffs::CoefficientList, multilinear::MultilinearPoint}, whir::{ committer::{CommitmentReader, CommitmentWriter}, domainsep::WhirDomainSeparator, @@ -46,8 +45,8 @@ impl PolynomialCommitmentScheme for WhirPCS { fn init_scratch_pad(params: &Self::Params) -> Self::ScratchPad { // todo: session identifier can be sampled from transcript? let domainsep = DomainSeparator::new("🌪️") - .commit_statement(¶ms) - .add_whir_proof(¶ms); + .commit_statement(params) + .add_whir_proof(params); domainsep.to_prover_state() } @@ -71,15 +70,13 @@ impl PolynomialCommitmentScheme for WhirPCS { let committer = CommitmentWriter::new(params.clone()); - let witness = committer.commit(prover_state, whir_poly.clone()).unwrap(); - - witness + committer.commit(prover_state, whir_poly.clone()).unwrap() } fn open( params: &Self::Params, commitment: &Self::Commitment, - proving_key: &::PKey, + _proving_key: &::PKey, poly: &Self::Poly, x: &Self::EvalPoint, prover_state: &mut Self::ScratchPad, @@ -118,12 +115,12 @@ impl PolynomialCommitmentScheme for WhirPCS { fn verify( params: &Self::Params, - verifying_key: &::VKey, - commitment: &Self::Commitment, + _verifying_key: &::VKey, + _commitment: &Self::Commitment, x: &Self::EvalPoint, eval: GoldilocksExt2, opening: &Self::Opening, - transcript: &mut impl Transcript, + _transcript: &mut impl Transcript, ) -> bool { let num_variables = x.len(); let mut statement = Statement::::new(num_variables); @@ -136,26 +133,27 @@ impl PolynomialCommitmentScheme for WhirPCS { let weights = Weights::evaluation(point.clone()); statement.add_constraint(weights, eval.into()); - let commitment_reader = CommitmentReader::new(¶ms); - let verifier = Verifier::new(¶ms); + let commitment_reader = CommitmentReader::new(params); + let verifier = Verifier::new(params); let domainsep = DomainSeparator::new("🌪️") - .commit_statement(¶ms) - .add_whir_proof(¶ms); + .commit_statement(params) + .add_whir_proof(params); let mut verifier_state = domainsep.to_verifier_state(opening); let parsed_commitment = commitment_reader .parse_commitment(&mut verifier_state) .unwrap(); - let (point, constraint) = + let (_point, constraint) = match verifier.verify(&mut verifier_state, &parsed_commitment, &statement) { Ok((p, c)) => (p, c), Err(_) => return false, }; - println!("WhirPCS: Verifying point: {:?}", point); - println!("WhirPCS: Verifying constraint: {:?}", constraint); + if !constraint.is_empty() { + return false; + } true } diff --git a/poly_commit/tests/test_whir.rs b/poly_commit/tests/test_whir.rs index 67987cc4..92137350 100644 --- a/poly_commit/tests/test_whir.rs +++ b/poly_commit/tests/test_whir.rs @@ -6,7 +6,7 @@ use goldilocks::{Goldilocks, GoldilocksExt2}; use poly_commit::{PolynomialCommitmentScheme, WhirPCS}; use polynomials::MultiLinearPoly; use rand::thread_rng; -use spongefish_pow::{keccak::KeccakPoW, PowStrategy}; +use spongefish_pow::keccak::KeccakPoW; use transcript::BytesHashTranscript; use whir::{ crypto::{ @@ -20,8 +20,6 @@ use whir::{ whir::parameters::WhirConfig, }; -const TEST_REPETITION: usize = 3; - fn test_whir_pcs_helper>( params: &P::Params, poly: &P::Poly, @@ -34,12 +32,8 @@ fn test_whir_pcs_helper> { - fn serialize_into(&self, mut writer: W) -> SerdeResult<()> { - todo!() - } - - fn deserialize_from(mut reader: R) -> SerdeResult { - todo!() - } -} From d3acbf8b0f2ea10177a7f14dd5374d9a097cd883 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Sat, 14 Jun 2025 13:37:22 -0400 Subject: [PATCH 55/57] fix clippy --- poly_commit/Cargo.toml | 4 +- poly_commit/benches/hyrax.rs | 5 +- poly_commit/benches/kzg.rs | 5 +- poly_commit/benches/pcs_all.rs | 96 ++++++++++++++++++++-------------- poly_commit/src/traits.rs | 2 +- poly_commit/src/whir.rs | 37 +++++++++++-- poly_commit/tests/test_whir.rs | 22 +------- serdes/src/serdes.rs | 13 +++++ 8 files changed, 114 insertions(+), 70 deletions(-) diff --git a/poly_commit/Cargo.toml b/poly_commit/Cargo.toml index c75c4627..a75a7318 100644 --- a/poly_commit/Cargo.toml +++ b/poly_commit/Cargo.toml @@ -54,6 +54,6 @@ name = "pcs_all" harness = false [features] -default = [ ] -# default = [ "profile" ] +# default = [ ] +default = [ "profile" ] profile = [ "utils/profile" ] \ No newline at end of file diff --git a/poly_commit/benches/hyrax.rs b/poly_commit/benches/hyrax.rs index dcc52f8a..b8c2c06f 100644 --- a/poly_commit/benches/hyrax.rs +++ b/poly_commit/benches/hyrax.rs @@ -64,7 +64,7 @@ fn hyrax_opening_benchmark_helper( let (srs, _) = HyraxPCS::::gen_srs_for_testing(&num_vars, &mut rng); let eval_point: Vec<_> = (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(); - let _ = HyraxPCS::::commit(&num_vars, &srs, &poly, &mut scratch_pad); + let com = HyraxPCS::::commit(&num_vars, &srs, &poly, &mut scratch_pad); group .bench_function( @@ -73,10 +73,11 @@ fn hyrax_opening_benchmark_helper( b.iter(|| { _ = black_box(HyraxPCS::::open( &num_vars, + &com, &srs, &poly, &eval_point, - &scratch_pad, + &mut scratch_pad, &mut transcript, )) }) diff --git a/poly_commit/benches/kzg.rs b/poly_commit/benches/kzg.rs index 7483df1e..d54b799e 100644 --- a/poly_commit/benches/kzg.rs +++ b/poly_commit/benches/kzg.rs @@ -64,7 +64,7 @@ fn hyperkzg_opening_benchmark_helper( let (srs, _) = HyperBiKZGPCS::::gen_srs_for_testing(&num_vars, &mut rng); let eval_point: Vec<_> = (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(); - let _ = HyperBiKZGPCS::::commit(&num_vars, &srs, &poly, &mut scratch_pad); + let com = HyperBiKZGPCS::::commit(&num_vars, &srs, &poly, &mut scratch_pad); group .bench_function( @@ -73,10 +73,11 @@ fn hyperkzg_opening_benchmark_helper( b.iter(|| { _ = black_box(HyperBiKZGPCS::::open( &num_vars, + &com, &srs, &poly, &eval_point, - &scratch_pad, + &mut scratch_pad, &mut transcript, )) }) diff --git a/poly_commit/benches/pcs_all.rs b/poly_commit/benches/pcs_all.rs index 5faf0e7d..2a2aeaba 100644 --- a/poly_commit/benches/pcs_all.rs +++ b/poly_commit/benches/pcs_all.rs @@ -4,9 +4,11 @@ use criterion::black_box; use gkr_engine::StructuredReferenceString; use gkr_engine::{root_println, MPIConfig, MPIEngine, Transcript}; use gkr_hashers::{Keccak256hasher, SHA256hasher}; +use goldilocks::{Goldilocks, GoldilocksExt2}; use halo2curves::bn256::{Bn256, G1Affine}; use poly_commit::{ - BatchOpeningPCS, HyperUniKZGPCS, HyraxPCS, OrionBaseFieldPCS, PolynomialCommitmentScheme, + BatchOpeningPCS, HyperUniKZGPCS, HyraxPCS, OrionSIMDFieldPCS, PolynomialCommitmentScheme, + WhirPCS, }; use polynomials::MultiLinearPoly; use rand::RngCore; @@ -21,46 +23,58 @@ fn main() { let world = universe.world(); let mpi_config = MPIConfig::prover_new(Some(&universe), Some(&world)); println!("=========================="); - for num_vars in 18..21 { + for num_vars in 10..21 { root_println!(mpi_config, "num vars: {}", num_vars); + bench_whir(&mpi_config, num_vars); + bench_orion(&mpi_config, num_vars); bench_kzg(&mpi_config, num_vars); bench_hyrax(&mpi_config, num_vars); - bench_orion(&mpi_config, num_vars); println!("=========================="); } } -fn bench_orion(mpi_config: &MPIConfig, num_vars: usize) { +fn bench_whir(mpi_config: &MPIConfig, num_vars: usize) { // full scalar let mut rng = test_rng(); - let (srs, _) = OrionBaseFieldPCS::::gen_srs_for_testing(&num_vars, &mut rng); - let poly = MultiLinearPoly::::random(num_vars, &mut rng); - let eval_point: Vec<_> = (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(); - pcs_bench::>( - mpi_config, - &num_vars, - &srs, - &poly, - &eval_point, - "orion full scalar ", - ); + let params = WhirPCS::random_params(num_vars, &mut rng); + let (srs, _) = WhirPCS::gen_srs_for_testing(¶ms, &mut rng); - // small scalar - let input = (0..1 << num_vars) - .map(|_| Fr::from(rng.next_u32())) - .collect::>(); - let poly = MultiLinearPoly::::new(input); - pcs_bench::>( + let poly = MultiLinearPoly::::random(num_vars, &mut rng); + let eval_point: Vec<_> = (0..num_vars) + .map(|_| GoldilocksExt2::random_unsafe(&mut rng)) + .collect(); + pcs_bench::( mpi_config, - &num_vars, + ¶ms, &srs, &poly, &eval_point, - "orion small scalar", + "Whir goldilocks ", ); } +fn bench_orion(mpi_config: &MPIConfig, num_vars: usize) { + let mut rng = test_rng(); + { + // Bn scalar + let (srs, _) = + OrionSIMDFieldPCS::::gen_srs_for_testing(&num_vars, &mut rng); + + let poly = MultiLinearPoly::::random(num_vars, &mut rng); + let eval_point: Vec<_> = (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(); + + pcs_bench::, Fr>( + mpi_config, + &num_vars, + &srs, + &poly, + &eval_point, + "orion Fr ", + ); + } +} + fn bench_hyrax(mpi_config: &MPIConfig, num_vars: usize) { // full scalar let mut rng = test_rng(); @@ -69,7 +83,7 @@ fn bench_hyrax(mpi_config: &MPIConfig, num_vars: usize) { let poly = MultiLinearPoly::::random(num_vars, &mut rng); let eval_point: Vec<_> = (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(); - pcs_bench::>( + pcs_bench::, Fr>( mpi_config, &num_vars, &srs, @@ -83,7 +97,7 @@ fn bench_hyrax(mpi_config: &MPIConfig, num_vars: usize) { .map(|_| Fr::from(rng.next_u32())) .collect::>(); let poly = MultiLinearPoly::::new(input); - pcs_bench::>( + pcs_bench::, Fr>( mpi_config, &num_vars, &srs, @@ -93,7 +107,7 @@ fn bench_hyrax(mpi_config: &MPIConfig, num_vars: usize) { ); // batch open - bench_batch_open::>(mpi_config, num_vars, NUM_POLY_BATCH_OPEN); + bench_batch_open::, Fr>(mpi_config, num_vars, NUM_POLY_BATCH_OPEN); } fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { @@ -104,7 +118,7 @@ fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { let poly = MultiLinearPoly::::random(num_vars, &mut rng); let eval_point: Vec<_> = (0..num_vars).map(|_| Fr::random_unsafe(&mut rng)).collect(); - pcs_bench::>( + pcs_bench::, Fr>( mpi_config, &num_vars, &srs, @@ -118,7 +132,7 @@ fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { .map(|_| Fr::from(rng.next_u32())) .collect::>(); let poly = MultiLinearPoly::::new(input); - pcs_bench::>( + pcs_bench::, Fr>( mpi_config, &num_vars, &srs, @@ -128,17 +142,20 @@ fn bench_kzg(mpi_config: &MPIConfig, num_vars: usize) { ); // batch open - bench_batch_open::>(mpi_config, num_vars, NUM_POLY_BATCH_OPEN); + bench_batch_open::, Fr>(mpi_config, num_vars, NUM_POLY_BATCH_OPEN); } -fn pcs_bench>( +fn pcs_bench( mpi_config: &MPIConfig, - num_vars: &PCS::Params, + params: &PCS::Params, srs: &PCS::SRS, poly: &PCS::Poly, eval_point: &PCS::EvalPoint, label: &str, -) { +) where + PCS: PolynomialCommitmentScheme, + F: Field + ExtensionField, +{ let timer = Timer::new( format!("{} commit ", label).as_ref(), mpi_config.is_root(), @@ -147,9 +164,9 @@ fn pcs_bench>( let (pk, vk) = srs.clone().into_keys(); let mut transcript = BytesHashTranscript::::new(); - let mut scratch_pad = PCS::init_scratch_pad(&num_vars); + let mut scratch_pad = PCS::init_scratch_pad(¶ms); - let com = black_box(PCS::commit(&num_vars, &pk, &poly, &mut scratch_pad)); + let com = black_box(PCS::commit(¶ms, &pk, &poly, &mut scratch_pad)); timer.stop(); let timer = Timer::new( @@ -157,11 +174,12 @@ fn pcs_bench>( mpi_config.is_root(), ); let (eval, open) = black_box(PCS::open( - &num_vars, + ¶ms, + &com, &pk, &poly, &eval_point, - &scratch_pad, + &mut scratch_pad, &mut transcript, )); timer.stop(); @@ -172,7 +190,7 @@ fn pcs_bench>( ); let mut transcript = BytesHashTranscript::::new(); assert!(black_box(PCS::verify( - &num_vars, + ¶ms, &vk, &com, &eval_point, @@ -204,10 +222,10 @@ fn pcs_bench>( root_println!(mpi_config, " --- "); } -fn bench_batch_open(mpi_config: &MPIConfig, num_vars: usize, num_poly: usize) +fn bench_batch_open(mpi_config: &MPIConfig, num_vars: usize, num_poly: usize) where - F: Field + ExtensionField, PCS: BatchOpeningPCS, Poly = MultiLinearPoly>, + F: Field + ExtensionField, { let mut rng = test_rng(); diff --git a/poly_commit/src/traits.rs b/poly_commit/src/traits.rs index 78493e82..a3353f71 100644 --- a/poly_commit/src/traits.rs +++ b/poly_commit/src/traits.rs @@ -15,7 +15,7 @@ pub trait PolynomialCommitmentScheme { type ScratchPad: Debug; type SRS: Clone + Debug + Default + ExpSerde + StructuredReferenceString; - type Commitment; + type Commitment: ExpSerde; type Opening: Clone + Debug + Default + ExpSerde; /// Generate a random structured reference string (SRS) for testing purposes. diff --git a/poly_commit/src/whir.rs b/poly_commit/src/whir.rs index 4353f3a1..9f0ea968 100644 --- a/poly_commit/src/whir.rs +++ b/poly_commit/src/whir.rs @@ -2,13 +2,18 @@ use ark_std::log2; use gkr_engine::{StructuredReferenceString, Transcript}; use goldilocks::{Goldilocks, GoldilocksExt2}; use polynomials::MultiLinearPoly; +use rand::RngCore; use spongefish::{DomainSeparator, ProverState}; use spongefish_pow::keccak::KeccakPoW; use whir::{ crypto::{ fields::{Field64, Field64_2}, - merkle_tree::keccak::KeccakMerkleTreeParams, + merkle_tree::{ + keccak::{KeccakCompress, KeccakLeafHash, KeccakMerkleTreeParams}, + parameters::default_config, + }, }, + parameters::{FoldingFactor, MultivariateParameters, ProtocolParameters, SoundnessType}, poly_utils::{coeffs::CoefficientList, multilinear::MultilinearPoint}, whir::{ committer::{CommitmentReader, CommitmentWriter}, @@ -39,8 +44,8 @@ impl PolynomialCommitmentScheme for WhirPCS { type ScratchPad = ProverState; type SRS = (); - type Commitment = WhirCommitment; //Vec; //WhirCommitment; - type Opening = Vec; //Goldilocks; + type Commitment = WhirCommitment; + type Opening = Vec; fn init_scratch_pad(params: &Self::Params) -> Self::ScratchPad { // todo: session identifier can be sampled from transcript? @@ -158,3 +163,29 @@ impl PolynomialCommitmentScheme for WhirPCS { true } } + +impl WhirPCS { + pub fn random_params(num_vars: usize, rng: &mut impl RngCore) -> WhirParam { + let (leaf_hash_params, two_to_one_params) = + default_config::, KeccakCompress>(rng); + + let mv_params = MultivariateParameters::::new(num_vars); + + let whir_params = ProtocolParameters::, KeccakPoW> { + initial_statement: true, + security_level: 100, + pow_bits: 0, + folding_factor: FoldingFactor::ConstantFromSecondRound(4, 2), + leaf_hash_params, + two_to_one_params, + soundness_type: SoundnessType::ConjectureList, + _pow_parameters: Default::default(), + starting_log_inv_rate: 1, + }; + + WhirConfig::, KeccakPoW>::new( + mv_params, + whir_params, + ) + } +} diff --git a/poly_commit/tests/test_whir.rs b/poly_commit/tests/test_whir.rs index 92137350..5288f65d 100644 --- a/poly_commit/tests/test_whir.rs +++ b/poly_commit/tests/test_whir.rs @@ -64,27 +64,7 @@ fn test_whir_pcs(num_vars_start: usize, num_vars_end: usize) { .collect(); let poly = MultiLinearPoly::::random(num_vars, &mut rng); - let (leaf_hash_params, two_to_one_params) = - default_config::, KeccakCompress>(&mut rng); - - let mv_params = MultivariateParameters::::new(num_vars); - - let whir_params = ProtocolParameters::, KeccakPoW> { - initial_statement: true, - security_level: 100, - pow_bits: 0, - folding_factor: FoldingFactor::ConstantFromSecondRound(4, 2), - leaf_hash_params, - two_to_one_params, - soundness_type: SoundnessType::ConjectureList, - _pow_parameters: Default::default(), - starting_log_inv_rate: 1, - }; - - let params = WhirConfig::, KeccakPoW>::new( - mv_params, - whir_params, - ); + let params = WhirPCS::random_params(num_vars, &mut rng); test_whir_pcs_helper::, WhirPCS>( ¶ms, &poly, &point, diff --git a/serdes/src/serdes.rs b/serdes/src/serdes.rs index 26d61a4c..4e18367d 100644 --- a/serdes/src/serdes.rs +++ b/serdes/src/serdes.rs @@ -9,6 +9,10 @@ use halo2curves::{ bn256::{Fr, G1Affine, G2Affine}, group::GroupEncoding, }; +use whir::{ + crypto::{fields::Field64_2, merkle_tree::keccak::KeccakMerkleTreeParams}, + whir::committer::Witness, +}; use crate::{exp_serde_for_generic_slices, exp_serde_for_number, SerdeError, SerdeResult}; @@ -208,3 +212,12 @@ impl ExpSerde for String { String::from_utf8(buf).map_err(|_| SerdeError::DeserializeError) } } + +impl ExpSerde for Witness> { + fn serialize_into(&self, mut _writer: W) -> SerdeResult<()> { + Ok(()) + } + fn deserialize_from(mut _reader: R) -> SerdeResult { + unimplemented!("Witness deserialization is not implemented for witness"); + } +} From e00e69e66617bb5a461ffe8b8dcb761d0cac19ae Mon Sep 17 00:00:00 2001 From: zhenfei Date: Sat, 14 Jun 2025 14:00:25 -0400 Subject: [PATCH 56/57] clean up --- poly_commit/tests/test_whir.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/poly_commit/tests/test_whir.rs b/poly_commit/tests/test_whir.rs index 5288f65d..ccd2242e 100644 --- a/poly_commit/tests/test_whir.rs +++ b/poly_commit/tests/test_whir.rs @@ -6,19 +6,7 @@ use goldilocks::{Goldilocks, GoldilocksExt2}; use poly_commit::{PolynomialCommitmentScheme, WhirPCS}; use polynomials::MultiLinearPoly; use rand::thread_rng; -use spongefish_pow::keccak::KeccakPoW; use transcript::BytesHashTranscript; -use whir::{ - crypto::{ - fields::Field64_2, - merkle_tree::{ - keccak::{KeccakCompress, KeccakLeafHash, KeccakMerkleTreeParams}, - parameters::default_config, - }, - }, - parameters::{FoldingFactor, MultivariateParameters, ProtocolParameters, SoundnessType}, - whir::parameters::WhirConfig, -}; fn test_whir_pcs_helper>( params: &P::Params, From 6361e3f76aeaa3153abf1e1173a4eb4cc81137a5 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Sat, 14 Jun 2025 14:01:40 -0400 Subject: [PATCH 57/57] clean up --- poly_commit/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/poly_commit/Cargo.toml b/poly_commit/Cargo.toml index a75a7318..c75c4627 100644 --- a/poly_commit/Cargo.toml +++ b/poly_commit/Cargo.toml @@ -54,6 +54,6 @@ name = "pcs_all" harness = false [features] -# default = [ ] -default = [ "profile" ] +default = [ ] +# default = [ "profile" ] profile = [ "utils/profile" ] \ No newline at end of file