Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented proof rerandomization #16

Merged
merged 7 commits into from
Dec 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions src/prover.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{r1cs_to_qap::R1CStoQAP, Proof, ProvingKey};
use crate::{r1cs_to_qap::R1CStoQAP, Proof, ProvingKey, VerifyingKey};
use ark_ec::{msm::VariableBaseMSM, AffineCurve, PairingEngine, ProjectiveCurve};
use ark_ff::{PrimeField, UniformRand, Zero};
use ark_ff::{Field, PrimeField, UniformRand, Zero};
use ark_poly::GeneralEvaluationDomain;
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem, Result as R1CSResult};
use ark_std::{cfg_into_iter, cfg_iter, vec::Vec};
Expand Down Expand Up @@ -144,6 +144,39 @@ where
})
}

/// Given a Groth16 proof, returns a fresh proof of the same statement. For a proof π of a
/// statement S, the output of the non-deterministic procedure `rerandomize_proof(π)` is
/// statistically indistinguishable from a fresh honest proof of S. For more info, see theorem 3 of
/// [\[BKSV20\]](https://eprint.iacr.org/2020/811)
pub fn rerandomize_proof<E, R>(rng: &mut R, vk: &VerifyingKey<E>, proof: &Proof<E>) -> Proof<E>
where
E: PairingEngine,
R: Rng,
{
// These are our rerandomization factors. They must be nonzero and uniformly sampled.
let (mut r1, mut r2) = (E::Fr::zero(), E::Fr::zero());
while r1.is_zero() || r2.is_zero() {
r1 = E::Fr::rand(rng);
r2 = E::Fr::rand(rng);
}

// See figure 1 in the paper referenced above:
// A' = (1/r₁)A
// B' = r₁B + r₁r₂(δG₂)
// C' = C + r₂A

// We can unwrap() this because r₁ is guaranteed to be nonzero
let new_a = proof.a.mul(r1.inverse().unwrap());
let new_b = proof.b.mul(r1) + &vk.delta_g2.mul(r1 * &r2);
let new_c = proof.c + proof.a.mul(r2).into_affine();

Proof {
a: new_a.into_affine(),
b: new_b.into_affine(),
c: new_c,
}
}

fn calculate_coeff<G: AffineCurve>(
initial: G::Projective,
query: &[G],
Expand Down
166 changes: 103 additions & 63 deletions src/test.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
use crate::{
create_random_proof, generate_random_parameters, prepare_verifying_key, rerandomize_proof,
verify_proof,
};
use ark_ec::PairingEngine;
use ark_ff::UniformRand;
use ark_std::test_rng;

use core::ops::MulAssign;

use ark_ff::{Field, Zero};
use ark_relations::{
lc,
Expand Down Expand Up @@ -35,71 +45,22 @@ impl<ConstraintF: Field> ConstraintSynthesizer<ConstraintF> for MySillyCircuit<C
}
}

mod bls12_377 {
use super::*;
use crate::{
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof,
};
use ark_std::{test_rng, UniformRand};

use ark_bls12_377::{Bls12_377, Fr};
use core::ops::MulAssign;

#[test]
fn prove_and_verify() {
let rng = &mut test_rng();

let params =
generate_random_parameters::<Bls12_377, _, _>(MySillyCircuit { a: None, b: None }, rng)
.unwrap();

let pvk = prepare_verifying_key::<Bls12_377>(&params.vk);

for _ in 0..100 {
let a = Fr::rand(rng);
let b = Fr::rand(rng);
let mut c = a;
c.mul_assign(&b);

let proof = create_random_proof(
MySillyCircuit {
a: Some(a),
b: Some(b),
},
&params,
rng,
)
.unwrap();

assert!(verify_proof(&pvk, &proof, &[c]).unwrap());
assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
}
}
}

mod cp6_782 {
use super::*;
use crate::{
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof,
};

use ark_std::{test_rng, UniformRand};

use ark_cp6_782::{Fr, CP6_782};

#[test]
fn prove_and_verify() {
let rng = &mut test_rng();
fn test_prove_and_verify<E>(n_iters: usize)
where
E: PairingEngine,
{
let rng = &mut test_rng();

let params =
generate_random_parameters::<CP6_782, _, _>(MySillyCircuit { a: None, b: None }, rng)
.unwrap();
let params =
generate_random_parameters::<E, _, _>(MySillyCircuit { a: None, b: None }, rng).unwrap();

let pvk = prepare_verifying_key::<CP6_782>(&params.vk);
let pvk = prepare_verifying_key::<E>(&params.vk);

let a = Fr::rand(rng);
let b = Fr::rand(rng);
let c = a * &b;
for _ in 0..n_iters {
let a = E::Fr::rand(rng);
let b = E::Fr::rand(rng);
let mut c = a;
c.mul_assign(&b);

let proof = create_random_proof(
MySillyCircuit {
Expand All @@ -112,6 +73,85 @@ mod cp6_782 {
.unwrap();

assert!(verify_proof(&pvk, &proof, &[c]).unwrap());
assert!(!verify_proof(&pvk, &proof, &[Fr::zero()]).unwrap());
assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
}
}

fn test_rerandomize<E>()
where
E: PairingEngine,
{
// First create an arbitrary Groth16 in the normal way

let rng = &mut test_rng();

let params =
generate_random_parameters::<E, _, _>(MySillyCircuit { a: None, b: None }, rng).unwrap();

let pvk = prepare_verifying_key::<E>(&params.vk);

let a = E::Fr::rand(rng);
let b = E::Fr::rand(rng);
let c = a * &b;

// Create the initial proof
let proof1 = create_random_proof(
MySillyCircuit {
a: Some(a),
b: Some(b),
},
&params,
rng,
)
.unwrap();

// Rerandomize the proof, then rerandomize that
let proof2 = rerandomize_proof(rng, &params.vk, &proof1);
let proof3 = rerandomize_proof(rng, &params.vk, &proof2);

// Check correctness: a rerandomized proof validates when the original validates
assert!(verify_proof(&pvk, &proof1, &[c]).unwrap());
assert!(verify_proof(&pvk, &proof2, &[c]).unwrap());
assert!(verify_proof(&pvk, &proof3, &[c]).unwrap());

// Check soundness: a rerandomized proof fails to validate when the original fails to validate
assert!(!verify_proof(&pvk, &proof1, &[E::Fr::zero()]).unwrap());
assert!(!verify_proof(&pvk, &proof2, &[E::Fr::zero()]).unwrap());
assert!(!verify_proof(&pvk, &proof3, &[E::Fr::zero()]).unwrap());
Pratyush marked this conversation as resolved.
Show resolved Hide resolved

// Check that the proofs are not equal as group elements
assert!(proof1 != proof2);
assert!(proof1 != proof3);
assert!(proof2 != proof3);
}

mod bls12_377 {
use super::{test_prove_and_verify, test_rerandomize};
use ark_bls12_377::Bls12_377;

#[test]
fn prove_and_verify() {
test_prove_and_verify::<Bls12_377>(100);
}

#[test]
fn rerandomize() {
test_rerandomize::<Bls12_377>();
}
}

mod cp6_782 {
use super::{test_prove_and_verify, test_rerandomize};

use ark_cp6_782::CP6_782;

#[test]
fn prove_and_verify() {
test_prove_and_verify::<CP6_782>(1);
}

#[test]
fn rerandomize() {
test_rerandomize::<CP6_782>();
}
}