Skip to main content

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