use crate::aggregation::{
commitment::PairCommitment, error::AggregationError, kzg::KZGOpening, srs,
};
use ark_ec::pairing::{Pairing, PairingOutput};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{string::ToString, vec::Vec};
#[derive(CanonicalSerialize, CanonicalDeserialize, Debug, Clone)]
pub struct AggregateProof<E: Pairing> {
pub com_ab: PairCommitment<E>,
pub com_c: PairCommitment<E>,
pub z_ab: PairingOutput<E>,
pub z_c: E::G1Affine,
pub tmipp: TippMippProof<E>,
}
impl<E: Pairing> PartialEq for AggregateProof<E> {
fn eq(&self, other: &Self) -> bool {
self.com_ab == other.com_ab
&& self.com_c == other.com_c
&& self.z_ab == other.z_ab
&& self.z_c == other.z_c
&& self.tmipp == other.tmipp
}
}
impl<E: Pairing> AggregateProof<E> {
pub fn parsing_check(&self) -> Result<(), AggregationError> {
let gipa = &self.tmipp.gipa;
if gipa.nproofs < 2 || gipa.nproofs as usize > srs::MAX_SRS_SIZE {
return Err(AggregationError::InvalidProof(
"Proof length out of bounds".to_string(),
));
}
if !gipa.nproofs.is_power_of_two() {
return Err(AggregationError::InvalidProof(
"Proof length not a power of two".to_string(),
));
}
let ref_len = (gipa.nproofs as f32).log2().ceil() as usize;
let all_same = ref_len == gipa.comms_ab.len()
&& ref_len == gipa.comms_c.len()
&& ref_len == gipa.z_ab.len()
&& ref_len == gipa.z_c.len();
if !all_same {
return Err(AggregationError::InvalidProof(
"Proof vectors unequal sizes".to_string(),
));
}
Ok(())
}
}
#[derive(Debug, Clone, CanonicalSerialize, CanonicalDeserialize)]
pub struct GipaProof<E: Pairing> {
pub nproofs: u32,
pub comms_ab: Vec<(PairCommitment<E>, PairCommitment<E>)>,
pub comms_c: Vec<(PairCommitment<E>, PairCommitment<E>)>,
pub z_ab: Vec<(PairingOutput<E>, PairingOutput<E>)>,
pub z_c: Vec<(E::G1Affine, E::G1Affine)>,
pub final_a: E::G1Affine,
pub final_b: E::G2Affine,
pub final_c: E::G1Affine,
pub final_vkey: (E::G2Affine, E::G2Affine),
pub final_wkey: (E::G1Affine, E::G1Affine),
}
impl<E: Pairing> PartialEq for GipaProof<E> {
fn eq(&self, other: &Self) -> bool {
self.nproofs == other.nproofs
&& self.comms_ab == other.comms_ab
&& self.comms_c == other.comms_c
&& self.z_ab == other.z_ab
&& self.z_c == other.z_c
&& self.final_a == other.final_a
&& self.final_b == other.final_b
&& self.final_c == other.final_c
&& self.final_vkey == other.final_vkey
&& self.final_wkey == other.final_wkey
}
}
impl<E: Pairing> GipaProof<E> {
fn log_proofs(nproofs: usize) -> usize {
(nproofs as f32).log2().ceil() as usize
}
pub fn is_valid(&self) -> bool {
let log_proofs = Self::log_proofs(self.nproofs as usize);
self.comms_ab.len() == log_proofs
&& self.comms_c.len() == log_proofs
&& self.z_ab.len() == log_proofs
&& self.z_c.len() == log_proofs
}
}
#[derive(CanonicalSerialize, CanonicalDeserialize, Debug, Clone)]
pub struct TippMippProof<E: Pairing> {
pub gipa: GipaProof<E>,
pub vkey_opening: KZGOpening<E::G2Affine>,
pub wkey_opening: KZGOpening<E::G1Affine>,
}
impl<E: Pairing> PartialEq for TippMippProof<E> {
fn eq(&self, other: &Self) -> bool {
self.gipa == other.gipa
&& self.vkey_opening == other.vkey_opening
&& self.wkey_opening == other.wkey_opening
}
}