polish-single-opening

This commit is contained in:
zhenfei
2022-05-24 18:40:35 -04:00
parent 9cca25443c
commit b89d72aa73
9 changed files with 578 additions and 608 deletions

View File

@@ -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"
]

View File

@@ -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<Bls12_381, UniPoly381>;
type UniPoly381 = DensePolynomial<Fr>;
type KzgBls12_381 = KZG10<Bls12_381, UniPoly381>;
#[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::<Fr>();
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 {:?} = {:?}",

View File

@@ -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<E: PairingEngine> {
pub g2_z: E::G2Affine,
pub g1_T: E::G1Affine,
pub g2_S: E::G2Affine,
pub pi_ped: ProofPed<E>,
pub pi_unity: CaulkProofUnity<E>,
}
//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<E: PairingEngine, R: RngCore>(
pp: &PublicParameters<E>,
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<E> {
// provers blinders for zero-knowledge
let a: Fr = random_field::<Fr>();
let s: Fr = random_field::<Fr>();
let a = E::Fr::rand(rng);
let s = E::Fr::rand(rng);
let domain_H: GeneralEvaluationDomain<Fr> =
let domain_H: GeneralEvaluationDomain<E::Fr> =
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>(
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>(
&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::<E, R>(&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::<Fr>(
hash_input,
hash_input = hash_caulk_single::<E>(
&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<E: PairingEngine>(
vk: &VerifierPublicParameters<E>,
g1_C: &E::G1Affine,
cm: &E::G1Affine,
proof: &CaulkProof<E>,
) -> 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_bls12_381::Parameters>,
ark_ec::bls12::G2Prepared<ark_bls12_381::Parameters>,
)> = 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>(
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>(
&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::<E>(&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::<Fr>(
hash_input,
hash_input = hash_caulk_single::<E>(
&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
}

View File

@@ -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<ark_bls12_381::Parameters>>,
pub poly_ck_d: G1Affine,
pub poly_ck_pen: G1Affine,
pub lagrange_polynomials_Vn: Vec<UniPoly381>,
pub poly_prod: UniPoly381,
pub poly_vk: VerifierKey<Bls12<ark_bls12_381::Parameters>>,
pub ped_g: G1Affine,
pub ped_h: G1Affine,
pub struct PublicParameters<E: PairingEngine> {
pub poly_ck: Powers<'static, E>,
pub poly_ck_d: E::G1Affine,
pub poly_ck_pen: E::G1Affine,
pub lagrange_polynomials_Vn: Vec<DensePolynomial<E::Fr>>,
pub poly_prod: DensePolynomial<E::Fr>,
pub poly_vk: VerifierKey<E>,
pub ped_g: E::G1Affine,
pub ped_h: E::G1Affine,
pub domain_H_size: usize,
pub logN: usize,
pub domain_Vn: GeneralEvaluationDomain<Fr>,
pub domain_Vn: GeneralEvaluationDomain<E::Fr>,
pub domain_Vn_size: usize,
pub verifier_pp: VerifierPublicParameters,
pub verifier_pp: VerifierPublicParameters<E>,
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<Fr>,
pub poly_prod: UniPoly381,
pub poly_vk: VerifierKey<Bls12<ark_bls12_381::Parameters>>,
pub ped_g: G1Affine,
pub g1_x: G1Affine,
pub ped_h: G1Affine,
pub struct VerifierPublicParameters<E: PairingEngine> {
pub poly_ck_pen: E::G1Affine,
pub lagrange_scalars_Vn: Vec<E::Fr>,
pub poly_prod: DensePolynomial<E::Fr>,
pub poly_vk: VerifierKey<E>,
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<Fr>,
pub domain_Vn: GeneralEvaluationDomain<E::Fr>,
pub domain_Vn_size: usize,
pub powers_of_g2: Vec<G2Affine>,
pub powers_of_g2: Vec<E::G2Affine>,
}
// Reduces full srs down to smaller srs for smaller polynomials
// Copied from arkworks library (where same function is private)
fn trim<E: PairingEngine, P: UVPolynomial<E::Fr>>(
srs: UniversalParams<E>,
srs: &UniversalParams<E>,
mut supported_degree: usize,
) -> (Powers<'static, E>, VerifierKey<E>) {
if supported_degree == 1 {
@@ -86,18 +83,21 @@ fn trim<E: PairingEngine, P: UVPolynomial<E::Fr>>(
// 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<E: PairingEngine, R: RngCore>(
max_degree: usize,
actual_degree: usize,
rng: &mut R,
) -> PublicParameters<E> {
let total_time = start_timer!(|| "total srs setup");
// domain where vector commitment is defined
let domain_H: GeneralEvaluationDomain<Fr> =
let domain_H: GeneralEvaluationDomain<E::Fr> =
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<Fr> = GeneralEvaluationDomain::new(6 + logN).unwrap();
let domain_Vn: GeneralEvaluationDomain<E::Fr> = 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::<E, DensePolynomial<E::Fr>>::setup(max(max_degree, poly_ck_size), true, rng)
.unwrap();
end_timer!(powers_time);
// trim down to size.
let (poly_ck, poly_vk) = trim::<Bls12_381, UniPoly381>(srs.clone(), poly_ck_size.clone());
let (poly_ck, poly_vk) = trim::<E, DensePolynomial<E::Fr>>(&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<UniPoly381> = Vec::new();
let mut lagrange_polynomials_Vn: Vec<DensePolynomial<E::Fr>> = 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<Fr> = Vec::new();
let mut lagrange_scalars_Vn: Vec<E::Fr> = Vec::new();
for i in 0..domain_Vn.size() {
let evals: Vec<Fp256<FrParameters>> = cfg_into_iter!(0..domain_Vn.size())
.map(|k| if k == i { Fr::one() } else { Fr::zero() })
let evals: Vec<E::Fr> = 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<FrParameters> = 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<G2Affine> = Vec::new();
for _ in 0..3.clone() {
powers_of_g2.push(temp.clone());
let mut powers_of_g2: Vec<E::G2Affine> = 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
}

View File

@@ -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<ark_bls12_381::Parameters>>,
pub gxd: G1Affine,
pub gxpen: G1Affine,
pub lagrange_polynomials_Vn: Vec<UniPoly381>,
pub poly_prod: UniPoly381,
pub struct PublicParametersUnity<E: PairingEngine> {
pub poly_ck: Powers<'static, E>,
pub gxd: E::G1Affine,
pub gxpen: E::G1Affine,
pub lagrange_polynomials_Vn: Vec<DensePolynomial<E::Fr>>,
pub poly_prod: DensePolynomial<E::Fr>,
pub logN: usize,
pub domain_Vn: GeneralEvaluationDomain<Fr>,
pub domain_Vn: GeneralEvaluationDomain<E::Fr>,
}
// verifier parameters structure for caulk_single_unity_verify
#[allow(non_snake_case)]
pub struct VerifierPublicParametersUnity {
pub poly_vk: VerifierKey<Bls12<ark_bls12_381::Parameters>>,
pub gxpen: G1Affine,
pub g1: G1Affine,
pub g1_x: G1Affine,
pub lagrange_scalars_Vn: Vec<Fr>,
pub poly_prod: UniPoly381,
pub struct VerifierPublicParametersUnity<E: PairingEngine> {
pub poly_vk: VerifierKey<E>,
pub gxpen: E::G1Affine,
pub g1: E::G1Affine,
pub g1_x: E::G1Affine,
pub lagrange_scalars_Vn: Vec<E::Fr>,
pub poly_prod: DensePolynomial<E::Fr>,
pub logN: usize,
pub domain_Vn: GeneralEvaluationDomain<Fr>,
pub powers_of_g2: Vec<G2Affine>,
pub domain_Vn: GeneralEvaluationDomain<E::Fr>,
pub powers_of_g2: Vec<E::G2Affine>,
}
// 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<FrParameters>,
pub v2: Fp256<FrParameters>,
pub pi1: G1Affine,
pub pi2: G1Affine,
// pub g1_q3: G1Affine,
pub struct CaulkProofUnity<E: PairingEngine> {
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<FrParameters>,
b: Fp256<FrParameters>,
) -> CaulkProofUnity {
pub fn caulk_single_unity_prove<E: PairingEngine, R: RngCore>(
pp: &PublicParametersUnity<E>,
hash_input: &mut E::Fr,
g2_z: &E::G2Affine,
a: &E::Fr,
b: &E::Fr,
rng: &mut R,
) -> CaulkProofUnity<E> {
// 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<FrParameters> = random_field::<Fr>();
let r1: Fp256<FrParameters> = random_field::<Fr>();
let r2: Fp256<FrParameters> = random_field::<Fr>();
let r3: Fp256<FrParameters> = random_field::<Fr>();
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<E::Fr> = 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<Fp256<FrParameters>> = Vec::new();
let mut a_div_b = *a * ((*b).inverse()).unwrap();
let mut vec_a_div_b: Vec<E::Fr> = 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<Fp256<FrParameters>> = cfg_into_iter!(0..pp.domain_Vn.size())
let f_evals: Vec<E::Fr> = 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::<Fr>(
hash_input.clone(),
Some(&[g1_F, g1_H].to_vec()),
Some(&[g2_z].to_vec()),
None,
);
let alpha = hash_caulk_single::<E>(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<E: PairingEngine>(
vk: &VerifierPublicParametersUnity<E>,
hash_input: &mut E::Fr,
g2_z: &E::G2Affine,
proof: &CaulkProofUnity<E>,
) -> 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::<Fr>(
hash_input.clone(),
Some(&[proof.g1_F, proof.g1_H].to_vec()),
Some(&[g2_z.clone()].to_vec()),
let alpha = hash_caulk_single::<E>(
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::<E>(
[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
}

View File

@@ -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};

View File

@@ -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<Fp256<FrParameters>>, //c(X) degree up to d<2^p , i.e. c_poly has at most d+1 coeffs non-zero
poly_ck: &Powers<Bls12_381>, //SRS
pub fn compute_h<E: PairingEngine>(
c_poly: &DensePolynomial<E::Fr>, //c(X) degree up to d<2^p , i.e. c_poly has at most d+1 coeffs non-zero
poly_ck: &Powers<E>, //SRS
p: usize,
) -> Vec<G1Projective> {
) -> Vec<E::G1Projective> {
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::<E>(&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::<E>(&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::<E>(&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<G1Projective>, p: usize) -> Vec<G1Projective> {
pub fn dft_g1<E: PairingEngine>(h: &[E::G1Projective], p: usize) -> Vec<E::G1Projective> {
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<Fr> = EvaluationDomain::new(dom_size).unwrap();
let input_domain: GeneralEvaluationDomain<E::Fr> = 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<Fr>, p: usize) -> Vec<Fr> {
pub fn dft_opt<E: PairingEngine>(h: &[E::Fr], p: usize) -> Vec<E::Fr> {
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<Fr> = EvaluationDomain::new(dom_size).unwrap();
let input_domain: GeneralEvaluationDomain<E::Fr> = 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<Fp256<FrParameters>>, //c(X)
poly_ck: &Powers<Bls12_381>, //SRS
pub fn multiple_open<E: PairingEngine>(
c_poly: &DensePolynomial<E::Fr>, //c(X)
poly_ck: &Powers<E>, //SRS
p: usize,
) -> Vec<G1Affine> {
) -> Vec<E::G1Affine> {
let degree = c_poly.coeffs.len() - 1;
let input_domain: GeneralEvaluationDomain<Fr> = EvaluationDomain::new(degree).unwrap();
let input_domain: GeneralEvaluationDomain<E::Fr> = 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::<E>(&h2, p);
//println!("Q2 computed in {:?}", now.elapsed());
//assert_eq!(q,q2);
let mut res: Vec<G1Affine> = vec![];
for i in 0..dom_size {
res.push(q2[i].into_affine());
let mut res: Vec<E::G1Affine> = 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<G1Projective>, p: usize) -> Vec<G1Projective> {
pub fn idft_g1<E: PairingEngine>(h: &[E::G1Projective], p: usize) -> Vec<E::G1Projective> {
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<Fr> = EvaluationDomain::new(dom_size).unwrap();
let input_domain: GeneralEvaluationDomain<E::Fr> = 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<Fp256<FrParameters>>, //c(X)
poly_ck: &Powers<Bls12_381>, //SRS
) -> G1Affine {
/// Various functions that are used for testing
fn commit_direct<E: PairingEngine>(
c_poly: &DensePolynomial<E::Fr>, //c(X)
poly_ck: &Powers<E>, //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<Fp256<FrParameters>>,
c_com_open: &Randomness<Fp256<FrParameters>, DensePolynomial<Fp256<FrParameters>>>,
poly_ck: &Powers<Bls12_381>,
fn multiple_open_naive<E: PairingEngine>(
c_poly: &DensePolynomial<E::Fr>,
c_com_open: &Randomness<E::Fr, DensePolynomial<E::Fr>>,
poly_ck: &Powers<E>,
degree: usize,
) -> Vec<G1Affine> {
let input_domain: GeneralEvaluationDomain<Fr> = EvaluationDomain::new(degree).unwrap();
let mut res: Vec<G1Affine> = vec![];
) -> Vec<E::G1Affine> {
let input_domain: GeneralEvaluationDomain<E::Fr> = EvaluationDomain::new(degree).unwrap();
let mut res: Vec<E::G1Affine> = 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::<E>(&c_poly, &omega_i, &c_com_open, &poly_ck).w);
}
return res;
res
}
////////////////////////////////////////////////
pub fn kzg_open_g1_test(
p: &DensePolynomial<Fp256<FrParameters>>,
omega_5: &Fp256<FrParameters>,
polycom_open: &Randomness<Fp256<FrParameters>, DensePolynomial<Fp256<FrParameters>>>,
poly_ck: &Powers<Bls12_381>,
) -> Proof<Bls12_381> {
fn kzg_open_g1_test<E: PairingEngine>(
p: &DensePolynomial<E::Fr>,
omega_5: &E::Fr,
polycom_open: &Randomness<E::Fr, DensePolynomial<E::Fr>>,
poly_ck: &Powers<E>,
) -> Proof<E> {
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::<E, _>::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<Bls12_381> = 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<Fp256<FrParameters>>, //c(X)
c_com_open: &Randomness<Fp256<FrParameters>, DensePolynomial<Fp256<FrParameters>>>, //
poly_ck: &Powers<Bls12_381>,
fn single_open_default<E: PairingEngine>(
c_poly: &DensePolynomial<E::Fr>, //c(X)
c_com_open: &Randomness<E::Fr, DensePolynomial<E::Fr>>, //
poly_ck: &Powers<E>,
i: usize, //
degree: usize,
) -> G1Affine {
let input_domain: GeneralEvaluationDomain<Fr> = EvaluationDomain::new(degree).unwrap();
) -> E::G1Affine {
let input_domain: GeneralEvaluationDomain<E::Fr> = 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<Fp256<FrParameters>>, //c(X)
poly_ck: &Powers<Bls12_381>, //SRS
i: usize, //y=w^i
degree: usize, //degree of c(X)
) -> G1Affine {
fn single_open_fast<E: PairingEngine>(
c_poly: &DensePolynomial<E::Fr>, //c(X)
poly_ck: &Powers<E>, //SRS
i: usize, //y=w^i
degree: usize, //degree of c(X)
) -> E::G1Affine {
//computing opening point
let input_domain: GeneralEvaluationDomain<Fr> = EvaluationDomain::new(degree).unwrap();
let input_domain: GeneralEvaluationDomain<E::Fr> = 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::<Bls12_381>();
test_single_helper::<Bls12_377>();
}
fn test_single_helper<E: PairingEngine>() {
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::<E::Fr>::rand(actual_degree, rng);
let (_c_com, c_com_open) = KZG10::<E, _>::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<G1Projective>, 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::<Bls12_381>();
test_dft_helper::<Bls12_377>();
}
pub fn test_commit() {
fn test_dft_helper<E: PairingEngine>() {
let mut rng = test_rng();
for i in 2..6 {
let size = 1 << i;
let h: Vec<E::G1Projective> =
(0..size).map(|_| E::G1Projective::rand(&mut rng)).collect();
let c_dft = dft_g1::<E>(&h, i);
let c_back = idft_g1::<E>(&c_dft, i);
assert_eq!(h, c_back);
}
}
#[test]
fn test_commit() {
test_commit_helper::<Bls12_381>();
test_commit_helper::<Bls12_377>();
}
pub fn test_commit_helper<E: PairingEngine>() {
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::<E::Fr>::rand(actual_degree, &mut rng);
let (c_com, _c_com_open) = KZG10::<E, _>::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::<Bls12_381>();
test_multi_helper::<Bls12_377>();
}
pub fn test_multi_helper<E: PairingEngine>() {
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::<E::Fr>::rand(actual_degree, &mut rng);
let (c_com, c_com_open) = KZG10::<E, _>::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);

View File

@@ -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<FrParameters>,
pub t2: Fp256<FrParameters>,
pub struct ProofPed<E: PairingEngine> {
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<FrParameters>,
b: &Fp256<FrParameters>,
) -> ProofPed {
pub fn prove_pedersen<E: PairingEngine, R: RngCore>(
g1: &E::G1Affine,
h1: &E::G1Affine,
hash_input: &mut E::Fr,
cm: &E::G1Affine,
a: &E::Fr,
b: &E::Fr,
rng: &mut R,
) -> ProofPed<E> {
// R = g^s1 h^s2
let s1: Fr = random_field::<Fr>();
let s2: Fr = random_field::<Fr>();
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::<Fr>(
hash_input.clone(),
Some(&[cm.clone(), g1_r].to_vec()),
None,
None,
);
*hash_input = c.clone();
let c = hash_caulk_single::<E>(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<E: PairingEngine>(
g1: &E::G1Affine,
h1: &E::G1Affine,
hash_input: &mut E::Fr,
cm: &E::G1Affine,
proof: &ProofPed<E>,
) -> bool {
// compute c = Hash(cm, R)
let c = hash_caulk_single::<Fr>(
hash_input.clone(),
Some(&[cm.clone(), proof.g1_r.clone()].to_vec()),
let c = hash_caulk_single::<E>(
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()
}

View File

@@ -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<<Bls12_381 as PairingEngine>::Fr>;
pub type KzgBls12_381 = KZG10<Bls12_381, UniPoly381>;
// Function for reading inputs from the command line.
pub fn read_line<T: FromStr>() -> T
where
@@ -42,11 +35,10 @@ where
//
//copied from arkworks
fn convert_to_bigints<F: PrimeField>(p: &Vec<F>) -> Vec<F::BigInt> {
let coeffs = ark_std::cfg_iter!(p)
fn convert_to_bigints<F: PrimeField>(p: &[F]) -> Vec<F::BigInt> {
ark_std::cfg_iter!(p)
.map(|s| s.into_repr())
.collect::<Vec<_>>();
coeffs
.collect::<Vec<_>>()
}
/////////////////////////////////////////////////////////////////////
@@ -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<Bls12_381>,
poly: &DensePolynomial<Fr>,
pub fn kzg_open_g1<E: PairingEngine>(
poly_ck: &Powers<E>,
poly: &DensePolynomial<E::Fr>,
max_deg: Option<&usize>,
points: Vec<&Fr>,
) -> (Vec<Fr>, G1Affine) {
points: &[E::Fr],
) -> (Vec<E::Fr>, 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<Bls12_381>,
poly: &DensePolynomial<Fr>,
fn kzg_open_g1_single<E: PairingEngine>(
poly_ck: &Powers<E>,
poly: &DensePolynomial<E::Fr>,
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<E: PairingEngine>(
//Verify that @c_com is a commitment to C(X) such that C(x)=z
powers_of_g1: &Vec<G1Affine>, // generator of G1
powers_of_g2: &Vec<G2Affine>, // [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<Fr>, // x such that eval = C(x)
evals: Vec<Fr>, //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<F: PrimeField>(personalization: &[u8], message: &[u8]) -> F {
let mut rng = rng_from_message(personalization, message);
loop {
let bytes: Vec<u8> = (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<F: PrimeField>(personalization: &[u8], message: &[u8]) -> F {
It returns a field element.
*/
pub fn hash_caulk_single<F: PrimeField>(
state: Fr,
g1_elements: Option<&Vec<G1Affine>>,
g2_elements: Option<&Vec<G2Affine>>,
field_elements: Option<&Vec<Fr>>,
) -> Fr {
pub fn hash_caulk_single<E: PairingEngine>(
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<u8> = 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::<Fr>(PERSONALIZATION, &hash_input);
}
/////////////////////////////////////////////////////////////////////
// Random field element
/////////////////////////////////////////////////////////////////////
// generating a random field element
pub fn random_field<F: PrimeField>() -> F {
let mut rng = thread_rng();
loop {
let bytes: Vec<u8> = (0..F::zero().serialized_size())
.map(|_| rng.gen())
.collect();
if let Some(p) = F::from_random_bytes(&bytes) {
return p;
}
}
hash_to_field::<E::Fr>(PERSONALIZATION, &hash_input)
}