Skip to main content

sp1_sdk/blocking/env/
mod.rs

1//! # SP1 Environment Prover
2//!
3//! A prover that can execute programs and generate proofs with a different implementation based on
4//! the value of the `SP1_PROVER` environment variable.
5
6#[cfg(feature = "network")]
7use crate::blocking::NetworkProver;
8#[cfg(feature = "cuda")]
9use crate::blocking::{cuda::builder::CudaProverBuilder, CudaProver};
10use crate::{
11    blocking::{prover::BaseProveRequest, CpuProver, LightProver, MockProver, Prover},
12    SP1ProofWithPublicValues, SP1VerificationError, StatusCode,
13};
14use sp1_core_executor::SP1CoreOpts;
15
16pub mod pk;
17/// The module that defines the prove request for the [`EnvProver`].
18pub mod prove;
19pub use pk::EnvProvingKey;
20use prove::EnvProveRequest;
21use sp1_core_machine::io::SP1Stdin;
22use sp1_core_machine::riscv::RiscvAir;
23use sp1_hypercube::Machine;
24use sp1_primitives::{Elf, SP1Field};
25use sp1_prover::{worker::SP1NodeCore, SP1VerifyingKey};
26
27/// A prover that can execute programs and generate proofs with a different implementation based on
28/// the value of the `SP1_PROVER` environment variable.
29#[derive(Clone)]
30pub enum EnvProver {
31    /// A mock prover that does not prove anything.
32    Mock(MockProver),
33    /// A light prover that only executes and verifies but does not generate proofs.
34    Light(LightProver),
35    /// A CPU prover.
36    Cpu(CpuProver),
37    /// A CUDA prover.
38    #[cfg(feature = "cuda")]
39    Cuda(CudaProver),
40    /// A network prover.
41    #[cfg(feature = "network")]
42    Network(Box<NetworkProver>),
43}
44
45impl Default for EnvProver {
46    fn default() -> Self {
47        Self::new()
48    }
49}
50
51impl EnvProver {
52    /// Creates a new [`EnvProver`] from the environment.
53    ///
54    /// This method will read from the `SP1_PROVER` environment variable to determine which prover
55    /// to use. If the variable is not set, it will default to the CPU prover.
56    ///
57    /// If the prover is a network prover, the `NETWORK_PRIVATE_KEY` variable must be set.
58    #[must_use]
59    pub fn new() -> Self {
60        Self::new_with_machine(RiscvAir::machine())
61    }
62
63    /// Same as [`Self::new`] but with a custom machine.
64    #[must_use]
65    pub fn new_with_machine(machine: Machine<SP1Field, RiscvAir<SP1Field>>) -> Self {
66        Self::from_env_with_opts_and_machine(None, machine)
67    }
68
69    /// Updates the core options for this prover.
70    ///
71    /// This method allows you to configure the prover after creation.
72    /// It recreates the prover with the new options based on the current environment settings.
73    ///
74    /// # Example
75    /// ```rust,no_run
76    /// use sp1_core_executor::SP1CoreOpts;
77    /// use sp1_sdk::blocking::ProverClient;
78    ///
79    /// let mut client = ProverClient::from_env();
80    /// let opts = SP1CoreOpts { shard_size: 500_000, ..Default::default() };
81    /// client = client.with_opts(opts);
82    /// ```
83    #[must_use]
84    pub fn with_opts(self, opts: SP1CoreOpts) -> Self {
85        Self::from_env_with_opts(Some(opts))
86    }
87
88    /// Creates an [`EnvProver`] from the environment with optional custom [`SP1CoreOpts`].
89    ///
90    /// This method will read from the `SP1_PROVER` environment variable to determine which prover
91    /// to use. If the variable is not set, it will default to the CPU prover.
92    ///
93    /// If the prover is a network prover, the `NETWORK_PRIVATE_KEY` variable must be set.
94    #[must_use]
95    pub fn from_env_with_opts(core_opts: Option<SP1CoreOpts>) -> Self {
96        Self::from_env_with_opts_and_machine(core_opts, RiscvAir::machine())
97    }
98
99    /// Same as [`Self::from_env_with_opts`] but with a custom machine.
100    #[must_use]
101    pub fn from_env_with_opts_and_machine(
102        core_opts: Option<SP1CoreOpts>,
103        machine: Machine<SP1Field, RiscvAir<SP1Field>>,
104    ) -> Self {
105        let prover = match std::env::var("SP1_PROVER") {
106            Ok(prover) => prover,
107            Err(_) => "cpu".to_string(),
108        };
109
110        match prover.as_str() {
111            "cpu" => Self::Cpu(CpuProver::new_with_opts_and_machine(core_opts, machine)),
112            #[cfg(feature = "cuda")]
113            "cuda" => Self::Cuda(CudaProverBuilder::new_with_machine(machine).build()),
114            #[cfg(not(feature = "cuda"))]
115            "cuda" => panic!("The CUDA prover requires the `cuda` feature to be enabled"),
116            "mock" => Self::Mock(MockProver::new_with_machine(machine)),
117            "light" => Self::Light(LightProver::new_with_machine(machine)),
118            #[cfg(feature = "network")]
119            "network" => Self::Network(Box::new(
120                crate::blocking::network::builder::NetworkProverBuilder::new_with_machine(machine)
121                    .build(),
122            )),
123            #[cfg(not(feature = "network"))]
124            "network" => panic!("The network prover requires the `network` feature to be enabled"),
125            _ => unreachable!(),
126        }
127    }
128}
129
130impl Prover for EnvProver {
131    type Error = anyhow::Error;
132    type ProvingKey = EnvProvingKey;
133    type ProveRequest<'a> = prove::EnvProveRequest<'a>;
134
135    fn inner(&self) -> &SP1NodeCore {
136        match self {
137            Self::Cpu(prover) => prover.inner(),
138            #[cfg(feature = "cuda")]
139            Self::Cuda(prover) => prover.inner(),
140            Self::Mock(prover) => prover.inner(),
141            Self::Light(prover) => prover.inner(),
142            #[cfg(feature = "network")]
143            Self::Network(prover) => prover.inner(),
144        }
145    }
146    fn setup(&self, elf: Elf) -> Result<Self::ProvingKey, Self::Error> {
147        match self {
148            Self::Cpu(prover) => {
149                let pk = prover.setup(elf)?;
150                Ok(EnvProvingKey::cpu(pk))
151            }
152            #[cfg(feature = "cuda")]
153            Self::Cuda(prover) => {
154                let pk = prover.setup(elf)?;
155                Ok(EnvProvingKey::cuda(pk))
156            }
157            Self::Mock(prover) => {
158                let pk = prover.setup(elf)?;
159                Ok(EnvProvingKey::mock(pk))
160            }
161            Self::Light(prover) => {
162                let pk = prover.setup(elf)?;
163                Ok(EnvProvingKey::light(pk))
164            }
165            #[cfg(feature = "network")]
166            Self::Network(prover) => {
167                let pk = prover.setup(elf)?;
168                Ok(EnvProvingKey::network(pk))
169            }
170        }
171    }
172
173    fn prove<'a>(&'a self, pk: &'a Self::ProvingKey, stdin: SP1Stdin) -> Self::ProveRequest<'a> {
174        EnvProveRequest { base: BaseProveRequest::new(self, pk, stdin) }
175    }
176
177    fn verify(
178        &self,
179        proof: &SP1ProofWithPublicValues,
180        vkey: &SP1VerifyingKey,
181        status_code: Option<StatusCode>,
182    ) -> Result<(), SP1VerificationError> {
183        match self {
184            Self::Cpu(prover) => prover.verify(proof, vkey, status_code),
185            #[cfg(feature = "cuda")]
186            Self::Cuda(prover) => prover.verify(proof, vkey, status_code),
187            Self::Mock(prover) => prover.verify(proof, vkey, status_code),
188            Self::Light(prover) => prover.verify(proof, vkey, status_code),
189            #[cfg(feature = "network")]
190            Self::Network(prover) => prover.verify(proof, vkey, status_code),
191        }
192    }
193}
194
195#[cfg(test)]
196mod tests {
197    use crate::{
198        blocking::{
199            prover::{ProveRequest, Prover},
200            MockProver,
201        },
202        utils::setup_logger,
203        SP1Stdin,
204    };
205
206    use super::EnvProver;
207
208    /// Regression: `EnvProver::Mock(...)` must delegate `verify` to the inner `MockProver`
209    /// for Plonk and Groth16 proofs. Before the dispatch fix, the trait default routed mock
210    /// proofs through the real verifier and failed parsing the formatted BN254 vkey hash
211    /// string with `invalid digit found in string`.
212    #[test]
213    fn test_envprover_mock_verifies_plonk_and_groth16() {
214        setup_logger();
215        let mock = MockProver::new();
216        let pk = mock.setup(test_artifacts::FIBONACCI_ELF).expect("failed to setup proving key");
217
218        let mut stdin = SP1Stdin::new();
219        stdin.write(&10usize);
220        let plonk_proof =
221            mock.prove(&pk, stdin).plonk().run().expect("failed to create mock Plonk proof");
222
223        let mut stdin = SP1Stdin::new();
224        stdin.write(&10usize);
225        let groth16_proof =
226            mock.prove(&pk, stdin).groth16().run().expect("failed to create mock Groth16 proof");
227
228        let env = EnvProver::Mock(mock);
229        env.verify(&plonk_proof, &pk.vk, None)
230            .expect("EnvProver::Mock must verify a mock Plonk proof");
231        env.verify(&groth16_proof, &pk.vk, None)
232            .expect("EnvProver::Mock must verify a mock Groth16 proof");
233    }
234}