use group::Group;
use midnight_circuits::{
hash::poseidon::PoseidonState,
types::Instantiable,
verifier::{Accumulator, AssignedAccumulator, AssignedVk},
};
use midnight_proofs::{
plonk::{self},
poly::kzg::{params::ParamsKZG, KZGCommitmentScheme},
transcript::{CircuitTranscript, Transcript},
};
use midnight_zk_stdlib::MidnightPK;
use rand::rngs::OsRng;
use super::{Ivc, IvcCircuit, IvcError, IvcInstance, IvcWitness, C, E, F, S};
#[derive(Clone, Debug)]
pub struct IvcProver<T: Ivc> {
pub(crate) params: ParamsKZG<E>,
pub(crate) relation: IvcCircuit<T>,
pub(crate) pk: MidnightPK<IvcCircuit<T>>,
pub(crate) state: T::State,
pub(crate) proof: Vec<u8>,
pub(crate) acc: Accumulator<S>,
}
impl<T: Ivc> IvcProver<T> {
pub fn resume_from(&mut self, state: T::State, proof: Vec<u8>, acc: Accumulator<S>) {
self.state = state;
self.proof = proof;
self.acc = acc;
}
pub fn prove_step(&mut self, transition_witness: T::Witness) -> Result<Vec<u8>, IvcError> {
let next_state =
T::transition(self.relation.ctx(), &self.state, transition_witness.clone());
let vk = self.pk.pk().get_vk();
let vk_repr = vk.transcript_repr();
let fixed_bases = midnight_circuits::verifier::fixed_bases::<S>("self_vk", vk);
let proof_acc = if T::is_genesis(self.relation.ctx(), &self.state) {
Accumulator::<S>::trivial(&fixed_bases.keys().cloned().collect::<Vec<_>>())
} else {
let prev_pi = [
AssignedVk::<S>::as_public_input(vk),
T::format_public_input(&self.state),
AssignedAccumulator::<S>::as_public_input(&self.acc),
]
.concat();
let mut transcript =
CircuitTranscript::<PoseidonState<F>>::init_from_bytes(&self.proof);
let dual_msm = plonk::prepare::<
F,
KZGCommitmentScheme<E>,
CircuitTranscript<PoseidonState<F>>,
>(vk, &[&[C::identity()]], &[&[&prev_pi]], &mut transcript)?;
if !dual_msm.clone().check(&self.params.verifier_params()) {
return Err(IvcError::InvalidProof);
}
Accumulator::from_dual_msm(dual_msm, "self_vk", &fixed_bases)
};
let mut next_acc = Accumulator::accumulate(&[proof_acc, self.acc.clone()]);
next_acc.collapse();
let instance = IvcInstance {
vk_repr,
state: next_state.clone(),
acc: next_acc.clone(),
};
let witness = IvcWitness {
prev_state: self.state.clone(),
prev_acc: self.acc.clone(),
prev_proof: self.proof.clone(),
transition_witness,
};
let proof = midnight_zk_stdlib::prove::<IvcCircuit<T>, PoseidonState<F>>(
&self.params,
&self.pk,
&self.relation,
&instance,
witness,
OsRng,
)?;
self.state = next_state;
self.proof = proof.clone();
self.acc = next_acc;
Ok(proof)
}
pub fn instance(&self) -> IvcInstance<T> {
IvcInstance {
vk_repr: self.pk.pk().get_vk().transcript_repr(),
state: self.state.clone(),
acc: self.acc.clone(),
}
}
}