use ark_bn254::{Bn254, Fr};
use ark_groth16::{
PreparedVerifyingKey, Proof as ArkProof, ProvingKey, VerifyingKey,
};
use ark_snark::SNARK;
use ark_groth16::Groth16;
use ark_ec::pairing::Pairing;
use ark_serialize::CanonicalSerialize;
use ark_std::rand::thread_rng;
use thiserror::Error;
use crate::circuits::{CircuitError, ArithmeticCircuit};
#[derive(Error, Debug)]
pub enum Groth16Error {
#[error("Setup failed")]
SetupError,
#[error("Proving failed")]
ProvingError,
#[error("Verification failed")]
VerificationError,
#[error("Circuit error: {0}")]
CircuitError(#[from] CircuitError),
#[error("Serialization error")]
SerializationError,
}
#[derive(Debug)]
pub struct Groth16Setup<E: Pairing> {
pub proving_key: ProvingKey<E>,
pub verifying_key: VerifyingKey<E>,
pub prepared_verifying_key: PreparedVerifyingKey<E>,
}
impl Groth16Setup<Bn254> {
pub fn new(num_constraints: usize, num_variables: usize) -> Result<Self, Groth16Error> {
let circuit: ArithmeticCircuit<Fr> = ArithmeticCircuit::new(num_constraints, num_variables, 1);
let rng = &mut thread_rng();
let (pk, vk) = Groth16::<Bn254>::circuit_specific_setup(
circuit,
rng,
).map_err(|_| Groth16Error::SetupError)?;
let pvk = match Groth16::<Bn254>::process_vk(&vk) {
Ok(pvk) => pvk,
Err(_) => return Err(Groth16Error::SetupError),
};
Ok(Self {
proving_key: pk,
verifying_key: vk,
prepared_verifying_key: pvk,
})
}
pub fn prove(&self, inputs: &[Fr], witness: &[Fr]) -> Result<ArkProof<Bn254>, Groth16Error> {
let rng = &mut thread_rng();
let circuit = ArithmeticCircuit {
num_constraints: inputs.len(),
num_variables: witness.len(),
num_inputs: 1,
witness: witness.to_vec(),
};
Groth16::<Bn254>::create_random_proof_with_reduction(
circuit,
&self.proving_key,
rng,
).map_err(|_| Groth16Error::ProvingError)
}
pub fn verify(
&self,
proof: &ArkProof<Bn254>,
public_inputs: &[Fr],
) -> Result<bool, Groth16Error> {
<Groth16<Bn254> as SNARK<Fr>>::verify_with_processed_vk(
&self.prepared_verifying_key,
public_inputs,
proof,
).map_err(|_| Groth16Error::VerificationError)
}
pub fn proof_to_evm_format(proof: &ArkProof<Bn254>) -> Result<Vec<u8>, Groth16Error> {
let mut bytes = Vec::new();
proof.serialize_compressed(&mut bytes)
.map_err(|_| Groth16Error::SerializationError)?;
Ok(bytes)
}
pub fn estimate_verification_gas(proof_size: usize, num_inputs: usize) -> u64 {
let base_cost = 150_000;
let input_cost = num_inputs as u64 * 1_000;
let data_cost = proof_size as u64 * 16;
base_cost + input_cost + data_cost
}
}