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}