deferring pairing and use pairing-products as final stage

This commit is contained in:
zhenfei
2022-06-02 22:38:19 -04:00
parent a5369c4e11
commit 0a1ade3be3
5 changed files with 251 additions and 87 deletions

View File

@@ -121,7 +121,7 @@ fn main() {
let now = Instant::now();
for _ in 0..number_of_openings {
verify_lookup_proof(&table.c_com, &phi_com, &proof, &unity_proof, &pp);
verify_lookup_proof(&table.c_com, &phi_com, &proof, &unity_proof, &pp, &mut rng);
}
println!(
"Time to verify {} times {} multi-openings of table size {:?} = {:?} ",
@@ -132,7 +132,7 @@ fn main() {
);
assert!(
verify_lookup_proof(&table.c_com, &phi_com, &proof, &unity_proof, &pp),
verify_lookup_proof(&table.c_com, &phi_com, &proof, &unity_proof, &pp, &mut rng),
"Result does not verify"
);
}

View File

@@ -148,7 +148,6 @@ where
let input_domain: GeneralEvaluationDomain<F> = EvaluationDomain::new(dom_size).unwrap();
let mut l = dom_size / 2;
let mut m: usize = 1;
let mut dom_fr = F::one();
// Stockham FFT
let mut xvec = h.to_vec();
for _ in 0..p {
@@ -165,12 +164,10 @@ where
}
l /= 2;
m *= 2;
dom_fr = dom_fr + dom_fr;
xvec = xt;
}
let domain_inverse = dom_fr.inverse().unwrap().into_repr();
let domain_inverse = F::from(1u64 << p).inverse().unwrap().into_repr();
let res = xvec.iter().map(|x| x.mul(domain_inverse)).collect();
end_timer!(timer);
@@ -187,7 +184,6 @@ pub fn field_inv_dft<F: PrimeField>(h: &[F], p: usize) -> Vec<F> {
let input_domain: GeneralEvaluationDomain<F> = EvaluationDomain::new(dom_size).unwrap();
let mut l = dom_size / 2;
let mut m: usize = 1;
let mut dom_fr = F::one();
// Stockham FFT
let mut xvec = h.to_vec();
for _ in 0..p {
@@ -205,11 +201,10 @@ pub fn field_inv_dft<F: PrimeField>(h: &[F], p: usize) -> Vec<F> {
}
l /= 2;
m *= 2;
dom_fr = dom_fr + dom_fr;
xvec = xt;
}
let domain_inverse = dom_fr.inverse().unwrap();
let domain_inverse = F::from(1u64 << p).inverse().unwrap();
let res = xvec.iter().map(|&x| x * domain_inverse).collect();
end_timer!(timer);

View File

@@ -241,6 +241,47 @@ impl<E: PairingEngine> KZGCommit<E> {
pi: &E::G1Affine, // proof
) -> bool {
let timer = start_timer!(|| "kzg verify g1");
let pairing_inputs = Self::verify_g1_defer_pairing(
powers_of_g1,
powers_of_g2,
c_com,
max_deg,
points,
evals,
pi,
);
let pairing_timer = start_timer!(|| "pairing product");
let prepared_pairing_inputs = vec![
(
E::G1Prepared::from(pairing_inputs[0].0.into_affine()),
E::G2Prepared::from(pairing_inputs[0].1.into_affine()),
),
(
E::G1Prepared::from(pairing_inputs[1].0.into_affine()),
E::G2Prepared::from(pairing_inputs[1].1.into_affine()),
),
];
let res = E::product_of_pairings(prepared_pairing_inputs.iter()).is_one();
end_timer!(pairing_timer);
end_timer!(timer);
res
}
// KZG.Verify( srs_KZG, F, deg, (alpha1, alpha2, ..., alphan), (v1, ..., vn), pi
// ) Algorithm described in Section 4.6.1, Multiple Openings
pub fn verify_g1_defer_pairing(
// Verify that @c_com is a commitment to C(X) such that C(x)=z
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: &[E::Fr], // x such that eval = C(x)
evals: &[E::Fr], // evaluation
pi: &E::G1Affine, // proof
) -> Vec<(E::G1Projective, E::G2Projective)> {
let timer = start_timer!(|| "kzg verify g1 (deferring pairing)");
// Interpolation set
// tau_i(X) = lagrange_tau[i] = polynomial equal to 0 at point[j] for j!= i and
@@ -294,18 +335,14 @@ impl<E: PairingEngine> KZGCommit<E> {
d += max_deg.unwrap();
}
let pairing_inputs = vec![
let res = vec![
(
E::G1Prepared::from((g1_tau - c_com.into_projective()).into_affine()),
E::G2Prepared::from(powers_of_g2[global_max_deg - d]),
),
(
E::G1Prepared::from(*pi),
E::G2Prepared::from(g2_z_tau.into_affine()),
g1_tau - c_com.into_projective(),
powers_of_g2[global_max_deg - d].into_projective(),
),
(pi.into_projective(), g2_z_tau),
];
let res = E::product_of_pairings(pairing_inputs.iter()).is_one();
end_timer!(timer);
res
}
@@ -323,23 +360,50 @@ impl<E: PairingEngine> KZGCommit<E> {
pi: &E::G1Affine, // proof
) -> bool {
let timer = start_timer!(|| "kzg partial verify g1");
let pairing_inputs = vec![
let pairing_inputs =
Self::partial_verify_g1_defer_pairing(srs, c_com, deg_x, point, partial_eval, pi);
let pairing_timer = start_timer!(|| "pairing product");
let prepared_pairing_inputs = vec![
(
E::G1Prepared::from(
(partial_eval.into_projective() - c_com.into_projective()).into_affine(),
),
E::G2Prepared::from(srs.g2_powers[0]),
E::G1Prepared::from(pairing_inputs[0].0.into_affine()),
E::G2Prepared::from(pairing_inputs[0].1.into_affine()),
),
(
E::G1Prepared::from(*pi),
E::G2Prepared::from(
(srs.g2_powers[deg_x].into_projective() - srs.g2_powers[0].mul(*point))
.into_affine(),
),
E::G1Prepared::from(pairing_inputs[1].0.into_affine()),
E::G2Prepared::from(pairing_inputs[1].1.into_affine()),
),
];
let res = E::product_of_pairings(pairing_inputs.iter()).is_one();
let res = E::product_of_pairings(prepared_pairing_inputs.iter()).is_one();
end_timer!(pairing_timer);
end_timer!(timer);
res
}
// KZG.Verify( srs_KZG, F, deg, alpha, F_alpha, pi )
// Algorithm described in Section 4.6.2, KZG for Bivariate Polynomials
// Be very careful here. Verification is only valid if it is paired with a
// degree check.
pub fn partial_verify_g1_defer_pairing(
srs: &crate::multi::PublicParameters<E>,
c_com: &E::G1Affine, // commitment
deg_x: usize,
point: &E::Fr,
partial_eval: &E::G1Affine,
pi: &E::G1Affine, // proof
) -> Vec<(E::G1Projective, E::G2Projective)> {
let timer = start_timer!(|| "kzg partial verify g1 (deferring pairing)");
let res = vec![
(
partial_eval.into_projective() - c_com.into_projective(),
srs.g2_powers[0].into_projective(),
),
(
pi.into_projective(),
srs.g2_powers[deg_x].into_projective() - srs.g2_powers[0].mul(*point),
),
];
end_timer!(timer);
res
}

View File

@@ -12,7 +12,7 @@ use ark_poly::{
GeneralEvaluationDomain, Polynomial, UVPolynomial,
};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{cfg_into_iter, rand::RngCore, One, UniformRand, Zero};
use ark_std::{cfg_into_iter, end_timer, rand::RngCore, start_timer, One, UniformRand, Zero};
#[cfg(feature = "parallel")]
use rayon::iter::{IntoParallelIterator, ParallelIterator};
pub use setup::PublicParameters;
@@ -20,10 +20,11 @@ use std::{
convert::TryInto,
fs::File,
io::{Read, Write},
ops::MulAssign,
time::Instant,
vec::Vec,
};
use unity::{prove_multiunity, verify_multiunity, ProofMultiUnity};
use unity::{prove_multiunity, verify_multiunity_defer_pairing, ProofMultiUnity};
pub struct LookupInstance<C: AffineCurve> {
pub c_com: C, // polynomial C(X) that represents a table
@@ -150,6 +151,8 @@ pub fn compute_lookup_proof<E: PairingEngine, R: RngCore>(
srs: &PublicParameters<E>,
rng: &mut R,
) -> (LookupProof<E>, ProofMultiUnity<E>) {
let timer = start_timer!(|| "lookup proof generation");
let m = input.positions.len();
///////////////////////////////////////////////////////////////////
@@ -269,8 +272,7 @@ pub fn compute_lookup_proof<E: PairingEngine, R: RngCore>(
let mut transcript = CaulkTranscript::new();
// let now = Instant::now();
let unity_proof =
prove_multiunity(srs, &mut transcript, &u_com, u_vals.clone(), extra_blinder2);
let unity_proof = prove_multiunity(srs, &mut transcript, &u_com, &u_vals, extra_blinder2);
// println!("Time to prove unity {:?}", now.elapsed());
// quick test can be uncommented to check if unity proof verifies
@@ -437,18 +439,20 @@ pub fn compute_lookup_proof<E: PairingEngine, R: RngCore>(
pi2,
pi3,
};
end_timer!(timer);
(proof, unity_proof)
}
#[allow(non_snake_case)]
pub fn verify_lookup_proof<E: PairingEngine>(
pub fn verify_lookup_proof<E: PairingEngine, R: RngCore>(
c_com: &E::G1Affine,
phi_com: &E::G1Affine,
proof: &LookupProof<E>,
unity_proof: &ProofMultiUnity<E>,
srs: &PublicParameters<E>,
rng: &mut R,
) -> bool {
let timer = start_timer!(|| "lookup proof verification");
///////////////////////////////////////////////////////////////////
// 1. check unity
///////////////////////////////////////////////////////////////////
@@ -456,8 +460,8 @@ pub fn verify_lookup_proof<E: PairingEngine>(
// hash_input initialised to zero
let mut transcript = CaulkTranscript::new();
let unity_check = verify_multiunity(srs, &mut transcript, &proof.u_com, unity_proof);
assert!(unity_check, "failure on unity");
let unity_check =
verify_multiunity_defer_pairing(srs, &mut transcript, &proof.u_com, unity_proof);
///////////////////////////////////////////////////////////////////
// 2. Hash outputs to get chi
@@ -498,7 +502,7 @@ pub fn verify_lookup_proof<E: PairingEngine>(
///////////////////////////////////////////////////////////////////
// KZG.Verify(srs_KZG, [u]_1, deg = bot, alpha, v1, pi1)
let check1 = KZGCommit::<E>::verify_g1(
let check1 = KZGCommit::<E>::verify_g1_defer_pairing(
&srs.poly_ck.powers_of_g,
&srs.g2_powers,
&proof.u_com,
@@ -508,8 +512,6 @@ pub fn verify_lookup_proof<E: PairingEngine>(
&proof.pi1,
);
assert!(check1, "failure on pi_1 check");
///////////////////////////////////////////////////////////////////
// 5. Check pi_2
///////////////////////////////////////////////////////////////////
@@ -521,7 +523,7 @@ pub fn verify_lookup_proof<E: PairingEngine>(
let p1_com = (proof.z_I_com.into_projective() + proof.C_I_com.mul(chi)).into_affine();
// KZG.Verify(srs_KZG, [P1]_1, deg = bot, v1_id, v2, pi2)
let check2 = KZGCommit::<E>::verify_g1(
let check2 = KZGCommit::<E>::verify_g1_defer_pairing(
&srs.poly_ck.powers_of_g,
&srs.g2_powers,
&p1_com,
@@ -530,7 +532,6 @@ pub fn verify_lookup_proof<E: PairingEngine>(
&[proof.v2],
&proof.pi2,
);
assert!(check2, "failure on pi_2 check");
///////////////////////////////////////////////////////////////////
// 6. Check pi_3
@@ -549,7 +550,7 @@ pub fn verify_lookup_proof<E: PairingEngine>(
.into_affine();
// KZG.Verify(srs_KZG, [P2]_1, deg = bot, alpha, 0, pi3)
let check3 = KZGCommit::<E>::verify_g1(
let check3 = KZGCommit::<E>::verify_g1_defer_pairing(
&srs.poly_ck.powers_of_g,
&srs.g2_powers,
&p2_com,
@@ -558,24 +559,58 @@ pub fn verify_lookup_proof<E: PairingEngine>(
&[E::Fr::zero()],
&proof.pi3,
);
assert!(check3, "failure on check 3");
///////////////////////////////////////////////////////////////////
// 7. Check final pairing
// 7. prepare final pairing
///////////////////////////////////////////////////////////////////
// pairing1 = e([C]_1 - [C_I]_1, [1]_2)
let pairing1 = E::pairing(
(c_com.into_projective() - proof.C_I_com.into_projective()).into_affine(),
srs.g2_powers[0],
);
let final_pairing = vec![
(
proof.C_I_com.into_projective() - c_com.into_projective(),
srs.g2_powers[0].into_projective(),
),
(
proof.z_I_com.into_projective(),
proof.H1_com.into_projective(),
),
];
// pairing2 = e([z_I]_1, [H_1]_2)
let pairing2 = E::pairing(proof.z_I_com, proof.H1_com);
///////////////////////////////////////////////////////////////////
// 7. Check pairing products
///////////////////////////////////////////////////////////////////
let pairing_timer = start_timer!(|| "pairing product");
let mut pairing_inputs: Vec<(E::G1Projective, E::G2Projective)> = [
unity_check.as_slice(),
check1.as_slice(),
check2.as_slice(),
check3.as_slice(),
final_pairing.as_slice(),
]
.concat();
assert!(pairing1 == pairing2, "failure on pairing check");
let mut zeta = E::Fr::rand(rng);
let mut prepared_pairing_inputs = vec![];
for i in 0..pairing_inputs.len() / 2 {
if i != 0 {
pairing_inputs[i * 2].0.mul_assign(zeta);
pairing_inputs[i * 2 + 1].0.mul_assign(zeta);
}
zeta.square_in_place();
prepared_pairing_inputs.push((
E::G1Prepared::from(pairing_inputs[i * 2].0.into_affine()),
E::G2Prepared::from(pairing_inputs[i * 2].1.into_affine()),
));
prepared_pairing_inputs.push((
E::G1Prepared::from(pairing_inputs[i * 2 + 1].0.into_affine()),
E::G2Prepared::from(pairing_inputs[i * 2 + 1].1.into_affine()),
));
}
let res = E::product_of_pairings(prepared_pairing_inputs.iter()).is_one();
true
end_timer!(pairing_timer);
end_timer!(timer);
res
}
#[allow(non_snake_case)]
@@ -804,7 +839,14 @@ mod tests {
compute_lookup_proof::<E, _>(&lookup_instance, &prover_input, &pp, &mut rng);
println!("Time to generate proof for = {:?}", now.elapsed());
let now = Instant::now();
let res = verify_lookup_proof(&table.c_com, &phi_com, &proof, &unity_proof, &pp);
let res = verify_lookup_proof(
&table.c_com,
&phi_com,
&proof,
&unity_proof,
&pp,
&mut rng,
);
println!("Time to verify proof for = {:?}", now.elapsed());
assert!(res);
println!("Lookup test succeeded");
@@ -844,7 +886,7 @@ mod tests {
now.elapsed()
);
let now = Instant::now();
let res = verify_lookup_proof(&c_com, &phi_com, &proof, &unity_proof, &srs);
let res = verify_lookup_proof(&c_com, &phi_com, &proof, &unity_proof, &srs, &mut rng);
println!(
"Time to verify proof for n={:?} = {:?}",
srs.n,

View File

@@ -9,7 +9,9 @@ use ark_poly::{
univariate::DensePolynomial, EvaluationDomain, Evaluations as EvaluationsOnDomain, Polynomial,
UVPolynomial,
};
use ark_std::{One, Zero};
use ark_std::{end_timer, start_timer, One, UniformRand, Zero};
use rand::RngCore;
use std::ops::MulAssign;
// output structure of prove_unity
pub struct ProofMultiUnity<E: PairingEngine> {
@@ -35,43 +37,45 @@ pub fn prove_multiunity<E: PairingEngine>(
pp: &PublicParameters<E>,
transcript: &mut CaulkTranscript<E::Fr>,
g1_u: &E::G1Affine,
mut vec_u_evals: Vec<E::Fr>,
vec_u_evals: &[E::Fr],
u_poly_quotient: DensePolynomial<E::Fr>,
) -> ProofMultiUnity<E> {
let timer = start_timer!(|| "prove multiunity");
// The test_rng is deterministic. Should be replaced with actual random
// generator.
let rng_arkworks = &mut ark_std::test_rng();
// let rng_arkworks = &mut ark_std::test_rng();
let n = pp.n;
let deg_blinders = 11 / n;
let z_Vm: DensePolynomial<E::Fr> = pp.domain_m.vanishing_polynomial().into();
let mut vec_u_evals = vec_u_evals.to_vec();
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 1. Compute polynomials u_s(X) = vec_u_polys[s] such that u_s( nu_i ) =
// w_i^{2^s}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
let step1_timer = start_timer!(|| "step 1");
let mut vec_u_polys = vec![
EvaluationsOnDomain::from_vec_and_domain(vec_u_evals.clone(), pp.domain_m).interpolate()
EvaluationsOnDomain::from_vec_and_domain(vec_u_evals.to_vec(), pp.domain_m).interpolate()
+ (&z_Vm * &u_poly_quotient),
];
for _ in 1..pp.domain_n.size() {
for u_eval in &mut vec_u_evals {
for u_eval in vec_u_evals.iter_mut() {
*u_eval = u_eval.square();
}
vec_u_polys.push(
EvaluationsOnDomain::from_vec_and_domain(vec_u_evals.clone(), pp.domain_m)
EvaluationsOnDomain::from_vec_and_domain(vec_u_evals.to_vec(), pp.domain_m)
.interpolate()
+ (&z_Vm * &DensePolynomial::<E::Fr>::rand(deg_blinders, rng_arkworks)),
);
}
end_timer!(step1_timer);
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 2. Compute U_bar(X,Y) = sum_{s= 1}^n u_{s-1} rho_s(Y)
//////////////////////////////////////////////////////////////////////////////////////////////////////////
let step2_timer = start_timer!(|| "step 2");
// bivariate polynomials such that bipoly_U_bar[j] = a_j(Y) where U_bar(X,Y) =
// sum_j X^j a_j(Y)
let mut bipoly_U_bar = Vec::new();
@@ -85,7 +89,7 @@ pub fn prove_multiunity<E: PairingEngine>(
*/
let mut temp = DensePolynomial::from_coefficients_slice(&[E::Fr::zero()]);
for (s, u_poly) in vec_u_polys.iter().enumerate().take(n).skip(1){
for (s, u_poly) in vec_u_polys.iter().enumerate().take(n).skip(1) {
let u_s_j = DensePolynomial::from_coefficients_slice(&[u_poly[j]]);
temp += &(&u_s_j * &pp.lagrange_polynomials_n[s]);
}
@@ -93,11 +97,11 @@ pub fn prove_multiunity<E: PairingEngine>(
// add a_j(X) to U_bar(X,Y)
bipoly_U_bar.push(temp);
}
end_timer!(step2_timer);
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 3. Hs(X) = u_{s-1}^2(X) - u_s(X)
//////////////////////////////////////////////////////////////////////////////////////////////////////////
let step3_timer = start_timer!(|| "step 3");
// id_poly(X) = 1 for omega_m in range and 0 for omega_m not in range.
let id_poly = pp.id_poly.clone();
@@ -118,11 +122,11 @@ pub fn prove_multiunity<E: PairingEngine>(
.unwrap();
assert!(remainder.is_zero());
vec_H_s_polys.push(poly_H_s);
end_timer!(step3_timer);
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 4. h_2(X,Y) = sum_{s=1}^n rho_s(Y) H_s(X)
//////////////////////////////////////////////////////////////////////////////////////////////////////////
let step4_timer = start_timer!(|| "step 4");
// h_2[j] = a_j(Y) where h_2(X,Y) = sum_j X^j a_j(Y)
let mut bipoly_h_2 = Vec::new();
@@ -152,25 +156,27 @@ pub fn prove_multiunity<E: PairingEngine>(
*coeff += &(&h_s_j * &pp.lagrange_polynomials_n[s]);
}
}
end_timer!(step4_timer);
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 5. Commit to U_bar(X^n, X) and h_2(X^n, X)
//////////////////////////////////////////////////////////////////////////////////////////////////////////
let step5_timer = start_timer!(|| "step 5");
let g1_u_bar = KZGCommit::<E>::bipoly_commit(pp, &bipoly_U_bar, pp.domain_n.size());
let g1_h_2 = KZGCommit::<E>::bipoly_commit(pp, &bipoly_h_2, pp.domain_n.size());
end_timer!(step5_timer);
////////////////////////////
// 6. alpha = Hash(g1_u, g1_u_bar, g1_h_2)
////////////////////////////
let step6_timer = start_timer!(|| "step 6");
transcript.append_element(b"u", g1_u);
transcript.append_element(b"u_bar", &g1_u_bar);
transcript.append_element(b"h2", &g1_h_2);
let alpha = transcript.get_and_append_challenge(b"alpha");
end_timer!(step6_timer);
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 7. Compute h_1(Y)
//////////////////////////////////////////////////////////////////////////////////////////////////////////
let step7_timer = start_timer!(|| "step 7");
// poly_U_alpha = sum_{s=1}^n u_{s-1}(alpha) rho_s(Y)
let mut poly_U_alpha = DensePolynomial::from_coefficients_slice(&[E::Fr::zero()]);
@@ -192,29 +198,31 @@ pub fn prove_multiunity<E: PairingEngine>(
.divide_by_vanishing_poly(pp.domain_n)
.unwrap();
assert!(remainder.is_zero(), "poly_h_1 does not divide");
end_timer!(step7_timer);
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 8. Commit to h_1(Y)
//////////////////////////////////////////////////////////////////////////////////////////////////////////
let step8_timer = start_timer!(|| "step 8");
assert!(pp.poly_ck.powers_of_g.len() >= poly_h_1.len());
let g1_h_1 = VariableBaseMSM::multi_scalar_mul(
&pp.poly_ck.powers_of_g,
convert_to_bigints(&poly_h_1.coeffs).as_slice(),
)
.into_affine();
end_timer!(step8_timer);
////////////////////////////
// 9. beta = Hash( g1_h_1 )
////////////////////////////
let step9_timer = start_timer!(|| "step 9");
transcript.append_element(b"h1", &g1_h_1);
let beta = transcript.get_and_append_challenge(b"beta");
end_timer!(step9_timer);
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 10. Compute p(Y) = (U^2(alpha, beta) - h1(Y) zVn(beta) ) - (u_bar(alpha, beta
// sigma^(-1)) + id(alpha) rho_n(Y)) - zVm(alpha )h2(alpha,Y)
//////////////////////////////////////////////////////////////////////////////////////////////////////////
let step10_timer = start_timer!(|| "step 10");
// p(Y) = U^2(alpha, beta)
let u_alpha_beta = poly_U_alpha.evaluate(&beta);
let mut poly_p = DensePolynomial::from_coefficients_slice(&[u_alpha_beta.square()]);
@@ -259,11 +267,11 @@ pub fn prove_multiunity<E: PairingEngine>(
// check p(beta) = 0
assert!(poly_p.evaluate(&beta) == E::Fr::zero());
end_timer!(step10_timer);
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 11. Open KZG commitments
//////////////////////////////////////////////////////////////////////////////////////////////////////////
let step11_timer = start_timer!(|| "step 11");
// KZG.Open( srs, u(X), deg = bot, X = alpha )
let (evals_1, pi_1) = KZGCommit::open_g1_batch(&pp.poly_ck, &vec_u_polys[0], None, &[alpha]);
@@ -293,7 +301,8 @@ pub fn prove_multiunity<E: PairingEngine>(
&[beta],
);
assert!(evals_3[0] == E::Fr::zero());
end_timer!(step11_timer);
end_timer!(timer);
ProofMultiUnity {
g1_u_bar,
g1_h_1,
@@ -314,12 +323,57 @@ pub fn prove_multiunity<E: PairingEngine>(
// Verify that the prover knows vec_u_evals such that g1_u = g1^(sum_j u_j
// mu_j(x)) and u_j^N = 1
#[allow(non_snake_case)]
pub fn verify_multiunity<E: PairingEngine>(
pub fn verify_multiunity<E: PairingEngine, R: RngCore>(
pp: &PublicParameters<E>,
transcript: &mut CaulkTranscript<E::Fr>,
g1_u: &E::G1Affine,
pi_unity: &ProofMultiUnity<E>,
rng: &mut R,
) -> bool {
let timer = start_timer!(|| "verify multiunity");
let mut pairing_inputs = verify_multiunity_defer_pairing(pp, transcript, g1_u, pi_unity);
assert_eq!(pairing_inputs.len(), 10);
let pairing_timer = start_timer!(|| "pairing product");
let mut zeta = E::Fr::rand(rng);
pairing_inputs[2].0.mul_assign(zeta);
pairing_inputs[3].0.mul_assign(zeta);
zeta.square_in_place();
pairing_inputs[4].0.mul_assign(zeta);
pairing_inputs[5].0.mul_assign(zeta);
zeta.square_in_place();
pairing_inputs[6].0.mul_assign(zeta);
pairing_inputs[7].0.mul_assign(zeta);
zeta.square_in_place();
pairing_inputs[8].0.mul_assign(zeta);
pairing_inputs[9].0.mul_assign(zeta);
let prepared_pairing_inputs: Vec<(E::G1Prepared, E::G2Prepared)> = pairing_inputs
.iter()
.map(|(g1, g2)| {
(
E::G1Prepared::from(g1.into_affine()),
E::G2Prepared::from(g2.into_affine()),
)
})
.collect();
let res = E::product_of_pairings(prepared_pairing_inputs.iter()).is_one();
end_timer!(pairing_timer);
end_timer!(timer);
res
}
// Verify that the prover knows vec_u_evals such that g1_u = g1^(sum_j u_j
// mu_j(x)) and u_j^N = 1
#[allow(non_snake_case)]
pub fn verify_multiunity_defer_pairing<E: PairingEngine>(
pp: &PublicParameters<E>,
transcript: &mut CaulkTranscript<E::Fr>,
g1_u: &E::G1Affine,
pi_unity: &ProofMultiUnity<E>,
) -> Vec<(E::G1Projective, E::G2Projective)> {
let timer = start_timer!(|| "verify multiunity (deferring pairing)");
////////////////////////////
// alpha = Hash(g1_u, g1_u_bar, g1_h_2)
////////////////////////////
@@ -360,7 +414,7 @@ pub fn verify_multiunity<E: PairingEngine>(
// Check the KZG openings
////////////////////////////
let check1 = KZGCommit::<E>::verify_g1(
let check1 = KZGCommit::<E>::verify_g1_defer_pairing(
&pp.poly_ck.powers_of_g,
&pp.g2_powers,
g1_u,
@@ -369,7 +423,7 @@ pub fn verify_multiunity<E: PairingEngine>(
&[pi_unity.v1],
&pi_unity.pi_1,
);
let check2 = KZGCommit::partial_verify_g1(
let check2 = KZGCommit::partial_verify_g1_defer_pairing(
pp,
&pi_unity.g1_u_bar,
pp.domain_n.size(),
@@ -377,7 +431,7 @@ pub fn verify_multiunity<E: PairingEngine>(
&pi_unity.g1_u_bar_alpha,
&pi_unity.pi_2,
);
let check3 = KZGCommit::partial_verify_g1(
let check3 = KZGCommit::partial_verify_g1_defer_pairing(
pp,
&pi_unity.g1_h_2,
pp.domain_n.size(),
@@ -385,7 +439,7 @@ pub fn verify_multiunity<E: PairingEngine>(
&pi_unity.g1_h_2_alpha,
&pi_unity.pi_3,
);
let check4 = KZGCommit::<E>::verify_g1(
let check4 = KZGCommit::<E>::verify_g1_defer_pairing(
&pp.poly_ck.powers_of_g,
&pp.g2_powers,
&pi_unity.g1_u_bar_alpha,
@@ -394,7 +448,7 @@ pub fn verify_multiunity<E: PairingEngine>(
&[E::Fr::zero(), pi_unity.v2, pi_unity.v3],
&pi_unity.pi_4,
);
let check5 = KZGCommit::<E>::verify_g1(
let check5 = KZGCommit::<E>::verify_g1_defer_pairing(
&pp.poly_ck.powers_of_g,
&pp.g2_powers,
&g1_P.into_affine(),
@@ -404,7 +458,16 @@ pub fn verify_multiunity<E: PairingEngine>(
&pi_unity.pi_5,
);
check1 && check2 && check3 && check4 && check5
let res = [
check1.as_slice(),
check2.as_slice(),
check3.as_slice(),
check4.as_slice(),
check5.as_slice(),
]
.concat();
end_timer!(timer);
res
}
#[cfg(test)]
@@ -485,7 +548,7 @@ pub mod tests {
&pp,
&mut prover_transcript,
&g1_u,
vec_u_evals.clone(),
&vec_u_evals,
u_poly_quotient,
);
@@ -495,7 +558,7 @@ pub mod tests {
let mut verifier_transcript = CaulkTranscript::new();
println!(
"unity proof verifies {:?}",
verify_multiunity::<E>(&pp, &mut verifier_transcript, &g1_u, &pi_unity)
verify_multiunity::<E, _>(&pp, &mut verifier_transcript, &g1_u, &pi_unity, &mut rng)
);
}
}