use group::Group;
use midnight_circuits::{hash::poseidon::PoseidonState, verifier::Accumulator};
use midnight_proofs::{
plonk::{self},
poly::kzg::{params::ParamsVerifierKZG, KZGCommitmentScheme},
transcript::{CircuitTranscript, Transcript},
};
use midnight_zk_stdlib::{MidnightVK, Relation};
use super::{Ivc, IvcCircuit, IvcError, IvcInstance, C, E, F, S};
#[derive(Clone, Debug)]
pub struct IvcVerifier<T: Ivc> {
pub(crate) ctx: T::Context,
pub(crate) vk: MidnightVK,
pub(crate) params_verifier: ParamsVerifierKZG<E>,
}
impl<T: Ivc> IvcVerifier<T> {
pub fn vk(&self) -> &MidnightVK {
&self.vk
}
pub fn params_verifier(&self) -> &ParamsVerifierKZG<E> {
&self.params_verifier
}
pub fn verify(&self, instance: &IvcInstance<T>, proof: &[u8]) -> Result<(), IvcError> {
if instance.vk_repr != self.vk.vk().transcript_repr() {
return Err(IvcError::VkMismatch);
}
if !T::decider(&self.ctx, &instance.state) {
return Err(IvcError::DeciderFailed);
}
let fixed_bases = midnight_circuits::verifier::fixed_bases::<S>("self_vk", self.vk.vk());
let pi =
IvcCircuit::<T>::format_instance(instance).map_err(|_| IvcError::InvalidInstance)?;
let mut transcript = CircuitTranscript::<PoseidonState<F>>::init_from_bytes(proof);
let dual_msm =
plonk::prepare::<F, KZGCommitmentScheme<E>, CircuitTranscript<PoseidonState<F>>>(
self.vk.vk(),
&[&[C::identity()]],
&[&[&pi]],
&mut transcript,
)
.map_err(|_| IvcError::InvalidProof)?;
transcript.assert_empty().map_err(|_| IvcError::TranscriptNotEmpty)?;
let proof_acc = Accumulator::from_dual_msm(dual_msm, "self_vk", &fixed_bases);
let final_acc = Accumulator::<S>::accumulate(&[proof_acc, instance.acc.clone()]);
if !final_acc.check(&self.params_verifier, &fixed_bases) {
return Err(IvcError::InvalidProof);
};
Ok(())
}
}