use derive_where::derive_where;
use slop_algebra::{PrimeField32, TwoAdicField};
use slop_basefold::FriConfig;
use slop_challenger::IopCtx;
use serde::{Deserialize, Serialize};
use slop_multilinear::MultilinearPcsVerifier;
use sp1_primitives::{SP1GlobalContext, SP1OuterGlobalContext};
use thiserror::Error;
use crate::{
prover::{CoreProofShape, PcsProof, ZerocheckAir},
Machine, SP1Pcs, ShardVerifierConfigError,
};
use super::{MachineVerifyingKey, ShardProof, ShardVerifier, ShardVerifierError};
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound(
serialize = "PcsProof: Serialize, GC::Challenger: Serialize",
deserialize = "PcsProof: Deserialize<'de>, GC::Challenger: Deserialize<'de>"
))]
pub struct MachineProof<GC: IopCtx, PcsProof> {
pub shard_proofs: Vec<ShardProof<GC, PcsProof>>,
}
impl<GC: IopCtx, C> From<Vec<ShardProof<GC, C>>> for MachineProof<GC, C> {
fn from(shard_proofs: Vec<ShardProof<GC, C>>) -> Self {
Self { shard_proofs }
}
}
pub trait ShardContext<GC: IopCtx>: 'static + Send + Sync {
type Config: MultilinearPcsVerifier<GC>;
type Air: ZerocheckAir<GC::F, GC::EF>;
}
pub struct ShardContextImpl<GC: IopCtx, Verifier, A>
where
Verifier: MultilinearPcsVerifier<GC>,
A: ZerocheckAir<GC::F, GC::EF>,
{
_marker: std::marker::PhantomData<(GC, Verifier, A)>,
}
pub type SP1SC<GC, A> = ShardContextImpl<GC, SP1Pcs<GC>, A>;
pub type InnerSC<A> = SP1SC<SP1GlobalContext, A>;
pub type OuterSC<A> = SP1SC<SP1OuterGlobalContext, A>;
impl<GC: IopCtx, Verifier, A> ShardContext<GC> for ShardContextImpl<GC, Verifier, A>
where
Verifier: MultilinearPcsVerifier<GC>,
A: ZerocheckAir<GC::F, GC::EF>,
{
type Config = Verifier;
type Air = A;
}
#[derive(Debug, Error)]
pub enum MachineVerifierError<EF, PcsError> {
#[error("invalid shard proof: {0}")]
InvalidShardProof(#[from] ShardVerifierError<EF, PcsError>),
#[error("invalid public values: {0}")]
InvalidPublicValues(&'static str),
#[error("too many shards")]
TooManyShards,
#[error("invalid verification key")]
InvalidVerificationKey,
#[error("verification key not initialized")]
UninitializedVerificationKey,
#[error("empty proof")]
EmptyProof,
}
pub type MachineVerifierConfigError<GC, C> =
MachineVerifierError<<GC as IopCtx>::EF, <C as MultilinearPcsVerifier<GC>>::VerifierError>;
#[derive_where(Clone)]
pub struct MachineVerifier<GC: IopCtx, SC: ShardContext<GC>> {
shard_verifier: ShardVerifier<GC, SC>,
}
impl<GC: IopCtx, SC: ShardContext<GC>> MachineVerifier<GC, SC> {
pub fn new(shard_verifier: ShardVerifier<GC, SC>) -> Self {
Self { shard_verifier }
}
pub fn challenger(&self) -> GC::Challenger {
self.shard_verifier.challenger()
}
pub fn machine(&self) -> &Machine<GC::F, SC::Air> {
&self.shard_verifier.machine
}
pub fn max_log_row_count(&self) -> usize {
self.shard_verifier.jagged_pcs_verifier.max_log_row_count
}
#[must_use]
#[inline]
pub fn log_stacking_height(&self) -> u32 {
self.shard_verifier.log_stacking_height()
}
pub fn shape_from_proof(
&self,
proof: &ShardProof<GC, PcsProof<GC, SC>>,
) -> CoreProofShape<GC::F, SC::Air> {
self.shard_verifier.shape_from_proof(proof)
}
#[must_use]
#[inline]
pub fn shard_verifier(&self) -> &ShardVerifier<GC, SC> {
&self.shard_verifier
}
}
impl<GC: IopCtx, SC: ShardContext<GC>> MachineVerifier<GC, SC>
where
GC::F: PrimeField32,
{
pub fn verify(
&self,
vk: &MachineVerifyingKey<GC>,
proof: &MachineProof<GC, PcsProof<GC, SC>>,
) -> Result<(), MachineVerifierConfigError<GC, SC::Config>>
where {
let mut challenger = self.challenger();
vk.observe_into(&mut challenger);
for (i, shard_proof) in proof.shard_proofs.iter().enumerate() {
let mut challenger = challenger.clone();
let span = tracing::debug_span!("verify shard", i).entered();
self.verify_shard(vk, shard_proof, &mut challenger)
.map_err(MachineVerifierError::InvalidShardProof)?;
span.exit();
}
Ok(())
}
pub fn verify_shard(
&self,
vk: &MachineVerifyingKey<GC>,
proof: &ShardProof<GC, PcsProof<GC, SC>>,
challenger: &mut GC::Challenger,
) -> Result<(), ShardVerifierConfigError<GC, SC::Config>>
where {
self.shard_verifier.verify_shard(vk, proof, challenger)
}
}
impl<GC: IopCtx, SC: ShardContext<GC, Config = SP1Pcs<GC>>> MachineVerifier<GC, SC>
where
GC::F: TwoAdicField,
GC::EF: TwoAdicField,
{
#[must_use]
#[inline]
pub fn fri_config(&self) -> &FriConfig<GC::F> {
&self.shard_verifier.jagged_pcs_verifier.pcs_verifier.basefold_verifier.fri_config
}
}