Skip to main content

sp1_sdk/cpu/
mod.rs

1//! # SP1 CPU Prover
2//!
3//! A prover that uses the CPU to execute and prove programs.
4
5pub mod builder;
6pub mod prove;
7
8use std::sync::Arc;
9
10use prove::CpuProveBuilder;
11use sp1_core_executor::ExecutionError;
12use sp1_core_machine::io::SP1Stdin;
13use sp1_core_machine::riscv::RiscvAir;
14use sp1_hypercube::Machine;
15use sp1_primitives::{Elf, SP1Field};
16use sp1_prover::worker::{
17    cpu_worker_builder_with_machine, SP1LocalNode, SP1LocalNodeBuilder, SP1NodeCore, TaskError,
18};
19
20use crate::{
21    prover::{Prover, SendFutureResult},
22    SP1ProvingKey,
23};
24
25use thiserror::Error;
26
27/// A prover that uses the CPU to execute and prove programs.
28#[derive(Clone)]
29pub struct CpuProver {
30    pub(crate) prover: Arc<SP1LocalNode>,
31}
32
33/// An error occurred while proving.
34#[derive(Debug, Error)]
35pub enum CPUProverError {
36    /// An error occurred while proving.
37    #[error(transparent)]
38    Prover(#[from] TaskError),
39
40    /// An error occurred while executing.
41    #[error(transparent)]
42    Execution(#[from] ExecutionError),
43
44    /// An unexpected error occurred.
45    #[error("An unexpected error occurred: {:?}", .0)]
46    Unexpected(#[from] anyhow::Error),
47}
48
49impl Prover for CpuProver {
50    type ProvingKey = SP1ProvingKey;
51    type Error = CPUProverError;
52    type ProveRequest<'a> = CpuProveBuilder<'a>;
53
54    fn inner(&self) -> &SP1NodeCore {
55        self.prover.core()
56    }
57
58    fn setup(&self, elf: Elf) -> impl SendFutureResult<Self::ProvingKey, Self::Error> {
59        async move {
60            let vk = self.prover.setup(&elf).await?;
61            Ok(SP1ProvingKey { vk, elf })
62        }
63    }
64
65    fn prove<'a>(&'a self, pk: &'a Self::ProvingKey, stdin: SP1Stdin) -> Self::ProveRequest<'a> {
66        CpuProveBuilder::new(self, pk, stdin)
67    }
68}
69
70impl CpuProver {
71    /// Creates a new [`CpuProver`], using the default [`LocalProverOpts`].
72    #[must_use]
73    pub async fn new() -> Self {
74        Self::new_with_machine(RiscvAir::machine()).await
75    }
76
77    /// Creates a new [`CpuProver`], using the default [`LocalProverOpts`] and a given machine.
78    #[must_use]
79    pub async fn new_with_machine(machine: Machine<SP1Field, RiscvAir<SP1Field>>) -> Self {
80        Self::new_with_opts_and_machine(None, machine).await
81    }
82
83    /// Creates a new [`CpuProver`] with optional custom [`SP1CoreOpts`].
84    #[must_use]
85    pub async fn new_with_opts(core_opts: Option<sp1_core_executor::SP1CoreOpts>) -> Self {
86        Self::new_with_opts_and_machine(core_opts, RiscvAir::machine()).await
87    }
88
89    /// Creates a new [`CpuProver`] with optional custom [`SP1CoreOpts`] and a given machine.
90    #[must_use]
91    pub async fn new_with_opts_and_machine(
92        core_opts: Option<sp1_core_executor::SP1CoreOpts>,
93        machine: Machine<SP1Field, RiscvAir<SP1Field>>,
94    ) -> Self {
95        tracing::info!("initializing cpu prover");
96        let worker_builder =
97            cpu_worker_builder_with_machine(machine).with_core_opts(core_opts.unwrap_or_default());
98        Self {
99            prover: Arc::new(
100                SP1LocalNodeBuilder::from_worker_client_builder(worker_builder)
101                    .build()
102                    .await
103                    .unwrap(),
104            ),
105        }
106    }
107
108    /// # ⚠️ WARNING: This prover is experimental and should not be used in production.
109    /// It is intended for development and debugging purposes.
110    ///
111    /// Creates a new [`CpuProver`], using the default [`LocalProverOpts`].
112    /// Verification of the proof system's verification key is skipped, meaning that the
113    /// recursion proofs are not guaranteed to be about a permitted recursion program.
114    #[cfg(feature = "experimental")]
115    #[must_use]
116    pub async fn new_experimental() -> Self {
117        Self::new_experimental_with_machine(RiscvAir::machine()).await
118    }
119
120    /// Same as [`Self::new_experimental`] but with a custom machine.
121    #[cfg(feature = "experimental")]
122    #[must_use]
123    pub async fn new_experimental_with_machine(
124        machine: Machine<SP1Field, RiscvAir<SP1Field>>,
125    ) -> Self {
126        Self::new_with_opts_and_machine(None, machine).await
127    }
128}