1use std::borrow::Borrow;
6
7use anyhow::Result;
8use itertools::Itertools;
9use p3_field::PrimeField32;
10use sp1_core_executor::{ExecutionReport, SP1Context};
11use sp1_core_machine::io::SP1Stdin;
12use sp1_primitives::io::SP1PublicValues;
13use sp1_prover::{
14 components::SP1ProverComponents, CoreSC, InnerSC, SP1CoreProofData, SP1Prover, SP1ProvingKey,
15 SP1VerifyingKey, SP1_CIRCUIT_VERSION,
16};
17use sp1_stark::{air::PublicValues, MachineVerificationError, Word};
18use thiserror::Error;
19
20use crate::{
21 install::try_install_circuit_artifacts, SP1Proof, SP1ProofMode, SP1ProofWithPublicValues,
22};
23
24pub trait Prover<C: SP1ProverComponents>: Send + Sync {
26 fn inner(&self) -> &SP1Prover<C>;
28
29 fn version(&self) -> &str {
31 SP1_CIRCUIT_VERSION
32 }
33
34 fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey);
36
37 fn execute(&self, elf: &[u8], stdin: &SP1Stdin) -> Result<(SP1PublicValues, ExecutionReport)> {
39 let (pv, _, report) = self.inner().execute(elf, stdin, SP1Context::default())?;
40 Ok((pv, report))
41 }
42
43 fn prove(
45 &self,
46 pk: &SP1ProvingKey,
47 stdin: &SP1Stdin,
48 mode: SP1ProofMode,
49 ) -> Result<SP1ProofWithPublicValues>;
50
51 fn verify(
55 &self,
56 bundle: &SP1ProofWithPublicValues,
57 vkey: &SP1VerifyingKey,
58 ) -> Result<(), SP1VerificationError> {
59 verify_proof(self.inner(), self.version(), bundle, vkey)
60 }
61}
62
63#[derive(Error, Debug)]
65pub enum SP1VerificationError {
66 #[error("Invalid public values")]
68 InvalidPublicValues,
69 #[error("Version mismatch")]
71 VersionMismatch(String),
72 #[error("Core machine verification error: {0}")]
74 Core(MachineVerificationError<CoreSC>),
75 #[error("Recursion verification error: {0}")]
77 Recursion(MachineVerificationError<InnerSC>),
78 #[error("Plonk verification error: {0}")]
80 Plonk(anyhow::Error),
81 #[error("Groth16 verification error: {0}")]
83 Groth16(anyhow::Error),
84 #[error("Unexpected error: {0:?}")]
86 Other(anyhow::Error),
87}
88
89pub(crate) fn verify_proof<C: SP1ProverComponents>(
99 prover: &SP1Prover<C>,
100 version: &str,
101 bundle: &SP1ProofWithPublicValues,
102 vkey: &SP1VerifyingKey,
103) -> Result<(), SP1VerificationError> {
104 if bundle.sp1_version != version {
106 return Err(SP1VerificationError::VersionMismatch(bundle.sp1_version.clone()));
107 }
108
109 match &bundle.proof {
110 SP1Proof::Core(proof) => {
111 let public_values: &PublicValues<Word<_>, _> =
112 proof.last().unwrap().public_values.as_slice().borrow();
113
114 let committed_value_digest_bytes = public_values
116 .committed_value_digest
117 .iter()
118 .flat_map(|w| w.0.iter().map(|x| x.as_canonical_u32() as u8))
119 .collect_vec();
120
121 if committed_value_digest_bytes != bundle.public_values.hash() &&
125 committed_value_digest_bytes != bundle.public_values.blake3_hash()
126 {
127 return Err(SP1VerificationError::InvalidPublicValues);
128 }
129
130 prover
132 .verify(&SP1CoreProofData(proof.clone()), vkey)
133 .map_err(SP1VerificationError::Core)
134 }
135 SP1Proof::Compressed(proof) => {
136 let public_values: &PublicValues<Word<_>, _> =
137 proof.proof.public_values.as_slice().borrow();
138
139 let committed_value_digest_bytes = public_values
141 .committed_value_digest
142 .iter()
143 .flat_map(|w| w.0.iter().map(|x| x.as_canonical_u32() as u8))
144 .collect_vec();
145
146 if committed_value_digest_bytes != bundle.public_values.hash() &&
150 committed_value_digest_bytes != bundle.public_values.blake3_hash()
151 {
152 return Err(SP1VerificationError::InvalidPublicValues);
153 }
154
155 prover.verify_compressed(proof, vkey).map_err(SP1VerificationError::Recursion)
156 }
157 SP1Proof::Plonk(proof) => prover
158 .verify_plonk_bn254(
159 proof,
160 vkey,
161 &bundle.public_values,
162 &if sp1_prover::build::sp1_dev_mode() {
163 sp1_prover::build::plonk_bn254_artifacts_dev_dir()
164 } else {
165 try_install_circuit_artifacts("plonk")
166 },
167 )
168 .map_err(SP1VerificationError::Plonk),
169 SP1Proof::Groth16(proof) => prover
170 .verify_groth16_bn254(
171 proof,
172 vkey,
173 &bundle.public_values,
174 &if sp1_prover::build::sp1_dev_mode() {
175 sp1_prover::build::groth16_bn254_artifacts_dev_dir()
176 } else {
177 try_install_circuit_artifacts("groth16")
178 },
179 )
180 .map_err(SP1VerificationError::Groth16),
181 }
182}