#![warn(clippy::pedantic)]
#![allow(clippy::similar_names)]
#![allow(clippy::cast_possible_wrap)]
#![allow(clippy::cast_possible_truncation)]
#![allow(clippy::cast_sign_loss)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::needless_range_loop)]
#![allow(clippy::cast_lossless)]
#![allow(clippy::bool_to_int_with_if)]
#![allow(clippy::should_panic_without_expect)]
#![allow(clippy::field_reassign_with_default)]
#![allow(clippy::manual_assert)]
#![allow(clippy::unreadable_literal)]
#![allow(clippy::match_wildcard_for_single_variants)]
#![allow(clippy::missing_panics_doc)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::explicit_iter_loop)]
#![warn(missing_docs)]
pub mod artifacts;
pub mod client;
pub mod cpu;
pub use cpu::CpuProver;
pub mod mock;
pub use mock::MockProver;
pub mod cuda;
pub use cuda::CudaProver;
pub mod env;
pub mod install;
#[cfg(feature = "network")]
pub mod network;
#[cfg(feature = "network")]
pub use network::prover::NetworkProver;
#[cfg(feature = "blocking")]
pub mod blocking;
pub mod utils;
pub use crate::client::ProverClient;
pub mod proof;
pub use proof::*;
pub mod prover;
pub use prover::{ProveRequest, Prover, ProvingKey, SP1ProvingKey, SP1VerificationError};
pub use sp1_build::include_elf;
pub use sp1_core_executor::{ExecutionReport, HookEnv, SP1Context, SP1ContextBuilder, StatusCode};
pub use sp1_core_machine::io::SP1Stdin;
pub use sp1_primitives::{io::SP1PublicValues, Elf};
pub use sp1_prover::{HashableKey, ProverMode, SP1VerifyingKey, SP1_CIRCUIT_VERSION};
pub mod prelude {
pub use super::{
include_elf, Elf, HashableKey, ProveRequest, Prover, ProvingKey, SP1ProofWithPublicValues,
SP1Stdin,
};
}
pub use utils::setup_logger;
#[cfg(all(test, feature = "slow-tests"))]
mod tests {
use sp1_primitives::io::SP1PublicValues;
use crate::{utils, MockProver, Prover, ProverClient, SP1Stdin};
#[tokio::test]
async fn test_execute() {
utils::setup_logger();
let client = ProverClient::builder().cpu().build().await;
let elf = test_artifacts::FIBONACCI_ELF;
let mut stdin = SP1Stdin::new();
stdin.write(&10usize);
let (_pv, report) = client.execute(elf, stdin).await.unwrap();
assert_eq!(report.exit_code, 0);
}
#[tokio::test]
async fn test_execute_panic() {
utils::setup_logger();
let client = ProverClient::builder().cpu().build().await;
let elf = test_artifacts::PANIC_ELF;
let mut stdin = SP1Stdin::new();
stdin.write(&10usize);
let (_, report) = client.execute(elf, stdin).await.unwrap();
assert_eq!(report.exit_code, 1);
}
#[should_panic]
#[tokio::test]
#[ignore = "The cycle limit logic needs to be reimplemented."]
async fn test_cycle_limit_fail() {
utils::setup_logger();
let client = ProverClient::builder().cpu().build().await;
let elf = test_artifacts::PANIC_ELF;
let mut stdin = SP1Stdin::new();
stdin.write(&10usize);
client.execute(elf, stdin).cycle_limit(1).await.unwrap();
}
#[tokio::test]
async fn test_cycle_tracker_report_variants() {
utils::setup_logger();
let client = MockProver::new().await;
let elf = test_artifacts::CYCLE_TRACKER_ELF;
let stdin = SP1Stdin::new();
let (_pv, report) = client.execute(elf, stdin).await.unwrap();
assert!(
report.cycle_tracker.contains_key("h"),
"Expected cycle_tracker to contain 'h', got: {:?}",
report.cycle_tracker
);
let h_cycles = *report.cycle_tracker.get("h").unwrap();
assert!(h_cycles > 0, "Expected 'h' to have positive cycles, got: {h_cycles}");
assert!(
report.cycle_tracker.contains_key("repeated"),
"Expected cycle_tracker to contain 'repeated', got: {:?}",
report.cycle_tracker
);
let repeated_cycles =
*report.cycle_tracker.get("repeated").expect("repeated should be populated");
assert!(
repeated_cycles > 0,
"Expected 'repeated' to have positive cycles, got: {repeated_cycles}"
);
assert!(
report.invocation_tracker.contains_key("repeated"),
"Expected invocation_tracker to contain 'repeated', got: {:?}",
report.invocation_tracker
);
let repeated_invocations =
*report.invocation_tracker.get("repeated").expect("repeated should be populated");
assert_eq!(
repeated_invocations, 3,
"Expected 'repeated' to have 3 invocations, got: {repeated_invocations}"
);
assert!(
!report.cycle_tracker.contains_key("f"),
"Expected cycle_tracker to NOT contain 'f' (non-report variant)"
);
assert!(
!report.cycle_tracker.contains_key("g"),
"Expected cycle_tracker to NOT contain 'g' (non-report variant)"
);
tracing::info!("report: {}", report);
}
#[tokio::test]
async fn test_cycle_tracker_macro_non_report() {
utils::setup_logger();
let client = MockProver::new().await;
let elf = test_artifacts::CYCLE_TRACKER_ELF;
let stdin = SP1Stdin::new();
let (_pv, report) = client.execute(elf, stdin).await.unwrap();
assert!(
!report.cycle_tracker.contains_key("f"),
"Non-report variant 'f' should not be in cycle_tracker"
);
}
#[tokio::test]
async fn test_cycle_tracker_across_chunks() {
use sp1_core_executor::SP1CoreOpts;
utils::setup_logger();
let mut opts = SP1CoreOpts::default();
opts.minimal_trace_chunk_threshold = 1000;
let client = MockProver::new_with_opts(opts).await;
let elf = test_artifacts::CYCLE_TRACKER_ELF;
let stdin = SP1Stdin::new();
let (_pv, report) = client.execute(elf, stdin).calculate_gas(true).await.unwrap();
assert!(report.cycle_tracker.contains_key("h"));
assert!(*report.cycle_tracker.get("h").unwrap() > 0);
assert!(report.cycle_tracker.contains_key("repeated"));
assert!(*report.cycle_tracker.get("repeated").unwrap() > 0);
assert_eq!(*report.invocation_tracker.get("repeated").unwrap_or(&0), 3);
}
#[tokio::test]
async fn test_e2e_core() {
utils::setup_logger();
let client = ProverClient::builder().cpu().build().await;
let elf = test_artifacts::FIBONACCI_ELF;
let pk = client.setup(elf).await.unwrap();
let mut stdin = SP1Stdin::new();
stdin.write(&10usize);
let mut proof = client.prove(&pk, stdin).await.unwrap();
client.verify(&proof, &pk.vk, None).unwrap();
proof.public_values = SP1PublicValues::from(&[255, 4, 84]);
if client.verify(&proof, &pk.vk, None).is_ok() {
panic!("verified proof with invalid public values")
}
}
#[tokio::test]
async fn test_e2e_core_panic() {
use sp1_core_executor::StatusCode;
use crate::{prover::ProveRequest, CpuProver};
utils::setup_logger();
let client = CpuProver::new().await;
let elf = test_artifacts::PANIC_ELF;
let pk = client.setup(elf).await.unwrap();
let stdin = SP1Stdin::new();
let proof = client.prove(&pk, stdin).core().await.unwrap();
client.verify(&proof, &pk.vk, StatusCode::new(1)).unwrap();
if client.verify(&proof, &pk.vk, None).is_ok() {
panic!("verified proof with invalid exit code")
}
if client.verify(&proof, &pk.vk, StatusCode::new(0)).is_ok() {
panic!("verified proof with invalid exit code")
}
}
#[tokio::test]
async fn test_e2e_compressed() {
use crate::{prover::ProveRequest, CpuProver};
utils::setup_logger();
let client = CpuProver::new().await;
let elf = test_artifacts::FIBONACCI_ELF;
let pk = client.setup(elf).await.unwrap();
let mut stdin = SP1Stdin::new();
stdin.write(&10usize);
let mut proof = client.prove(&pk, stdin).compressed().await.unwrap();
client.verify(&proof, &pk.vk, None).unwrap();
proof.public_values = SP1PublicValues::from(&[255, 4, 84]);
if client.verify(&proof, &pk.vk, None).is_ok() {
panic!("verified proof with invalid public values")
}
}
#[tokio::test]
async fn test_e2e_compressed_panic() {
use sp1_core_executor::StatusCode;
use crate::{prover::ProveRequest, CpuProver};
utils::setup_logger();
let client = CpuProver::new().await;
let elf = test_artifacts::PANIC_ELF;
let pk = client.setup(elf).await.unwrap();
let stdin = SP1Stdin::new();
let proof = client.prove(&pk, stdin).compressed().await.unwrap();
client.verify(&proof, &pk.vk, StatusCode::new(1)).unwrap();
if client.verify(&proof, &pk.vk, None).is_ok() {
panic!("verified proof with invalid exit code")
}
if client.verify(&proof, &pk.vk, StatusCode::new(0)).is_ok() {
panic!("verified proof with invalid exit code")
}
}
#[tokio::test]
async fn test_e2e_plonk() {
use crate::{prover::ProveRequest, CpuProver};
utils::setup_logger();
let client = CpuProver::new().await;
let pk = client.setup(test_artifacts::FIBONACCI_ELF).await.unwrap();
let mut stdin = SP1Stdin::new();
stdin.write(&10usize);
let proof = client.prove(&pk, stdin).plonk().await.unwrap();
client.verify(&proof, &pk.vk, None).unwrap();
}
#[tokio::test]
async fn test_e2e_groth16() {
use crate::{prover::ProveRequest, CpuProver};
utils::setup_logger();
let client = CpuProver::new().await;
let elf = test_artifacts::FIBONACCI_ELF;
let pk = client.setup(elf).await.unwrap();
let mut stdin = SP1Stdin::new();
stdin.write(&10usize);
let proof = client.prove(&pk, stdin).groth16().await.unwrap();
client.verify(&proof, &pk.vk, None).unwrap();
}
}