Skip to main content

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