Skip to main content

sp1_hypercube/verifier/
machine.rs

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/// A complete proof of program execution.
18#[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    /// The shard proofs.
25    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
34/// A shortcut trait to package a multilinear PCS verifier and a zerocheck AIR. Reduces number of
35/// generic parameters in the `MachineVerifier` type and `AirProver` trait.
36pub trait ShardContext<GC: IopCtx>: 'static + Send + Sync {
37    /// The multilinear PCS verifier.
38    type Config: MultilinearPcsVerifier<GC>;
39    /// The AIR for which we'll be proving zerocheck.
40    type Air: ZerocheckAir<GC::F, GC::EF>;
41}
42
43/// The canonical type implementing `ShardContext`.
44pub 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}
51/// A type alias assuming `SP1Pcs` (stacked Basefold) as the PCS verifier, generic in the `IopCtx`
52/// and the AIR.
53pub type SP1SC<GC, A> = ShardContextImpl<GC, SP1Pcs<GC>, A>;
54
55/// A type alias for the shard contexts used in all stages of SP1 proving except wrap. Generic only
56/// in the AIR (allowing this SC to be used for the Risc-V and the recursion AIRs).
57pub type InnerSC<A> = SP1SC<SP1GlobalContext, A>;
58
59/// A type alias for the shard contexts used in the outer (wrap) stage of SP1 proving. Generic only
60/// in the AIR.
61pub 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/// An error that occurs during the verification of a machine proof.
73#[derive(Debug, Error)]
74pub enum MachineVerifierError<EF, PcsError> {
75    /// An error that occurs during the verification of a shard proof.
76    #[error("invalid shard proof: {0}")]
77    InvalidShardProof(#[from] ShardVerifierError<EF, PcsError>),
78    /// The public values are invalid
79    #[error("invalid public values: {0}")]
80    InvalidPublicValues(&'static str),
81    /// There are too many shards.
82    #[error("too many shards")]
83    TooManyShards,
84    /// Invalid verification key.
85    #[error("invalid verification key")]
86    InvalidVerificationKey,
87    /// Verification key not initialized.
88    #[error("verification key not initialized")]
89    UninitializedVerificationKey,
90    /// Empty proof.
91    #[error("empty proof")]
92    EmptyProof,
93}
94
95/// Derive the error type from the machine config.
96pub type MachineVerifierConfigError<GC, C> =
97    MachineVerifierError<<GC as IopCtx>::EF, <C as MultilinearPcsVerifier<GC>>::VerifierError>;
98
99/// A verifier for a machine proof.
100#[derive_where(Clone)]
101pub struct MachineVerifier<GC: IopCtx, SC: ShardContext<GC>> {
102    /// Shard proof verifier.
103    shard_verifier: ShardVerifier<GC, SC>,
104}
105
106impl<GC: IopCtx, SC: ShardContext<GC>> MachineVerifier<GC, SC> {
107    /// Create a new machine verifier.
108    pub fn new(shard_verifier: ShardVerifier<GC, SC>) -> Self {
109        Self { shard_verifier }
110    }
111
112    /// Get a new challenger.
113    pub fn challenger(&self) -> GC::Challenger {
114        self.shard_verifier.challenger()
115    }
116
117    /// Get the machine.
118    pub fn machine(&self) -> &Machine<GC::F, SC::Air> {
119        &self.shard_verifier.machine
120    }
121
122    /// Get the maximum log row count.
123    pub fn max_log_row_count(&self) -> usize {
124        self.shard_verifier.jagged_pcs_verifier.max_log_row_count
125    }
126
127    /// Get the log stacking height.
128    #[must_use]
129    #[inline]
130    pub fn log_stacking_height(&self) -> u32 {
131        self.shard_verifier.log_stacking_height()
132    }
133
134    /// Get the shape of a shard proof.
135    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    /// Get the shard verifier.
143    #[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    /// Verify the machine proof.
155    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        // Observe the verifying key.
163        vk.observe_into(&mut challenger);
164
165        // Verify the shard proofs.
166        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    /// Verify a shard proof.
178    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    /// Get the FRI config.
195    #[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}