diff --git a/poly_commit/src/kzg/hyperkzg.rs b/poly_commit/src/kzg/hyperkzg.rs index df7f394e..758e7b4a 100644 --- a/poly_commit/src/kzg/hyperkzg.rs +++ b/poly_commit/src/kzg/hyperkzg.rs @@ -1,73 +1,166 @@ +use std::iter; + use arith::ExtensionField; -use halo2curves::{ff::Field, group::Group, pairing::MultiMillerLoop, CurveAffine}; +use halo2curves::{ff::Field, group::GroupEncoding, pairing::MultiMillerLoop, CurveAffine}; +use itertools::izip; use transcript::Transcript; use crate::{ - coeff_form_uni_kzg_commit, coeff_form_uni_kzg_open, even_odd_coeffs_separate, merge_coeffs, - powers_of_field_elements, univariate_evaluate, + coeff_form_uni_kzg_commit, even_odd_coeffs_separate, powers_of_field_elements, + univariate_degree_one_quotient, univariate_evaluate, }; -use super::CoefFormUniKZGSRS; +use super::{CoefFormUniKZGSRS, HyperKZGOpening}; pub fn coeff_form_uni_hyperkzg_open>( srs: &CoefFormUniKZGSRS, - coeffs: &[E::Fr], + coeffs: &Vec, alphas: &[E::Fr], _eval: E::Fr, - beta: E::Fr, - gamma: E::Fr, - _transcript: &mut T, -) where + fs_transcript: &mut T, +) -> HyperKZGOpening +where E::G1Affine: CurveAffine, E::Fr: ExtensionField, { - let beta2 = beta * beta; - let power_series = powers_of_field_elements(&beta2, coeffs.len() >> 1); let mut local_coeffs = coeffs.to_vec(); - let mut combine_weight = E::Fr::ONE; - let mut folded_commitment_agg: E::G1 = E::G1::generator() * E::Fr::ZERO; - let mut odd_commitment_agg: E::G1 = E::G1::generator() * E::Fr::ZERO; - let mut even_commitment_agg: E::G1 = E::G1::generator() * E::Fr::ZERO; + let (folded_oracle_commits, folded_oracle_coeffs): (Vec, Vec>) = alphas + [..alphas.len() - 1] + .iter() + .map(|alpha| { + let (evens, odds) = even_odd_coeffs_separate(&local_coeffs); + + local_coeffs = izip!(&evens, &odds) + .map(|(e, o)| (E::Fr::ONE - alpha) * e + *alpha * *o) + .collect(); + + let folded_oracle_commit = coeff_form_uni_kzg_commit(srs, &local_coeffs); + + fs_transcript.append_u8_slice(folded_oracle_commit.to_bytes().as_ref()); + + (folded_oracle_commit, local_coeffs.clone()) + }) + .unzip(); + + let beta = fs_transcript.generate_challenge_field_element(); + let beta2 = beta * beta; + let beta_inv = beta.invert().unwrap(); + let two_inv = E::Fr::ONE.double().invert().unwrap(); + let beta_pow_series = powers_of_field_elements(&beta, coeffs.len()); + let neg_beta_pow_series = powers_of_field_elements(&(-beta), coeffs.len()); + + let beta2_eval = { + let beta2_pow_series = powers_of_field_elements(&beta2, coeffs.len()); + univariate_evaluate(coeffs, &beta2_pow_series) + }; - let mut total_opening_agg: E::G1 = E::G1::generator() * E::Fr::ZERO; - let mut odd_opening_agg: E::G1 = E::G1::generator() * E::Fr::ZERO; - let mut even_opening_agg: E::G1 = E::G1::generator() * E::Fr::ZERO; + fs_transcript.append_field_element(&beta2_eval); + let mut beta2_evals = vec![beta2_eval]; - let mut odd_eval_agg: E::Fr = E::Fr::ZERO; - let mut even_eval_agg: E::Fr = E::Fr::ZERO; + let (beta_evals, neg_beta_evals): (Vec, Vec) = izip!( + iter::once(coeffs).chain(folded_oracle_coeffs.iter()), + alphas + ) + .enumerate() + .map(|(i, (cs, alpha))| { + let beta_eval = univariate_evaluate(cs, &beta_pow_series); + let neg_beta_eval = univariate_evaluate(cs, &neg_beta_pow_series); - alphas.iter().enumerate().for_each(|(i, alpha)| { - if i != 0 { - let local_com = coeff_form_uni_kzg_commit(srs, &local_coeffs); - folded_commitment_agg += local_com * combine_weight; + if i < alphas.len() - 1 { + let beta2_eval = (beta_eval + neg_beta_eval) * two_inv * (E::Fr::ONE - alpha) + + (beta_eval - neg_beta_eval) * two_inv * beta_inv * alpha; + + beta2_evals.push(beta2_eval); } - let (evens, odds) = even_odd_coeffs_separate(&local_coeffs); + fs_transcript.append_field_element(&beta_eval); + fs_transcript.append_field_element(&neg_beta_eval); + + (beta_eval, neg_beta_eval) + }) + .unzip(); + + let gamma = fs_transcript.generate_challenge_field_element(); + let gamma_pow_series = powers_of_field_elements(&gamma, alphas.len()); + let v_beta = univariate_evaluate(&beta_evals, &gamma_pow_series); + let v_neg_beta = univariate_evaluate(&neg_beta_evals, &gamma_pow_series); + let v_beta2 = univariate_evaluate(&beta2_evals, &gamma_pow_series); + let f_gamma = { + let mut f = coeffs.clone(); + izip!(&gamma_pow_series[1..], &folded_oracle_coeffs).for_each(|(gamma_i, folded_f)| { + izip!(&mut f, folded_f).for_each(|(f_i, folded_f_i)| { + *f_i += *folded_f_i * *gamma_i; + }); + }); + f + }; + let lagrange_degree2: Vec = { + let l_beta_nom = vec![-beta2 * beta, -beta2 + beta, E::Fr::ONE]; + let l_beta_denom_inv: E::Fr = ((beta - beta2) * (beta + beta)).invert().unwrap(); + let l_beta: Vec = l_beta_nom.iter().map(|i| *i * l_beta_denom_inv).collect(); + + let l_neg_beta_norm = vec![beta2 * beta, -beta2 - beta, E::Fr::ONE]; + let l_neg_beta_denom_inv: E::Fr = ((beta2 - beta) * (beta2 + beta)).invert().unwrap(); + let l_neg_beta: Vec = l_neg_beta_norm + .iter() + .map(|i| *i * l_neg_beta_denom_inv) + .collect(); + + let l_beta2_norm = vec![-beta2, E::Fr::ZERO, E::Fr::ONE]; + let l_beta2_denom_inv: E::Fr = ((beta + beta2) * (beta + beta)).invert().unwrap(); + let l_beta2: Vec = l_beta2_norm + .iter() + .map(|i| *i * l_beta2_denom_inv) + .collect(); + + izip!(l_beta, l_neg_beta, l_beta2) + .map(|(l_beta_i, l_neg_beta_i, l_beta2_i)| { + l_beta_i * v_beta + l_neg_beta_i * v_neg_beta + l_beta2_i * v_beta2 + }) + .collect() + }; + let f_gamma_quotient = { + let mut nom = f_gamma.clone(); + izip!(&mut nom, &lagrange_degree2).for_each(|(n, l)| *n -= l); + + let (nom_1, remainder_1) = univariate_degree_one_quotient(&nom, beta); + assert_eq!(remainder_1, E::Fr::ZERO); + + let (nom_2, remainder_2) = univariate_degree_one_quotient(&nom_1, beta2); + assert_eq!(remainder_2, E::Fr::ZERO); - let local_evens_com = coeff_form_uni_kzg_commit(srs, &evens); - even_commitment_agg += local_evens_com * combine_weight; + let (nom_3, remainder_3) = univariate_degree_one_quotient(&nom_2, -beta); + assert_eq!(remainder_3, E::Fr::ZERO); - let local_odds_com = coeff_form_uni_kzg_commit(srs, &odds); - odd_commitment_agg += local_odds_com * combine_weight; + nom_3 + }; + let f_gamma_quotient_com = coeff_form_uni_kzg_commit(srs, &f_gamma_quotient); + fs_transcript.append_u8_slice(f_gamma_quotient_com.to_bytes().as_ref()); - let evens_beta2_eval = univariate_evaluate(&evens, &power_series); - let local_even_opening = coeff_form_uni_kzg_open(srs, &evens, beta2, evens_beta2_eval); - even_opening_agg += local_even_opening * combine_weight; - even_eval_agg += evens_beta2_eval * combine_weight; + let tau = fs_transcript.generate_challenge_field_element(); + let vanishing_at_tau = { + let f_gamma_denom = (tau - beta) * (tau + beta) * (tau - beta2); + let lagrange_degree2_at_tau = + lagrange_degree2[0] + lagrange_degree2[1] * tau + lagrange_degree2[2] * tau * tau; - let odds_beta2_eval = univariate_evaluate(&odds, &power_series); - let local_odd_opening = coeff_form_uni_kzg_open(srs, &odds, beta2, odds_beta2_eval); - odd_opening_agg += local_odd_opening * combine_weight; - odd_eval_agg += odds_beta2_eval * combine_weight; + let mut poly = f_gamma.clone(); + poly[0] -= lagrange_degree2_at_tau; + izip!(&mut poly, &f_gamma_quotient).for_each(|(p, f)| *p -= *f * f_gamma_denom); - let current_eval = evens_beta2_eval + beta * odds_beta2_eval; - let local_total_opening = coeff_form_uni_kzg_open(srs, &local_coeffs, beta, current_eval); - total_opening_agg += local_total_opening * combine_weight; + let (quotient, remainder) = univariate_degree_one_quotient(&poly, tau); + assert_eq!(remainder, E::Fr::ZERO); - local_coeffs = merge_coeffs(evens, odds, *alpha); - combine_weight *= gamma; - }); + quotient + }; + let vanishing_at_tau_commitment = coeff_form_uni_kzg_commit(srs, &vanishing_at_tau); - todo!() + HyperKZGOpening { + folded_oracle_commitments: folded_oracle_commits, + f_beta2: beta2_eval, + evals_at_beta: beta_evals, + evals_at_neg_beta: neg_beta_evals, + beta_commitment: f_gamma_quotient_com, + tau_vanishing_commitment: vanishing_at_tau_commitment, + } } diff --git a/poly_commit/src/kzg/structs.rs b/poly_commit/src/kzg/structs.rs index 66100fc6..16c705cc 100644 --- a/poly_commit/src/kzg/structs.rs +++ b/poly_commit/src/kzg/structs.rs @@ -113,3 +113,13 @@ impl From<&CoefFormUniKZGSRS> for UniKZGVerifierParams { } } } + +#[derive(Debug, Default)] +pub struct HyperKZGOpening { + pub folded_oracle_commitments: Vec, + pub f_beta2: E::Fr, + pub evals_at_beta: Vec, + pub evals_at_neg_beta: Vec, + pub beta_commitment: E::G1, + pub tau_vanishing_commitment: E::G1, +} diff --git a/poly_commit/src/kzg/utils.rs b/poly_commit/src/kzg/utils.rs index d1464532..13d49ccb 100644 --- a/poly_commit/src/kzg/utils.rs +++ b/poly_commit/src/kzg/utils.rs @@ -60,9 +60,3 @@ pub(crate) fn even_odd_coeffs_separate(coeffs: &[F]) -> (Vec, Vec(evens: Vec, odds: Vec, alpha: F) -> Vec { - assert_eq!(evens.len(), odds.len()); - - izip!(&evens, &odds).map(|(e, o)| *e + alpha * *o).collect() -}