From 9d76c71a0cfbaf7228da23eee67ed73286ce80fb Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 31 May 2022 20:44:24 -0400 Subject: [PATCH] refactoring multiple_open --- .../examples/single_opening.rs | 3 +- caulk_single_opening/src/caulk_single.rs | 20 +------ .../src/caulk_single_setup.rs | 18 +++--- .../src/caulk_single_unity.rs | 27 +++++++-- .../src/{multiopen.rs => dft.rs} | 59 +++++-------------- caulk_single_opening/src/kzg.rs | 44 ++++++++++++-- caulk_single_opening/src/lib.rs | 7 +-- caulk_single_opening/src/pedersen.rs | 8 +-- 8 files changed, 90 insertions(+), 96 deletions(-) rename caulk_single_opening/src/{multiopen.rs => dft.rs} (90%) diff --git a/caulk_single_opening/examples/single_opening.rs b/caulk_single_opening/examples/single_opening.rs index b2b85ce..4fc6a19 100644 --- a/caulk_single_opening/examples/single_opening.rs +++ b/caulk_single_opening/examples/single_opening.rs @@ -6,7 +6,6 @@ use ark_poly_commit::kzg10::KZG10; use ark_std::test_rng; use ark_std::UniformRand; use caulk_single_opening::caulk_single_setup; -use caulk_single_opening::multiple_open; use caulk_single_opening::CaulkTranscript; use caulk_single_opening::KZGCommit; use caulk_single_opening::{caulk_single_prove, caulk_single_verify}; @@ -95,7 +94,7 @@ fn main() { //compute all openings let now = Instant::now(); - let g1_qs = multiple_open(&c_poly, &pp.poly_ck, p); + let g1_qs = KZGCommit::multiple_open(&c_poly, &pp.poly_ck, p); g1_q = g1_qs[position]; println!("Time to compute all KZG openings {:?}", now.elapsed()); } diff --git a/caulk_single_opening/src/caulk_single.rs b/caulk_single_opening/src/caulk_single.rs index 5487f2d..57b6d6a 100644 --- a/caulk_single_opening/src/caulk_single.rs +++ b/caulk_single_opening/src/caulk_single.rs @@ -16,6 +16,7 @@ use ark_poly::{EvaluationDomain, GeneralEvaluationDomain}; use ark_std::rand::RngCore; use ark_std::UniformRand; use ark_std::{One, Zero}; +use std::ops::Neg; // Structure of opening proofs output by prove. #[allow(non_snake_case)] @@ -131,12 +132,7 @@ pub fn caulk_single_verify( // check that e( - C + cm, [1]_2) + e( [T]_1, [z]_2 ) + e( [h]_1, [S]_2 ) = 1 let eq1: Vec<(E::G1Prepared, E::G2Prepared)> = vec![ - ( - (g1_C.mul(-E::Fr::one()) + cm.into_projective()) - .into_affine() - .into(), - vk.poly_vk.prepared_h.clone(), - ), + ((g1_C.neg() + *cm).into(), vk.poly_vk.prepared_h.clone()), ((proof.g1_T).into(), proof.g2_z.into()), (vk.pedersen_param.h.into(), proof.g2_S.into()), ]; @@ -165,17 +161,7 @@ pub fn caulk_single_verify( transcript.append_element(b"t1", &proof.pi_ped.t1); transcript.append_element(b"t2", &proof.pi_ped.t2); - let vk_unity = VerifierPublicParametersUnity { - poly_vk: vk.poly_vk.clone(), - gxpen: vk.poly_ck_pen, - g1: vk.pedersen_param.g, - g1_x: vk.g1_x, - lagrange_scalars_Vn: vk.lagrange_scalars_Vn.clone(), - poly_prod: vk.poly_prod.clone(), - logN: vk.logN, - domain_Vn: vk.domain_Vn, - powers_of_g2: vk.powers_of_g2.clone(), - }; + let vk_unity = VerifierPublicParametersUnity::from(vk); // Verify that g2_z = [ ax - b ]_1 for (a/b)**N = 1 let check3 = caulk_single_unity_verify(&vk_unity, transcript, &proof.g2_z, &proof.pi_unity); diff --git a/caulk_single_opening/src/caulk_single_setup.rs b/caulk_single_opening/src/caulk_single_setup.rs index 635e328..336f606 100644 --- a/caulk_single_opening/src/caulk_single_setup.rs +++ b/caulk_single_opening/src/caulk_single_setup.rs @@ -50,10 +50,10 @@ fn trim>( if supported_degree == 1 { supported_degree += 1; } - let pp = srs.clone(); - let powers_of_g = pp.powers_of_g[..=supported_degree].to_vec(); + + let powers_of_g = srs.powers_of_g[..=supported_degree].to_vec(); let powers_of_gamma_g = (0..=supported_degree) - .map(|i| pp.powers_of_gamma_g[&i]) + .map(|i| srs.powers_of_gamma_g[&i]) .collect(); let powers = Powers { @@ -61,12 +61,12 @@ fn trim>( powers_of_gamma_g: ark_std::borrow::Cow::Owned(powers_of_gamma_g), }; let vk = VerifierKey { - g: pp.powers_of_g[0], - gamma_g: pp.powers_of_gamma_g[&0], - h: pp.h, - beta_h: pp.beta_h, - prepared_h: pp.prepared_h.clone(), - prepared_beta_h: pp.prepared_beta_h.clone(), + g: srs.powers_of_g[0], + gamma_g: srs.powers_of_gamma_g[&0], + h: srs.h, + beta_h: srs.beta_h, + prepared_h: srs.prepared_h.clone(), + prepared_beta_h: srs.prepared_beta_h.clone(), }; (powers, vk) } diff --git a/caulk_single_opening/src/caulk_single_unity.rs b/caulk_single_opening/src/caulk_single_unity.rs index f5f64a2..114ce87 100644 --- a/caulk_single_opening/src/caulk_single_unity.rs +++ b/caulk_single_opening/src/caulk_single_unity.rs @@ -3,7 +3,7 @@ This file includes the Caulk's unity prover and verifier for single openings. The protocol is described in Figure 2. */ -use crate::caulk_single_setup::PublicParameters; +use crate::caulk_single_setup::{PublicParameters, VerifierPublicParameters}; use crate::kzg::KZGCommit; use crate::CaulkTranscript; use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; @@ -69,6 +69,22 @@ impl From<&PublicParameters> for PublicParametersUnity { } } +impl From<&VerifierPublicParameters> for VerifierPublicParametersUnity { + fn from(vk: &VerifierPublicParameters) -> Self { + Self { + poly_vk: vk.poly_vk.clone(), + gxpen: vk.poly_ck_pen, + g1: vk.pedersen_param.g, + g1_x: vk.g1_x, + lagrange_scalars_Vn: vk.lagrange_scalars_Vn.clone(), + poly_prod: vk.poly_prod.clone(), + logN: vk.logN, + domain_Vn: vk.domain_Vn, + powers_of_g2: vk.powers_of_g2.clone(), + } + } +} + // Prove knowledge of a, b such that g2_z = [ax - b]_2 and a^n = b^n #[allow(non_snake_case)] pub fn caulk_single_unity_prove( @@ -185,12 +201,11 @@ pub fn caulk_single_unity_prove( //////////////////////////// // Commit to f(X) and h(X) //////////////////////////// - let (g1_F, _) = KZG10::commit(&pp.poly_ck, &f_poly, None, None).unwrap(); - let g1_F: E::G1Affine = g1_F.0; - let (h_hat_com, _) = KZG10::commit(&pp.poly_ck, &h_hat_poly, None, None).unwrap(); + let g1_F = KZGCommit::::commit(&pp.poly_ck, &f_poly); + let h_hat_com = KZGCommit::::commit(&pp.poly_ck, &h_hat_poly); // g1_H is a commitment to h_hat_poly + X^(d-1) z(X) - let g1_H = h_hat_com.0 + (pp.gxd.mul(-*a) + pp.gxpen.mul(*b)).into_affine(); + let g1_H = (h_hat_com.into_projective() + pp.gxd.mul(-*a) + pp.gxpen.mul(*b)).into_affine(); //////////////////////////// // alpha = Hash([z]_2, [F]_1, [H]_1) @@ -392,7 +407,7 @@ pub fn caulk_single_unity_verify( ), ( ((vk.g1.mul(-rho0 - rho1) + vk.gxpen.mul(-zalpha)).into_affine()).into(), - g2_z.into_projective().into_affine().into(), + (*g2_z).into(), ), ((-g1_q).into(), vk.poly_vk.prepared_beta_h.clone()), ]; diff --git a/caulk_single_opening/src/multiopen.rs b/caulk_single_opening/src/dft.rs similarity index 90% rename from caulk_single_opening/src/multiopen.rs rename to caulk_single_opening/src/dft.rs index 619fcf2..b222ca3 100644 --- a/caulk_single_opening/src/multiopen.rs +++ b/caulk_single_opening/src/dft.rs @@ -5,16 +5,15 @@ It is useful for preprocessing. The full algorithm is described here https://github.com/khovratovich/Kate/blob/master/Kate_amortized.pdf */ +use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; use ark_ff::{Field, PrimeField}; use ark_poly::univariate::DensePolynomial; +use ark_poly::{EvaluationDomain, GeneralEvaluationDomain, UVPolynomial}; +use ark_poly_commit::kzg10::*; use ark_std::One; use ark_std::Zero; use std::vec::Vec; -use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; -use ark_poly::{EvaluationDomain, GeneralEvaluationDomain, UVPolynomial}; -use ark_poly_commit::kzg10::*; - //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( @@ -29,12 +28,14 @@ pub fn compute_h( //let now = Instant::now(); //1. x_ext = [[x^(d-1)], [x^{d-2},...,[x],[1], d+2 [0]'s] - let mut x_ext = vec![]; - for i in 0..=dom_size - 2 { - x_ext.push(poly_ck.powers_of_g[dom_size - 2 - i].into_projective()); - } - let g1inf = poly_ck.powers_of_g[0].mul(fpzero); - x_ext.resize(2 * dom_size, g1inf); //filling 2d+2 neutral elements + let mut x_ext: Vec = poly_ck + .powers_of_g + .iter() + .take(dom_size - 1) + .rev() + .map(|x| x.into_projective()) + .collect(); + x_ext.resize(2 * dom_size, E::G1Projective::zero()); //filling 2d+2 neutral elements let y = dft_g1::(&x_ext, p + 1); //println!("Step 1 computed in {:?}", now.elapsed()); @@ -125,39 +126,6 @@ pub fn dft_opt(h: &[E::Fr], p: usize) -> Vec { xvec } -//compute all openings to c_poly using a smart formula -pub fn multiple_open( - c_poly: &DensePolynomial, //c(X) - poly_ck: &Powers, //SRS - p: usize, -) -> Vec { - let degree = c_poly.coeffs.len() - 1; - let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(degree).unwrap(); - - //let now = Instant::now(); - let h2 = compute_h(c_poly, poly_ck, p); - //println!("H2 computed in {:?}", now.elapsed()); - //assert_eq!(h,h2); - - let dom_size = input_domain.size(); - assert_eq!(1 << p, dom_size); - assert_eq!(degree + 1, dom_size); - /*let now = Instant::now(); - let q = DFTG1(&h,p); - println!("Q computed in {:?}", now.elapsed());*/ - - //let now = Instant::now(); - let q2 = dft_g1::(&h2, p); - //println!("Q2 computed in {:?}", now.elapsed()); - //assert_eq!(q,q2); - - let mut res: Vec = vec![]; - for e in q2.iter() { - res.push(e.into_affine()); - } - res -} - //compute idft of size @dom_size over vector of G1 elements //q_i = (h_0 + h_1w^-i + h_2w^{-2i}+\cdots + h_{dom_size-1}w^{-(dom_size-1)i})/dom_size for 0<= i< dom_size=2^p pub fn idft_g1(h: &[E::G1Projective], p: usize) -> Vec { @@ -194,8 +162,9 @@ pub fn idft_g1(h: &[E::G1Projective], p: usize) -> Vec { } impl KZGCommit { - pub fn commit( - powers: &Powers, - polynomial: &DensePolynomial, - ) -> E::G1Affine { + pub fn commit(powers: &Powers, polynomial: &DensePolynomial) -> E::G1Affine { let (com, _randomness) = KZG10::::commit(powers, polynomial, None, None).unwrap(); com.0 } + // 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. + // It is useful for preprocessing. + // The full algorithm is described here https://github.com/khovratovich/Kate/blob/master/Kate_amortized.pdf + pub fn multiple_open( + c_poly: &DensePolynomial, //c(X) + poly_ck: &Powers, //SRS + p: usize, + ) -> Vec { + 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 h2 = compute_h(c_poly, poly_ck, 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 = dft_g1::(&h2, p); + end_timer!(dft_timer); + + let res = E::G1Projective::batch_normalization_into_affine(q2.as_ref()); + + end_timer!(timer); + res + } + /* KZG.Open( srs_KZG, f(X), deg, (alpha1, alpha2, ..., alphan) ) returns ([f(alpha1), ..., f(alphan)], pi) @@ -63,7 +95,7 @@ impl KZGCommit { proofs.push(pi); } - let mut res: E::G1Projective = E::G1Projective::zero(); //default value + let mut res = E::G1Projective::zero(); //default value for j in 0..points.len() { let w_j = points[j]; diff --git a/caulk_single_opening/src/lib.rs b/caulk_single_opening/src/lib.rs index 21868da..c2ad329 100644 --- a/caulk_single_opening/src/lib.rs +++ b/caulk_single_opening/src/lib.rs @@ -1,15 +1,15 @@ mod caulk_single; mod caulk_single_setup; mod caulk_single_unity; +mod dft; mod kzg; -mod multiopen; mod pedersen; mod transcript; pub use caulk_single::{caulk_single_prove, caulk_single_verify}; pub use caulk_single_setup::caulk_single_setup; +pub use dft::*; pub use kzg::KZGCommit; -pub use multiopen::multiple_open; pub use pedersen::PedersenParam; pub use transcript::CaulkTranscript; @@ -17,7 +17,6 @@ pub use transcript::CaulkTranscript; mod tests { use crate::caulk_single_setup; - use crate::multiple_open; use crate::CaulkTranscript; use crate::KZGCommit; use crate::{caulk_single_prove, caulk_single_verify}; @@ -97,7 +96,7 @@ mod tests { } // compute all openings { - let g1_qs = multiple_open(&c_poly, &pp.poly_ck, p); + let g1_qs = KZGCommit::multiple_open(&c_poly, &pp.poly_ck, p); let g1_q = g1_qs[position]; // run the prover diff --git a/caulk_single_opening/src/pedersen.rs b/caulk_single_opening/src/pedersen.rs index e2ce15f..1ef45d9 100644 --- a/caulk_single_opening/src/pedersen.rs +++ b/caulk_single_opening/src/pedersen.rs @@ -6,7 +6,6 @@ The protocol is informally described in Appendix A.2, Proof of Opening of a Pede use crate::CaulkTranscript; use ark_ec::{AffineCurve, ProjectiveCurve}; use ark_ff::PrimeField; -use ark_std::Zero; use ark_std::{rand::RngCore, UniformRand}; use std::marker::PhantomData; @@ -67,11 +66,6 @@ impl PedersenCommit { let c = transcript.get_and_append_challenge(b"get c"); // check that R g^(-t1) h^(-t2) cm^(c) = 1 - let check = proof.g1_r.into_projective() - + param.g.mul(-proof.t1) - + param.h.mul(-proof.t2) - + cm.mul(c); - - check.is_zero() + proof.g1_r.into_projective() + cm.mul(c) == param.g.mul(proof.t1) + param.h.mul(proof.t2) } }