use alloc::vec::Vec;
use bn::{pairing_batch, AffineG1, AffineG2, Fr, Gt, G1, G2};
use super::error::Groth16Error;
#[derive(Clone, PartialEq)]
pub(crate) struct Groth16G1 {
pub(crate) alpha: AffineG1,
pub(crate) k: Vec<AffineG1>,
}
#[derive(Clone, PartialEq)]
pub(crate) struct Groth16G2 {
pub(crate) beta: AffineG2,
pub(crate) delta: AffineG2,
pub(crate) gamma: AffineG2,
}
#[derive(Clone, PartialEq)]
pub(crate) struct Groth16VerifyingKey {
pub(crate) g1: Groth16G1,
pub(crate) g2: Groth16G2,
}
pub(crate) struct Groth16Proof {
pub(crate) ar: AffineG1,
pub(crate) krs: AffineG1,
pub(crate) bs: AffineG2,
}
fn prepare_inputs(vk: Groth16VerifyingKey, public_inputs: &[Fr]) -> Result<G1, Groth16Error> {
if (public_inputs.len() + 1) != vk.g1.k.len() {
return Err(Groth16Error::PrepareInputsFailed);
}
Ok(public_inputs
.iter()
.zip(vk.g1.k.iter().skip(1))
.fold(vk.g1.k[0], |acc, (i, b)| if *i != Fr::zero() { acc + (*b * *i) } else { acc })
.into())
}
pub(crate) fn verify_groth16_algebraic(
vk: &Groth16VerifyingKey,
proof: &Groth16Proof,
public_inputs: &[Fr],
) -> Result<(), Groth16Error> {
let prepared_inputs = prepare_inputs(vk.clone(), public_inputs)?;
if pairing_batch(&[
(-Into::<G1>::into(proof.ar), proof.bs.into()),
(prepared_inputs, vk.g2.gamma.into()),
(proof.krs.into(), vk.g2.delta.into()),
(vk.g1.alpha.into(), -Into::<G2>::into(vk.g2.beta)),
]) == Gt::one()
{
Ok(())
} else {
Err(Groth16Error::ProofVerificationFailed)
}
}