1#![warn(clippy::pedantic)]
9#![allow(clippy::similar_names)]
10#![allow(clippy::cast_possible_wrap)]
11#![allow(clippy::cast_possible_truncation)]
12#![allow(clippy::cast_sign_loss)]
13#![allow(clippy::module_name_repetitions)]
14#![allow(clippy::needless_range_loop)]
15#![allow(clippy::cast_lossless)]
16#![allow(clippy::bool_to_int_with_if)]
17#![allow(clippy::should_panic_without_expect)]
18#![allow(clippy::field_reassign_with_default)]
19#![allow(clippy::manual_assert)]
20#![allow(clippy::unreadable_literal)]
21#![allow(clippy::match_wildcard_for_single_variants)]
22#![allow(clippy::missing_panics_doc)]
23#![allow(clippy::missing_errors_doc)]
24#![allow(clippy::explicit_iter_loop)]
25#![warn(missing_docs)]
26
27pub mod artifacts;
28pub mod client;
29pub mod cpu;
30pub use cpu::CpuProver;
31pub mod mock;
32pub use mock::MockProver;
33pub mod light;
34pub use light::LightProver;
35#[cfg(feature = "cuda")]
36pub mod cuda;
37#[cfg(feature = "cuda")]
38pub use cuda::CudaProver;
39pub mod env;
40
41pub mod install;
42#[cfg(feature = "network")]
43pub mod network;
44#[cfg(feature = "network")]
45pub use network::prover::NetworkProver;
46
47#[cfg(feature = "blocking")]
48pub mod blocking;
49
50pub mod utils;
51
52pub use crate::client::ProverClient;
54
55pub mod proof;
57pub use proof::*;
58pub mod prover;
59
60pub use prover::{ProveRequest, Prover, ProvingKey, SP1ProvingKey, SP1VerificationError};
62
63pub use sp1_build::include_elf;
65pub use sp1_core_executor::{ExecutionReport, HookEnv, SP1Context, SP1ContextBuilder, StatusCode};
66
67pub use sp1_core_machine::io::SP1Stdin;
69pub use sp1_core_machine::riscv::RiscvAir;
70pub use sp1_primitives::{io::SP1PublicValues, Elf};
71pub use sp1_prover::{HashableKey, ProverMode, SP1VerifyingKey, SP1_CIRCUIT_VERSION};
72
73pub mod prelude {
75 pub use super::{
76 include_elf, Elf, HashableKey, ProveRequest, Prover, ProvingKey, RiscvAir,
77 SP1ProofWithPublicValues, SP1Stdin,
78 };
79}
80
81pub use utils::setup_logger;
83
84#[cfg(all(test, feature = "slow-tests"))]
85mod tests {
86 use sp1_primitives::io::SP1PublicValues;
87
88 use crate::{utils, MockProver, Prover, ProverClient, SP1Stdin};
89
90 #[tokio::test]
91 async fn test_execute() {
92 utils::setup_logger();
93 let client = ProverClient::builder().cpu().build().await;
94 let elf = test_artifacts::FIBONACCI_ELF;
95 let mut stdin = SP1Stdin::new();
96 stdin.write(&10usize);
97 let (_pv, report) = client.execute(elf, stdin).await.unwrap();
98
99 assert_eq!(report.exit_code, 0);
100 }
101
102 #[tokio::test]
103 async fn test_execute_panic() {
104 utils::setup_logger();
105 let client = ProverClient::builder().cpu().build().await;
106 let elf = test_artifacts::PANIC_ELF;
107 let mut stdin = SP1Stdin::new();
108 stdin.write(&10usize);
109 let (_, report) = client.execute(elf, stdin).await.unwrap();
110 assert_eq!(report.exit_code, 1);
111 }
112
113 #[should_panic]
115 #[tokio::test]
116 #[ignore = "The cycle limit logic needs to be reimplemented."]
117 async fn test_cycle_limit_fail() {
118 utils::setup_logger();
119 let client = ProverClient::builder().cpu().build().await;
120 let elf = test_artifacts::PANIC_ELF;
121 let mut stdin = SP1Stdin::new();
122 stdin.write(&10usize);
123 client.execute(elf, stdin).cycle_limit(1).await.unwrap();
124 }
125
126 #[tokio::test]
132 async fn test_cycle_tracker_report_variants() {
133 utils::setup_logger();
134 let client = MockProver::new().await;
135 let elf = test_artifacts::CYCLE_TRACKER_ELF;
136 let stdin = SP1Stdin::new();
137
138 let (_pv, report) = client.execute(elf, stdin).await.unwrap();
139
140 assert!(
143 report.cycle_tracker.contains_key("h"),
144 "Expected cycle_tracker to contain 'h', got: {:?}",
145 report.cycle_tracker
146 );
147 let h_cycles = *report.cycle_tracker.get("h").unwrap();
148 assert!(h_cycles > 0, "Expected 'h' to have positive cycles, got: {h_cycles}");
149
150 assert!(
152 report.cycle_tracker.contains_key("repeated"),
153 "Expected cycle_tracker to contain 'repeated', got: {:?}",
154 report.cycle_tracker
155 );
156 let repeated_cycles =
157 *report.cycle_tracker.get("repeated").expect("repeated should be populated");
158 assert!(
159 repeated_cycles > 0,
160 "Expected 'repeated' to have positive cycles, got: {repeated_cycles}"
161 );
162
163 assert!(
165 report.invocation_tracker.contains_key("repeated"),
166 "Expected invocation_tracker to contain 'repeated', got: {:?}",
167 report.invocation_tracker
168 );
169 let repeated_invocations =
170 *report.invocation_tracker.get("repeated").expect("repeated should be populated");
171 assert_eq!(
172 repeated_invocations, 3,
173 "Expected 'repeated' to have 3 invocations, got: {repeated_invocations}"
174 );
175
176 assert!(
179 !report.cycle_tracker.contains_key("f"),
180 "Expected cycle_tracker to NOT contain 'f' (non-report variant)"
181 );
182 assert!(
183 !report.cycle_tracker.contains_key("g"),
184 "Expected cycle_tracker to NOT contain 'g' (non-report variant)"
185 );
186
187 tracing::info!("report: {}", report);
188 }
189
190 #[tokio::test]
194 async fn test_cycle_tracker_macro_non_report() {
195 utils::setup_logger();
196 let client = MockProver::new().await;
197 let elf = test_artifacts::CYCLE_TRACKER_ELF;
198 let stdin = SP1Stdin::new();
199
200 let (_pv, report) = client.execute(elf, stdin).await.unwrap();
201
202 assert!(
204 !report.cycle_tracker.contains_key("f"),
205 "Non-report variant 'f' should not be in cycle_tracker"
206 );
207 }
208
209 #[tokio::test]
211 async fn test_cycle_tracker_across_chunks() {
212 use sp1_core_executor::SP1CoreOpts;
213
214 utils::setup_logger();
215
216 let mut opts = SP1CoreOpts::default();
218 opts.minimal_trace_chunk_threshold = 1000;
219
220 let client = MockProver::new_with_opts(opts).await;
221 let elf = test_artifacts::CYCLE_TRACKER_ELF;
222 let stdin = SP1Stdin::new();
223
224 let (_pv, report) = client.execute(elf, stdin).calculate_gas(true).await.unwrap();
226
227 assert!(report.cycle_tracker.contains_key("h"));
229 assert!(*report.cycle_tracker.get("h").unwrap() > 0);
230
231 assert!(report.cycle_tracker.contains_key("repeated"));
232 assert!(*report.cycle_tracker.get("repeated").unwrap() > 0);
233
234 assert_eq!(*report.invocation_tracker.get("repeated").unwrap_or(&0), 3);
235 }
236
237 #[tokio::test]
238 async fn test_e2e_core() {
239 utils::setup_logger();
240 let client = ProverClient::builder().cpu().build().await;
241 let elf = test_artifacts::FIBONACCI_ELF;
242 let pk = client.setup(elf).await.unwrap();
243 let mut stdin = SP1Stdin::new();
244 stdin.write(&10usize);
245
246 let mut proof = client.prove(&pk, stdin).await.unwrap();
248 client.verify(&proof, &pk.vk, None).unwrap();
249
250 proof.public_values = SP1PublicValues::from(&[255, 4, 84]);
252 if client.verify(&proof, &pk.vk, None).is_ok() {
253 panic!("verified proof with invalid public values")
254 }
255 }
256
257 #[tokio::test]
258 async fn test_e2e_core_panic() {
259 use sp1_core_executor::StatusCode;
260
261 use crate::{prover::ProveRequest, CpuProver};
262
263 utils::setup_logger();
264 let client = CpuProver::new().await;
265 let elf = test_artifacts::PANIC_ELF;
266 let pk = client.setup(elf).await.unwrap();
267 let stdin = SP1Stdin::new();
268
269 let proof = client.prove(&pk, stdin).core().await.unwrap();
271 client.verify(&proof, &pk.vk, StatusCode::new(1)).unwrap();
272
273 if client.verify(&proof, &pk.vk, None).is_ok() {
274 panic!("verified proof with invalid exit code")
275 }
276
277 if client.verify(&proof, &pk.vk, StatusCode::new(0)).is_ok() {
278 panic!("verified proof with invalid exit code")
279 }
280 }
281
282 #[tokio::test]
299 async fn test_e2e_compressed() {
300 use crate::{prover::ProveRequest, CpuProver};
301
302 utils::setup_logger();
303 let client = CpuProver::new().await;
304 let elf = test_artifacts::FIBONACCI_ELF;
305 let pk = client.setup(elf).await.unwrap();
306 let mut stdin = SP1Stdin::new();
307 stdin.write(&10usize);
308
309 let mut proof = client.prove(&pk, stdin).compressed().await.unwrap();
311 client.verify(&proof, &pk.vk, None).unwrap();
312
313 proof.public_values = SP1PublicValues::from(&[255, 4, 84]);
315 if client.verify(&proof, &pk.vk, None).is_ok() {
316 panic!("verified proof with invalid public values")
317 }
318 }
319
320 #[tokio::test]
321 async fn test_e2e_compressed_panic() {
322 use sp1_core_executor::StatusCode;
323
324 use crate::{prover::ProveRequest, CpuProver};
325
326 utils::setup_logger();
327 let client = CpuProver::new().await;
328 let elf = test_artifacts::PANIC_ELF;
329 let pk = client.setup(elf).await.unwrap();
330 let stdin = SP1Stdin::new();
331
332 let proof = client.prove(&pk, stdin).compressed().await.unwrap();
334 client.verify(&proof, &pk.vk, StatusCode::new(1)).unwrap();
335
336 if client.verify(&proof, &pk.vk, None).is_ok() {
337 panic!("verified proof with invalid exit code")
338 }
339
340 if client.verify(&proof, &pk.vk, StatusCode::new(0)).is_ok() {
341 panic!("verified proof with invalid exit code")
342 }
343 }
344
345 #[tokio::test]
346 async fn test_e2e_plonk() {
347 use crate::{prover::ProveRequest, CpuProver};
348
349 utils::setup_logger();
350 let client = CpuProver::new().await;
351 let pk = client.setup(test_artifacts::FIBONACCI_ELF).await.unwrap();
352 let mut stdin = SP1Stdin::new();
353 stdin.write(&10usize);
354
355 let proof = client.prove(&pk, stdin).plonk().await.unwrap();
356 client.verify(&proof, &pk.vk, None).unwrap();
357 }
358
359 #[tokio::test]
360 async fn test_e2e_groth16() {
361 use crate::{prover::ProveRequest, CpuProver};
362
363 utils::setup_logger();
364 let client = CpuProver::new().await;
365 let elf = test_artifacts::FIBONACCI_ELF;
366 let pk = client.setup(elf).await.unwrap();
367 let mut stdin = SP1Stdin::new();
368 stdin.write(&10usize);
369
370 let proof = client.prove(&pk, stdin).groth16().await.unwrap();
371
372 client.verify(&proof, &pk.vk, None).unwrap();
373 }
374}