pub mod builder;
use std::pin::Pin;
use sp1_core_executor::SP1CoreOpts;
use sp1_core_machine::{io::SP1Stdin, riscv::RiscvAir};
use sp1_hypercube::Machine;
use sp1_primitives::SP1Field;
use sp1_prover::worker::{SP1LightNode, SP1NodeCore};
use crate::{
prover::{BaseProveRequest, ProveRequest},
Prover, SP1ProofWithPublicValues, SP1ProvingKey,
};
use std::future::{Future, IntoFuture};
#[derive(Clone)]
pub struct LightProver {
inner: SP1LightNode,
}
impl LightProver {
#[must_use]
pub async fn new() -> Self {
Self::new_with_machine(RiscvAir::machine()).await
}
#[must_use]
pub async fn new_with_machine(machine: Machine<SP1Field, RiscvAir<SP1Field>>) -> Self {
tracing::info!("initializing light prover");
Self { inner: SP1LightNode::new_with_machine(machine).await }
}
#[must_use]
pub async fn new_with_opts(opts: SP1CoreOpts) -> Self {
Self::new_with_opts_and_machine(RiscvAir::machine(), opts).await
}
#[must_use]
pub async fn new_with_opts_and_machine(
machine: Machine<SP1Field, RiscvAir<SP1Field>>,
opts: SP1CoreOpts,
) -> Self {
Self { inner: SP1LightNode::with_opts_and_machine(machine, opts).await }
}
}
impl Prover for LightProver {
type ProvingKey = SP1ProvingKey;
type Error = anyhow::Error;
type ProveRequest<'a> = LightProveRequest<'a>;
fn inner(&self) -> &SP1NodeCore {
self.inner.inner()
}
fn prove<'a>(&'a self, pk: &'a Self::ProvingKey, stdin: SP1Stdin) -> Self::ProveRequest<'a> {
LightProveRequest { base: BaseProveRequest::new(self, pk, stdin) }
}
fn setup(
&self,
elf: sp1_build::Elf,
) -> impl crate::prover::SendFutureResult<Self::ProvingKey, Self::Error> {
async move {
let vk = self.inner.setup(&elf).await?;
let pk = SP1ProvingKey { vk, elf };
Ok(pk)
}
}
}
pub struct LightProveRequest<'a> {
pub(crate) base: BaseProveRequest<'a, LightProver>,
}
impl<'a> ProveRequest<'a, LightProver> for LightProveRequest<'a> {
fn base(&mut self) -> &mut BaseProveRequest<'a, LightProver> {
&mut self.base
}
}
impl<'a> IntoFuture for LightProveRequest<'a> {
type Output = Result<SP1ProofWithPublicValues, anyhow::Error>;
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send + 'a>>;
fn into_future(self) -> Self::IntoFuture {
Box::pin(async move {
Err(anyhow::anyhow!(
"Use LightProver for executing and verifying only. For proving, use CpuProver"
))
})
}
}
#[cfg(test)]
mod tests {
use crate::{prover::ProveRequest, utils::setup_logger, LightProver, Prover, SP1Stdin};
#[tokio::test]
async fn test_light_execute_and_prove() {
setup_logger();
let prover = LightProver::new().await;
let pk =
prover.setup(test_artifacts::FIBONACCI_ELF).await.expect("failed to setup proving key");
let mut stdin = SP1Stdin::new();
stdin.write(&10usize);
let (pv, _) =
prover.execute(pk.elf.clone(), stdin).await.expect("failed to execute program");
assert!(!pv.as_slice().is_empty());
let mut stdin = SP1Stdin::new();
stdin.write(&10usize);
let result = prover.prove(&pk, stdin).core().await;
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("executing and verifying only"));
}
}