Skip to main content

sp1_sdk/mock/
mod.rs

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