From 37cb42f65cdae220cd33513763f1da2933f03a11 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 18 Jun 2024 20:56:20 -0400 Subject: [PATCH] clean up; fix clippy --- bi-kzg/src/bi_fft.rs | 71 +------ bi-kzg/src/coeff_form_bi_kzg.rs | 49 +---- bi-kzg/src/lagrange_form_bi_kzg.rs | 21 +- bi-kzg/src/lib.rs | 6 +- bi-kzg/src/pcs.rs | 27 +-- bi-kzg/src/poly.rs | 264 ++---------------------- bi-kzg/src/structs.rs | 79 +------- bi-kzg/src/tests.rs | 310 +++++++++++++++++++++++++++-- bi-kzg/src/util.rs | 2 +- 9 files changed, 341 insertions(+), 488 deletions(-) diff --git a/bi-kzg/src/bi_fft.rs b/bi-kzg/src/bi_fft.rs index acf87772..1ac7fd5d 100644 --- a/bi-kzg/src/bi_fft.rs +++ b/bi-kzg/src/bi_fft.rs @@ -21,6 +21,7 @@ fn deep_swap_chunks(a: &mut [&mut [F]], rk: usize, k: usize) { let x = a[k].as_mut_ptr(); let y = a[rk].as_mut_ptr(); unsafe { + // is there a for i in 0..a[k].len() { std::ptr::swap(x.add(i), y.add(i)); } @@ -129,7 +130,7 @@ pub fn best_fft_vec_in_place(a: &mut [F], omega: F, log_n: u32, l twiddle_chunk /= 2; } } else { - recursive_butterfly_arithmetic(&mut a_vec_ptrs, m, n, 1, &twiddles) + recursive_butterfly_arithmetic(&mut a_vec_ptrs, m, 1, &twiddles) } } @@ -137,7 +138,6 @@ pub fn best_fft_vec_in_place(a: &mut [F], omega: F, log_n: u32, l fn recursive_butterfly_arithmetic( a: &mut [&mut [F]], m: usize, - n: usize, twiddle_chunk: usize, twiddles: &[F], ) { @@ -154,8 +154,8 @@ fn recursive_butterfly_arithmetic( } else { let (left, right) = a.split_at_mut(m / 2); rayon::join( - || recursive_butterfly_arithmetic(left, m / 2, n, twiddle_chunk * 2, twiddles), - || recursive_butterfly_arithmetic(right, m / 2, n, twiddle_chunk * 2, twiddles), + || recursive_butterfly_arithmetic(left, m / 2, twiddle_chunk * 2, twiddles), + || recursive_butterfly_arithmetic(right, m / 2, twiddle_chunk * 2, twiddles), ); // case when twiddle factor is one @@ -188,6 +188,7 @@ fn recursive_butterfly_arithmetic( } } +/// Convert a polynomial in coefficient form to evaluation form using a two layer FFT pub(crate) fn bi_fft_in_place(coeffs: &mut [F], degree_n: usize, degree_m: usize) { assert_eq!(coeffs.len(), degree_n * degree_m); assert!(degree_n.is_power_of_two()); @@ -196,71 +197,17 @@ pub(crate) fn bi_fft_in_place(coeffs: &mut [F], degree_n: usize, // 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) / degree_n as u64]); - let omega_1 = omega.pow_vartime(&[(1 << F::S) / degree_m as u64]); + let omega_0 = omega.pow_vartime([(1 << F::S) / degree_n as u64]); + let omega_1 = omega.pow_vartime([(1 << F::S) / degree_m as u64]); (omega_0, omega_1) }; + // inner layer of FFT over variable x coeffs .chunks_exact_mut(degree_n) .for_each(|chunk| best_fft(chunk, omega_0, log2(degree_n))); + // outer layer of FFT over variable y best_fft_vec_in_place(coeffs, omega_1, log2(degree_n), log2(degree_m)); } - -#[cfg(test)] -mod tests { - use ark_std::test_rng; - use halo2curves::bn256::Fr; - - use crate::BivariatePolynomial; - - use super::bi_fft_in_place; - - #[test] - fn test_bi_fft() { - { - let n = 4; - let m = 4; - let poly = BivariatePolynomial::new( - vec![ - Fr::from(1u64), - Fr::from(2u64), - Fr::from(4u64), - Fr::from(8u64), - Fr::from(16u64), - Fr::from(32u64), - Fr::from(64u64), - Fr::from(128u64), - Fr::from(256u64), - Fr::from(128u64), - Fr::from(64u64), - Fr::from(32u64), - Fr::from(16u64), - Fr::from(8u64), - Fr::from(4u64), - Fr::from(2u64), - ], - n, - m, - ); - let mut poly_lag2 = poly.coefficients.clone(); - let poly_lag = poly.interpolate(); - bi_fft_in_place(&mut poly_lag2, n, m); - assert_eq!(poly_lag, poly_lag2); - } - - let mut rng = test_rng(); - - for m in [2, 4, 8, 16, 32, 64].iter() { - for n in [2, 4, 8, 16, 32, 64].iter() { - let poly = BivariatePolynomial::::random(&mut rng, *n, *m); - let mut poly_lag2 = poly.coefficients.clone(); - let poly_lag = poly.evaluate_at_roots(); - bi_fft_in_place(&mut poly_lag2, *n, *m); - assert_eq!(poly_lag, poly_lag2); - } - } - } -} diff --git a/bi-kzg/src/coeff_form_bi_kzg.rs b/bi-kzg/src/coeff_form_bi_kzg.rs index e4ab5b92..4f4eb908 100644 --- a/bi-kzg/src/coeff_form_bi_kzg.rs +++ b/bi-kzg/src/coeff_form_bi_kzg.rs @@ -47,36 +47,30 @@ where supported_n: usize, supported_m: usize, ) -> Self::SRS { - // LagrangeFormBiKZG::::gen_srs_for_testing(rng, supported_n, supported_m) - assert!(supported_n.is_power_of_two()); assert!(supported_m.is_power_of_two()); let tau_0 = E::Fr::random(&mut rng); let tau_1 = E::Fr::random(&mut rng); - // let tau_0 = E::Fr::from(5); - // let tau_1 = E::Fr::from(7); - let g1 = E::G1Affine::generator(); // roots of unity for supported_n and supported_m let (omega_0, omega_1) = { let omega = E::Fr::ROOT_OF_UNITY; - 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]); + 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]); assert!( - omega_0.pow_vartime(&[supported_n as u64]) == E::Fr::ONE, + omega_0.pow_vartime([supported_n as u64]) == E::Fr::ONE, "omega_0 is not root of unity for supported_n" ); assert!( - omega_1.pow_vartime(&[supported_m as u64]) == E::Fr::ONE, + omega_1.pow_vartime([supported_m as u64]) == E::Fr::ONE, "omega_1 is not root of unity for supported_m" ); (omega_0, omega_1) }; - // println!("start to compute the scalars"); // computes the vector of L_i^N(tau_0) * L_j^M(tau_1) for i in 0..supported_n and j in 0..supported_m let (scalars, lagrange_scalars) = { let powers_of_omega_0 = powers_of_field_elements(&omega_0, supported_n); @@ -91,7 +85,6 @@ where (scalars, lagrange_scalars) }; - // println!("start to compute the affine bases"); let g1_prog = g1.to_curve(); let coeff_bases = { let mut proj_bases = vec![E::G1::identity(); supported_n * supported_m]; @@ -110,8 +103,6 @@ where g_bases }; - // println!("start to compute the lagrange bases"); - let lagrange_bases = { let mut proj_bases = vec![E::G1::identity(); supported_n * supported_m]; parallelize(&mut proj_bases, |g, start| { @@ -132,8 +123,6 @@ where affine_bases }; - // assert_eq!(coeff_bases[..supported_n], f_x_b_scalars); - BiKZGSRS { powers_of_g: coeff_bases, powers_of_g_lagrange_over_both_roots: lagrange_bases, @@ -189,7 +178,7 @@ where let timer2 = start_timer!(|| "Computing the proof pi0"); let (pi_0, f_x_b) = { // t = f(x, b) - f(a, b) - let f_x_b = polynomial.evaluate_y(&point.1); + let f_x_b = polynomial.evaluate_at_y(&point.1); let mut t = f_x_b.clone(); t[0] -= u; // q_0(x, b) = t(x) / (x - a) @@ -274,14 +263,10 @@ where where E: MultiMillerLoop, { + let timers = start_timer!(|| "Verifying the proof"); let pi0_a_pi1_b_g1_cmu = best_multiexp( &[point.0, point.1, E::Fr::ONE, -*value], - &[ - proof.pi0, - proof.pi1, - commitment.com.into(), - verifier_param.g.into(), - ], + &[proof.pi0, proof.pi1, commitment.com, verifier_param.g], ); let pi0_a_pi1_b_g1_cmu = (-pi0_a_pi1_b_g1_cmu).to_affine(); let res = E::multi_miller_loop(&[ @@ -290,25 +275,9 @@ where (&pi0_a_pi1_b_g1_cmu, &verifier_param.h.into()), ]); let res = res.final_exponentiation().is_identity().into(); - + end_timer!(timers); res } - fn multi_open( - _prover_param: impl Borrow, - _polynomials: &[Self::Polynomial], - _points: &[Self::Point], - _evals: &[Self::Evaluation], - ) -> Self::BatchProof { - unimplemented!() - } - - fn batch_verify( - _verifier_param: &Self::VerifierParam, - _commitments: &[Self::Commitment], - _points: &[Self::Point], - _batch_proof: &Self::BatchProof, - ) -> bool { - unimplemented!() - } + // TODO: implement multi-opening and batch verification } diff --git a/bi-kzg/src/lagrange_form_bi_kzg.rs b/bi-kzg/src/lagrange_form_bi_kzg.rs index c3781467..ffa0a738 100644 --- a/bi-kzg/src/lagrange_form_bi_kzg.rs +++ b/bi-kzg/src/lagrange_form_bi_kzg.rs @@ -1,3 +1,5 @@ +//! We don't need this file for now. We will use the `CoeffFormBiKZG`. + use std::{borrow::Borrow, marker::PhantomData}; use ark_std::{end_timer, start_timer}; @@ -276,21 +278,6 @@ where res } - fn multi_open( - _prover_param: impl Borrow, - _polynomials: &[Self::Polynomial], - _points: &[Self::Point], - _evals: &[Self::Evaluation], - ) -> Self::BatchProof { - unimplemented!() - } - - fn batch_verify( - _verifier_param: &Self::VerifierParam, - _commitments: &[Self::Commitment], - _points: &[Self::Point], - _batch_proof: &Self::BatchProof, - ) -> bool { - unimplemented!() - } + + // TODO: implement multi-opening and batch verification } diff --git a/bi-kzg/src/lib.rs b/bi-kzg/src/lib.rs index 96079f99..3d4f5d8d 100644 --- a/bi-kzg/src/lib.rs +++ b/bi-kzg/src/lib.rs @@ -1,16 +1,18 @@ mod bi_fft; mod coeff_form_bi_kzg; -// mod lagrange_form_bi_kzg; mod pcs; mod poly; mod structs; mod util; +// mod lagrange_form_bi_kzg; + #[cfg(test)] mod tests; pub use coeff_form_bi_kzg::CoeffFormBiKZG; -// pub use lagrange_form_bi_kzg::LagrangeFormBiKZG; pub use pcs::PolynomialCommitmentScheme; pub use structs::BivariatePolynomial; pub use structs::{BiKZGCommitment, BiKZGProof, BiKZGSRS, BiKZGVerifierParam}; + +// pub use lagrange_form_bi_kzg::LagrangeFormBiKZG; diff --git a/bi-kzg/src/pcs.rs b/bi-kzg/src/pcs.rs index cb54a764..8a32ccd0 100644 --- a/bi-kzg/src/pcs.rs +++ b/bi-kzg/src/pcs.rs @@ -1,6 +1,6 @@ use std::{borrow::Borrow, fmt::Debug}; -use halo2curves::{ff::Field, serde::SerdeObject}; +use halo2curves::ff::Field; use rand::RngCore; /// This trait defines APIs for polynomial commitment schemes. @@ -21,9 +21,9 @@ pub trait PolynomialCommitmentScheme { /// Polynomial Evaluation type Evaluation: Field; /// Commitments - type Commitment: Clone + SerdeObject + Debug; + type Commitment: Clone + Debug; /// Proofs - type Proof: Clone + SerdeObject + Debug; + type Proof: Clone + Debug; /// Batch proofs type BatchProof; @@ -34,22 +34,6 @@ pub trait PolynomialCommitmentScheme { /// THE OUTPUT SRS SHOULD NOT BE USED IN PRODUCTION. fn gen_srs_for_testing(rng: impl RngCore, supported_n: usize, supported_m: usize) -> Self::SRS; - // /// Trim the universal parameters to specialize the public parameters. - // /// Input both `supported_degree` for univariate and - // /// `supported_num_vars` for multilinear. - // /// ## Note on function signature - // /// Usually, data structure like SRS and ProverParam are huge and users - // /// might wish to keep them in heap using different kinds of smart pointers - // /// (instead of only in stack) therefore our `impl Borrow<_>` interface - // /// allows for passing in any pointer type, e.g.: `trim(srs: &Self::SRS, - // /// ..)` or `trim(srs: Box, ..)` or `trim(srs: Arc, - // /// ..)` etc. - // fn trim( - // srs: impl Borrow, - // supported_degree: Option, - // supported_num_vars: Option, - // ) -> (Self::ProverParam, Self::VerifierParam); - /// Generate a commitment for a polynomial /// ## Note on function signature /// Usually, data structure like SRS and ProverParam are huge and users @@ -72,14 +56,12 @@ pub trait PolynomialCommitmentScheme { point: &Self::Point, ) -> (Self::Proof, Self::Evaluation); - /// Input a list of multilinear extensions, and a same number of points, and - /// a transcript, compute a multi-opening for all the polynomials. + /// Input a list of polynomials, and a same number of points, compute a multi-opening for all the polynomials. fn multi_open( _prover_param: impl Borrow, _polynomials: &[Self::Polynomial], _points: &[Self::Point], _evals: &[Self::Evaluation], - // _transcript: &mut IOPTranscript, ) -> Self::BatchProof { // the reason we use unimplemented!() is to enable developers to implement the // trait without always implementing the batching APIs. @@ -103,7 +85,6 @@ pub trait PolynomialCommitmentScheme { _commitments: &[Self::Commitment], _points: &[Self::Point], _batch_proof: &Self::BatchProof, - // _transcript: &mut IOPTranscript, ) -> bool { // the reason we use unimplemented!() is to enable developers to implement the // trait without always implementing the batching APIs. diff --git a/bi-kzg/src/poly.rs b/bi-kzg/src/poly.rs index bdb7cd81..47df6675 100644 --- a/bi-kzg/src/poly.rs +++ b/bi-kzg/src/poly.rs @@ -26,6 +26,7 @@ impl BivariatePolynomial { Self::new(coefficients, degree_0, degree_1) } + /// evaluate the polynomial at (x, y) pub fn evaluate(&self, x: &F, y: &F) -> F { let x_power = powers_of_field_elements(x, self.degree_0); let y_power = powers_of_field_elements(y, self.degree_1); @@ -42,7 +43,8 @@ impl BivariatePolynomial { }) } - pub fn evaluate_y(&self, y: &F) -> Vec { + /// evaluate the polynomial at y, return a univariate polynomial in x + pub fn evaluate_at_y(&self, y: &F) -> Vec { let mut f_x_b = self.coefficients[0..self.degree_0].to_vec(); let powers_of_b = powers_of_field_elements(y, self.degree_1); powers_of_b @@ -69,15 +71,15 @@ impl BivariatePolynomial { // 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]); + 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.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.pow_vartime([self.degree_1 as u64]) == F::ONE, "omega_1 is not root of unity for supported_m" ); (omega_0, omega_1) @@ -109,8 +111,8 @@ impl BivariatePolynomial { } } -/// 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}`` +/// For a point x, compute the coefficients of Lagrange polynomial L_{i}(x) 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() @@ -130,13 +132,11 @@ pub(crate) fn lagrange_coefficients(roots: &[F], points: .collect() } -/// Compute poly / (x-point) -/// -// TODO: this algorithm is quadratic. is this more efficient than FFT? +/// Compute poly / (x-point) using univariate division pub(crate) fn univariate_quotient(poly: &[F], point: &F) -> Vec { let timer = start_timer!(|| format!("Univariate quotient of degree {}", poly.len())); let mut dividend_coeff = poly.to_vec(); - let divisor = vec![-*point, F::from(1u64)]; + let divisor = [-*point, F::from(1u64)]; let mut coefficients = vec![]; let mut dividend_pos = dividend_coeff.len() - 1; @@ -194,251 +194,13 @@ impl BivariateLagrangePolynomial { // roots of unity for supported_n and supported_m let omega_1 = { let omega = F::ROOT_OF_UNITY; - omega.pow_vartime(&[(1 << F::S) / m as u64]) + omega.pow_vartime([(1 << F::S) / m as u64]) }; let mut coeffs = vec![F::ZERO; n * m]; for i in 0..m { - let element = omega_1.pow_vartime(&[i as u64]) - *b; + let element = omega_1.pow_vartime([i as u64]) - *b; coeffs[i * n..(i + 1) * n].copy_from_slice(vec![element; n].as_slice()); } BivariateLagrangePolynomial::new(coeffs, n, m) } } - -#[cfg(test)] -mod tests { - use crate::structs::BivariatePolynomial; - use halo2curves::bn256::Fr; - - #[test] - fn test_bivariate_poly_eval() { - { - let poly = BivariatePolynomial::new( - vec![ - Fr::from(1u64), - Fr::from(2u64), - Fr::from(3u64), - Fr::from(4u64), - ], - 2, - 2, - ); - let x = Fr::from(5u64); - let y = Fr::from(7u64); - let result = poly.evaluate(&x, &y); - assert_eq!( - result, - Fr::from(1u64) + Fr::from(2u64) * x + Fr::from(3u64) * y + Fr::from(4u64) * x * y - ); - } - - { - let poly = BivariatePolynomial::new( - vec![ - Fr::from(1u64), - Fr::from(2u64), - Fr::from(3u64), - Fr::from(4u64), - Fr::from(5u64), - Fr::from(6u64), - Fr::from(7u64), - Fr::from(8u64), - ], - 2, - 4, - ); - let x = Fr::from(9u64); - let y = Fr::from(10u64); - let result = poly.evaluate(&x, &y); - assert_eq!( - result, - Fr::from(1u64) - + Fr::from(2u64) * x - + (Fr::from(3u64) + Fr::from(4u64) * x) * y - + (Fr::from(5u64) + Fr::from(6u64) * x) * y * y - + (Fr::from(7u64) + Fr::from(8u64) * x) * y * y * y - ); - } - - let poly = BivariatePolynomial::new( - vec![ - Fr::from(1u64), - Fr::from(2u64), - Fr::from(3u64), - Fr::from(4u64), - Fr::from(5u64), - Fr::from(6u64), - Fr::from(7u64), - Fr::from(8u64), - ], - 4, - 2, - ); - let x = Fr::from(9u64); - let y = Fr::from(10u64); - let result = poly.evaluate(&x, &y); - assert_eq!( - result, - Fr::from(1u64) - + Fr::from(2u64) * x - + Fr::from(3u64) * x * x - + Fr::from(4u64) * x * x * x - + (Fr::from(5u64) - + Fr::from(6u64) * x - + Fr::from(7u64) * x * x - + Fr::from(8u64) * x * x * x) - * y - ); - } - - #[test] - fn test_eval_at_y() { - let poly = BivariatePolynomial::new( - vec![ - Fr::from(1u64), - Fr::from(2u64), - Fr::from(3u64), - Fr::from(4u64), - Fr::from(5u64), - Fr::from(6u64), - Fr::from(7u64), - Fr::from(8u64), - ], - 2, - 4, - ); - let eval_at_y = poly.evaluate_y(&Fr::from(10u64)); - assert_eq!(eval_at_y, vec![Fr::from(7531u64), Fr::from(8642u64)]); - } - - #[test] - fn test_poly_div() { - { - // x^3 + 1 = (x + 1)(x^2 - x + 1) - let poly = vec![ - Fr::from(1u64), - Fr::from(0u64), - Fr::from(0u64), - Fr::from(1u64), - ]; - let point = -Fr::from(1u64); - let result = super::univariate_quotient(&poly, &point); - assert_eq!( - result, - vec![ - Fr::from(1u64), - -Fr::from(1u64), - Fr::from(1u64), - Fr::from(0u64) - ] - ); - } - { - // x^3 - 1 = (x-1)(x^2 + x + 1) - let poly = vec![ - -Fr::from(1u64), - Fr::from(0u64), - Fr::from(0u64), - Fr::from(1u64), - ]; - let point = Fr::from(1u64); - let result = super::univariate_quotient(&poly, &point); - assert_eq!( - result, - vec![ - Fr::from(1u64), - Fr::from(1u64), - Fr::from(1u64), - Fr::from(0u64) - ] - ); - } - } - - #[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(6u64), - Fr::from(7u64), - Fr::from(8u64), - ], - 2, - 4, - ); - - let lagrange_coeffs = poly.interpolate(); - - // From sage script - // poly_lag_coeff = [ - // 0x0000000000000000000000000000000000000000000000000000000000000024, - // 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffffd, - // 0x00000000000000059e26bcea0d48bac65a4e1a8be2302529067f891b047e4e50, - // 0x0000000000000000000000000000000000000000000000000000000000000000, - // 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffff9, - // 0x0000000000000000000000000000000000000000000000000000000000000000, - // 0x30644e72e131a0241a2988cc74389d96cde5cdbc97894b683d626c78eb81b1a1, - // 0x0000000000000000000000000000000000000000000000000000000000000000] - assert_eq!(lagrange_coeffs.len(), 8); - assert_eq!( - format!("{:?}", lagrange_coeffs[0]), - "0x0000000000000000000000000000000000000000000000000000000000000024" - ); - assert_eq!( - format!("{:?}", lagrange_coeffs[1]), - "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffffd" - ); - assert_eq!( - format!("{:?}", lagrange_coeffs[2]), - "0x00000000000000059e26bcea0d48bac65a4e1a8be2302529067f891b047e4e50" - ); - assert_eq!( - format!("{:?}", lagrange_coeffs[3]), - "0x0000000000000000000000000000000000000000000000000000000000000000" - ); - assert_eq!( - format!("{:?}", lagrange_coeffs[4]), - "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffff9" - ); - assert_eq!( - format!("{:?}", lagrange_coeffs[5]), - "0x0000000000000000000000000000000000000000000000000000000000000000" - ); - assert_eq!( - format!("{:?}", lagrange_coeffs[6]), - "0x30644e72e131a0241a2988cc74389d96cde5cdbc97894b683d626c78eb81b1a1" - ); - assert_eq!( - format!("{:?}", lagrange_coeffs[7]), - "0x0000000000000000000000000000000000000000000000000000000000000000" - ); - } - - #[test] - fn test_from_y() { - let b = Fr::from(10u64); - let n = 2; - let m = 4; - let poly1 = super::BivariateLagrangePolynomial::from_y_monomial(&b, n, m); - let poly2 = super::BivariatePolynomial::new( - vec![ - -b, - Fr::from(0u64), - Fr::from(1u64), - Fr::from(0u64), - Fr::from(0u64), - Fr::from(0u64), - Fr::from(0u64), - Fr::from(0u64), - ], - n, - m, - ); - assert_eq!(poly1.coefficients, poly2.interpolate()); - } -} diff --git a/bi-kzg/src/structs.rs b/bi-kzg/src/structs.rs index eea62a42..0bc3eeaf 100644 --- a/bi-kzg/src/structs.rs +++ b/bi-kzg/src/structs.rs @@ -1,6 +1,4 @@ -use std::io::{self, Read, Write}; - -use halo2curves::{pairing::Engine, serde::SerdeObject}; +use halo2curves::pairing::Engine; #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct BivariatePolynomial { @@ -36,13 +34,6 @@ pub struct BiKZGSRS { pub tau_1_h: E::G2Affine, } -// /// `BiKZGProverParam` is used to generate a proof -// #[derive(Clone, Debug, Eq, PartialEq, Default)] -// pub struct BiKZGProverParam { -// /// Parameters -// pub powers_of_g: Vec, -// } - /// `UnivariateVerifierParam` is used to check evaluation proofs for a given /// commitment. #[derive(Clone, Debug, Eq, PartialEq, Default)] @@ -82,71 +73,3 @@ impl From<&BiKZGSRS> for BiKZGVerifierParam { } } } - -impl SerdeObject for BiKZGCommitment { - /// The purpose of unchecked functions is to read the internal memory representation - /// of a type from bytes as quickly as possible. No sanitization checks are performed - /// to ensure the bytes represent a valid object. As such this function should only be - /// used internally as an extension of machine memory. It should not be used to deserialize - /// externally provided data. - fn from_raw_bytes_unchecked(_bytes: &[u8]) -> Self { - todo!("Implement this function") - } - fn from_raw_bytes(_bytes: &[u8]) -> Option { - todo!("Implement this function") - } - - fn to_raw_bytes(&self) -> Vec { - todo!("Implement this function") - } - - /// The purpose of unchecked functions is to read the internal memory representation - /// of a type from disk as quickly as possible. No sanitization checks are performed - /// to ensure the bytes represent a valid object. This function should only be used - /// internally when some machine state cannot be kept in memory (e.g., between runs) - /// and needs to be reloaded as quickly as possible. - fn read_raw_unchecked(_reader: &mut R) -> Self { - todo!("Implement this function") - } - fn read_raw(_reader: &mut R) -> io::Result { - todo!("Implement this function") - } - - fn write_raw(&self, _writer: &mut W) -> io::Result<()> { - todo!("Implement this function") - } -} - -impl SerdeObject for BiKZGProof { - /// The purpose of unchecked functions is to read the internal memory representation - /// of a type from bytes as quickly as possible. No sanitization checks are performed - /// to ensure the bytes represent a valid object. As such this function should only be - /// used internally as an extension of machine memory. It should not be used to deserialize - /// externally provided data. - fn from_raw_bytes_unchecked(_bytes: &[u8]) -> Self { - todo!("Implement this function") - } - fn from_raw_bytes(_bytes: &[u8]) -> Option { - todo!("Implement this function") - } - - fn to_raw_bytes(&self) -> Vec { - todo!("Implement this function") - } - - /// The purpose of unchecked functions is to read the internal memory representation - /// of a type from disk as quickly as possible. No sanitization checks are performed - /// to ensure the bytes represent a valid object. This function should only be used - /// internally when some machine state cannot be kept in memory (e.g., between runs) - /// and needs to be reloaded as quickly as possible. - fn read_raw_unchecked(_reader: &mut R) -> Self { - todo!("Implement this function") - } - fn read_raw(_reader: &mut R) -> io::Result { - todo!("Implement this function") - } - - fn write_raw(&self, _writer: &mut W) -> io::Result<()> { - todo!("Implement this function") - } -} diff --git a/bi-kzg/src/tests.rs b/bi-kzg/src/tests.rs index f79a9f31..4b20c041 100644 --- a/bi-kzg/src/tests.rs +++ b/bi-kzg/src/tests.rs @@ -5,13 +5,17 @@ use halo2curves::{ }; use crate::{ - coeff_form_bi_kzg::CoeffFormBiKZG, pcs::PolynomialCommitmentScheme, - poly::lagrange_coefficients, util::tensor_product_parallel, BiKZGVerifierParam, - BivariatePolynomial, + bi_fft::bi_fft_in_place, + coeff_form_bi_kzg::CoeffFormBiKZG, + pcs::PolynomialCommitmentScheme, + poly::{lagrange_coefficients, univariate_quotient}, + structs::BivariateLagrangePolynomial, + util::tensor_product_parallel, + BiKZGVerifierParam, BivariatePolynomial, }; #[test] -fn test_bi_kzg_with_profiling() { +fn test_bi_kzg_single_pass() { let mut rng = test_rng(); let n = 16; let m = 32; @@ -98,16 +102,6 @@ fn test_bi_kzg_e2e() { } } -#[test] -fn test_lagrange_coeffs() { - let roots = vec![Fr::from(1u64), Fr::from(2u64), Fr::from(3u64)]; - let point = Fr::from(4u64); - let result = lagrange_coefficients(&roots, &point); - assert_eq!(result[0], Fr::from(1u64)); - assert_eq!(result[1], -Fr::from(3u64)); - assert_eq!(result[2], Fr::from(3u64)); -} - #[test] fn test_tensor_product() { let vec1 = vec![Fr::from(1u64), Fr::from(2u64), Fr::from(3u64)]; @@ -123,3 +117,291 @@ fn test_tensor_product() { assert_eq!(result[7], Fr::from(2u64) * Fr::from(6u64)); assert_eq!(result[8], Fr::from(3u64) * Fr::from(6u64)); } + +#[test] +fn test_bivariate_poly_eval() { + { + let poly = BivariatePolynomial::new( + vec![ + Fr::from(1u64), + Fr::from(2u64), + Fr::from(3u64), + Fr::from(4u64), + ], + 2, + 2, + ); + let x = Fr::from(5u64); + let y = Fr::from(7u64); + let result = poly.evaluate(&x, &y); + assert_eq!( + result, + Fr::from(1u64) + Fr::from(2u64) * x + Fr::from(3u64) * y + Fr::from(4u64) * x * y + ); + } + + { + let poly = BivariatePolynomial::new( + vec![ + Fr::from(1u64), + Fr::from(2u64), + Fr::from(3u64), + Fr::from(4u64), + Fr::from(5u64), + Fr::from(6u64), + Fr::from(7u64), + Fr::from(8u64), + ], + 2, + 4, + ); + let x = Fr::from(9u64); + let y = Fr::from(10u64); + let result = poly.evaluate(&x, &y); + assert_eq!( + result, + Fr::from(1u64) + + Fr::from(2u64) * x + + (Fr::from(3u64) + Fr::from(4u64) * x) * y + + (Fr::from(5u64) + Fr::from(6u64) * x) * y * y + + (Fr::from(7u64) + Fr::from(8u64) * x) * y * y * y + ); + } + + let poly = BivariatePolynomial::new( + vec![ + Fr::from(1u64), + Fr::from(2u64), + Fr::from(3u64), + Fr::from(4u64), + Fr::from(5u64), + Fr::from(6u64), + Fr::from(7u64), + Fr::from(8u64), + ], + 4, + 2, + ); + let x = Fr::from(9u64); + let y = Fr::from(10u64); + let result = poly.evaluate(&x, &y); + assert_eq!( + result, + Fr::from(1u64) + + Fr::from(2u64) * x + + Fr::from(3u64) * x * x + + Fr::from(4u64) * x * x * x + + (Fr::from(5u64) + + Fr::from(6u64) * x + + Fr::from(7u64) * x * x + + Fr::from(8u64) * x * x * x) + * y + ); +} + +#[test] +fn test_eval_at_y() { + let poly = BivariatePolynomial::new( + vec![ + Fr::from(1u64), + Fr::from(2u64), + Fr::from(3u64), + Fr::from(4u64), + Fr::from(5u64), + Fr::from(6u64), + Fr::from(7u64), + Fr::from(8u64), + ], + 2, + 4, + ); + let eval_at_y = poly.evaluate_at_y(&Fr::from(10u64)); + assert_eq!(eval_at_y, vec![Fr::from(7531u64), Fr::from(8642u64)]); +} + +#[test] +fn test_univariate_division() { + { + // x^3 + 1 = (x + 1)(x^2 - x + 1) + let poly = vec![ + Fr::from(1u64), + Fr::from(0u64), + Fr::from(0u64), + Fr::from(1u64), + ]; + let point = -Fr::from(1u64); + let result = univariate_quotient(&poly, &point); + assert_eq!( + result, + vec![ + Fr::from(1u64), + -Fr::from(1u64), + Fr::from(1u64), + Fr::from(0u64) + ] + ); + } + { + // x^3 - 1 = (x-1)(x^2 + x + 1) + let poly = vec![ + -Fr::from(1u64), + Fr::from(0u64), + Fr::from(0u64), + Fr::from(1u64), + ]; + let point = Fr::from(1u64); + let result = univariate_quotient(&poly, &point); + assert_eq!( + result, + vec![ + Fr::from(1u64), + Fr::from(1u64), + Fr::from(1u64), + Fr::from(0u64) + ] + ); + } +} + +#[test] +fn test_lagrange_coeffs() { + let roots = vec![Fr::from(1u64), Fr::from(2u64), Fr::from(3u64)]; + let point = Fr::from(4u64); + let result = lagrange_coefficients(&roots, &point); + assert_eq!(result[0], Fr::from(1u64)); + assert_eq!(result[1], -Fr::from(3u64)); + assert_eq!(result[2], Fr::from(3u64)); +} + +#[test] +fn test_interpolation() { + let poly = BivariatePolynomial::new( + vec![ + Fr::from(1u64), + Fr::from(2u64), + Fr::from(3u64), + Fr::from(4u64), + Fr::from(5u64), + Fr::from(6u64), + Fr::from(7u64), + Fr::from(8u64), + ], + 2, + 4, + ); + + let lagrange_coeffs = poly.interpolate(); + + // From sage script + // poly_lag_coeff = [ + // 0x0000000000000000000000000000000000000000000000000000000000000024, + // 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffffd, + // 0x00000000000000059e26bcea0d48bac65a4e1a8be2302529067f891b047e4e50, + // 0x0000000000000000000000000000000000000000000000000000000000000000, + // 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffff9, + // 0x0000000000000000000000000000000000000000000000000000000000000000, + // 0x30644e72e131a0241a2988cc74389d96cde5cdbc97894b683d626c78eb81b1a1, + // 0x0000000000000000000000000000000000000000000000000000000000000000] + assert_eq!(lagrange_coeffs.len(), 8); + assert_eq!( + format!("{:?}", lagrange_coeffs[0]), + "0x0000000000000000000000000000000000000000000000000000000000000024" + ); + assert_eq!( + format!("{:?}", lagrange_coeffs[1]), + "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffffd" + ); + assert_eq!( + format!("{:?}", lagrange_coeffs[2]), + "0x00000000000000059e26bcea0d48bac65a4e1a8be2302529067f891b047e4e50" + ); + assert_eq!( + format!("{:?}", lagrange_coeffs[3]), + "0x0000000000000000000000000000000000000000000000000000000000000000" + ); + assert_eq!( + format!("{:?}", lagrange_coeffs[4]), + "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffff9" + ); + assert_eq!( + format!("{:?}", lagrange_coeffs[5]), + "0x0000000000000000000000000000000000000000000000000000000000000000" + ); + assert_eq!( + format!("{:?}", lagrange_coeffs[6]), + "0x30644e72e131a0241a2988cc74389d96cde5cdbc97894b683d626c78eb81b1a1" + ); + assert_eq!( + format!("{:?}", lagrange_coeffs[7]), + "0x0000000000000000000000000000000000000000000000000000000000000000" + ); +} + +#[test] +fn test_from_y() { + let b = Fr::from(10u64); + let n = 2; + let m = 4; + let poly1 = BivariateLagrangePolynomial::from_y_monomial(&b, n, m); + let poly2 = BivariatePolynomial::new( + vec![ + -b, + Fr::from(0u64), + Fr::from(1u64), + Fr::from(0u64), + Fr::from(0u64), + Fr::from(0u64), + Fr::from(0u64), + Fr::from(0u64), + ], + n, + m, + ); + assert_eq!(poly1.coefficients, poly2.interpolate()); +} + +#[test] +fn test_bi_fft() { + { + let n = 4; + let m = 4; + let poly = BivariatePolynomial::new( + vec![ + Fr::from(1u64), + Fr::from(2u64), + Fr::from(4u64), + Fr::from(8u64), + Fr::from(16u64), + Fr::from(32u64), + Fr::from(64u64), + Fr::from(128u64), + Fr::from(256u64), + Fr::from(128u64), + Fr::from(64u64), + Fr::from(32u64), + Fr::from(16u64), + Fr::from(8u64), + Fr::from(4u64), + Fr::from(2u64), + ], + n, + m, + ); + let mut poly_lag2 = poly.coefficients.clone(); + let poly_lag = poly.interpolate(); + bi_fft_in_place(&mut poly_lag2, n, m); + assert_eq!(poly_lag, poly_lag2); + } + + let mut rng = test_rng(); + + for m in [2, 4, 8, 16, 32, 64].iter() { + for n in [2, 4, 8, 16, 32, 64].iter() { + let poly = BivariatePolynomial::::random(&mut rng, *n, *m); + let mut poly_lag2 = poly.coefficients.clone(); + let poly_lag = poly.evaluate_at_roots(); + bi_fft_in_place(&mut poly_lag2, *n, *m); + assert_eq!(poly_lag, poly_lag2); + } + } +} diff --git a/bi-kzg/src/util.rs b/bi-kzg/src/util.rs index d539b323..49084e90 100644 --- a/bi-kzg/src/util.rs +++ b/bi-kzg/src/util.rs @@ -26,7 +26,7 @@ pub(crate) fn parallelize_internal Vec { let n = v.len(); let num_threads = rayon::current_num_threads(); - let mut chunk = (n as usize) / num_threads; + let mut chunk = n / num_threads; if chunk < num_threads { chunk = 1; }