lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit a9f2f4c67d597ee1ebf4332c0dfe5f8adb3c6b99
parent 9e3cf381fb8c520cce3e4a7479c43aedee86605d
Author: triesap <tyson@radroots.org>
Date:   Thu, 21 May 2026 21:24:12 +0000

sp1_host_trade: add proof engine selection

- add verifier/prover feature separation for remote proof requests
- bind remote proof requests to expected public-values hashes
- expose explicit cpu and cuda proof-engine generation paths
- update lock state for SP1 CUDA proving support

Diffstat:
MCargo.lock | 24++++++++++++++++++++++++
Mcrates/sp1_host_trade/Cargo.toml | 2++
Mcrates/sp1_host_trade/src/lib.rs | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
3 files changed, 125 insertions(+), 4 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -4392,6 +4392,7 @@ version = "0.1.0-alpha.2" dependencies = [ "base64 0.22.1", "bincode", + "futures", "radroots_events", "radroots_sp1_guest_trade", "radroots_trade", @@ -5945,6 +5946,28 @@ dependencies = [ ] [[package]] +name = "sp1-cuda" +version = "6.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f787fa4b5cbd29e9baddee1e590c5e689333f2b01e5f704293b7f6f17570c" +dependencies = [ + "bincode", + "bytes", + "reqwest", + "serde", + "serde_json", + "sp1-core-executor", + "sp1-core-machine", + "sp1-hypercube", + "sp1-primitives", + "sp1-prover", + "sp1-prover-types", + "thiserror 1.0.69", + "tokio", + "tracing", +] + +[[package]] name = "sp1-curves" version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6320,6 +6343,7 @@ dependencies = [ "sp1-core-executor", "sp1-core-executor-runner", "sp1-core-machine", + "sp1-cuda", "sp1-hypercube", "sp1-primitives", "sp1-prover", diff --git a/crates/sp1_host_trade/Cargo.toml b/crates/sp1_host_trade/Cargo.toml @@ -15,10 +15,12 @@ homepage.workspace = true default = [] sp1_verify = ["dep:bincode", "dep:sp1-build", "dep:sp1-sdk"] sp1_proving = ["sp1_verify"] +sp1_cuda = ["dep:futures", "sp1_proving", "sp1-sdk/cuda"] [dependencies] base64 = { workspace = true } bincode = { workspace = true, optional = true } +futures = { workspace = true, optional = true } radroots_sp1_guest_trade = { workspace = true } radroots_trade = { workspace = true, default-features = false, features = [ "serde_json", diff --git a/crates/sp1_host_trade/src/lib.rs b/crates/sp1_host_trade/src/lib.rs @@ -169,6 +169,36 @@ impl core::fmt::Display for RadrootsSp1TradeProverBackend { #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] +pub enum RadrootsSp1TradeProofEngine { + Cpu, + Cuda, +} + +impl RadrootsSp1TradeProofEngine { + pub const fn as_str(self) -> &'static str { + match self { + Self::Cpu => "cpu", + Self::Cuda => "cuda", + } + } + + pub fn from_label(value: &str) -> Option<Self> { + match value { + "cpu" => Some(Self::Cpu), + "cuda" => Some(Self::Cuda), + _ => None, + } + } +} + +impl core::fmt::Display for RadrootsSp1TradeProofEngine { + fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + formatter.write_str(self.as_str()) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] pub enum RadrootsSp1TradeRemoteProverStatus { Accepted, Running, @@ -228,6 +258,7 @@ pub struct RadrootsSp1TradeRemoteProverRequest { pub witness: RadrootsSp1TradeOrderAcceptanceWitness, pub expected_sp1_program_hash: String, pub expected_sp1_verifying_key_hash: String, + pub expected_public_values_hash: String, pub expected_reducer_program_hash: String, pub expected_protocol_version: String, pub expected_witness_version: u32, @@ -330,6 +361,8 @@ pub enum RadrootsSp1TradeHostError { Sp1PublicValuesMismatch, #[error("SP1 proof generation requires the sp1_proving feature")] Sp1ProofGenerationRequired, + #[error("SP1 CUDA proof generation is unavailable: {0}")] + Sp1CudaProofEngineUnavailable(String), #[error("SP1 proof mode is required")] Sp1ProofModeRequired, #[error("SP1 setup failed: {0}")] @@ -461,12 +494,72 @@ pub async fn generate_order_acceptance_sp1_proof( witness: &RadrootsSp1TradeOrderAcceptanceWitness, mode: RadrootsSp1TradeProofMode, ) -> Result<RadrootsSp1TradeProofBundle, RadrootsSp1TradeHostError> { - use sp1_sdk::{ - HashableKey, ProveRequest, Prover, ProverClient, ProvingKey, SP1Stdin, StatusCode, - }; + generate_order_acceptance_sp1_proof_with_engine(witness, mode, RadrootsSp1TradeProofEngine::Cpu) + .await +} + +#[cfg(feature = "sp1_proving")] +pub async fn generate_order_acceptance_sp1_proof_with_engine( + witness: &RadrootsSp1TradeOrderAcceptanceWitness, + mode: RadrootsSp1TradeProofMode, + engine: RadrootsSp1TradeProofEngine, +) -> Result<RadrootsSp1TradeProofBundle, RadrootsSp1TradeHostError> { + match engine { + RadrootsSp1TradeProofEngine::Cpu => { + let client = sp1_sdk::ProverClient::builder().cpu().build().await; + generate_order_acceptance_sp1_proof_with_client(&client, witness, mode).await + } + RadrootsSp1TradeProofEngine::Cuda => { + generate_order_acceptance_sp1_cuda_proof(witness, mode).await + } + } +} + +#[cfg(all(feature = "sp1_proving", feature = "sp1_cuda"))] +async fn generate_order_acceptance_sp1_cuda_proof( + witness: &RadrootsSp1TradeOrderAcceptanceWitness, + mode: RadrootsSp1TradeProofMode, +) -> Result<RadrootsSp1TradeProofBundle, RadrootsSp1TradeHostError> { + use futures::FutureExt; + let client = std::panic::AssertUnwindSafe(sp1_sdk::ProverClient::builder().cuda().build()) + .catch_unwind() + .await + .map_err(cuda_panic_to_host_error)?; + generate_order_acceptance_sp1_proof_with_client(&client, witness, mode).await +} + +#[cfg(all(feature = "sp1_proving", feature = "sp1_cuda"))] +fn cuda_panic_to_host_error(payload: Box<dyn std::any::Any + Send>) -> RadrootsSp1TradeHostError { + let message = payload + .downcast_ref::<&str>() + .map(|value| (*value).to_owned()) + .or_else(|| payload.downcast_ref::<String>().cloned()) + .unwrap_or_else(|| "CUDA prover initialization failed".to_owned()); + RadrootsSp1TradeHostError::Sp1CudaProofEngineUnavailable(message) +} + +#[cfg(all(feature = "sp1_proving", not(feature = "sp1_cuda")))] +async fn generate_order_acceptance_sp1_cuda_proof( + _witness: &RadrootsSp1TradeOrderAcceptanceWitness, + _mode: RadrootsSp1TradeProofMode, +) -> Result<RadrootsSp1TradeProofBundle, RadrootsSp1TradeHostError> { + Err(RadrootsSp1TradeHostError::Sp1CudaProofEngineUnavailable( + "build without sp1_cuda feature".to_owned(), + )) +} + +#[cfg(feature = "sp1_proving")] +async fn generate_order_acceptance_sp1_proof_with_client<P>( + client: &P, + witness: &RadrootsSp1TradeOrderAcceptanceWitness, + mode: RadrootsSp1TradeProofMode, +) -> Result<RadrootsSp1TradeProofBundle, RadrootsSp1TradeHostError> +where + P: sp1_sdk::Prover, +{ + use sp1_sdk::{HashableKey, ProveRequest, ProvingKey, SP1Stdin, StatusCode}; let sp1_mode = sp1_proof_mode(mode)?; - let client = ProverClient::builder().cpu().build().await; let elf = order_acceptance_guest_elf(); let sp1_program_hash = sp1_program_hash_for_elf(&elf); let pk = client @@ -1945,6 +2038,8 @@ mod tests { "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".to_string(), expected_sp1_verifying_key_hash: "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb".to_string(), + expected_public_values_hash: + "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc".to_string(), expected_reducer_program_hash: RADROOTS_SP1_TRADE_REDUCER_PROGRAM_HASH.to_string(), expected_protocol_version: RADROOTS_SP1_TRADE_PROTOCOL_VERSION.to_string(), expected_witness_version: RADROOTS_SP1_TRADE_WITNESS_VERSION,