Skip to main content

sp1_sdk/prover/
prove.rs

1use super::{IntoSendFutureResult, Prover};
2use crate::{ProvingKey, SP1ProofMode, SP1ProofWithPublicValues, StatusCode};
3use sp1_build::Elf;
4use sp1_core_executor::SP1ContextBuilder;
5use sp1_core_machine::io::SP1Stdin;
6use sp1_prover::SP1VerifyingKey;
7
8#[derive(Clone)]
9/// A proving key for the SP1 prover.
10///
11/// Contains only the minimal information required to implement the `ProvingKey` trait.
12pub struct SP1ProvingKey {
13    /// Verifying key for verifying a proof created with this proving key
14    pub(crate) vk: SP1VerifyingKey,
15    /// ELF of the program to be proven
16    pub(crate) elf: Elf,
17}
18
19impl SP1ProvingKey {
20    /// Creates a new `SP1ProvingKey` from a verifying key and ELF.
21    #[must_use]
22    pub fn new(vk: SP1VerifyingKey, elf: Elf) -> Self {
23        Self { vk, elf }
24    }
25}
26
27impl ProvingKey for SP1ProvingKey {
28    fn verifying_key(&self) -> &SP1VerifyingKey {
29        &self.vk
30    }
31
32    fn elf(&self) -> &Elf {
33        &self.elf
34    }
35}
36
37/// A unified collection of methods for all prover types.
38pub trait ProveRequest<'a, P>
39where
40    Self: IntoSendFutureResult<SP1ProofWithPublicValues, P::Error> + Sized + Send,
41    P: Prover + 'a,
42{
43    /// Get the base request for the prover.
44    fn base(&mut self) -> &mut BaseProveRequest<'a, P>;
45
46    /// Set the proof mode to the given [`SP1ProofKind`].
47    ///
48    /// # Details
49    /// This method is useful for setting the proof mode to a custom mode.
50    ///
51    /// # Example
52    /// ```rust,no_run
53    /// use sp1_sdk::{Elf, ProveRequest, Prover, ProverClient, SP1ProofMode, SP1Stdin};
54    ///
55    /// tokio_test::block_on(async {
56    ///     let elf = Elf::Static(&[1, 2, 3]);
57    ///     let stdin = SP1Stdin::new();
58    ///
59    ///     let client = ProverClient::builder().cpu().build().await;
60    ///     let pk = client.setup(elf).await.unwrap();
61    ///     let proof = client.prove(&pk, stdin).mode(SP1ProofMode::Groth16).await.unwrap();
62    /// });
63    /// ```
64    #[must_use]
65    fn mode(mut self, mode: SP1ProofMode) -> Self {
66        self.base().mode(mode);
67        self
68    }
69
70    /// Set the proof kind to [`SP1ProofKind::Compressed`] mode.
71    ///
72    /// # Details
73    /// This mode produces a proof that is of constant size, regardless of the number of cycles. It
74    /// takes longer to prove than [`SP1ProofKind::Core`] due to the need to recursively aggregate
75    /// proofs into a single proof.
76    ///
77    /// # Example
78    /// ```rust,no_run
79    /// use sp1_sdk::{Elf, ProveRequest, Prover, ProverClient, SP1Stdin};
80    ///
81    /// tokio_test::block_on(async {
82    ///     let elf = Elf::Static(&[1, 2, 3]);
83    ///     let stdin = SP1Stdin::new();
84    ///
85    ///     let client = ProverClient::builder().cpu().build().await;
86    ///     let pk = client.setup(elf).await.unwrap();
87    ///     let proof = client.prove(&pk, stdin).compressed().await.unwrap();
88    /// });
89    /// ```
90    #[must_use]
91    fn compressed(mut self) -> Self {
92        self.base().compressed();
93        self
94    }
95
96    /// Set the proof mode to [`SP1ProofKind::Plonk`] mode.
97    ///
98    /// # Details
99    /// This mode produces a const size PLONK proof that can be verified on chain for roughly ~300k
100    /// gas. This mode is useful for producing a maximally small proof that can be verified on
101    /// chain. For more efficient SNARK wrapping, you can use the [`SP1ProofKind::Groth16`] mode but
102    /// this mode is more .
103    ///
104    /// # Example
105    /// ```rust,no_run
106    /// use sp1_sdk::{Elf, ProveRequest, Prover, ProverClient, SP1Stdin};
107    ///
108    /// tokio_test::block_on(async {
109    ///     let elf = Elf::Static(&[1, 2, 3]);
110    ///     let stdin = SP1Stdin::new();
111    ///
112    ///     let client = ProverClient::builder().cpu().build().await;
113    ///     let pk = client.setup(elf).await.unwrap();
114    ///     let builder = client.prove(&pk, stdin).plonk().await;
115    /// });
116    /// ```
117    #[must_use]
118    fn plonk(mut self) -> Self {
119        self.base().plonk();
120        self
121    }
122
123    /// Set the proof mode to [`SP1ProofKind::Groth16`] mode.
124    ///
125    /// # Details
126    /// This mode produces a Groth16 proof that can be verified on chain for roughly ~100k gas. This
127    /// mode is useful for producing a proof that can be verified on chain with minimal gas.
128    ///
129    /// # Example
130    /// ```rust,no_run
131    /// use sp1_sdk::{Elf, ProveRequest, Prover, ProverClient, SP1Stdin};
132    ///
133    /// tokio_test::block_on(async {
134    ///     let elf = Elf::Static(&[1, 2, 3]);
135    ///     let stdin = SP1Stdin::new();
136    ///
137    ///     let client = ProverClient::builder().cpu().build().await;
138    ///     let pk = client.setup(elf).await.unwrap();
139    ///     let proof = client.prove(&pk, stdin).groth16().await.unwrap();
140    /// });
141    /// ```
142    #[must_use]
143    fn groth16(mut self) -> Self {
144        self.base().groth16();
145        self
146    }
147
148    /// Set the proof kind to [`SP1ProofKind::Core`] mode.
149    ///
150    /// # Details
151    /// This is the default mode for the prover. The proofs grow linearly in size with the number
152    /// of cycles.
153    ///
154    /// # Example
155    /// ```rust,no_run
156    /// use sp1_sdk::{Elf, ProveRequest, Prover, ProverClient, SP1Stdin};
157    ///
158    /// tokio_test::block_on(async {
159    ///     let elf = Elf::Static(&[1, 2, 3]);
160    ///     let stdin = SP1Stdin::new();
161    ///
162    ///     let client = ProverClient::builder().cpu().build().await;
163    ///     let pk = client.setup(elf).await.unwrap();
164    ///     let proof = client.prove(&pk, stdin).core().await.unwrap();
165    /// });
166    /// ```
167    #[must_use]
168    fn core(mut self) -> Self {
169        self.base().core();
170        self
171    }
172
173    /// Set the maximum number of cpu cycles to use for execution.
174    ///
175    /// # Details
176    /// If the cycle limit is exceeded, execution will return
177    /// [`sp1_core_executor::ExecutionError::ExceededCycleLimit`].
178    ///
179    /// # Example
180    /// ```rust,no_run
181    /// use sp1_sdk::{Elf, ProveRequest, Prover, ProverClient, SP1Stdin};
182    ///
183    /// tokio_test::block_on(async {
184    ///     let elf = Elf::Static(&[1, 2, 3]);
185    ///     let stdin = SP1Stdin::new();
186    ///
187    ///     let client = ProverClient::builder().cpu().build().await;
188    ///     let pk = client.setup(elf).await.unwrap();
189    ///     let proof = client.prove(&pk, stdin).cycle_limit(1000000).await.unwrap();
190    /// });
191    /// ```
192    #[must_use]
193    fn cycle_limit(mut self, cycle_limit: u64) -> Self {
194        self.base().cycle_limit(cycle_limit);
195        self
196    }
197
198    /// Whether to enable deferred proof verification in the executor.
199    ///
200    /// # Arguments
201    /// * `value` - Whether to enable deferred proof verification in the executor.
202    ///
203    /// # Details
204    /// Default: `true`. If set to `false`, the executor will skip deferred proof verification.
205    /// This is useful for reducing the execution time of the program and optimistically assuming
206    /// that the deferred proofs are correct. Can also be used for mock proof setups that require
207    /// verifying mock compressed proofs.
208    ///
209    /// # Example
210    /// ```rust,no_run
211    /// use sp1_sdk::{Elf, ProveRequest, Prover, ProverClient, SP1Stdin};
212    ///
213    /// tokio_test::block_on(async {
214    ///     let elf = Elf::Static(&[1, 2, 3]);
215    ///     let stdin = SP1Stdin::new();
216    ///
217    ///     let client = ProverClient::builder().cpu().build().await;
218    ///     let pk = client.setup(elf).await.unwrap();
219    ///     let proof = client.prove(&pk, stdin).deferred_proof_verification(false).await.unwrap();
220    /// });
221    /// ```
222    #[must_use]
223    fn deferred_proof_verification(mut self, value: bool) -> Self {
224        self.base().deferred_proof_verification(value);
225        self
226    }
227
228    /// Set the expected exit code of the program.
229    ///
230    /// # Arguments
231    /// * `code` - The expected exit code of the program.
232    #[must_use]
233    fn expected_exit_code(mut self, code: StatusCode) -> Self {
234        self.base().expected_exit_code(code);
235        self
236    }
237
238    /// Set the proof nonce for this execution.
239    ///
240    /// The nonce ensures each proof is unique even for identical programs and inputs.
241    /// If not provided, will default to 0.
242    ///
243    /// # Arguments
244    /// * `nonce` - A 4-element array representing 128 bits of nonce data.
245    #[must_use]
246    fn with_proof_nonce(mut self, nonce: [u32; 4]) -> Self {
247        self.base().context_builder.proof_nonce(nonce);
248        self
249    }
250}
251
252/// The base prove request for a prover.
253///
254/// This exposes all the options that are shared across different prover types.
255pub struct BaseProveRequest<'a, P: Prover> {
256    pub(crate) prover: &'a P,
257    pub(crate) pk: &'a P::ProvingKey,
258    pub(crate) stdin: SP1Stdin,
259    pub(crate) mode: SP1ProofMode,
260    pub(crate) context_builder: SP1ContextBuilder<'static>,
261}
262
263impl<'a, P: Prover> BaseProveRequest<'a, P> {
264    /// Create a new [`BaseProveRequest`] with the given prover, proving key, and stdin.
265    ///
266    /// # Arguments
267    /// * `prover` - The prover to use.
268    /// * `pk` - The proving key to use.
269    /// * `stdin` - The stdin to use.
270    pub const fn new(prover: &'a P, pk: &'a P::ProvingKey, stdin: SP1Stdin) -> Self {
271        Self {
272            prover,
273            pk,
274            stdin,
275            mode: SP1ProofMode::Core,
276            context_builder: SP1ContextBuilder::new(),
277        }
278    }
279
280    /// See [`ProveRequest::compressed`].
281    pub fn compressed(&mut self) {
282        self.mode = SP1ProofMode::Compressed;
283    }
284
285    /// See [`ProveRequest::plonk`].
286    pub fn plonk(&mut self) {
287        self.mode = SP1ProofMode::Plonk;
288    }
289
290    /// See [`ProveRequest::groth16`].
291    pub fn groth16(&mut self) {
292        self.mode = SP1ProofMode::Groth16;
293    }
294
295    /// See [`ProveRequest::core`].
296    pub fn core(&mut self) {
297        self.mode = SP1ProofMode::Core;
298    }
299
300    /// See [`ProveRequest::mode`].
301    pub fn mode(&mut self, mode: SP1ProofMode) {
302        self.mode = mode;
303    }
304
305    /// See [`ProveRequest::cycle_limit`].
306    pub fn cycle_limit(&mut self, cycle_limit: u64) {
307        self.context_builder.max_cycles(cycle_limit);
308    }
309
310    /// See [`ProveRequest::deferred_proof_verification`].
311    pub fn deferred_proof_verification(&mut self, value: bool) {
312        self.context_builder.set_deferred_proof_verification(value);
313    }
314
315    /// See [`ProveRequest::expected_exit_code`].
316    pub fn expected_exit_code(&mut self, code: StatusCode) {
317        self.context_builder.expected_exit_code(code);
318    }
319
320    pub fn with_nonce(&mut self, nonce: [u32; 4]) {
321        self.context_builder.proof_nonce(nonce);
322    }
323}