From b89d72aa73955a276c8084b2108e62c8fc756373 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Tue, 24 May 2022 18:40:35 -0400 Subject: [PATCH] polish-single-opening --- caulk_single_opening/Cargo.toml | 12 + .../main.rs => examples/single_opening.rs} | 37 +-- caulk_single_opening/src/caulk_single.rs | 135 ++++---- .../src/caulk_single_setup.rs | 163 +++++----- .../src/caulk_single_unity.rs | 216 ++++++------- caulk_single_opening/src/lib.rs | 11 + caulk_single_opening/src/multiopen.rs | 301 ++++++++++-------- caulk_single_opening/src/pedersen.rs | 77 ++--- caulk_single_opening/src/tools.rs | 234 +++++--------- 9 files changed, 578 insertions(+), 608 deletions(-) rename caulk_single_opening/{src/main.rs => examples/single_opening.rs} (84%) create mode 100644 caulk_single_opening/src/lib.rs diff --git a/caulk_single_opening/Cargo.toml b/caulk_single_opening/Cargo.toml index e288982..efdea3d 100644 --- a/caulk_single_opening/Cargo.toml +++ b/caulk_single_opening/Cargo.toml @@ -16,6 +16,7 @@ ark-relations = { version = "^0.3.0", default-features = false } ark-crypto-primitives = { version = "^0.3.0", default-features = false } ark-r1cs-std = { version = "^0.3.0", default-features = false, optional = true } ark-bls12-381 = { version = "^0.3.0", features = [ "std" ] } +ark-bls12-377 = { version = "^0.3.0", features = [ "std" ] } ark-poly-commit = { version = "^0.3.0", default-features = false } ark-marlin = { version = "^0.3.0", default-features = false } @@ -26,6 +27,17 @@ rand_chacha = { version = "0.2.1" } thiserror = "1.0.19" blake2s_simd = "0.5.10" +rayon = { version = "1.5.2", default-features = false, optional = true } [features] asm = [ "ark-ff/asm" ] +parallel = [ + "rayon", + "ark-std/parallel", + "ark-ff/parallel", + "ark-poly/parallel" + ] +print-trace = [ + "ark-std/print-trace" +] + diff --git a/caulk_single_opening/src/main.rs b/caulk_single_opening/examples/single_opening.rs similarity index 84% rename from caulk_single_opening/src/main.rs rename to caulk_single_opening/examples/single_opening.rs index f16f761..609ae57 100644 --- a/caulk_single_opening/src/main.rs +++ b/caulk_single_opening/examples/single_opening.rs @@ -1,25 +1,23 @@ use ark_bls12_381::{Bls12_381, Fr, G1Affine}; use ark_ec::{AffineCurve, ProjectiveCurve}; +use ark_poly::univariate::DensePolynomial; use ark_poly::{EvaluationDomain, GeneralEvaluationDomain, Polynomial, UVPolynomial}; 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::{caulk_single_prove, caulk_single_verify}; +use caulk_single_opening::{kzg_open_g1, read_line}; use std::time::Instant; -mod caulk_single; -mod caulk_single_setup; -mod caulk_single_unity; -mod multiopen; -mod pedersen; -mod tools; - -use crate::caulk_single::{caulk_single_prove, caulk_single_verify}; -use crate::caulk_single_setup::caulk_single_setup; -use crate::multiopen::multiple_open; -use crate::tools::{kzg_open_g1, random_field, read_line, UniPoly381}; - -pub type KzgBls12_381 = KZG10; +type UniPoly381 = DensePolynomial; +type KzgBls12_381 = KZG10; #[allow(non_snake_case)] fn main() { + let mut rng = test_rng(); + // setting public parameters // current kzg setup should be changed with output from a setup ceremony println!("What is the bitsize of the degree of the polynomial inside the commitment? "); @@ -29,7 +27,7 @@ fn main() { // run the setup let now = Instant::now(); - let pp = caulk_single_setup(max_degree, actual_degree); + let pp = caulk_single_setup(max_degree, actual_degree, &mut rng); println!( "Time to setup single openings of table size {:?} = {:?}", actual_degree + 1, @@ -39,8 +37,7 @@ fn main() { //polynomial and commitment let now = Instant::now(); // deterministic randomness. Should never be used in practice. - let rng = &mut ark_std::test_rng(); - let c_poly = UniPoly381::rand(actual_degree, rng); + let c_poly = UniPoly381::rand(actual_degree, &mut rng); let (g1_C, _) = KzgBls12_381::commit(&pp.poly_ck, &c_poly, None, None).unwrap(); let g1_C = g1_C.0; println!( @@ -68,7 +65,7 @@ fn main() { if (open_all == "NO") || (open_all == "No") || (open_all == "no") { // Q = g1_q = g^( (c(x) - c(w_i)) / (x - w_i) ) let now = Instant::now(); - let a = kzg_open_g1(&pp.poly_ck, &c_poly, None, [&omega_i].to_vec()); + let a = kzg_open_g1(&pp.poly_ck, &c_poly, None, &[omega_i]); println!( "Time to KZG open one element from table size {:?} = {:?}", actual_degree + 1, @@ -90,7 +87,7 @@ fn main() { // z = c(w_i) and cm = g^z h^r for random r let z = c_poly.evaluate(&omega_i); - let r = random_field::(); + let r = Fr::rand(&mut rng); let cm = (pp.ped_g.mul(z) + pp.ped_h.mul(r)).into_affine(); // run the prover @@ -98,9 +95,9 @@ fn main() { let number_of_openings: usize = read_line(); let now = Instant::now(); - let mut proof_evaluate = caulk_single_prove(&pp, &g1_C, &cm, position, &g1_q, &z, &r); + let mut proof_evaluate = caulk_single_prove(&pp, &g1_C, &cm, position, &g1_q, &z, &r, &mut rng); for _ in 1..(number_of_openings - 1) { - proof_evaluate = caulk_single_prove(&pp, &g1_C, &cm, position, &g1_q, &z, &r); + proof_evaluate = caulk_single_prove(&pp, &g1_C, &cm, position, &g1_q, &z, &r, &mut rng); } println!( "Time to evaluate {} single openings of table size {:?} = {:?}", diff --git a/caulk_single_opening/src/caulk_single.rs b/caulk_single_opening/src/caulk_single.rs index 6b055ad..f5de9ec 100644 --- a/caulk_single_opening/src/caulk_single.rs +++ b/caulk_single_opening/src/caulk_single.rs @@ -3,10 +3,11 @@ This file includes the Caulk prover and verifier for single openings. The protocol is described in Figure 1. */ -use ark_bls12_381::{Bls12_381, Fr, G1Affine, G2Affine}; use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; use ark_ff::{Field, PrimeField}; use ark_poly::{EvaluationDomain, GeneralEvaluationDomain}; +use ark_std::rand::RngCore; +use ark_std::UniformRand; use ark_std::{One, Zero}; use crate::caulk_single_setup::{PublicParameters, VerifierPublicParameters}; @@ -15,16 +16,16 @@ use crate::caulk_single_unity::{ VerifierPublicParametersUnity, }; use crate::pedersen::{prove_pedersen, verify_pedersen, ProofPed}; -use crate::tools::{hash_caulk_single, random_field}; +use crate::tools::hash_caulk_single; // Structure of opening proofs output by prove. #[allow(non_snake_case)] -pub struct CaulkProof { - pub g2_z: G2Affine, - pub g1_T: G1Affine, - pub g2_S: G2Affine, - pub pi_ped: ProofPed, - pub pi_unity: CaulkProofUnity, +pub struct CaulkProof { + pub g2_z: E::G2Affine, + pub g1_T: E::G1Affine, + pub g2_S: E::G2Affine, + pub pi_ped: ProofPed, + pub pi_unity: CaulkProofUnity, } //Proves knowledge of (i, Q, z, r) such that @@ -33,20 +34,22 @@ pub struct CaulkProof { //Takes as input opening proof Q. Does not need knowledge of contents of C = g1_C. #[allow(non_snake_case)] -pub fn caulk_single_prove( - pp: &PublicParameters, - g1_C: &G1Affine, - cm: &G1Affine, +#[allow(clippy::too_many_arguments)] +pub fn caulk_single_prove( + pp: &PublicParameters, + g1_C: &E::G1Affine, + cm: &E::G1Affine, index: usize, - g1_q: &G1Affine, - v: &Fr, - r: &Fr, -) -> CaulkProof { + g1_q: &E::G1Affine, + v: &E::Fr, + r: &E::Fr, + rng: &mut R, +) -> CaulkProof { // provers blinders for zero-knowledge - let a: Fr = random_field::(); - let s: Fr = random_field::(); + let a = E::Fr::rand(rng); + let s = E::Fr::rand(rng); - let domain_H: GeneralEvaluationDomain = + let domain_H: GeneralEvaluationDomain = GeneralEvaluationDomain::new(pp.domain_H_size).unwrap(); /////////////////////////////// @@ -68,80 +71,76 @@ pub fn caulk_single_prove( /////////////////////////////// // hash the instance and the proof elements to determine hash inputs for Pedersen prover - let mut hash_input = hash_caulk_single::( - Fr::zero(), - Some(&[g1_C.clone(), g1_T.clone()].to_vec()), - Some(&[g2_z.clone(), g2_S.clone()].to_vec()), + let mut hash_input = hash_caulk_single::( + &E::Fr::zero(), + Some(&[*g1_C, g1_T]), + Some(&[g2_z, g2_S]), None, ); // proof that cm = g^z h^rs - let pi_ped = prove_pedersen(&pp.ped_g, &pp.ped_h, &mut hash_input, &cm, v, r); + let pi_ped = prove_pedersen::(&pp.ped_g, &pp.ped_h, &mut hash_input, cm, v, r, rng); /////////////////////////////// // Unity prove /////////////////////////////// // hash the last round of the pedersen proof to determine hash input to the unity prover - hash_input = hash_caulk_single::( - hash_input, + hash_input = hash_caulk_single::( + &hash_input, None, None, - Some(&[pi_ped.t1.clone(), pi_ped.t2.clone()].to_vec()), + Some(&[pi_ped.t1, pi_ped.t2]), ); // Setting up the public parameters for the unity prover let pp_unity = PublicParametersUnity { poly_ck: pp.poly_ck.clone(), - gxd: pp.poly_ck_d.clone(), - gxpen: pp.poly_ck_pen.clone(), + gxd: pp.poly_ck_d, + gxpen: pp.poly_ck_pen, lagrange_polynomials_Vn: pp.lagrange_polynomials_Vn.clone(), poly_prod: pp.poly_prod.clone(), - logN: pp.logN.clone(), - domain_Vn: pp.domain_Vn.clone(), + logN: pp.logN, + domain_Vn: pp.domain_Vn, }; // proof that A = [a x - b ]_2 for a^n = b^n let pi_unity = caulk_single_unity_prove( &pp_unity, &mut hash_input, - g2_z, - a, - a * domain_H.element(index), + &g2_z, + &a, + &(a * domain_H.element(index)), + rng, ); - let proof = CaulkProof { - g2_z: g2_z, - g1_T: g1_T, - g2_S: g2_S, - pi_ped: pi_ped, - pi_unity: pi_unity, - }; - - proof + CaulkProof { + g2_z, + g1_T, + g2_S, + pi_ped, + pi_unity, + } } //Verifies that the prover knows of (i, Q, z, r) such that // 1) Q is a KZG opening proof that g1_C opens to z at i // 2) cm = g^z h^r #[allow(non_snake_case)] -pub fn caulk_single_verify( - vk: &VerifierPublicParameters, - g1_C: &G1Affine, - cm: &G1Affine, - proof: &CaulkProof, +pub fn caulk_single_verify( + vk: &VerifierPublicParameters, + g1_C: &E::G1Affine, + cm: &E::G1Affine, + proof: &CaulkProof, ) -> bool { /////////////////////////////// // Pairing check /////////////////////////////// // check that e( - C + cm, [1]_2) + e( [T]_1, [z]_2 ) + e( [h]_1, [S]_2 ) = 1 - let eq1: Vec<( - ark_ec::bls12::G1Prepared, - ark_ec::bls12::G2Prepared, - )> = vec![ + let eq1: Vec<(E::G1Prepared, E::G2Prepared)> = vec![ ( - (g1_C.mul(-Fr::one()) + cm.into_projective()) + (g1_C.mul(-E::Fr::one()) + cm.into_projective()) .into_affine() .into(), vk.poly_vk.prepared_h.clone(), @@ -150,44 +149,44 @@ pub fn caulk_single_verify( (vk.ped_h.into(), proof.g2_S.into()), ]; - let check1 = Bls12_381::product_of_pairings(&eq1).is_one(); + let check1 = E::product_of_pairings(&eq1).is_one(); /////////////////////////////// // Pedersen check /////////////////////////////// // hash the instance and the proof elements to determine hash inputs for Pedersen prover - let mut hash_input = hash_caulk_single::( - Fr::zero(), - Some(&[g1_C.clone(), proof.g1_T.clone()].to_vec()), - Some(&[proof.g2_z.clone(), proof.g2_S.clone()].to_vec()), + let mut hash_input = hash_caulk_single::( + &E::Fr::zero(), + Some(&[*g1_C, proof.g1_T]), + Some(&[proof.g2_z, proof.g2_S]), None, ); // verify that cm = [v + r h] - let check2 = verify_pedersen(&vk.ped_g, &vk.ped_h, &mut hash_input, &cm, &proof.pi_ped); + let check2 = verify_pedersen::(&vk.ped_g, &vk.ped_h, &mut hash_input, cm, &proof.pi_ped); /////////////////////////////// // Unity check /////////////////////////////// // hash the last round of the pedersen proof to determine hash input to the unity prover - hash_input = hash_caulk_single::( - hash_input, + hash_input = hash_caulk_single::( + &hash_input, None, None, - Some(&[proof.pi_ped.t1.clone(), proof.pi_ped.t2.clone()].to_vec()), + Some(&[proof.pi_ped.t1, proof.pi_ped.t2]), ); let vk_unity = VerifierPublicParametersUnity { poly_vk: vk.poly_vk.clone(), - gxpen: vk.poly_ck_pen.clone(), - g1: vk.ped_g.clone(), - g1_x: vk.g1_x.clone(), + gxpen: vk.poly_ck_pen, + g1: vk.ped_g, + g1_x: vk.g1_x, lagrange_scalars_Vn: vk.lagrange_scalars_Vn.clone(), poly_prod: vk.poly_prod.clone(), - logN: vk.logN.clone(), - domain_Vn: vk.domain_Vn.clone(), + logN: vk.logN, + domain_Vn: vk.domain_Vn, powers_of_g2: vk.powers_of_g2.clone(), }; @@ -195,5 +194,5 @@ pub fn caulk_single_verify( let check3 = caulk_single_unity_verify(&vk_unity, &mut hash_input, &proof.g2_z, &proof.pi_unity); - return check1 && check2 && check3; + check1 && check2 && check3 } diff --git a/caulk_single_opening/src/caulk_single_setup.rs b/caulk_single_opening/src/caulk_single_setup.rs index 40330f4..9629664 100644 --- a/caulk_single_opening/src/caulk_single_setup.rs +++ b/caulk_single_opening/src/caulk_single_setup.rs @@ -3,60 +3,57 @@ This file includes the setup algorithm for Caulk with single openings. A full description of the setup is not formally given in the paper. */ -use ark_bls12_381::{Bls12_381, Fr, FrParameters, G1Affine, G1Projective, G2Affine}; -use ark_ec::{bls12::Bls12, AffineCurve, PairingEngine, ProjectiveCurve}; -use ark_ff::{Field, Fp256, UniformRand}; +use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; +use ark_ff::{Field, UniformRand}; use ark_poly::{ univariate::DensePolynomial, EvaluationDomain, Evaluations as EvaluationsOnDomain, GeneralEvaluationDomain, UVPolynomial, }; use ark_poly_commit::kzg10::*; -use ark_std::{cfg_into_iter, One, Zero}; +use ark_std::{cfg_into_iter, rand::RngCore, One, Zero}; +use ark_std::{end_timer, start_timer}; use std::cmp::max; -use crate::tools::{KzgBls12_381, UniPoly381}; -use std::time::Instant; - // structure of public parameters #[allow(non_snake_case)] -pub struct PublicParameters { - pub poly_ck: Powers<'static, Bls12>, - pub poly_ck_d: G1Affine, - pub poly_ck_pen: G1Affine, - pub lagrange_polynomials_Vn: Vec, - pub poly_prod: UniPoly381, - pub poly_vk: VerifierKey>, - pub ped_g: G1Affine, - pub ped_h: G1Affine, +pub struct PublicParameters { + pub poly_ck: Powers<'static, E>, + pub poly_ck_d: E::G1Affine, + pub poly_ck_pen: E::G1Affine, + pub lagrange_polynomials_Vn: Vec>, + pub poly_prod: DensePolynomial, + pub poly_vk: VerifierKey, + pub ped_g: E::G1Affine, + pub ped_h: E::G1Affine, pub domain_H_size: usize, pub logN: usize, - pub domain_Vn: GeneralEvaluationDomain, + pub domain_Vn: GeneralEvaluationDomain, pub domain_Vn_size: usize, - pub verifier_pp: VerifierPublicParameters, + pub verifier_pp: VerifierPublicParameters, pub actual_degree: usize, } // smaller set of public parameters used by verifier #[allow(non_snake_case)] -pub struct VerifierPublicParameters { - pub poly_ck_pen: G1Affine, - pub lagrange_scalars_Vn: Vec, - pub poly_prod: UniPoly381, - pub poly_vk: VerifierKey>, - pub ped_g: G1Affine, - pub g1_x: G1Affine, - pub ped_h: G1Affine, +pub struct VerifierPublicParameters { + pub poly_ck_pen: E::G1Affine, + pub lagrange_scalars_Vn: Vec, + pub poly_prod: DensePolynomial, + pub poly_vk: VerifierKey, + pub ped_g: E::G1Affine, + pub g1_x: E::G1Affine, + pub ped_h: E::G1Affine, pub domain_H_size: usize, pub logN: usize, - pub domain_Vn: GeneralEvaluationDomain, + pub domain_Vn: GeneralEvaluationDomain, pub domain_Vn_size: usize, - pub powers_of_g2: Vec, + pub powers_of_g2: Vec, } // Reduces full srs down to smaller srs for smaller polynomials // Copied from arkworks library (where same function is private) fn trim>( - srs: UniversalParams, + srs: &UniversalParams, mut supported_degree: usize, ) -> (Powers<'static, E>, VerifierKey) { if supported_degree == 1 { @@ -86,18 +83,21 @@ fn trim>( // setup algorithm for Caulk with single openings // also includes a bunch of precomputation. #[allow(non_snake_case)] -pub fn caulk_single_setup(max_degree: usize, actual_degree: usize) -> PublicParameters { - // deterministic randomness. Should never be used in practice. - let rng = &mut ark_std::test_rng(); +pub fn caulk_single_setup( + max_degree: usize, + actual_degree: usize, + rng: &mut R, +) -> PublicParameters { + let total_time = start_timer!(|| "total srs setup"); // domain where vector commitment is defined - let domain_H: GeneralEvaluationDomain = + let domain_H: GeneralEvaluationDomain = GeneralEvaluationDomain::new(actual_degree).unwrap(); let logN: usize = ((actual_degree as f32).log(2.0)).ceil() as usize; // smaller domain for unity proofs with generator w - let domain_Vn: GeneralEvaluationDomain = GeneralEvaluationDomain::new(6 + logN).unwrap(); + let domain_Vn: GeneralEvaluationDomain = GeneralEvaluationDomain::new(6 + logN).unwrap(); // Determining how big an srs we need. // Need an srs of size actual_degree to commit to the polynomial. @@ -106,12 +106,13 @@ pub fn caulk_single_setup(max_degree: usize, actual_degree: usize) -> PublicPara let poly_ck_size = max(actual_degree, 2 * domain_Vn.size() + 3); // Setup algorithm. To be replaced by output of a universal setup before being production ready. - let now = Instant::now(); - let srs = KzgBls12_381::setup(max(max_degree, poly_ck_size), true, rng).unwrap(); - println!("time to setup powers = {:?}", now.elapsed()); + let powers_time = start_timer!(|| "setup powers"); + let srs = KZG10::>::setup(max(max_degree, poly_ck_size), true, rng) + .unwrap(); + end_timer!(powers_time); // trim down to size. - let (poly_ck, poly_vk) = trim::(srs.clone(), poly_ck_size.clone()); + let (poly_ck, poly_vk) = trim::>(&srs, poly_ck_size); // g^x^d = maximum power given in setup let poly_ck_d = srs.powers_of_g[srs.powers_of_g.len() - 1]; @@ -120,39 +121,39 @@ pub fn caulk_single_setup(max_degree: usize, actual_degree: usize) -> PublicPara let poly_ck_pen = srs.powers_of_g[srs.powers_of_g.len() - 2]; // random pedersen commitment generatoor - let ped_h: G1Affine = G1Projective::rand(rng).into_affine(); + let ped_h: E::G1Affine = E::G1Projective::rand(rng).into_affine(); // precomputation to speed up prover // lagrange_polynomials_Vn[i] = polynomial equal to 0 at w^j for j!= i and 1 at w^i - let mut lagrange_polynomials_Vn: Vec = Vec::new(); + let mut lagrange_polynomials_Vn: Vec> = Vec::new(); // precomputation to speed up verifier. // scalars such that lagrange_scalars_Vn[i] = prod_(j != i) (w^i - w^j)^(-1) - let mut lagrange_scalars_Vn: Vec = Vec::new(); + let mut lagrange_scalars_Vn: Vec = Vec::new(); for i in 0..domain_Vn.size() { - let evals: Vec> = cfg_into_iter!(0..domain_Vn.size()) - .map(|k| if k == i { Fr::one() } else { Fr::zero() }) + let evals: Vec = cfg_into_iter!(0..domain_Vn.size()) + .map(|k| if k == i { E::Fr::one() } else { E::Fr::zero() }) .collect(); lagrange_polynomials_Vn .push(EvaluationsOnDomain::from_vec_and_domain(evals, domain_Vn).interpolate()); } for i in 0..5 { - let mut temp = Fr::one(); + let mut temp = E::Fr::one(); for j in 0..domain_Vn.size() { if j != i { - temp = temp * (domain_Vn.element(i) - domain_Vn.element(j)); + temp *= domain_Vn.element(i) - domain_Vn.element(j); } } lagrange_scalars_Vn.push(temp.inverse().unwrap()); } // also want lagrange_scalars_Vn[logN + 5] - let mut temp = Fr::one(); + let mut temp = E::Fr::one(); for j in 0..domain_Vn.size() { if j != (logN + 5) { - temp = temp * (domain_Vn.element(logN + 5) - domain_Vn.element(j)); + temp *= domain_Vn.element(logN + 5) - domain_Vn.element(j); } } lagrange_scalars_Vn.push(temp.inverse().unwrap()); @@ -160,19 +161,28 @@ pub fn caulk_single_setup(max_degree: usize, actual_degree: usize) -> PublicPara // poly_prod = (X - 1) (X - w) (X - w^2) (X - w^3) (X - w^4) (X - w^(5 + logN)) (X - w^(6 + logN)) // for efficiency not including (X - w^i) for i > 6 + logN // prover sets these evaluations to 0 anyway. - let mut poly_prod = DensePolynomial::from_coefficients_slice(&[Fr::one()]); + let mut poly_prod = DensePolynomial::from_coefficients_slice(&[E::Fr::one()]); for i in 0..domain_Vn.size() { if i < 5 { poly_prod = &poly_prod - * (&DensePolynomial::from_coefficients_slice(&[-domain_Vn.element(i), Fr::one()])) + * (&DensePolynomial::from_coefficients_slice(&[ + -domain_Vn.element(i), + E::Fr::one(), + ])) } if i == (5 + logN) { poly_prod = &poly_prod - * (&DensePolynomial::from_coefficients_slice(&[-domain_Vn.element(i), Fr::one()])) + * (&DensePolynomial::from_coefficients_slice(&[ + -domain_Vn.element(i), + E::Fr::one(), + ])) } if i == (6 + logN) { poly_prod = &poly_prod - * (&DensePolynomial::from_coefficients_slice(&[-domain_Vn.element(i), Fr::one()])) + * (&DensePolynomial::from_coefficients_slice(&[ + -domain_Vn.element(i), + E::Fr::one(), + ])) } } @@ -183,46 +193,47 @@ pub fn caulk_single_setup(max_degree: usize, actual_degree: usize) -> PublicPara // arkworks setup doesn't give these powers but the setup does use a fixed randomness to generate them. // so we can generate powers of g2 directly. let rng = &mut ark_std::test_rng(); - let beta: Fp256 = Fr::rand(rng); - let mut temp = poly_vk.h.clone(); + let beta = E::Fr::rand(rng); + let mut temp = poly_vk.h; - let mut powers_of_g2: Vec = Vec::new(); - for _ in 0..3.clone() { - powers_of_g2.push(temp.clone()); + let mut powers_of_g2: Vec = Vec::new(); + for _ in 0..3 { + powers_of_g2.push(temp); temp = temp.mul(beta).into_affine(); } let verifier_pp = VerifierPublicParameters { - poly_ck_pen: poly_ck_pen, - lagrange_scalars_Vn: lagrange_scalars_Vn, + poly_ck_pen, + lagrange_scalars_Vn, poly_prod: poly_prod.clone(), poly_vk: poly_vk.clone(), - ped_g: ped_g, + ped_g, g1_x: srs.powers_of_g[1], - ped_h: ped_h, + ped_h, domain_H_size: domain_H.size(), - logN: logN, - domain_Vn: domain_Vn.clone(), + logN, + domain_Vn, domain_Vn_size: domain_Vn.size(), - powers_of_g2: powers_of_g2.clone(), + powers_of_g2, }; let pp = PublicParameters { - poly_ck: poly_ck, - poly_ck_d: poly_ck_d, - poly_ck_pen: poly_ck_pen, - lagrange_polynomials_Vn: lagrange_polynomials_Vn, - poly_prod: poly_prod, - ped_g: ped_g, - ped_h: ped_h, + poly_ck, + poly_ck_d, + poly_ck_pen, + lagrange_polynomials_Vn, + poly_prod, + ped_g, + ped_h, domain_H_size: domain_H.size(), - logN: logN, - poly_vk: poly_vk, + logN, + poly_vk, domain_Vn_size: domain_Vn.size(), - domain_Vn: domain_Vn, - verifier_pp: verifier_pp, - actual_degree: actual_degree.clone(), + domain_Vn, + verifier_pp, + actual_degree, }; - return pp; + end_timer!(total_time); + pp } diff --git a/caulk_single_opening/src/caulk_single_unity.rs b/caulk_single_opening/src/caulk_single_unity.rs index 7fe77dc..efd53df 100644 --- a/caulk_single_opening/src/caulk_single_unity.rs +++ b/caulk_single_opening/src/caulk_single_unity.rs @@ -3,110 +3,108 @@ This file includes the Caulk's unity prover and verifier for single openings. The protocol is described in Figure 2. */ -use ark_bls12_381::{Bls12_381, Fr, FrParameters, G1Affine, G2Affine}; -use ark_ec::{bls12::Bls12, AffineCurve, PairingEngine, ProjectiveCurve}; -use ark_ff::{Field, Fp256}; +use crate::tools::{hash_caulk_single, kzg_open_g1, kzg_verify_g1}; +use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; +use ark_ff::Field; use ark_poly::{ univariate::DensePolynomial, EvaluationDomain, Evaluations as EvaluationsOnDomain, GeneralEvaluationDomain, Polynomial, UVPolynomial, }; use ark_poly_commit::kzg10::*; use ark_std::{cfg_into_iter, One, Zero}; - -use crate::tools::{ - hash_caulk_single, kzg_open_g1, kzg_verify_g1, random_field, KzgBls12_381, UniPoly381, -}; +use ark_std::{rand::RngCore, UniformRand}; // prover public parameters structure for caulk_single_unity_prove #[allow(non_snake_case)] -pub struct PublicParametersUnity { - pub poly_ck: Powers<'static, Bls12>, - pub gxd: G1Affine, - pub gxpen: G1Affine, - pub lagrange_polynomials_Vn: Vec, - pub poly_prod: UniPoly381, +pub struct PublicParametersUnity { + pub poly_ck: Powers<'static, E>, + pub gxd: E::G1Affine, + pub gxpen: E::G1Affine, + pub lagrange_polynomials_Vn: Vec>, + pub poly_prod: DensePolynomial, pub logN: usize, - pub domain_Vn: GeneralEvaluationDomain, + pub domain_Vn: GeneralEvaluationDomain, } // verifier parameters structure for caulk_single_unity_verify #[allow(non_snake_case)] -pub struct VerifierPublicParametersUnity { - pub poly_vk: VerifierKey>, - pub gxpen: G1Affine, - pub g1: G1Affine, - pub g1_x: G1Affine, - pub lagrange_scalars_Vn: Vec, - pub poly_prod: UniPoly381, +pub struct VerifierPublicParametersUnity { + pub poly_vk: VerifierKey, + pub gxpen: E::G1Affine, + pub g1: E::G1Affine, + pub g1_x: E::G1Affine, + pub lagrange_scalars_Vn: Vec, + pub poly_prod: DensePolynomial, pub logN: usize, - pub domain_Vn: GeneralEvaluationDomain, - pub powers_of_g2: Vec, + pub domain_Vn: GeneralEvaluationDomain, + pub powers_of_g2: Vec, } // output structure of caulk_single_unity_prove #[allow(non_snake_case)] -pub struct CaulkProofUnity { - pub g1_F: G1Affine, - pub g1_H: G1Affine, - pub v1: Fp256, - pub v2: Fp256, - pub pi1: G1Affine, - pub pi2: G1Affine, - // pub g1_q3: G1Affine, +pub struct CaulkProofUnity { + pub g1_F: E::G1Affine, + pub g1_H: E::G1Affine, + pub v1: E::Fr, + pub v2: E::Fr, + pub pi1: E::G1Affine, + pub pi2: E::G1Affine, } // 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( - pp: &PublicParametersUnity, - hash_input: &mut Fr, - g2_z: G2Affine, - a: Fp256, - b: Fp256, -) -> CaulkProofUnity { +pub fn caulk_single_unity_prove( + pp: &PublicParametersUnity, + hash_input: &mut E::Fr, + g2_z: &E::G2Affine, + a: &E::Fr, + b: &E::Fr, + rng: &mut R, +) -> CaulkProofUnity { // a_poly = a X - b - let a_poly = DensePolynomial::from_coefficients_slice(&[-b, a]); + let a_poly = DensePolynomial::from_coefficients_slice(&[-*b, *a]); // provers blinders for zero-knowledge - let r0: Fp256 = random_field::(); - let r1: Fp256 = random_field::(); - let r2: Fp256 = random_field::(); - let r3: Fp256 = random_field::(); + let r0 = E::Fr::rand(rng); + let r1 = E::Fr::rand(rng); + let r2 = E::Fr::rand(rng); + let r3 = E::Fr::rand(rng); + let r_poly = DensePolynomial::from_coefficients_slice(&[r1, r2, r3]); // roots of unity in domain of size m = log_2(n) + 6 let sigma = pp.domain_Vn.element(1); // X^n - 1 - let z: UniPoly381 = pp.domain_Vn.vanishing_polynomial().into(); + let z: DensePolynomial = pp.domain_Vn.vanishing_polynomial().into(); // computing [ (a/b), (a/b)^2, (a/b)^4, ..., (a/b)^(2^logN) = (a/b)^n ] - let mut a_div_b = a * (b.inverse()).unwrap(); - let mut vec_a_div_b: Vec> = Vec::new(); + let mut a_div_b = *a * ((*b).inverse()).unwrap(); + let mut vec_a_div_b: Vec = Vec::new(); for _ in 0..(pp.logN + 1) { - vec_a_div_b.push(a_div_b.clone()); + vec_a_div_b.push(a_div_b); a_div_b = a_div_b * a_div_b; } //////////////////////////// // computing f(X). First compute in domain. //////////////////////////// - let f_evals: Vec> = cfg_into_iter!(0..pp.domain_Vn.size()) + let f_evals: Vec = cfg_into_iter!(0..pp.domain_Vn.size()) .map(|k| { if k == 0 { - a - b + *a - *b } else if k == 1 { - a * sigma - b + *a * sigma - *b } else if k == 2 { - a + *a } else if k == 3 { - b + *b } else if k > 3 && k < (pp.logN + 5) { vec_a_div_b[k - 4] } else if k == pp.logN + 5 { r0 } else { - Fr::zero() + E::Fr::zero() } }) .collect(); @@ -117,14 +115,14 @@ pub fn caulk_single_unity_prove( // computing f( sigma^(-1) X) and f( sigma^(-2) X) let mut f_poly_shift_1 = f_poly.clone(); let mut f_poly_shift_2 = f_poly.clone(); - let mut shift_1 = Fr::one(); - let mut shift_2 = Fr::one(); + let mut shift_1 = E::Fr::one(); + let mut shift_2 = E::Fr::one(); for i in 0..f_poly.len() { - f_poly_shift_1[i] = f_poly_shift_1[i] * shift_1; - f_poly_shift_2[i] = f_poly_shift_2[i] * shift_2; - shift_1 = shift_1 * pp.domain_Vn.element(pp.domain_Vn.size() - 1); - shift_2 = shift_2 * pp.domain_Vn.element(pp.domain_Vn.size() - 2); + f_poly_shift_1[i] *= shift_1; + f_poly_shift_2[i] *= shift_2; + shift_1 *= pp.domain_Vn.element(pp.domain_Vn.size() - 1); + shift_2 *= pp.domain_Vn.element(pp.domain_Vn.size() - 2); } //////////////////////////// @@ -137,7 +135,8 @@ pub fn caulk_single_unity_prove( // p(X) = p(X) + ( (1 - sigma) f(X) - f(sigma^(-2)X) + f(sigma^(-1) X) ) rho_3(X) p_poly = &p_poly - + &(&(&(&(&DensePolynomial::from_coefficients_slice(&[(Fr::one() - sigma)]) * &f_poly) + + &(&(&(&(&DensePolynomial::from_coefficients_slice(&[(E::Fr::one() - sigma)]) + * &f_poly) - &f_poly_shift_2) + &f_poly_shift_1) * &pp.lagrange_polynomials_Vn[2]); @@ -158,7 +157,7 @@ pub fn caulk_single_unity_prove( // p(X) = p(X) + ( f(sigma^(-1) X) - 1 ) rho_(logN + 6)(X) p_poly = &p_poly - + &(&(&f_poly_shift_1 - &(DensePolynomial::from_coefficients_slice(&[Fr::one()]))) + + &(&(&f_poly_shift_1 - &(DensePolynomial::from_coefficients_slice(&[E::Fr::one()]))) * &pp.lagrange_polynomials_Vn[pp.logN + 5]); // Compute h_hat_poly = p(X) / z_Vn(X) and abort if division is not perfect @@ -168,25 +167,20 @@ pub fn caulk_single_unity_prove( //////////////////////////// // Commit to f(X) and h(X) //////////////////////////// - let (g1_F, _) = KzgBls12_381::commit(&pp.poly_ck, &f_poly, None, None).unwrap(); - let g1_F: G1Affine = g1_F.0; - let (h_hat_com, _) = KzgBls12_381::commit(&pp.poly_ck, &h_hat_poly, None, None).unwrap(); + 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(); // 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.0 + (pp.gxd.mul(-*a) + pp.gxpen.mul(*b)).into_affine(); //////////////////////////// // alpha = Hash([z]_2, [F]_1, [H]_1) //////////////////////////// - let alpha = hash_caulk_single::( - hash_input.clone(), - Some(&[g1_F, g1_H].to_vec()), - Some(&[g2_z].to_vec()), - None, - ); + let alpha = hash_caulk_single::(hash_input, Some(&[g1_F, g1_H]), Some(&[*g2_z]), None); - *hash_input = alpha.clone(); + *hash_input = alpha; //////////////////////////// // v1 = f(sigma^(-1) alpha) and v2 = f(w^(-2) alpha) @@ -226,7 +220,8 @@ pub fn caulk_single_unity_prove( // p_alpha(X) = p_alpha(X) + ( (1-sigma) f(X) - v2 + v1 ) rho3(alpha) p_alpha_poly = &p_alpha_poly - + &(&(&(&(&DensePolynomial::from_coefficients_slice(&[(Fr::one() - sigma)]) * &f_poly) + + &(&(&(&(&DensePolynomial::from_coefficients_slice(&[(E::Fr::one() - sigma)]) + * &f_poly) - &pv2) + &pv1) * &prho3); @@ -248,46 +243,44 @@ pub fn caulk_single_unity_prove( We use p_alpha(X) = p_alpha(X) + ( v1 - 1 ) rho_(logN + 6)(alpha) to allow for any value of logN */ p_alpha_poly = &p_alpha_poly - + &(&(&pv1 - &(DensePolynomial::from_coefficients_slice(&[Fr::one()]))) * &prhologN6); + + &(&(&pv1 - &(DensePolynomial::from_coefficients_slice(&[E::Fr::one()]))) * &prhologN6); //////////////////////////// // Compute opening proofs //////////////////////////// // KZG.Open(srs_KZG, f(X), deg = bot, (alpha1, alpha2)) - let (_evals1, pi1) = kzg_open_g1(&pp.poly_ck, &f_poly, None, [&alpha1, &alpha2].to_vec()); + let (_evals1, pi1) = kzg_open_g1(&pp.poly_ck, &f_poly, None, [alpha1, alpha2].as_ref()); // KZG.Open(srs_KZG, p_alpha(X), deg = bot, alpha) - let (evals2, pi2) = kzg_open_g1(&pp.poly_ck, &p_alpha_poly, None, [&alpha].to_vec()); + let (evals2, pi2) = kzg_open_g1(&pp.poly_ck, &p_alpha_poly, None, &[alpha]); // abort if p_alpha( alpha) != 0 assert!( - evals2[0] == Fr::zero(), + evals2[0] == E::Fr::zero(), "p_alpha(X) does not equal 0 at alpha" ); - let proof = CaulkProofUnity { - g1_F: g1_F, - g1_H: g1_H, - v1: v1, - v2: v2, - pi1: pi1, - pi2: pi2, - }; - - proof + CaulkProofUnity { + g1_F, + g1_H, + v1, + v2, + pi1, + pi2, + } } // Verify that the prover knows a, b such that g2_z = g2^(a x - b) and a^n = b^n #[allow(non_snake_case)] -pub fn caulk_single_unity_verify( - vk: &VerifierPublicParametersUnity, - hash_input: &mut Fr, - g2_z: &G2Affine, - proof: &CaulkProofUnity, +pub fn caulk_single_unity_verify( + vk: &VerifierPublicParametersUnity, + hash_input: &mut E::Fr, + g2_z: &E::G2Affine, + proof: &CaulkProofUnity, ) -> bool { // g2_z must not be the identity - assert!(g2_z.is_zero() == false, "g2_z is the identity"); + assert!(!g2_z.is_zero(), "g2_z is the identity"); // roots of unity in domain of size m = log1_2(n) + 6 let sigma = vk.domain_Vn.element(1); @@ -298,17 +291,17 @@ pub fn caulk_single_unity_verify( // alpha = Hash(A, F, H) //////////////////////////// - let alpha = hash_caulk_single::( - hash_input.clone(), - Some(&[proof.g1_F, proof.g1_H].to_vec()), - Some(&[g2_z.clone()].to_vec()), + let alpha = hash_caulk_single::( + hash_input, + Some(&[proof.g1_F, proof.g1_H]), + Some(&[*g2_z]), None, ); - *hash_input = alpha.clone(); + *hash_input = alpha; // alpha1 = sigma^(-1) alpha and alpha2 = sigma^(-2) alpha - let alpha1: Fr = alpha * vk.domain_Vn.element(vk.domain_Vn.size() - 1); - let alpha2: Fr = alpha * vk.domain_Vn.element(vk.domain_Vn.size() - 2); + let alpha1: E::Fr = alpha * vk.domain_Vn.element(vk.domain_Vn.size() - 1); + let alpha2: E::Fr = alpha * vk.domain_Vn.element(vk.domain_Vn.size() - 2); /////////////////////////////// // Compute P = commitment to p_alpha(X) @@ -347,9 +340,10 @@ pub fn caulk_single_unity_verify( let g1_p = proof.g1_H.mul(-zalpha) + proof .g1_F - .mul(rho0 + rho1 + (Fr::one() - sigma) * rho2 + rho3 + v1 * rho4 + pprod) + .mul(rho0 + rho1 + (E::Fr::one() - sigma) * rho2 + rho3 + v1 * rho4 + pprod) + vk.g1.mul( - (v1 - v2) * rho2 + (v2 - sigma * v1) * rho3 - v2 * rho4 + (v1 - Fr::one()) * rhologN5 + (v1 - v2) * rho2 + (v2 - sigma * v1) * rho3 - v2 * rho4 + + (v1 - E::Fr::one()) * rhologN5 - v1 * v1 * pprod, ); @@ -361,17 +355,17 @@ pub fn caulk_single_unity_verify( // KZG opening check /////////////////////////////// - let check1 = kzg_verify_g1( - &[vk.g1, vk.g1_x].to_vec(), + let check1 = kzg_verify_g1::( + [vk.g1, vk.g1_x].as_ref(), &vk.powers_of_g2, - proof.g1_F, + &proof.g1_F, None, - [alpha1, alpha2].to_vec(), - [proof.v1, proof.v2].to_vec(), - proof.pi1, + [alpha1, alpha2].as_ref(), + [proof.v1, proof.v2].as_ref(), + &proof.pi1, ); - let g1_q = proof.pi2.clone(); + let g1_q = proof.pi2; // check that e(P Q3^(-alpha), g2)e( g^(-(rho0 + rho1) - zH(alpha) x^(d-1)), A ) e( Q3, g2^x ) = 1 // Had to move A from affine to projective and back to affine to get it to compile. @@ -388,7 +382,7 @@ pub fn caulk_single_unity_verify( ((-g1_q).into(), vk.poly_vk.prepared_beta_h.clone()), ]; - let check2 = Bls12_381::product_of_pairings(&eq1).is_one(); + let check2 = E::product_of_pairings(&eq1).is_one(); - return check1 && check2; + check1 && check2 } diff --git a/caulk_single_opening/src/lib.rs b/caulk_single_opening/src/lib.rs new file mode 100644 index 0000000..ad9e595 --- /dev/null +++ b/caulk_single_opening/src/lib.rs @@ -0,0 +1,11 @@ +mod caulk_single; +mod caulk_single_setup; +mod caulk_single_unity; +mod multiopen; +mod pedersen; +mod tools; + +pub use caulk_single::{caulk_single_prove, caulk_single_verify}; +pub use caulk_single_setup::caulk_single_setup; +pub use multiopen::multiple_open; +pub use tools::{kzg_open_g1, read_line}; diff --git a/caulk_single_opening/src/multiopen.rs b/caulk_single_opening/src/multiopen.rs index 984b850..5ea03c6 100644 --- a/caulk_single_opening/src/multiopen.rs +++ b/caulk_single_opening/src/multiopen.rs @@ -5,28 +5,26 @@ It is useful for preprocessing. The full algorithm is described here https://github.com/khovratovich/Kate/blob/master/Kate_amortized.pdf */ -use std::str::FromStr; -//use std::time::{Instant}; +use ark_ff::{Field, PrimeField}; +use ark_poly::univariate::DensePolynomial; +use ark_std::One; +use ark_std::Zero; use std::vec::Vec; -use ark_bls12_381::{Bls12_381, Fr, FrParameters, G1Affine, G1Projective}; -use ark_ff::{Field, Fp256, PrimeField}; -use ark_poly::univariate::DensePolynomial; - -use ark_ec::{AffineCurve, ProjectiveCurve}; +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( - c_poly: &DensePolynomial>, //c(X) degree up to d<2^p , i.e. c_poly has at most d+1 coeffs non-zero - poly_ck: &Powers, //SRS +pub fn compute_h( + c_poly: &DensePolynomial, //c(X) degree up to d<2^p , i.e. c_poly has at most d+1 coeffs non-zero + poly_ck: &Powers, //SRS p: usize, -) -> Vec { +) -> Vec { let mut coeffs = c_poly.coeffs().to_vec(); let dom_size = 1 << p; - let fpzero = Fp256::from_str("0").unwrap(); + let fpzero = E::Fr::zero(); coeffs.resize(dom_size, fpzero); //let now = Instant::now(); @@ -38,26 +36,25 @@ pub fn compute_h( let g1inf = poly_ck.powers_of_g[0].mul(fpzero); x_ext.resize(2 * dom_size, g1inf); //filling 2d+2 neutral elements - let y = dft_g1(&x_ext, p + 1); + let y = dft_g1::(&x_ext, p + 1); //println!("Step 1 computed in {:?}", now.elapsed()); //2. c_ext = [c_d, d zeroes, c_d,c_{0},c_1,...,c_{d-2},c_{d-1}] //let now = Instant::now(); - let mut c_ext = vec![]; - c_ext.push(coeffs[coeffs.len() - 1]); + let mut c_ext = vec![coeffs[coeffs.len() - 1]]; c_ext.resize(dom_size, fpzero); c_ext.push(coeffs[coeffs.len() - 1]); - for i in 0..coeffs.len() - 1 { - c_ext.push(coeffs[i]); + for &e in coeffs.iter().take(coeffs.len() - 1) { + c_ext.push(e); } assert_eq!(c_ext.len(), 2 * dom_size); - let v = dft_opt(&c_ext, p + 1); + let v = dft_opt::(&c_ext, p + 1); //println!("Step 2 computed in {:?}", now.elapsed()); //3. u = y o v //let now = Instant::now(); - let u = y + let u: Vec<_> = y .into_iter() .zip(v.into_iter()) .map(|(a, b)| a.mul(b.into_repr())) @@ -66,76 +63,76 @@ pub fn compute_h( //4. h_ext = idft_{2d+2}(u) //let now = Instant::now(); - let h_ext = idft_g1(&u, p + 1); + let h_ext = idft_g1::(&u, p + 1); //println!("Step 4 computed in {:?}", now.elapsed()); - return h_ext[0..dom_size].to_vec(); + h_ext[0..dom_size].to_vec() } //compute DFT 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} for 0<= i< dom_size=2^p -pub fn dft_g1(h: &Vec, p: usize) -> Vec { +pub fn dft_g1(h: &[E::G1Projective], p: usize) -> Vec { let dom_size = 1 << p; assert_eq!(h.len(), dom_size); //we do not support inputs of size not power of 2 - let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(dom_size).unwrap(); + let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(dom_size).unwrap(); let mut l = dom_size / 2; let mut m: usize = 1; //Stockham FFT - let mut xvec = vec![h.to_vec()]; - for t in 1..=p { - let mut xt = xvec[t - 1].clone(); + let mut xvec = h.to_vec(); + for _ in 0..p { + let mut xt = xvec.clone(); for j in 0..l { for k in 0..m { - let c0 = xvec[t - 1][k + j * m].clone(); - let c1 = &xvec[t - 1][k + j * m + l * m]; + let c0 = xvec[k + j * m]; + let c1 = xvec[k + j * m + l * m]; xt[k + 2 * j * m] = c0 + c1; let wj_2l = input_domain.element((j * dom_size / (2 * l)) % dom_size); xt[k + 2 * j * m + m] = (c0 - c1).mul(wj_2l.into_repr()); } } - l = l / 2; - m = m * 2; - xvec.push(xt.to_vec()); + l /= 2; + m *= 2; + xvec= xt; } - return xvec[p].to_vec(); + xvec } //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 -pub fn dft_opt(h: &Vec, p: usize) -> Vec { +pub fn dft_opt(h: &[E::Fr], p: usize) -> Vec { let dom_size = 1 << p; assert_eq!(h.len(), dom_size); //we do not support inputs of size not power of 2 - let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(dom_size).unwrap(); + let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(dom_size).unwrap(); let mut l = dom_size / 2; let mut m: usize = 1; //Stockham FFT - let mut xvec = vec![h.to_vec()]; - for t in 1..=p { - let mut xt = xvec[t - 1].clone(); + let mut xvec = h.to_vec(); + for _ in 0..p { + let mut xt = xvec.clone(); for j in 0..l { for k in 0..m { - let c0 = xvec[t - 1][k + j * m].clone(); - let c1 = &xvec[t - 1][k + j * m + l * m]; + let c0 = xvec[k + j * m]; + let c1 = xvec[k + j * m + l * m]; xt[k + 2 * j * m] = c0 + c1; let wj_2l = input_domain.element((j * dom_size / (2 * l)) % dom_size); xt[k + 2 * j * m + m] = (c0 - c1) * (wj_2l); } } - l = l / 2; - m = m * 2; - xvec.push(xt.to_vec()); + l /= 2; + m *= 2; + xvec = xt; } - return xvec[p].to_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 +pub fn multiple_open( + c_poly: &DensePolynomial, //c(X) + poly_ck: &Powers, //SRS p: usize, -) -> Vec { +) -> Vec { let degree = c_poly.coeffs.len() - 1; - let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(degree).unwrap(); + let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(degree).unwrap(); //let now = Instant::now(); let h2 = compute_h(c_poly, poly_ck, p); @@ -150,138 +147,141 @@ pub fn multiple_open( println!("Q computed in {:?}", now.elapsed());*/ //let now = Instant::now(); - let q2 = dft_g1(&h2, p); + let q2 = dft_g1::(&h2, p); //println!("Q2 computed in {:?}", now.elapsed()); //assert_eq!(q,q2); - let mut res: Vec = vec![]; - for i in 0..dom_size { - res.push(q2[i].into_affine()); + let mut res: Vec = vec![]; + for e in q2.iter() { + res.push(e.into_affine()); } - return res; + 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: &Vec, p: usize) -> Vec { +pub fn idft_g1(h: &[E::G1Projective], p: usize) -> Vec { let dom_size = 1 << p; assert_eq!(h.len(), dom_size); //we do not support inputs of size not power of 2 - let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(dom_size).unwrap(); + let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(dom_size).unwrap(); let mut l = dom_size / 2; let mut m: usize = 1; - let mut dom_fr = Fr::from_str("1").unwrap(); + let mut dom_fr = E::Fr::one(); //Stockham FFT - let mut xvec = vec![h.to_vec()]; - for t in 1..=p { - let mut xt = xvec[t - 1].clone(); + let mut xvec = h.to_vec(); + for _ in 0..p { + let mut xt = xvec.clone(); for j in 0..l { for k in 0..m { - let c0 = xvec[t - 1][k + j * m].clone(); - let c1 = &xvec[t - 1][k + j * m + l * m]; + let c0 = xvec[k + j * m]; + let c1 = xvec[k + j * m + l * m]; xt[k + 2 * j * m] = c0 + c1; let wj_2l = input_domain .element((dom_size - (j * dom_size / (2 * l)) % dom_size) % dom_size); xt[k + 2 * j * m + m] = (c0 - c1).mul(wj_2l.into_repr()); //Difference #1 to forward DFT } } - l = l / 2; - m = m * 2; + l /= 2; + m *= 2; dom_fr = dom_fr + dom_fr; - xvec.push(xt.to_vec()); + xvec = xt; } - let res = xvec[p] - .to_vec() + + let domain_inverse = dom_fr.inverse().unwrap().into_repr(); + + xvec .iter() - .map(|x| x.mul(dom_fr.inverse().unwrap().into_repr())) - .collect(); - return res; + .map(|x| x.mul(domain_inverse)) + .collect() } #[cfg(test)] pub mod tests { - use crate::*; - use crate::caulk_single_setup::caulk_single_setup; use crate::multiopen::*; - use crate::tools::kzg_open_g1; - - use ark_ff::Fp256; + use ark_bls12_377::Bls12_377; + use ark_bls12_381::Bls12_381; + use ark_ec::PairingEngine; use ark_poly::univariate::DensePolynomial; + use ark_std::test_rng; + use ark_std::time::Instant; + use ark_std::UniformRand; - pub fn commit_direct( - c_poly: &DensePolynomial>, //c(X) - poly_ck: &Powers, //SRS - ) -> G1Affine { + /// Various functions that are used for testing + + fn commit_direct( + c_poly: &DensePolynomial, //c(X) + poly_ck: &Powers, //SRS + ) -> E::G1Affine { assert!(c_poly.coeffs.len() <= poly_ck.powers_of_g.len()); let mut com = poly_ck.powers_of_g[0].mul(c_poly.coeffs[0]); for i in 1..c_poly.coeffs.len() { com = com + poly_ck.powers_of_g[i].mul(c_poly.coeffs[i]); } - return com.into_affine(); + com.into_affine() } //compute all openings to c_poly by mere calling `open` N times - pub fn multiple_open_naive( - c_poly: &DensePolynomial>, - c_com_open: &Randomness, DensePolynomial>>, - poly_ck: &Powers, + fn multiple_open_naive( + c_poly: &DensePolynomial, + c_com_open: &Randomness>, + poly_ck: &Powers, degree: usize, - ) -> Vec { - let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(degree).unwrap(); - let mut res: Vec = vec![]; + ) -> Vec { + let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(degree).unwrap(); + let mut res: Vec = vec![]; for i in 0..input_domain.size() { let omega_i = input_domain.element(i); - res.push(kzg_open_g1_test(&c_poly, &omega_i, &c_com_open, &poly_ck).w); + res.push(kzg_open_g1_test::(&c_poly, &omega_i, &c_com_open, &poly_ck).w); } - return res; + res } //////////////////////////////////////////////// - pub fn kzg_open_g1_test( - p: &DensePolynomial>, - omega_5: &Fp256, - polycom_open: &Randomness, DensePolynomial>>, - poly_ck: &Powers, - ) -> Proof { + fn kzg_open_g1_test( + p: &DensePolynomial, + omega_5: &E::Fr, + polycom_open: &Randomness>, + poly_ck: &Powers, + ) -> Proof { let rng = &mut ark_std::test_rng(); let (witness_polynomial, _random_witness_polynomial) = - KzgBls12_381::compute_witness_polynomial(p, omega_5.clone(), polycom_open).unwrap(); + KZG10::::compute_witness_polynomial(p, omega_5.clone(), polycom_open).unwrap(); let (temp0, _temp1) = KZG10::commit(poly_ck, &witness_polynomial, None, Some(rng)).unwrap(); - let poly_open: Proof = Proof { + Proof { w: temp0.0, random_v: None, - }; - return poly_open; + } } //compute KZG proof Q = g1_q = g^( (c(x) - c(w^i)) / (x - w^i) ) where x is secret, w^i is the point where we open, and c(X) is the committed polynomial - pub fn single_open_default( - c_poly: &DensePolynomial>, //c(X) - c_com_open: &Randomness, DensePolynomial>>, // - poly_ck: &Powers, + fn single_open_default( + c_poly: &DensePolynomial, //c(X) + c_com_open: &Randomness>, // + poly_ck: &Powers, i: usize, // degree: usize, - ) -> G1Affine { - let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(degree).unwrap(); + ) -> E::G1Affine { + let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(degree).unwrap(); let omega_i = input_domain.element(i); let c_poly_open = kzg_open_g1_test(&c_poly, &omega_i, &c_com_open, &poly_ck); - return c_poly_open.w; + c_poly_open.w } //KZG proof/opening at point y for c(X) = sum_i c_i X^i //(1)T_y(X) = sum_i t_i X^i //(2) t_{deg-1} = c_deg //(3) t_j = c_{j+1} + y*t_{j+1} - pub fn single_open_fast( - c_poly: &DensePolynomial>, //c(X) - poly_ck: &Powers, //SRS - i: usize, //y=w^i - degree: usize, //degree of c(X) - ) -> G1Affine { + fn single_open_fast( + c_poly: &DensePolynomial, //c(X) + poly_ck: &Powers, //SRS + i: usize, //y=w^i + degree: usize, //degree of c(X) + ) -> E::G1Affine { //computing opening point - let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(degree).unwrap(); + let input_domain: GeneralEvaluationDomain = EvaluationDomain::new(degree).unwrap(); let y = input_domain.element(i); //compute quotient @@ -292,24 +292,32 @@ pub mod tests { } //commit - let (t_com, _) = KzgBls12_381::commit(&poly_ck, &t_poly, None, None).unwrap(); - return t_com.0; + let (t_com, _) = KZG10::commit(&poly_ck, &t_poly, None, None).unwrap(); + t_com.0 } - pub fn test_single() { + #[test] + fn test_single() { + test_single_helper::(); + test_single_helper::(); + } + + fn test_single_helper() { + let mut rng = test_rng(); + // setting public parameters // current kzg setup should be changed with output from a setup ceremony let max_degree: usize = 100; let actual_degree: usize = 63; - let pp = caulk_single_setup(max_degree, actual_degree); + let pp = caulk_single_setup(max_degree, actual_degree, &mut rng); // Setting up test instance to run evaluate on. // test randomness for c_poly is same everytime. // test index equals 5 everytime // g_c = g^(c(x)) - let rng = &mut ark_std::test_rng(); - let c_poly = UniPoly381::rand(actual_degree, rng); - let (c_com, c_com_open) = KzgBls12_381::commit(&pp.poly_ck, &c_poly, None, None).unwrap(); + let rng = &mut test_rng(); + let c_poly = DensePolynomial::::rand(actual_degree, rng); + let (_c_com, c_com_open) = KZG10::::commit(&pp.poly_ck, &c_poly, None, None).unwrap(); let i: usize = 6; let q = single_open_default(&c_poly, &c_com_open, &pp.poly_ck, i, actual_degree); @@ -317,25 +325,44 @@ pub mod tests { assert_eq!(q, q2); } - pub fn test_dft(h: &Vec, p: usize) { - let c_dft = dft_g1(h, p); - let c_back = idft_g1(&c_dft, p); - assert_eq!(h, &c_back); - println!("DFT test passed"); + #[test] + fn test_dft() { + test_dft_helper::(); + test_dft_helper::(); } - pub fn test_commit() { + fn test_dft_helper() { + let mut rng = test_rng(); + for i in 2..6 { + let size = 1 << i; + let h: Vec = + (0..size).map(|_| E::G1Projective::rand(&mut rng)).collect(); + + let c_dft = dft_g1::(&h, i); + let c_back = idft_g1::(&c_dft, i); + assert_eq!(h, c_back); + } + } + + #[test] + fn test_commit() { + test_commit_helper::(); + test_commit_helper::(); + } + + pub fn test_commit_helper() { + let mut rng = test_rng(); + // current kzg setup should be changed with output from a setup ceremony let max_degree: usize = 100; let actual_degree: usize = 63; - let pp = caulk_single_setup(max_degree, actual_degree); + let pp = caulk_single_setup(max_degree, actual_degree, &mut rng); // Setting up test instance to run evaluate on. // test randomness for c_poly is same everytime. // g_c = g^(c(x)) - let rng = &mut ark_std::test_rng(); - let c_poly = UniPoly381::rand(actual_degree, rng); - let (c_com, c_com_open) = KzgBls12_381::commit(&pp.poly_ck, &c_poly, None, None).unwrap(); + let c_poly = DensePolynomial::::rand(actual_degree, &mut rng); + let (c_com, _c_com_open) = KZG10::::commit(&pp.poly_ck, &c_poly, None, None).unwrap(); let g_c1 = c_com.0; let g_c2 = commit_direct(&c_poly, &pp.poly_ck); @@ -345,20 +372,26 @@ pub mod tests { #[test] pub fn test_multi() { + test_multi_helper::(); + test_multi_helper::(); + } + + pub fn test_multi_helper() { + let mut rng = test_rng(); + // current kzg setup should be changed with output from a setup ceremony let p: usize = 9; let max_degree: usize = 1 << p + 1; let actual_degree: usize = (1 << p) - 1; - let pp = caulk_single_setup(max_degree, actual_degree); + let pp = caulk_single_setup(max_degree, actual_degree, &mut rng); // Setting up test instance to run evaluate on. // test randomness for c_poly is same everytime. // test index equals 5 everytime // g_c = g^(c(x)) - let rng = &mut ark_std::test_rng(); - let c_poly = UniPoly381::rand(actual_degree, rng); - let (c_com, c_com_open) = KzgBls12_381::commit(&pp.poly_ck, &c_poly, None, None).unwrap(); - let g_c = c_com.0; + let c_poly = DensePolynomial::::rand(actual_degree, &mut rng); + let (c_com, c_com_open) = KZG10::::commit(&pp.poly_ck, &c_poly, None, None).unwrap(); + let _g_c = c_com.0; let now = Instant::now(); let q = multiple_open_naive(&c_poly, &c_com_open, &pp.poly_ck, actual_degree); diff --git a/caulk_single_opening/src/pedersen.rs b/caulk_single_opening/src/pedersen.rs index 6d81218..cb1370c 100644 --- a/caulk_single_opening/src/pedersen.rs +++ b/caulk_single_opening/src/pedersen.rs @@ -3,77 +3,66 @@ This file includes a prover and verifier for demonstrating knowledge of an openi The protocol is informally described in Appendix A.2, Proof of Opening of a Pedersen Commitment */ -use ark_bls12_381::{Fr, FrParameters, G1Affine}; -use ark_ec::{AffineCurve, ProjectiveCurve}; -use ark_ff::{Fp256, PrimeField}; +use ark_ec::{AffineCurve, PairingEngine, ProjectiveCurve}; +use ark_ff::PrimeField; use ark_std::Zero; +use ark_std::{rand::RngCore, UniformRand}; -use crate::tools::{hash_caulk_single, random_field}; +use crate::tools::hash_caulk_single; // Structure of proof output by prove_pedersen -pub struct ProofPed { - pub g1_r: G1Affine, - pub t1: Fp256, - pub t2: Fp256, +pub struct ProofPed { + pub g1_r: E::G1Affine, + pub t1: E::Fr, + pub t2: E::Fr, } // prove knowledge of a and b such that cm = g^a h^b -pub fn prove_pedersen( - g1: &G1Affine, - h1: &G1Affine, - hash_input: &mut Fr, - cm: &G1Affine, - a: &Fp256, - b: &Fp256, -) -> ProofPed { +pub fn prove_pedersen( + g1: &E::G1Affine, + h1: &E::G1Affine, + hash_input: &mut E::Fr, + cm: &E::G1Affine, + a: &E::Fr, + b: &E::Fr, + rng: &mut R, +) -> ProofPed { // R = g^s1 h^s2 - let s1: Fr = random_field::(); - let s2: Fr = random_field::(); + let s1 = E::Fr::rand(rng); + let s2 = E::Fr::rand(rng); let g1_r = (g1.mul(s1.into_repr()) + h1.mul(s2.into_repr())).into_affine(); // c = Hash(cm, R) - - let c = hash_caulk_single::( - hash_input.clone(), - Some(&[cm.clone(), g1_r].to_vec()), - None, - None, - ); - *hash_input = c.clone(); + let c = hash_caulk_single::(hash_input, Some(&[*cm, g1_r]), None, None); + *hash_input = c; let t1 = s1 + c * a; let t2 = s2 + c * b; - let proof = ProofPed { - g1_r: g1_r, - t1: t1, - t2: t2, - }; - - return proof; + ProofPed { g1_r, t1, t2 } } // Verify that prover knows a and b such that cm = g^a h^b -pub fn verify_pedersen( - g1: &G1Affine, - h1: &G1Affine, - hash_input: &mut Fr, - cm: &G1Affine, - proof: &ProofPed, +pub fn verify_pedersen( + g1: &E::G1Affine, + h1: &E::G1Affine, + hash_input: &mut E::Fr, + cm: &E::G1Affine, + proof: &ProofPed, ) -> bool { // compute c = Hash(cm, R) - let c = hash_caulk_single::( - hash_input.clone(), - Some(&[cm.clone(), proof.g1_r.clone()].to_vec()), + let c = hash_caulk_single::( + hash_input, + Some(&[*cm, proof.g1_r]), None, None, ); - *hash_input = c.clone(); + *hash_input = c; // check that R g^(-t1) h^(-t2) cm^(c) = 1 let check = proof.g1_r.into_projective() + g1.mul(-proof.t1) + h1.mul(-proof.t2) + cm.mul(c); - return check.is_zero(); + check.is_zero() } diff --git a/caulk_single_opening/src/tools.rs b/caulk_single_opening/src/tools.rs index e04ce55..092e861 100644 --- a/caulk_single_opening/src/tools.rs +++ b/caulk_single_opening/src/tools.rs @@ -7,24 +7,17 @@ This file includes backend tools: (5) random_field is for generating random field elements */ -use ark_bls12_381::{Bls12_381, Fr, G1Affine, G1Projective, G2Affine}; +use ark_ec::{msm::VariableBaseMSM, AffineCurve, PairingEngine, ProjectiveCurve}; use ark_ff::{Field, PrimeField}; use ark_poly::{univariate::DensePolynomial, Polynomial, UVPolynomial}; +use ark_poly_commit::kzg10::*; use ark_serialize::CanonicalSerialize; use ark_std::{One, Zero}; - use blake2s_simd::Params; -use rand::{thread_rng, Rng, SeedableRng}; +use rand::{RngCore, SeedableRng}; use rand_chacha::ChaChaRng; use std::{error::Error, io, str::FromStr}; -use ark_ec::{msm::VariableBaseMSM, AffineCurve, PairingEngine, ProjectiveCurve}; -use ark_poly::univariate::DensePolynomial as DensePoly; -use ark_poly_commit::kzg10::*; - -pub type UniPoly381 = DensePoly<::Fr>; -pub type KzgBls12_381 = KZG10; - // Function for reading inputs from the command line. pub fn read_line() -> T where @@ -42,11 +35,10 @@ where // //copied from arkworks -fn convert_to_bigints(p: &Vec) -> Vec { - let coeffs = ark_std::cfg_iter!(p) +fn convert_to_bigints(p: &[F]) -> Vec { + ark_std::cfg_iter!(p) .map(|s| s.into_repr()) - .collect::>(); - coeffs + .collect::>() } ///////////////////////////////////////////////////////////////////// @@ -58,48 +50,47 @@ KZG.Open( srs_KZG, f(X), deg, (alpha1, alpha2, ..., alphan) ) returns ([f(alpha1), ..., f(alphan)], pi) Algorithm described in Section 4.6.1, Multiple Openings */ -pub fn kzg_open_g1( - poly_ck: &Powers, - poly: &DensePolynomial, +pub fn kzg_open_g1( + poly_ck: &Powers, + poly: &DensePolynomial, max_deg: Option<&usize>, - points: Vec<&Fr>, -) -> (Vec, G1Affine) { + points: &[E::Fr], +) -> (Vec, E::G1Affine) { let mut evals = Vec::new(); let mut proofs = Vec::new(); - for i in 0..points.len() { - let (eval, pi) = kzg_open_g1_single(poly_ck, poly, max_deg, points[i]); + for p in points.iter() { + let (eval, pi) = kzg_open_g1_single(poly_ck, poly, max_deg, p); evals.push(eval); proofs.push(pi); } - let mut res: G1Projective = G1Projective::zero(); //default value + let mut res: E::G1Projective = E::G1Projective::zero(); //default value for j in 0..points.len() { - let w_j = points[j].clone(); + let w_j = points[j]; //1. Computing coefficient [1/prod] - let mut prod = Fr::one(); - for k in 0..points.len() { - let w_k = points[k]; + let mut prod = E::Fr::one(); + for (k, p) in points.iter().enumerate() { if k != j { - prod = prod * (w_j - w_k); + prod *= w_j - p; } } //2. Summation let q_add = proofs[j].mul(prod.inverse().unwrap()); //[1/prod]Q_{j} - res = res + q_add; + res += q_add; } - return (evals, res.into_affine()); + (evals, res.into_affine()) } //KZG.Open( srs_KZG, f(X), deg, alpha ) returns (f(alpha), pi) -fn kzg_open_g1_single( - poly_ck: &Powers, - poly: &DensePolynomial, +fn kzg_open_g1_single( + poly_ck: &Powers, + poly: &DensePolynomial, max_deg: Option<&usize>, - point: &Fr, -) -> (Fr, G1Affine) { - let eval = poly.evaluate(&point); + point: &E::Fr, +) -> (E::Fr, E::G1Affine) { + let eval = poly.evaluate(point); let global_max_deg = poly_ck.powers_of_g.len(); @@ -109,45 +100,45 @@ fn kzg_open_g1_single( } else { d += max_deg.unwrap(); } - let divisor = DensePolynomial::from_coefficients_vec(vec![-point.clone(), Fr::one()]); + let divisor = DensePolynomial::from_coefficients_vec(vec![-*point, E::Fr::one()]); let witness_polynomial = poly / &divisor; assert!(poly_ck.powers_of_g[(global_max_deg - d)..].len() >= witness_polynomial.len()); let proof = VariableBaseMSM::multi_scalar_mul( &poly_ck.powers_of_g[(global_max_deg - d)..], - &convert_to_bigints(&witness_polynomial.coeffs).as_slice(), + convert_to_bigints(&witness_polynomial.coeffs).as_slice(), ) .into_affine(); - return (eval, proof); + (eval, proof) } /* // KZG.Verify( srs_KZG, F, deg, (alpha1, alpha2, ..., alphan), (v1, ..., vn), pi ) Algorithm described in Section 4.6.1, Multiple Openings */ -pub fn kzg_verify_g1( +pub fn kzg_verify_g1( //Verify that @c_com is a commitment to C(X) such that C(x)=z - powers_of_g1: &Vec, // generator of G1 - powers_of_g2: &Vec, // [1]_2, [x]_2, [x^2]_2, ... - c_com: G1Affine, //commitment + powers_of_g1: &[E::G1Affine], // generator of G1 + powers_of_g2: &[E::G2Affine], // [1]_2, [x]_2, [x^2]_2, ... + c_com: &E::G1Affine, //commitment max_deg: Option<&usize>, // max degree - points: Vec, // x such that eval = C(x) - evals: Vec, //evaluation - pi: G1Affine, //proof + points: &[E::Fr], // x such that eval = C(x) + evals: &[E::Fr], //evaluation + pi: &E::G1Affine, //proof ) -> bool { // Interpolation set // tau_i(X) = lagrange_tau[i] = polynomial equal to 0 at point[j] for j!= i and 1 at points[i] - let mut lagrange_tau = DensePolynomial::from_coefficients_slice(&[Fr::zero()]); + let mut lagrange_tau = DensePolynomial::from_coefficients_slice(&[E::Fr::zero()]); + // TODO: improve the efficiency here to linear for i in 0..points.len() { - let mut temp: UniPoly381 = DensePolynomial::from_coefficients_slice(&[Fr::one()]); - for j in 0..points.len() { + let mut temp = DensePolynomial::from_coefficients_slice(&[E::Fr::one()]); + for (j, &p) in points.iter().enumerate() { if i != j { - temp = - &temp * (&DensePolynomial::from_coefficients_slice(&[-points[j], Fr::one()])); + temp = &temp * (&DensePolynomial::from_coefficients_slice(&[-p, E::Fr::one()])); } } - let lagrange_scalar = temp.evaluate(&points[i]).inverse().unwrap() * &evals[i]; + let lagrange_scalar = temp.evaluate(&points[i]).inverse().unwrap() * evals[i]; lagrange_tau = lagrange_tau + &temp * (&DensePolynomial::from_coefficients_slice(&[lagrange_scalar])); } @@ -165,9 +156,9 @@ pub fn kzg_verify_g1( // vanishing polynomial // z_tau[i] = polynomial equal to 0 at point[j] - let mut z_tau = DensePolynomial::from_coefficients_slice(&[Fr::one()]); - for i in 0..points.len() { - z_tau = &z_tau * (&DensePolynomial::from_coefficients_slice(&[-points[i], Fr::one()])); + let mut z_tau = DensePolynomial::from_coefficients_slice(&[E::Fr::one()]); + for &p in points.iter() { + z_tau = &z_tau * (&DensePolynomial::from_coefficients_slice(&[-p, E::Fr::one()])); } // commit to z_tau(X) in g2 @@ -189,13 +180,18 @@ pub fn kzg_verify_g1( d += max_deg.unwrap(); } - let pairing1 = Bls12_381::pairing( - c_com.into_projective() - g1_tau, - powers_of_g2[global_max_deg - d], - ); - let pairing2 = Bls12_381::pairing(pi, g2_z_tau); + let pairing_inputs = vec![ + ( + E::G1Prepared::from((c_com.into_projective() - g1_tau).into_affine()), + E::G2Prepared::from(powers_of_g2[global_max_deg - d]), + ), + ( + E::G1Prepared::from(*pi), + E::G2Prepared::from(g2_z_tau.into_affine()), + ), + ]; - return pairing1 == pairing2; + E::product_of_pairings(pairing_inputs.iter()).is_one() } ///////////////////////////////////////////////////////////////////// @@ -213,20 +209,15 @@ fn rng_from_message(personalization: &[u8], message: &[u8]) -> ChaChaRng { .finalize(); let mut seed = [0u8; 32]; seed.copy_from_slice(hash.as_bytes()); - let rng = ChaChaRng::from_seed(seed); - rng + ChaChaRng::from_seed(seed) } +// statistical uniform with bias < 2^-128 for field size < 384 bits fn hash_to_field(personalization: &[u8], message: &[u8]) -> F { let mut rng = rng_from_message(personalization, message); - loop { - let bytes: Vec = (0..F::zero().serialized_size()) - .map(|_| rng.gen()) - .collect(); - if let Some(p) = F::from_random_bytes(&bytes) { - return p; - } - } + let mut buf = [0u8; 64]; + rng.fill_bytes(&mut buf); + F::from_le_bytes_mod_order(buf.as_ref()) } /* hash function that takes as input: @@ -237,98 +228,31 @@ fn hash_to_field(personalization: &[u8], message: &[u8]) -> F { It returns a field element. */ -pub fn hash_caulk_single( - state: Fr, - g1_elements: Option<&Vec>, - g2_elements: Option<&Vec>, - field_elements: Option<&Vec>, -) -> Fr { +pub fn hash_caulk_single( + state: &E::Fr, + g1_elements: Option<&[E::G1Affine]>, + g2_elements: Option<&[E::G2Affine]>, + field_elements: Option<&[E::Fr]>, +) -> E::Fr { // PERSONALIZATION distinguishes this hash from other hashes that may be in the system const PERSONALIZATION: &[u8] = b"CAULK1"; - /////////////////////////////////////////////////////////// - // Handling cases where no g1_elements or no g1_elements or no field elements are input - /////////////////////////////////////////////////////////// - let g1_elements_len: usize; - let g2_elements_len: usize; - let field_elements_len: usize; + let mut hash_input = vec![]; + state.serialize(&mut hash_input).ok(); - if g1_elements == None { - g1_elements_len = 0; - } else { - g1_elements_len = g1_elements.unwrap().len(); + match g1_elements { + None => (), + Some(p) => p.iter().for_each(|x| x.serialize(&mut hash_input).unwrap()), } - - if g2_elements == None { - g2_elements_len = 0; - } else { - g2_elements_len = g2_elements.unwrap().len(); + match g2_elements { + None => (), + Some(p) => p.iter().for_each(|x| x.serialize(&mut hash_input).unwrap()), } - - if field_elements == None { - field_elements_len = 0; - } else { - field_elements_len = field_elements.unwrap().len(); - } - - /////////////////////////////////////////////////////////// - // Transform inputs into bytes - /////////////////////////////////////////////////////////// - let mut state_bytes = vec![]; - state.serialize(&mut state_bytes).ok(); - - let mut g1_elements_bytes = Vec::new(); - for i in 0..g1_elements_len { - let mut temp = vec![]; - g1_elements.unwrap()[i].serialize(&mut temp).ok(); - g1_elements_bytes.append(&mut temp.clone()); - } - - let mut g2_elements_bytes = Vec::new(); - for i in 0..g2_elements_len { - let mut temp = vec![]; - g2_elements.unwrap()[i].serialize(&mut temp).ok(); - g2_elements_bytes.append(&mut temp.clone()); - } - - let mut field_elements_bytes = Vec::new(); - for i in 0..field_elements_len { - let mut temp = vec![]; - field_elements.unwrap()[i].serialize(&mut temp).ok(); - field_elements_bytes.append(&mut temp.clone()); - } - - // Transform bytes into vector of bytes of the form expected by hash_to_field - let mut hash_input: Vec = state_bytes.clone(); - for i in 0..g1_elements_bytes.len() { - hash_input = [&hash_input as &[_], &[g1_elements_bytes[i]]].concat(); - } - - for i in 0..g2_elements_bytes.len() { - hash_input = [&hash_input as &[_], &[g2_elements_bytes[i]]].concat(); - } - - for i in 0..field_elements_bytes.len() { - hash_input = [&hash_input as &[_], &[field_elements_bytes[i]]].concat(); + match field_elements { + None => (), + Some(p) => p.iter().for_each(|x| x.serialize(&mut hash_input).unwrap()), } // hash_to_field - return hash_to_field::(PERSONALIZATION, &hash_input); -} - -///////////////////////////////////////////////////////////////////// -// Random field element -///////////////////////////////////////////////////////////////////// - -// generating a random field element -pub fn random_field() -> F { - let mut rng = thread_rng(); - loop { - let bytes: Vec = (0..F::zero().serialized_size()) - .map(|_| rng.gen()) - .collect(); - if let Some(p) = F::from_random_bytes(&bytes) { - return p; - } - } + hash_to_field::(PERSONALIZATION, &hash_input) }