Skip to main content

sp1_sdk/blocking/mock/
mod.rs

1//! # Mock Prover
2//!
3//! A mock prover that can be used for testing.
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::{
12    worker::{SP1LightNode, SP1NodeCore},
13    Groth16Bn254Proof, PlonkBn254Proof, SP1VerifyingKey,
14};
15
16use crate::{
17    blocking::{
18        block_on,
19        cpu::CPUProverError,
20        prover::{BaseProveRequest, ProveRequest, Prover},
21    },
22    proof::verify_mock_public_inputs,
23    SP1Proof, SP1ProofWithPublicValues, SP1ProvingKey, SP1VerificationError, StatusCode,
24};
25
26/// A mock prover that can be used for testing.
27#[derive(Clone)]
28pub struct MockProver {
29    inner: SP1LightNode,
30}
31
32impl Default for MockProver {
33    fn default() -> Self {
34        Self::new()
35    }
36}
37
38impl MockProver {
39    /// Create a new mock prover.
40    #[must_use]
41    pub fn new() -> Self {
42        Self::new_with_machine(RiscvAir::machine())
43    }
44
45    /// Create a new mock prover with a given machine
46    #[must_use]
47    pub fn new_with_machine(machine: Machine<SP1Field, RiscvAir<SP1Field>>) -> Self {
48        tracing::info!("initializing mock prover");
49        Self { inner: block_on(SP1LightNode::new_with_machine(machine)) }
50    }
51
52    /// Create a mock prover from an existing light node.
53    pub(crate) fn from_node(inner: SP1LightNode) -> Self {
54        Self { inner }
55    }
56}
57
58impl Prover for MockProver {
59    type ProvingKey = SP1ProvingKey;
60
61    type Error = CPUProverError;
62
63    type ProveRequest<'a> = MockProveRequest<'a>;
64
65    fn inner(&self) -> &SP1NodeCore {
66        self.inner.inner()
67    }
68
69    fn prove<'a>(&'a self, pk: &'a Self::ProvingKey, stdin: SP1Stdin) -> Self::ProveRequest<'a> {
70        MockProveRequest { base: BaseProveRequest::new(self, pk, stdin) }
71    }
72
73    fn setup(&self, elf: sp1_build::Elf) -> Result<Self::ProvingKey, Self::Error> {
74        let vk = block_on(self.inner.setup(&elf))?;
75        Ok(SP1ProvingKey { vk, elf })
76    }
77
78    fn verify(
79        &self,
80        proof: &SP1ProofWithPublicValues,
81        vkey: &SP1VerifyingKey,
82        _status_code: Option<StatusCode>,
83    ) -> Result<(), SP1VerificationError> {
84        match &proof.proof {
85            SP1Proof::Plonk(PlonkBn254Proof { public_inputs, .. }) => {
86                // Verify the mock Plonk proof by checking public inputs match.
87                verify_mock_public_inputs(vkey, &proof.public_values, public_inputs)
88                    .map_err(SP1VerificationError::Plonk)
89            }
90            SP1Proof::Groth16(Groth16Bn254Proof { public_inputs, .. }) => {
91                // Verify the mock Groth16 proof by checking public inputs match.
92                verify_mock_public_inputs(vkey, &proof.public_values, public_inputs)
93                    .map_err(SP1VerificationError::Groth16)
94            }
95            _ => Ok(()),
96        }
97    }
98}
99
100/// A mock prove request that can be used for testing.
101pub struct MockProveRequest<'a> {
102    pub(crate) base: BaseProveRequest<'a, MockProver>,
103}
104
105impl<'a> ProveRequest<'a, MockProver> for MockProveRequest<'a> {
106    fn base(&mut self) -> &mut BaseProveRequest<'a, MockProver> {
107        &mut self.base
108    }
109
110    fn run(self) -> Result<SP1ProofWithPublicValues, CPUProverError> {
111        let BaseProveRequest { prover, pk, mode, stdin, context_builder } = self.base;
112        tracing::info!(mode = ?mode, "generating mock proof");
113        let mut req = prover.execute(pk.elf.clone(), stdin);
114        req.context_builder = context_builder;
115        let (public_values, _) = req.run()?;
116        Ok(SP1ProofWithPublicValues::create_mock_proof(
117            &pk.vk,
118            public_values,
119            mode,
120            prover.version(),
121        ))
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use crate::{
128        blocking::prover::{ProveRequest, Prover},
129        utils::setup_logger,
130        SP1Stdin,
131    };
132
133    use super::MockProver;
134
135    /// Test mock proof creation and verification for all proof types.
136    #[test]
137    fn test_mock_proof_all_types() {
138        setup_logger();
139        let prover = MockProver::new();
140        let pk = prover.setup(test_artifacts::FIBONACCI_ELF).expect("failed to setup proving key");
141
142        // Test Core proof.
143        let mut stdin = SP1Stdin::new();
144        stdin.write(&10usize);
145        let core_proof =
146            prover.prove(&pk, stdin).core().run().expect("failed to create mock Core proof");
147        prover.verify(&core_proof, &pk.vk, None).expect("failed to verify mock Core proof");
148
149        // Test Compressed proof.
150        let mut stdin = SP1Stdin::new();
151        stdin.write(&10usize);
152        let compressed_proof = prover
153            .prove(&pk, stdin)
154            .compressed()
155            .run()
156            .expect("failed to create mock Compressed proof");
157        prover
158            .verify(&compressed_proof, &pk.vk, None)
159            .expect("failed to verify mock Compressed proof");
160
161        // Test Plonk proof.
162        let mut stdin = SP1Stdin::new();
163        stdin.write(&10usize);
164        let plonk_proof =
165            prover.prove(&pk, stdin).plonk().run().expect("failed to create mock Plonk proof");
166        prover.verify(&plonk_proof, &pk.vk, None).expect("failed to verify mock Plonk proof");
167
168        // Test Groth16 proof.
169        let mut stdin = SP1Stdin::new();
170        stdin.write(&10usize);
171        let groth16_proof =
172            prover.prove(&pk, stdin).groth16().run().expect("failed to create mock Groth16 proof");
173        prover.verify(&groth16_proof, &pk.vk, None).expect("failed to verify mock Groth16 proof");
174    }
175
176    /// Test that mock proofs have correct public values.
177    #[test]
178    fn test_mock_proof_public_values() {
179        setup_logger();
180        let prover = MockProver::new();
181        let pk = prover.setup(test_artifacts::FIBONACCI_ELF).expect("failed to setup proving key");
182        let mut stdin = SP1Stdin::new();
183        stdin.write(&10usize);
184
185        // Execute first to get expected public values.
186        let (expected_pv, _) =
187            prover.execute(pk.elf.clone(), stdin.clone()).run().expect("failed to execute program");
188
189        // Create a mock core proof.
190        let proof =
191            prover.prove(&pk, stdin).core().run().expect("failed to create mock Core proof");
192
193        // Verify public values match.
194        assert_eq!(proof.public_values.as_slice(), expected_pv.as_slice());
195    }
196
197    /// Test that mock Plonk proof verification fails with wrong vkey.
198    #[test]
199    fn test_mock_plonk_proof_wrong_vkey_fails() {
200        setup_logger();
201        let prover = MockProver::new();
202
203        // Setup two different programs.
204        let pk1 =
205            prover.setup(test_artifacts::FIBONACCI_ELF).expect("failed to setup proving key 1");
206        let pk2 =
207            prover.setup(test_artifacts::HELLO_WORLD_ELF).expect("failed to setup proving key 2");
208
209        // Create a Plonk proof with pk1.
210        let mut stdin = SP1Stdin::new();
211        stdin.write(&10usize);
212        let proof =
213            prover.prove(&pk1, stdin).plonk().run().expect("failed to create mock Plonk proof");
214
215        // Verification with pk2's vkey should fail.
216        let result = prover.verify(&proof, &pk2.vk, None);
217        assert!(result.is_err(), "Verification should fail with wrong vkey");
218    }
219
220    /// Test that mock Groth16 proof verification fails with wrong vkey.
221    #[test]
222    fn test_mock_groth16_proof_wrong_vkey_fails() {
223        setup_logger();
224        let prover = MockProver::new();
225
226        // Setup two different programs.
227        let pk1 =
228            prover.setup(test_artifacts::FIBONACCI_ELF).expect("failed to setup proving key 1");
229        let pk2 =
230            prover.setup(test_artifacts::HELLO_WORLD_ELF).expect("failed to setup proving key 2");
231
232        // Create a Groth16 proof with pk1.
233        let mut stdin = SP1Stdin::new();
234        stdin.write(&10usize);
235        let proof =
236            prover.prove(&pk1, stdin).groth16().run().expect("failed to create mock Groth16 proof");
237
238        // Verification with pk2's vkey should fail.
239        let result = prover.verify(&proof, &pk2.vk, None);
240        assert!(result.is_err(), "Verification should fail with wrong vkey");
241    }
242
243    /// Test that mock Plonk proof verification fails with tampered public values.
244    #[test]
245    fn test_mock_plonk_proof_tampered_public_values_fails() {
246        setup_logger();
247        let prover = MockProver::new();
248        let pk = prover.setup(test_artifacts::FIBONACCI_ELF).expect("failed to setup proving key");
249
250        // Create a Plonk proof.
251        let mut stdin = SP1Stdin::new();
252        stdin.write(&10usize);
253        let mut proof =
254            prover.prove(&pk, stdin).plonk().run().expect("failed to create mock Plonk proof");
255
256        // Tamper with public values.
257        proof.public_values = sp1_primitives::io::SP1PublicValues::from(&[0xDE, 0xAD, 0xBE, 0xEF]);
258
259        // Verification should fail because public_values hash won't match.
260        let result = prover.verify(&proof, &pk.vk, None);
261        assert!(result.is_err(), "Verification should fail with tampered public values");
262    }
263
264    /// Test that mock Groth16 proof verification fails with tampered public values.
265    #[test]
266    fn test_mock_groth16_proof_tampered_public_values_fails() {
267        setup_logger();
268        let prover = MockProver::new();
269        let pk = prover.setup(test_artifacts::FIBONACCI_ELF).expect("failed to setup proving key");
270
271        // Create a Groth16 proof.
272        let mut stdin = SP1Stdin::new();
273        stdin.write(&10usize);
274        let mut proof =
275            prover.prove(&pk, stdin).groth16().run().expect("failed to create mock Groth16 proof");
276
277        // Tamper with public values.
278        proof.public_values = sp1_primitives::io::SP1PublicValues::from(&[0xDE, 0xAD, 0xBE, 0xEF]);
279
280        // Verification should fail because public_values hash won't match.
281        let result = prover.verify(&proof, &pk.vk, None);
282        assert!(result.is_err(), "Verification should fail with tampered public values");
283    }
284}