From 4768d0e5cf5e6b4f768cc5bf91ef52b082feca7d Mon Sep 17 00:00:00 2001 From: Dmitry Khovratovich Date: Tue, 6 Feb 2024 13:44:24 +0100 Subject: [PATCH] duplicate code --- src/dft.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/kzg.rs | 47 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/src/dft.rs b/src/dft.rs index 4fe1528..e1e34da 100644 --- a/src/dft.rs +++ b/src/dft.rs @@ -68,6 +68,63 @@ where h_ext[0..dom_size].to_vec() } +// compute all pre-proofs using DFT +// h_i= c_d[x^{d-i-1}]+c_{d-1}[x^{d-i-2}]+c_{d-2}[x^{d-i-3}]+\cdots + +// c_{i+2}[x]+c_{i+1}[1] +pub fn compute_h_23( + c_poly: &DensePolynomial, /* c(X) degree up to d<2^p , i.e. c_poly has at most d+1 coeffs + * non-zero */ + powers: &[G], // SRS + p: usize, +) -> Vec +where + F: PrimeField, + G: ProjectiveCurve, +{ + let timer = start_timer!(|| "compute h"); + let mut coeffs = c_poly.coeffs().to_vec(); + let dom_size = 1 << p; + let fpzero = F::zero(); + coeffs.resize(dom_size, fpzero); + + // 1. x_ext = [[x^(d-1)], [x^{d-2},...,[x],[1], d+2 [0]'s] + let step1_timer = start_timer!(|| "step 1"); + let mut x_ext: Vec = powers.iter().take(dom_size - 1).rev().copied().collect(); + x_ext.resize(2 * dom_size, G::zero()); // filling 2d+2 neutral elements + let y = group_dft::(&x_ext, p + 1); + end_timer!(step1_timer); + + // 2. c_ext = [c_d, d zeroes, c_d,c_{0},c_1,...,c_{d-2},c_{d-1}] + let step2_timer = start_timer!(|| "step 2"); + + let mut c_ext = vec![coeffs[coeffs.len() - 1]]; + c_ext.resize(dom_size, fpzero); + c_ext.push(coeffs[coeffs.len() - 1]); + for &e in coeffs.iter().take(coeffs.len() - 1) { + c_ext.push(e); + } + assert_eq!(c_ext.len(), 2 * dom_size); + let v = field_dft::(&c_ext, p + 1); + end_timer!(step2_timer); + + // 3. u = y o v + let step3_timer = start_timer!(|| "step 3"); + let u: Vec<_> = y + .into_iter() + .zip(v.into_iter()) + .map(|(a, b)| a.mul(b.into_repr())) + .collect(); + end_timer!(step3_timer); + + // 4. h_ext = idft_{2d+2}(u) + let step4_timer = start_timer!(|| "step 4"); + let h_ext = group_inv_dft::(&u, p + 1); + end_timer!(step4_timer); + + end_timer!(timer); + h_ext[0..dom_size].to_vec() +} + // compute DFT of size @dom_size over vector of Fr elements // q_i = h_0 + h_1w^i + h_2w^{2i}+\cdots + h_{dom_size-1}w^{(dom_size-1)i} for // 0<= i< dom_size=2^p diff --git a/src/kzg.rs b/src/kzg.rs index e7e74d7..a7d649f 100644 --- a/src/kzg.rs +++ b/src/kzg.rs @@ -5,7 +5,7 @@ // (4) hash_caulk_single is for hashing group and field elements into a field // element (5) random_field is for generating random field elements -use crate::{compute_h, group_dft, util::convert_to_bigints}; +use crate::{compute_h,compute_h_23, group_dft, util::convert_to_bigints}; use ark_ec::{msm::VariableBaseMSM, AffineCurve, PairingEngine, ProjectiveCurve}; use ark_ff::{Field, PrimeField}; use ark_poly::{ @@ -118,6 +118,44 @@ impl KZGCommit { res } + // compute all openings to c_poly using a smart formula + // This Code implements an algorithm for calculating n openings of a KZG vector + // commitment of size n in n log(n) time. The algorithm is by Feist and + // Khovratovich updated in the 2023 paper https://eprint.iacr.org/2023/033.pdf + pub fn multiple_open_23( + c_poly: &DensePolynomial, // c(X) + powers: &[G], // SRS + p: usize, + ) -> Vec + where + G: AffineCurve + Sized, + { + let timer = start_timer!(|| "multiple open"); + + let degree = c_poly.coeffs.len() - 1; + let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(degree).unwrap(); + + let h_timer = start_timer!(|| "compute h"); + let powers: Vec = powers.iter().map(|x| x.into_projective()).collect(); + let h2 = compute_h_23(c_poly, &powers, p); + end_timer!(h_timer); + + let dom_size = input_domain.size(); + assert_eq!(1 << p, dom_size); + assert_eq!(degree + 1, dom_size); + + let dft_timer = start_timer!(|| "G1 dft"); + let q2 = group_dft::(&h2, p); + end_timer!(dft_timer); + + let normalization_timer = start_timer!(|| "batch normalization"); + let res = G::Projective::batch_normalization_into_affine(q2.as_ref()); + end_timer!(normalization_timer); + + end_timer!(timer); + res + } + //////////////////////////////////////////////// // KZG.Open( srs_KZG, f(X, Y), deg, alpha ) // returns ([f(alpha, x)]_1, pi) @@ -648,7 +686,7 @@ pub mod tests { let mut rng = test_rng(); // current kzg setup should be changed with output from a setup ceremony - let p: usize = 9; + let p: usize = 4; let max_degree: usize = 1 << p + 1; let actual_degree: usize = (1 << p) - 1; let pp = caulk_single_setup(max_degree, actual_degree, &mut rng); @@ -669,6 +707,11 @@ pub mod tests { let q2 = KZGCommit::::multiple_open::(&c_poly, &pp.poly_ck.powers_of_g, p); println!("Multi advanced computed in {:?}", now.elapsed()); assert_eq!(q, q2); + + let now = Instant::now(); + let q3 = KZGCommit::::multiple_open_23::(&c_poly, &pp.poly_ck.powers_of_g, p); + println!("Multi advanced 2023 computed in {:?}", now.elapsed()); + assert_eq!(q, q3); } #[test]