use crate::{prepare_verifying_key, Groth16};
use ark_crypto_primitives::snark::{CircuitSpecificSetupSNARK, SNARK};
use ark_ec::pairing::Pairing;
use ark_ff::Field;
use ark_relations::{
gr1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError},
lc,
};
use ark_std::{
rand::{RngCore, SeedableRng},
test_rng, UniformRand,
};
struct MySillyCircuit<F: Field> {
a: Option<F>,
b: Option<F>,
}
impl<ConstraintF: Field> ConstraintSynthesizer<ConstraintF> for MySillyCircuit<ConstraintF> {
fn generate_constraints(
self,
cs: ConstraintSystemRef<ConstraintF>,
) -> Result<(), SynthesisError> {
let a = cs.new_witness_variable(|| self.a.ok_or(SynthesisError::AssignmentMissing))?;
let b = cs.new_witness_variable(|| self.b.ok_or(SynthesisError::AssignmentMissing))?;
let c = cs.new_input_variable(|| {
let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?;
let b = self.b.ok_or(SynthesisError::AssignmentMissing)?;
a *= &b;
Ok(a)
})?;
cs.enforce_r1cs_constraint(|| lc!() + a, || lc!() + b, || lc!() + c)?;
cs.enforce_r1cs_constraint(|| lc!() + a, || lc!() + b, || lc!() + c)?;
cs.enforce_r1cs_constraint(|| lc!() + a, || lc!() + b, || lc!() + c)?;
cs.enforce_r1cs_constraint(|| lc!() + a, || lc!() + b, || lc!() + c)?;
cs.enforce_r1cs_constraint(|| lc!() + a, || lc!() + b, || lc!() + c)?;
cs.enforce_r1cs_constraint(|| lc!() + a, || lc!() + b, || lc!() + c)?;
Ok(())
}
}
fn test_prove_and_verify<E>(n_iters: usize)
where
E: Pairing,
{
let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64());
let (pk, vk) = Groth16::<E>::setup(MySillyCircuit { a: None, b: None }, &mut rng).unwrap();
let pvk = prepare_verifying_key::<E>(&vk);
for _ in 0..n_iters {
let a = E::ScalarField::rand(&mut rng);
let b = E::ScalarField::rand(&mut rng);
let mut c = a;
c *= b;
let proof = Groth16::<E>::prove(
&pk,
MySillyCircuit {
a: Some(a),
b: Some(b),
},
&mut rng,
)
.unwrap();
assert!(Groth16::<E>::verify_with_processed_vk(&pvk, &[c], &proof).unwrap());
assert!(!Groth16::<E>::verify_with_processed_vk(&pvk, &[a], &proof).unwrap());
}
}
fn test_rerandomize<E>()
where
E: Pairing,
{
let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64());
let (pk, vk) = Groth16::<E>::setup(MySillyCircuit { a: None, b: None }, &mut rng).unwrap();
let pvk = prepare_verifying_key::<E>(&vk);
for _ in 0..10 {
let a = E::ScalarField::rand(&mut rng);
let b = E::ScalarField::rand(&mut rng);
let mut c = a;
c *= b;
let proof1 = Groth16::<E>::prove(
&pk,
MySillyCircuit {
a: Some(a),
b: Some(b),
},
&mut rng,
)
.unwrap();
let proof2 = Groth16::<E>::rerandomize_proof(&vk, &proof1, &mut rng);
let proof3 = Groth16::<E>::rerandomize_proof(&vk, &proof2, &mut rng);
assert!(Groth16::<E>::verify_with_processed_vk(&pvk, &[c], &proof1).unwrap());
assert!(Groth16::<E>::verify_with_processed_vk(&pvk, &[c], &proof2).unwrap());
assert!(Groth16::<E>::verify_with_processed_vk(&pvk, &[c], &proof3).unwrap());
assert!(!Groth16::<E>::verify_with_processed_vk(&pvk, &[a], &proof1).unwrap());
assert!(!Groth16::<E>::verify_with_processed_vk(&pvk, &[a], &proof2).unwrap());
assert!(!Groth16::<E>::verify_with_processed_vk(&pvk, &[a], &proof3).unwrap());
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 bw6_761 {
use super::{test_prove_and_verify, test_rerandomize};
use ark_bw6_761::BW6_761;
#[test]
fn prove_and_verify() {
test_prove_and_verify::<BW6_761>(1);
}
#[test]
fn rerandomize() {
test_rerandomize::<BW6_761>();
}
}
mod bn_254 {
use super::test_prove_and_verify;
use ark_bn254::Bn254;
#[test]
fn prove_and_verify() {
test_prove_and_verify::<Bn254>(100);
}
}