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}