Skip to main content

sp1_sdk/blocking/light/
mod.rs

1//! # Light Prover (Blocking)
2//!
3//! A lightweight blocking prover that only executes and verifies but does not generate proofs.
4
5pub mod builder;
6
7use sp1_core_machine::io::SP1Stdin;
8use sp1_core_machine::riscv::RiscvAir;
9use sp1_hypercube::Machine;
10use sp1_primitives::SP1Field;
11use sp1_prover::worker::{SP1LightNode, SP1NodeCore};
12
13use crate::{
14    blocking::{
15        block_on,
16        cpu::CPUProverError,
17        prover::{BaseProveRequest, ProveRequest, Prover},
18    },
19    SP1ProofWithPublicValues, SP1ProvingKey,
20};
21
22/// A lightweight blocking prover that only executes and verifies but does not generate proofs.
23#[derive(Clone)]
24pub struct LightProver {
25    inner: SP1LightNode,
26}
27
28impl Default for LightProver {
29    fn default() -> Self {
30        Self::new()
31    }
32}
33
34impl LightProver {
35    /// Create a new light prover.
36    #[must_use]
37    pub fn new() -> Self {
38        Self::new_with_machine(RiscvAir::machine())
39    }
40
41    /// Create a new light prover with a given machine.
42    #[must_use]
43    pub fn new_with_machine(machine: Machine<SP1Field, RiscvAir<SP1Field>>) -> Self {
44        tracing::info!("initializing light prover");
45        let node = block_on(SP1LightNode::new_with_machine(machine));
46        Self { inner: node }
47    }
48
49    /// Create a light prover from an existing light node.
50    pub(crate) fn from_node(inner: SP1LightNode) -> Self {
51        Self { inner }
52    }
53}
54
55impl Prover for LightProver {
56    type ProvingKey = SP1ProvingKey;
57
58    type Error = CPUProverError;
59
60    type ProveRequest<'a> = LightProveRequest<'a>;
61
62    fn inner(&self) -> &SP1NodeCore {
63        self.inner.inner()
64    }
65
66    fn prove<'a>(&'a self, pk: &'a Self::ProvingKey, stdin: SP1Stdin) -> Self::ProveRequest<'a> {
67        LightProveRequest { base: BaseProveRequest::new(self, pk, stdin) }
68    }
69
70    fn setup(&self, elf: sp1_build::Elf) -> Result<Self::ProvingKey, Self::Error> {
71        let vk = block_on(self.inner.setup(&elf))?;
72        Ok(SP1ProvingKey { vk, elf })
73    }
74
75    // verify() is intentionally NOT overridden here.
76    // The default Prover::verify performs real cryptographic verification,
77    // unlike MockProver which only checks public value hashes.
78}
79
80/// A light prove request.
81pub struct LightProveRequest<'a> {
82    pub(crate) base: BaseProveRequest<'a, LightProver>,
83}
84
85impl<'a> ProveRequest<'a, LightProver> for LightProveRequest<'a> {
86    fn base(&mut self) -> &mut BaseProveRequest<'a, LightProver> {
87        &mut self.base
88    }
89
90    fn run(self) -> Result<SP1ProofWithPublicValues, CPUProverError> {
91        Err(CPUProverError::Unexpected(anyhow::anyhow!(
92            "Use LightProver for executing and verifying only. For proving, use CpuProver"
93        )))
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use crate::{
100        blocking::prover::{ProveRequest, Prover},
101        utils::setup_logger,
102        SP1Stdin,
103    };
104
105    use super::LightProver;
106
107    /// Test that execute works and prove errors.
108    #[test]
109    fn test_light_execute_and_prove() {
110        setup_logger();
111        let prover = LightProver::new();
112        let pk = prover.setup(test_artifacts::FIBONACCI_ELF).expect("failed to setup proving key");
113
114        // Execute should succeed.
115        let mut stdin = SP1Stdin::new();
116        stdin.write(&10usize);
117        let (pv, _) = prover.execute(pk.elf.clone(), stdin).run().expect("failed to execute");
118        assert!(!pv.as_slice().is_empty());
119
120        // Prove should error.
121        let mut stdin = SP1Stdin::new();
122        stdin.write(&10usize);
123        let result = prover.prove(&pk, stdin).core().run();
124        assert!(result.is_err());
125        assert!(result.unwrap_err().to_string().contains("executing and verifying only"));
126    }
127}