Skip to main content

sp1_verifier/compressed/
mod.rs

1// TODO: After finalizing vkeys, decide on a vkey verification solution. Then, clean up the
2// constants and error enum in this file and update sp1_prover::tests::sp1_verifier_valid.
3
4use alloc::boxed::Box;
5
6use sp1_hypercube::{MachineVerifierConfigError, SP1InnerPcs, VcsError};
7use sp1_primitives::{SP1Field, SP1GlobalContext};
8use strum::IntoDiscriminant;
9use thiserror::Error;
10
11// NOTE: that all these constants and types are checked by sp1_prover::tests::sp1_verifier_valid.
12// If you add a new proof, you MUST add to the test in that crate.
13
14mod config;
15mod internal;
16
17use crate::{SP1Proof, SP1ProofMode};
18
19pub use self::internal::SP1CompressedVerifier;
20pub use config::{RECURSION_LOG_STACKING_HEIGHT, RECURSION_MAX_LOG_ROW_COUNT};
21
22/// A reason why the verifier rejects a given proof.
23#[derive(Debug, Error)]
24#[non_exhaustive]
25pub enum CompressedError {
26    #[error("invalid proof type")]
27    InvalidProofType(SP1ProofMode),
28    #[error("failed to deserialize proof: {0}")]
29    DeserializeProof(Box<bincode::ErrorKind>),
30    #[error("failed to deserialize vkey hash: {0}")]
31    DeserializeVkeyHash(Box<bincode::ErrorKind>),
32    #[error("failed to verify proof: {0}")]
33    ProofRejected(#[from] MachineVerifierConfigError<SP1GlobalContext, SP1InnerPcs>),
34    #[error("given public values do not match the commitment in the proof")]
35    PublicValuesMismatch,
36    #[error("incorrect vkey")]
37    InvalidVkey(VcsError),
38}
39
40/// A verifier for SP1 "compressed" proofs given as raw bytes.
41///
42/// This struct priovides a convenient interface for verifying compressed proofs given as raw bytes.
43/// If possible, it's usually better to use the [SP1CompressedVerifier] struct instead.
44#[derive(Debug)]
45pub struct SP1CompressedVerifierRaw;
46
47impl SP1CompressedVerifierRaw {
48    /// Attempts to verify an SP1 "compressed" proof, as generated by the SP1 SDK.
49    /// Returns `Ok` if the proof verifies or `Err` with the reason that verification failed.
50    ///
51    /// Due to technical limitations, this verifier rejects single-shard proofs, which roughly means
52    /// proofs that come from very short programs. In this case, the verifier returns
53    /// `Err(CompressedError::SingleShard)`.
54    ///
55    /// # Arguments
56    ///
57    /// * `proof` - The proof bytes.
58    /// * `sp1_vkey_hash` - The SP1 vkey hash.
59    ///
60    /// The arguments may be generated in the following manner:
61    ///
62    /// ```ignore
63    /// use sp1_sdk::{HashableKey, ProverClient, SP1Proof};
64    /// let client = ProverClient::builder().cpu().build();
65    /// let (pk, vk) = client.setup(ELF);
66    /// let sp1_vkey_hash = bincode::serialize(&vk.hash_babybear()).unwrap();
67    /// let proof = match client.prove(&pk, &stdin).compressed().run().unwrap().proof {
68    ///     SP1Proof::Compressed(proof) => bincode::serialize(&proof),
69    ///     _ => unreachable!("expected compressed proof"),
70    /// };
71    /// ```
72    pub fn verify_with_public_values(
73        proof: &[u8],
74        sp1_public_inputs: &[u8],
75        sp1_vkey_hash: &[u8],
76    ) -> Result<(), CompressedError> {
77        let recursion_proof: SP1Proof =
78            bincode::deserialize(proof).map_err(CompressedError::DeserializeProof)?;
79        let vkey_hash: [SP1Field; 8] =
80            bincode::deserialize(sp1_vkey_hash).map_err(CompressedError::DeserializeVkeyHash)?;
81
82        let verifier = SP1CompressedVerifier::new();
83
84        if let SP1Proof::Compressed(proof) = recursion_proof {
85            verifier.verify_compressed_with_public_values(&proof, sp1_public_inputs, &vkey_hash)?;
86        } else {
87            return Err(CompressedError::InvalidProofType(recursion_proof.discriminant()));
88        }
89
90        Ok(())
91    }
92
93    /// Attempts to verify an SP1 "compressed" proof, as generated by the SP1 SDK.
94    /// Returns `Ok` if the proof verifies or `Err` with the reason that verification failed.
95    ///
96    /// Due to technical limitations, this verifier rejects single-shard proofs, which roughly means
97    /// proofs that come from very short programs. In this case, the verifier returns
98    /// `Err(CompressedError::SingleShard)`.
99    ///
100    /// # Arguments
101    ///
102    /// * `proof` - The proof bytes.
103    /// * `sp1_vkey_hash` - The SP1 vkey hash.
104    ///
105    /// The arguments may be generated in the following manner:
106    ///
107    /// ```ignore
108    /// use sp1_sdk::{HashableKey, ProverClient, SP1Proof};
109    /// let client = ProverClient::builder().cpu().build();
110    /// let (pk, vk) = client.setup(ELF);
111    /// let sp1_vkey_hash = bincode::serialize(&vk.hash_babybear()).unwrap();
112    /// let proof = match client.prove(&pk, &stdin).compressed().run().unwrap().proof {
113    ///     SP1Proof::Compressed(proof) => bincode::serialize(&proof),
114    ///     _ => unreachable!("expected compressed proof"),
115    /// };
116    /// ```
117    pub fn verify(proof: &[u8], sp1_vkey_hash: &[u8]) -> Result<(), CompressedError> {
118        let recursion_proof: SP1Proof =
119            bincode::deserialize(proof).map_err(CompressedError::DeserializeProof)?;
120        let vkey_hash: [SP1Field; 8] =
121            bincode::deserialize(sp1_vkey_hash).map_err(CompressedError::DeserializeVkeyHash)?;
122
123        let verifier = SP1CompressedVerifier::new();
124
125        if let SP1Proof::Compressed(proof) = recursion_proof {
126            verifier.verify_compressed(&proof, &vkey_hash)?;
127        } else {
128            return Err(CompressedError::InvalidProofType(recursion_proof.discriminant()));
129        }
130
131        Ok(())
132    }
133}