diff --git a/bi-kzg/src/bi_kzg.rs b/bi-kzg/src/bi_kzg.rs index 80bcc02b..7c881a85 100644 --- a/bi-kzg/src/bi_kzg.rs +++ b/bi-kzg/src/bi_kzg.rs @@ -16,8 +16,8 @@ use rand::Rng; use rand::RngCore; use crate::msm::best_multiexp; -use crate::structs::BivaraitePolynomial; -use crate::util::lagrange_coefficients; +use crate::poly::lagrange_coefficients; +use crate::structs::BivariatePolynomial; use crate::util::parallelize; use crate::{ pcs::PolynomialCommitmentScheme, @@ -26,7 +26,7 @@ use crate::{ }; pub struct BiKZG { - _MultiMillerLoop: PhantomData, + _phantom: PhantomData, } impl PolynomialCommitmentScheme for BiKZG @@ -36,7 +36,7 @@ where type SRS = BiKZGSRS; type ProverParam = BiKZGSRS; type VerifierParam = BiKZGVerifierParam; - type Polynomial = BivaraitePolynomial; + type Polynomial = BivariatePolynomial; type Commitment = BiKZGCommitment; type Proof = BiKZGProof; type Evaluation = E::Fr; @@ -64,6 +64,9 @@ where let omega_0 = omega.pow_vartime(&[(1 << E::Fr::S) / supported_n as u64]); let omega_1 = omega.pow_vartime(&[(1 << E::Fr::S) / supported_m as u64]); + println!("omega 0: {:?}", omega_0); + println!("omega 1: {:?}", omega_1); + assert!( omega_0.pow_vartime(&[supported_n as u64]) == E::Fr::ONE, "omega_0 is not root of unity for supported_n" @@ -101,18 +104,15 @@ where let mut g_bases = vec![E::G1Affine::identity(); supported_n * supported_m]; parallelize(&mut g_bases, |g, starts| { - E::G1::batch_normalize( - &proj_bases[starts..(starts + g.len())], - g, - ); + E::G1::batch_normalize(&proj_bases[starts..(starts + g.len())], g); }); drop(proj_bases); g_bases }; - println!("start to compute the lagrange bases"); - let largrange_bases = { + println!("lagrange scalars: {:?} ", lagrange_scalars); + let lagrange_bases = { let mut proj_bases = vec![E::G1::identity(); supported_n * supported_m]; parallelize(&mut proj_bases, |g, start| { for (idx, g) in g.iter_mut().enumerate() { @@ -136,7 +136,7 @@ where tau_0, tau_1, powers_of_g: coeff_bases, - powers_of_g_largrange: largrange_bases, + powers_of_g_lagrange: lagrange_bases, h: E::G2Affine::generator(), tau_0_h: (E::G2Affine::generator() * tau_0).into(), tau_1_h: (E::G2Affine::generator() * tau_1).into(), @@ -169,6 +169,17 @@ where "commitment is not equal to evaluation" ); + let lag_coeff = poly.lagrange_coeffs(); + let com_lag = best_multiexp( + &lag_coeff, + prover_param.borrow().powers_of_g_lagrange.as_slice(), + ) + .into(); + assert_eq!( + com, com_lag, + "commitment is not equal to lagrange commitment" + ); + Self::Commitment { com } } diff --git a/bi-kzg/src/lib.rs b/bi-kzg/src/lib.rs index ff74f138..4d557237 100644 --- a/bi-kzg/src/lib.rs +++ b/bi-kzg/src/lib.rs @@ -7,5 +7,6 @@ mod structs; mod tests; mod util; -pub use structs::BivaraitePolynomial; +pub use pcs::PolynomialCommitmentScheme; +pub use structs::BivariatePolynomial; pub use structs::{BiKZGCommitment, BiKZGProof, BiKZGSRS, BiKZGVerifierParam}; diff --git a/bi-kzg/src/pcs.rs b/bi-kzg/src/pcs.rs index a257491a..4a3fee9d 100644 --- a/bi-kzg/src/pcs.rs +++ b/bi-kzg/src/pcs.rs @@ -29,9 +29,6 @@ pub trait PolynomialCommitmentScheme { /// Build SRS for testing. /// - /// - For univariate polynomials, `supported_size` is the maximum degree. - /// - For multilinear polynomials, `supported_size` is the number of - /// variables. /// /// WARNING: THIS FUNCTION IS FOR TESTING PURPOSE ONLY. /// THE OUTPUT SRS SHOULD NOT BE USED IN PRODUCTION. @@ -113,39 +110,3 @@ pub trait PolynomialCommitmentScheme { unimplemented!() } } - -// /// API definitions for structured reference string -// /// -// /// Credit: https://github.com/EspressoSystems/hyperplonk/blob/8698369edfe82bd6617a9609602380f21cabd1da/subroutines/src/pcs/mod.rs#L135 -// pub trait StructuredReferenceString: Sized { -// /// Prover parameters -// type ProverParam; -// /// Verifier parameters -// type VerifierParam; - -// /// Extract the prover parameters from the public parameters. -// fn extract_prover_param(&self, supported_size: usize) -> Self::ProverParam; -// /// Extract the verifier parameters from the public parameters. -// fn extract_verifier_param(&self, supported_size: usize) -> Self::VerifierParam; - -// /// Trim the universal parameters to specialize the public parameters -// /// for polynomials to the given `supported_size`, and -// /// returns committer key and verifier key. -// /// -// /// - For univariate polynomials, `supported_size` is the maximum degree. -// /// - For multilinear polynomials, `supported_size` is 2 to the number of -// /// variables. -// /// -// /// `supported_log_size` should be in range `1..=params.log_size` -// fn trim(&self, supported_size: usize) -> (Self::ProverParam, Self::VerifierParam); - -// /// Build SRS for testing. -// /// -// /// - For univariate polynomials, `supported_size` is the maximum degree. -// /// - For multilinear polynomials, `supported_size` is the number of -// /// variables. -// /// -// /// WARNING: THIS FUNCTION IS FOR TESTING PURPOSE ONLY. -// /// THE OUTPUT SRS SHOULD NOT BE USED IN PRODUCTION. -// fn gen_srs_for_testing(rng: &mut R, supported_size: usize) -> Self; -// } diff --git a/bi-kzg/src/poly.rs b/bi-kzg/src/poly.rs index f8c86d22..b00845f1 100644 --- a/bi-kzg/src/poly.rs +++ b/bi-kzg/src/poly.rs @@ -1,10 +1,11 @@ -use halo2curves::ff::Field; +use halo2curves::ff::{Field, PrimeField}; use rand::RngCore; +use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; -use crate::structs::BivaraitePolynomial; +use crate::structs::{BivariateLagrangePolynomial, BivariatePolynomial}; use crate::util::powers_of_field_elements; -impl BivaraitePolynomial { +impl BivariatePolynomial { #[inline] pub fn new(coefficients: Vec, degree_0: usize, degree_1: usize) -> Self { assert_eq!(coefficients.len(), degree_0 * degree_1); @@ -37,16 +38,105 @@ impl BivaraitePolynomial { * y_i }) } + + /// + pub fn lagrange_coeffs(&self) -> Vec { + // roots of unity for supported_n and supported_m + let (omega_0, omega_1) = { + let omega = F::ROOT_OF_UNITY; + let omega_0 = omega.pow_vartime(&[(1 << F::S) / self.degree_0 as u64]); + let omega_1 = omega.pow_vartime(&[(1 << F::S) / self.degree_1 as u64]); + + assert!( + omega_0.pow_vartime(&[self.degree_0 as u64]) == F::ONE, + "omega_0 is not root of unity for supported_n" + ); + assert!( + omega_1.pow_vartime(&[self.degree_1 as u64]) == F::ONE, + "omega_1 is not root of unity for supported_m" + ); + (omega_0, omega_1) + }; + let powers_of_omega_0 = powers_of_field_elements(&omega_0, self.degree_0); + let powers_of_omega_1 = powers_of_field_elements(&omega_1, self.degree_1); + println!( + "omega len {} {}", + powers_of_omega_0.len(), + powers_of_omega_1.len() + ); + + // Todo! Optimize me. This is not efficient. + let mut res = vec![]; + for omega_1_power in powers_of_omega_1.iter() { + for omega_0_power in powers_of_omega_0.iter() { + res.push(self.evaluate(omega_0_power, omega_1_power)); + } + } + + println!("res: {:?}", res); + res + } + + // pub fn from_lagrange_coeffs(coeffs: Vec, degree_0: usize, degree_1: usize) -> Self { + // assert_eq!(coeffs.len(), degree_0 * degree_1); + // todo!() + // } +} + +/// For x in points, compute the Lagrange coefficients at x given the roots. +/// `L_{i}(x) = \prod_{j \neq i} \frac{x - r_j}{r_i - r_j}`` +pub(crate) fn lagrange_coefficients(roots: &[F], points: &[F]) -> Vec { + roots + .par_iter() + .enumerate() + .map(|(i, _)| { + let mut numerator = F::ONE; + let mut denominator = F::ONE; + for j in 0..roots.len() { + if i == j { + continue; + } + numerator *= roots[j] - points[i]; + denominator *= roots[j] - roots[i]; + } + numerator * denominator.invert().unwrap() + }) + .collect() +} + +impl BivariateLagrangePolynomial { + fn new(coeffs: Vec, degree_0: usize, degree_1: usize) -> Self { + assert_eq!(coeffs.len(), degree_0 * degree_1); + Self { + coefficients: coeffs, + degree_0, + degree_1, + } + } +} + +impl From> for BivariateLagrangePolynomial { + fn from(poly: BivariatePolynomial) -> Self { + let coeffs = poly.lagrange_coeffs(); + BivariateLagrangePolynomial::new(coeffs, poly.degree_0, poly.degree_1) + } +} + +impl From> for BivariatePolynomial { + fn from(poly: BivariateLagrangePolynomial) -> Self { + todo!() + } } #[cfg(test)] mod tests { + use crate::structs::BivariatePolynomial; + use halo2curves::bn256::Fr; + #[test] fn test_bivariate_poly_eval() { - use crate::structs::BivaraitePolynomial; - use halo2curves::bn256::Fr; { - let poly = BivaraitePolynomial::new( + let poly = BivariatePolynomial::new( vec![ Fr::from(1u64), Fr::from(2u64), @@ -66,7 +156,7 @@ mod tests { } { - let poly = BivaraitePolynomial::new( + let poly = BivariatePolynomial::new( vec![ Fr::from(1u64), Fr::from(2u64), @@ -93,7 +183,7 @@ mod tests { ); } - let poly = BivaraitePolynomial::new( + let poly = BivariatePolynomial::new( vec![ Fr::from(1u64), Fr::from(2u64), @@ -123,4 +213,30 @@ mod tests { * y ); } + + // #[test] + // fn test_lagrange_coeffs() { + // let poly = BivariatePolynomial::new( + // vec![ + // Fr::from(1u64), + // Fr::from(2u64), + // Fr::from(3u64), + // Fr::from(4u64), + // Fr::from(5u64), + // Fr::from(10u64), + // Fr::from(15u64), + // Fr::from(20u64), + // ], + // 4, + // 2, + // ); + + // let lagrange_coeffs = poly.lagrange_coeffs(); + // println!("lag: {:?}", lagrange_coeffs); + // assert_eq!(lagrange_coeffs.len(), 8); + // assert_eq!(lagrange_coeffs[0], Fr::from(1u64)); + // assert_eq!(lagrange_coeffs[1], Fr::from(2u64)); + // assert_eq!(lagrange_coeffs[2], Fr::from(3u64)); + // assert_eq!(lagrange_coeffs[3], Fr::from(4u64)); + // } } diff --git a/bi-kzg/src/structs.rs b/bi-kzg/src/structs.rs index 4d1163d9..8d25f512 100644 --- a/bi-kzg/src/structs.rs +++ b/bi-kzg/src/structs.rs @@ -3,7 +3,14 @@ use std::io::{self, Read, Write}; use halo2curves::{pairing::Engine, serde::SerdeObject}; #[derive(Clone, Debug, Default, PartialEq, Eq)] -pub struct BivaraitePolynomial { +pub struct BivariatePolynomial { + pub coefficients: Vec, + pub degree_0: usize, + pub degree_1: usize, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct BivariateLagrangePolynomial { pub coefficients: Vec, pub degree_0: usize, pub degree_1: usize, @@ -24,7 +31,7 @@ pub struct BiKZGSRS { /// ) pub powers_of_g: Vec, /// g in lagrange form - pub powers_of_g_largrange: Vec, + pub powers_of_g_lagrange: Vec, /// The generator of G2. pub h: E::G2Affine, /// tau_0 times the above generator of G2. diff --git a/bi-kzg/src/tests.rs b/bi-kzg/src/tests.rs index 25a2887b..cbbf2ea1 100644 --- a/bi-kzg/src/tests.rs +++ b/bi-kzg/src/tests.rs @@ -1,7 +1,30 @@ use ark_std::test_rng; use halo2curves::bn256::{Bn256, Fr}; -use crate::{bi_kzg::BiKZG, pcs::PolynomialCommitmentScheme, BivaraitePolynomial}; +use crate::{ + bi_kzg::BiKZG, pcs::PolynomialCommitmentScheme, poly::lagrange_coefficients, + util::tensor_product_parallel, BivariatePolynomial, +}; + +// #[test] +// fn test_interpolation() { +// let f = (0..8).map(|x| Fr::from(x as u64)).collect::>(); +// let f = BivariatePolynomial::new(f, 2, 4); +// let r1 = (0..2).map(|x| Fr::from(x as u64)).collect::>(); +// let r2 = (0..4).map(|x| Fr::from(x as u64)).collect::>(); + +// let evals = r2 +// .iter() +// .flat_map(|r2| { +// r1.iter() +// .map(|&r1| f.evaluate(&r1, &r2)) +// .collect::>() +// }) +// .collect::>(); + +// let power + +// } #[test] fn test_bi_kzg_e2e() { @@ -10,7 +33,7 @@ fn test_bi_kzg_e2e() { let m = 4; let srs = BiKZG::::gen_srs_for_testing(&mut rng, n, m); - let poly = BivaraitePolynomial::new( + let poly = BivariatePolynomial::new( vec![ Fr::from(1u64), Fr::from(2u64), @@ -24,7 +47,7 @@ fn test_bi_kzg_e2e() { n, m, ); - // let poly = BivaraitePolynomial::random(&mut rng, n, m); + // let poly = BivariatePolynomial::random(&mut rng, n, m); let x = Fr::from(5u64); let y = Fr::from(6u64); @@ -42,3 +65,29 @@ fn test_bi_kzg_e2e() { assert!(false) } + +#[test] +fn test_lagrange_eval() { + let roots = vec![Fr::from(1u64), Fr::from(2u64), Fr::from(3u64)]; + let points = vec![Fr::from(4u64), Fr::from(5u64), Fr::from(6u64)]; + let result = lagrange_coefficients(&roots, &points); + assert_eq!(result[0], Fr::from(1u64)); + assert_eq!(result[1], -Fr::from(8u64)); + assert_eq!(result[2], Fr::from(10u64)); +} + +#[test] +fn test_tensor_product() { + let vec1 = vec![Fr::from(1u64), Fr::from(2u64), Fr::from(3u64)]; + let vec2 = vec![Fr::from(4u64), Fr::from(5u64), Fr::from(6u64)]; + let result = tensor_product_parallel(&vec1, &vec2); + assert_eq!(result[0], Fr::from(4u64)); + assert_eq!(result[1], Fr::from(2u64) * Fr::from(4u64)); + assert_eq!(result[2], Fr::from(3u64) * Fr::from(4u64)); + assert_eq!(result[3], Fr::from(5u64)); + assert_eq!(result[4], Fr::from(2u64) * Fr::from(5u64)); + assert_eq!(result[5], Fr::from(3u64) * Fr::from(5u64)); + assert_eq!(result[6], Fr::from(6u64)); + assert_eq!(result[7], Fr::from(2u64) * Fr::from(6u64)); + assert_eq!(result[8], Fr::from(3u64) * Fr::from(6u64)); +} diff --git a/bi-kzg/src/util.rs b/bi-kzg/src/util.rs index 8794455c..377a482b 100644 --- a/bi-kzg/src/util.rs +++ b/bi-kzg/src/util.rs @@ -17,27 +17,6 @@ pub(crate) fn tensor_product_parallel(vec1: &[F], vec2: &[F]) -> Vec(roots: &[F], points: &[F]) -> Vec { - roots - .par_iter() - .enumerate() - .map(|(i, _)| { - let mut numerator = F::ONE; - let mut denominator = F::ONE; - for j in 0..roots.len() { - if i == j { - continue; - } - numerator *= roots[j] - points[i]; - denominator *= roots[j] - roots[i]; - } - numerator * denominator.invert().unwrap() - }) - .collect() -} - /// This simple utility function will parallelize an operation that is to be /// performed over a mutable slice. /// credit: https://github.com/scroll-tech/halo2/blob/1070391642dd64b2d68b47ec246cba9e35bd3c15/halo2_proofs/src/arithmetic.rs#L546 @@ -71,34 +50,3 @@ pub(crate) fn parallelize_internal(v: &mut [T], f: F) { parallelize_internal(v, f); } - -#[test] -fn test_lagrange_eval() { - use halo2curves::bn256::Fr; - let roots = vec![Fr::from(1u64), Fr::from(2u64), Fr::from(3u64)]; - let points = vec![Fr::from(4u64), Fr::from(5u64), Fr::from(6u64)]; - let result = lagrange_coefficients(&roots, &points); - assert_eq!(result[0], Fr::from(1u64)); - assert_eq!(result[1], -Fr::from(8u64)); - assert_eq!(result[2], Fr::from(10u64)); -} - - -#[test] -fn test_tensor_product(){ - use halo2curves::bn256::Fr; - let vec1 = vec![Fr::from(1u64), Fr::from(2u64), Fr::from(3u64)]; - let vec2 = vec![Fr::from(4u64), Fr::from(5u64), Fr::from(6u64)]; - let result = tensor_product_parallel(&vec1, &vec2); - assert_eq!(result[0], Fr::from(4u64)); - assert_eq!(result[1], Fr::from(2u64)*Fr::from(4u64)); - assert_eq!(result[2], Fr::from(3u64)*Fr::from(4u64)); - assert_eq!(result[3], Fr::from(5u64)); - assert_eq!(result[4], Fr::from(2u64)*Fr::from(5u64)); - assert_eq!(result[5], Fr::from(3u64)*Fr::from(5u64)); - assert_eq!(result[6], Fr::from(6u64)); - assert_eq!(result[7], Fr::from(2u64)*Fr::from(6u64)); - assert_eq!(result[8], Fr::from(3u64)*Fr::from(6u64)); -} - -