1use derive_where::derive_where;
2use slop_algebra::{PrimeField32, TwoAdicField};
3use slop_basefold::FriConfig;
4use slop_challenger::IopCtx;
5
6use serde::{Deserialize, Serialize};
7use slop_multilinear::MultilinearPcsVerifier;
8use sp1_primitives::{SP1GlobalContext, SP1OuterGlobalContext};
9use thiserror::Error;
10
11use crate::{
12 prover::{CoreProofShape, PcsProof, ZerocheckAir},
13 Machine, SP1Pcs, ShardVerifierConfigError,
14};
15
16use super::{MachineVerifyingKey, ShardProof, ShardVerifier, ShardVerifierError};
17#[derive(Clone, Serialize, Deserialize)]
19#[serde(bound(
20 serialize = "PcsProof: Serialize, GC::Challenger: Serialize",
21 deserialize = "PcsProof: Deserialize<'de>, GC::Challenger: Deserialize<'de>"
22))]
23pub struct MachineProof<GC: IopCtx, PcsProof> {
24 pub shard_proofs: Vec<ShardProof<GC, PcsProof>>,
26}
27
28impl<GC: IopCtx, C> From<Vec<ShardProof<GC, C>>> for MachineProof<GC, C> {
29 fn from(shard_proofs: Vec<ShardProof<GC, C>>) -> Self {
30 Self { shard_proofs }
31 }
32}
33
34pub trait ShardContext<GC: IopCtx>: 'static + Send + Sync {
37 type Config: MultilinearPcsVerifier<GC>;
39 type Air: ZerocheckAir<GC::F, GC::EF>;
41}
42
43pub struct ShardContextImpl<GC: IopCtx, Verifier, A>
45where
46 Verifier: MultilinearPcsVerifier<GC>,
47 A: ZerocheckAir<GC::F, GC::EF>,
48{
49 _marker: std::marker::PhantomData<(GC, Verifier, A)>,
50}
51pub type SP1SC<GC, A> = ShardContextImpl<GC, SP1Pcs<GC>, A>;
54
55pub type InnerSC<A> = SP1SC<SP1GlobalContext, A>;
58
59pub type OuterSC<A> = SP1SC<SP1OuterGlobalContext, A>;
62
63impl<GC: IopCtx, Verifier, A> ShardContext<GC> for ShardContextImpl<GC, Verifier, A>
64where
65 Verifier: MultilinearPcsVerifier<GC>,
66 A: ZerocheckAir<GC::F, GC::EF>,
67{
68 type Config = Verifier;
69 type Air = A;
70}
71
72#[derive(Debug, Error)]
74pub enum MachineVerifierError<EF, PcsError> {
75 #[error("invalid shard proof: {0}")]
77 InvalidShardProof(#[from] ShardVerifierError<EF, PcsError>),
78 #[error("invalid public values: {0}")]
80 InvalidPublicValues(&'static str),
81 #[error("too many shards")]
83 TooManyShards,
84 #[error("invalid verification key")]
86 InvalidVerificationKey,
87 #[error("verification key not initialized")]
89 UninitializedVerificationKey,
90 #[error("empty proof")]
92 EmptyProof,
93}
94
95pub type MachineVerifierConfigError<GC, C> =
97 MachineVerifierError<<GC as IopCtx>::EF, <C as MultilinearPcsVerifier<GC>>::VerifierError>;
98
99#[derive_where(Clone)]
101pub struct MachineVerifier<GC: IopCtx, SC: ShardContext<GC>> {
102 shard_verifier: ShardVerifier<GC, SC>,
104}
105
106impl<GC: IopCtx, SC: ShardContext<GC>> MachineVerifier<GC, SC> {
107 pub fn new(shard_verifier: ShardVerifier<GC, SC>) -> Self {
109 Self { shard_verifier }
110 }
111
112 pub fn challenger(&self) -> GC::Challenger {
114 self.shard_verifier.challenger()
115 }
116
117 pub fn machine(&self) -> &Machine<GC::F, SC::Air> {
119 &self.shard_verifier.machine
120 }
121
122 pub fn max_log_row_count(&self) -> usize {
124 self.shard_verifier.jagged_pcs_verifier.max_log_row_count
125 }
126
127 #[must_use]
129 #[inline]
130 pub fn log_stacking_height(&self) -> u32 {
131 self.shard_verifier.log_stacking_height()
132 }
133
134 pub fn shape_from_proof(
136 &self,
137 proof: &ShardProof<GC, PcsProof<GC, SC>>,
138 ) -> CoreProofShape<GC::F, SC::Air> {
139 self.shard_verifier.shape_from_proof(proof)
140 }
141
142 #[must_use]
144 #[inline]
145 pub fn shard_verifier(&self) -> &ShardVerifier<GC, SC> {
146 &self.shard_verifier
147 }
148}
149
150impl<GC: IopCtx, SC: ShardContext<GC>> MachineVerifier<GC, SC>
151where
152 GC::F: PrimeField32,
153{
154 pub fn verify(
156 &self,
157 vk: &MachineVerifyingKey<GC>,
158 proof: &MachineProof<GC, PcsProof<GC, SC>>,
159 ) -> Result<(), MachineVerifierConfigError<GC, SC::Config>>
160where {
161 let mut challenger = self.challenger();
162 vk.observe_into(&mut challenger);
164
165 for (i, shard_proof) in proof.shard_proofs.iter().enumerate() {
167 let mut challenger = challenger.clone();
168 let span = tracing::debug_span!("verify shard", i).entered();
169 self.verify_shard(vk, shard_proof, &mut challenger)
170 .map_err(MachineVerifierError::InvalidShardProof)?;
171 span.exit();
172 }
173
174 Ok(())
175 }
176
177 pub fn verify_shard(
179 &self,
180 vk: &MachineVerifyingKey<GC>,
181 proof: &ShardProof<GC, PcsProof<GC, SC>>,
182 challenger: &mut GC::Challenger,
183 ) -> Result<(), ShardVerifierConfigError<GC, SC::Config>>
184where {
185 self.shard_verifier.verify_shard(vk, proof, challenger)
186 }
187}
188
189impl<GC: IopCtx, SC: ShardContext<GC, Config = SP1Pcs<GC>>> MachineVerifier<GC, SC>
190where
191 GC::F: TwoAdicField,
192 GC::EF: TwoAdicField,
193{
194 #[must_use]
196 #[inline]
197 pub fn fri_config(&self) -> &FriConfig<GC::F> {
198 &self.shard_verifier.jagged_pcs_verifier.pcs_verifier.basefold_verifier.fri_config
199 }
200}