sp1_sdk/cpu/
prove.rs

1//! # CPU Proving
2//!
3//! This module provides a builder for proving a program on the CPU.
4
5use anyhow::Result;
6use sp1_core_executor::{IoWriter, SP1ContextBuilder};
7use sp1_core_machine::io::SP1Stdin;
8use sp1_prover::SP1ProvingKey;
9use sp1_stark::{SP1CoreOpts, SP1ProverOpts};
10
11use super::CpuProver;
12use crate::{SP1ProofMode, SP1ProofWithPublicValues};
13
14/// A builder for proving a program on the CPU.
15///
16/// This builder provides a typed interface for configuring the SP1 RISC-V prover. The builder is
17/// used for only the [`crate::cpu::CpuProver`] client type.
18pub struct CpuProveBuilder<'a> {
19    pub(crate) prover: &'a CpuProver,
20    pub(crate) mode: SP1ProofMode,
21    pub(crate) context_builder: SP1ContextBuilder<'a>,
22    pub(crate) pk: &'a SP1ProvingKey,
23    pub(crate) stdin: SP1Stdin,
24    pub(crate) core_opts: SP1CoreOpts,
25    pub(crate) recursion_opts: SP1CoreOpts,
26    pub(crate) mock: bool,
27}
28
29impl<'a> CpuProveBuilder<'a> {
30    /// Set the proof kind to [`SP1ProofKind::Core`] mode.
31    ///
32    /// # Details
33    /// This is the default mode for the prover. The proofs grow linearly in size with the number
34    /// of cycles.
35    ///
36    /// # Example
37    /// ```rust,no_run
38    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
39    ///
40    /// let elf = &[1, 2, 3];
41    /// let stdin = SP1Stdin::new();
42    ///
43    /// let client = ProverClient::builder().cpu().build();
44    /// let (pk, vk) = client.setup(elf);
45    /// let builder = client.prove(&pk, &stdin).core().run();
46    /// ```
47    #[must_use]
48    pub fn core(mut self) -> Self {
49        self.mode = SP1ProofMode::Core;
50        self
51    }
52
53    /// Set the proof kind to [`SP1ProofKind::Compressed`] mode.
54    ///
55    /// # Details
56    /// This mode produces a proof that is of constant size, regardless of the number of cycles. It
57    /// takes longer to prove than [`SP1ProofKind::Core`] due to the need to recursively aggregate
58    /// proofs into a single proof.
59    ///
60    /// # Example
61    /// ```rust,no_run
62    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
63    ///
64    /// let elf = &[1, 2, 3];
65    /// let stdin = SP1Stdin::new();
66    ///
67    /// let client = ProverClient::builder().cpu().build();
68    /// let (pk, vk) = client.setup(elf);
69    /// let builder = client.prove(&pk, &stdin).compressed().run();
70    /// ```
71    #[must_use]
72    pub fn compressed(mut self) -> Self {
73        self.mode = SP1ProofMode::Compressed;
74        self
75    }
76
77    /// Set the proof mode to [`SP1ProofKind::Plonk`] mode.
78    ///
79    /// # Details
80    /// This mode produces a const size PLONK proof that can be verified on chain for roughly ~300k
81    /// gas. This mode is useful for producing a maximally small proof that can be verified on
82    /// chain. For more efficient SNARK wrapping, you can use the [`SP1ProofKind::Groth16`] mode but
83    /// this mode is more .
84    ///
85    /// # Example
86    /// ```rust,no_run
87    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
88    ///
89    /// let elf = &[1, 2, 3];
90    /// let stdin = SP1Stdin::new();
91    ///
92    /// let client = ProverClient::builder().cpu().build();
93    /// let (pk, vk) = client.setup(elf);
94    /// let builder = client.prove(&pk, &stdin).plonk().run();
95    /// ```
96    #[must_use]
97    pub fn plonk(mut self) -> Self {
98        self.mode = SP1ProofMode::Plonk;
99        self
100    }
101
102    /// Set the proof mode to [`SP1ProofKind::Groth16`] mode.
103    ///
104    /// # Details
105    /// This mode produces a Groth16 proof that can be verified on chain for roughly ~100k gas. This
106    /// mode is useful for producing a proof that can be verified on chain with minimal gas.
107    ///
108    /// # Example
109    /// ```rust,no_run
110    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
111    ///
112    /// let elf = &[1, 2, 3];
113    /// let stdin = SP1Stdin::new();
114    ///
115    /// let client = ProverClient::builder().cpu().build();
116    /// let (pk, vk) = client.setup(elf);
117    /// let builder = client.prove(&pk, &stdin).groth16().run();
118    /// ```
119    #[must_use]
120    pub fn groth16(mut self) -> Self {
121        self.mode = SP1ProofMode::Groth16;
122        self
123    }
124
125    /// Set the proof mode to the given [`SP1ProofKind`].
126    ///
127    /// # Details
128    /// This method is useful for setting the proof mode to a custom mode.
129    ///
130    /// # Example
131    /// ```rust,no_run
132    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1ProofMode, SP1Stdin};
133    ///
134    /// let elf = &[1, 2, 3];
135    /// let stdin = SP1Stdin::new();
136    ///
137    /// let client = ProverClient::builder().cpu().build();
138    /// let (pk, vk) = client.setup(elf);
139    /// let builder = client.prove(&pk, &stdin).mode(SP1ProofMode::Groth16).run();
140    /// ```
141    #[must_use]
142    pub fn mode(mut self, mode: SP1ProofMode) -> Self {
143        self.mode = mode;
144        self
145    }
146
147    /// Set the shard size for proving.
148    ///
149    /// # Details
150    /// The value should be 2^16, 2^17, ..., 2^22. You must be careful to set this value
151    /// correctly, as it will affect the memory usage of the prover and the recursion/verification
152    /// complexity. By default, the value is set to some predefined values that are optimized for
153    /// performance based on the available amount of RAM on the system.
154    ///
155    /// # Example
156    /// ```rust,no_run
157    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
158    ///
159    /// let elf = &[1, 2, 3];
160    /// let stdin = SP1Stdin::new();
161    ///
162    /// let client = ProverClient::builder().cpu().build();
163    /// let (pk, vk) = client.setup(elf);
164    /// let builder = client.prove(&pk, &stdin).shard_size(1 << 16).run();
165    /// ```
166    #[must_use]
167    pub fn shard_size(mut self, value: usize) -> Self {
168        assert!(value.is_power_of_two(), "shard size must be a power of 2");
169        self.core_opts.shard_size = value;
170        self
171    }
172
173    /// Set the shard batch size for proving.
174    ///
175    /// # Details
176    /// This is the number of shards that are processed in a single batch in the prover. You should
177    /// probably not change this value unless you know what you are doing.
178    ///
179    /// # Example
180    /// ```rust,no_run
181    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
182    ///
183    /// let elf = &[1, 2, 3];
184    /// let stdin = SP1Stdin::new();
185    ///
186    /// let client = ProverClient::builder().cpu().build();
187    /// let (pk, vk) = client.setup(elf);
188    /// let builder = client.prove(&pk, &stdin).shard_batch_size(4).run();
189    /// ```
190    #[must_use]
191    pub fn shard_batch_size(mut self, value: usize) -> Self {
192        self.core_opts.shard_batch_size = value;
193        self
194    }
195
196    /// Set the maximum number of cpu cycles to use for execution.
197    ///
198    /// # Details
199    /// If the cycle limit is exceeded, execution will return
200    /// [`sp1_core_executor::ExecutionError::ExceededCycleLimit`].
201    ///
202    /// # Example
203    /// ```rust,no_run
204    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
205    ///
206    /// let elf = &[1, 2, 3];
207    /// let stdin = SP1Stdin::new();
208    ///
209    /// let client = ProverClient::builder().cpu().build();
210    /// let (pk, vk) = client.setup(elf);
211    /// let builder = client.prove(&pk, &stdin).cycle_limit(1000000).run();
212    /// ```
213    #[must_use]
214    pub fn cycle_limit(mut self, cycle_limit: u64) -> Self {
215        self.context_builder.max_cycles(cycle_limit);
216        self
217    }
218
219    /// Whether to enable deferred proof verification in the executor.
220    ///
221    /// # Arguments
222    /// * `value` - Whether to enable deferred proof verification in the executor.
223    ///
224    /// # Details
225    /// Default: `true`. If set to `false`, the executor will skip deferred proof verification.
226    /// This is useful for reducing the execution time of the program and optimistically assuming
227    /// that the deferred proofs are correct. Can also be used for mock proof setups that require
228    /// verifying mock compressed proofs.
229    ///
230    /// # Example
231    /// ```rust,no_run
232    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
233    ///
234    /// let elf = &[1, 2, 3];
235    /// let stdin = SP1Stdin::new();
236    ///
237    /// let client = ProverClient::builder().cpu().build();
238    /// let (pk, vk) = client.setup(elf);
239    /// let builder = client.prove(&pk, &stdin).deferred_proof_verification(false).run();
240    /// ```
241    #[must_use]
242    pub fn deferred_proof_verification(mut self, value: bool) -> Self {
243        self.context_builder.set_deferred_proof_verification(value);
244        self
245    }
246
247    /// Override the default stdout of the guest program.
248    ///
249    /// # Example
250    /// ```rust,no_run
251    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
252    ///
253    /// let mut stdout = Vec::new();
254    ///
255    /// let elf = &[1, 2, 3];
256    /// let stdin = SP1Stdin::new();
257    ///
258    /// let client = ProverClient::builder().cpu().build();
259    /// client.execute(elf, &stdin).stdout(&mut stdout).run();
260    /// ```
261    #[must_use]
262    pub fn stdout<W: IoWriter>(mut self, writer: &'a mut W) -> Self {
263        self.context_builder.stdout(writer);
264        self
265    }
266
267    /// Override the default stdout of the guest program.
268    ///
269    /// # Example
270    /// ```rust,no_run
271    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
272    ///
273    /// let mut stderr = Vec::new();
274    ///
275    /// let elf = &[1, 2, 3];
276    /// let stdin = SP1Stdin::new();
277    ///
278    /// let client = ProverClient::builder().cpu().build();
279    /// client.execute(elf, &stdin).stderr(&mut stderr).run();
280    /// ```````
281    #[must_use]
282    pub fn stderr<W: IoWriter>(mut self, writer: &'a mut W) -> Self {
283        self.context_builder.stderr(writer);
284        self
285    }
286
287    /// Run the prover with the built arguments.
288    ///
289    /// # Details
290    /// This method will run the prover with the built arguments. If the prover fails to run, the
291    /// method will return an error.
292    ///
293    /// # Example
294    /// ```rust,no_run
295    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
296    ///
297    /// let elf = &[1, 2, 3];
298    /// let stdin = SP1Stdin::new();
299    ///
300    /// let client = ProverClient::builder().cpu().build();
301    /// let (pk, vk) = client.setup(elf);
302    /// let proof = client.prove(&pk, &stdin).run().unwrap();
303    /// ```
304    pub fn run(self) -> Result<SP1ProofWithPublicValues> {
305        // Get the arguments.
306        let Self { prover, mode, pk, stdin, mut context_builder, core_opts, recursion_opts, mock } =
307            self;
308        let opts = SP1ProverOpts { core_opts, recursion_opts };
309        let context = context_builder.build();
310
311        // Dump the program and stdin to files for debugging if `SP1_DUMP` is set.
312        crate::utils::sp1_dump(&pk.elf, &stdin);
313
314        // Run the prover.
315        if mock {
316            prover.mock_prove_impl(pk, &stdin, context, mode)
317        } else {
318            prover.prove_impl(pk, &stdin, opts, context, mode)
319        }
320    }
321}