From 34b03acd32565682967945127c531958e9f74fde Mon Sep 17 00:00:00 2001 From: Stefan Date: Mon, 4 May 2026 21:12:25 +0200 Subject: [PATCH 1/2] feat(server): in-process verifier-only zkVM backend Adds `kind: verifier` to zkVMConfig: zkboost links the lightweight ere-verifier-* crate in-process and verifies proofs without an ere-server. The program verifying key (.vk) is downloaded at startup from `program_vk_url` (HTTP or file://); pre-computed .vk files are shipped in eth-act/ere-guests releases alongside the .elf. - Cargo.toml: add ere-verifier-core, ere-verifier-zisk workspace deps pinned to ere v0.8.1 - crates/server: optional ere-verifier-core/zisk deps + verifier-zisk feature, in default features - crates/server/src/proof/verifier.rs: DynVerifier enum (feature-gated per zkVM), per-proof_type construction from program_vk_url, verify via in-process zkVMVerifier - zkVMInstance::Verifier variant; prove returns error, verify dispatches in-process; no worker spawned --- Cargo.lock | 301 +++++++++++++++++++++++++--- Cargo.toml | 2 + crates/server/Cargo.toml | 5 +- crates/server/src/config.rs | 24 ++- crates/server/src/proof.rs | 1 + crates/server/src/proof/verifier.rs | 94 +++++++++ crates/server/src/proof/zkvm.rs | 46 ++++- crates/server/src/server.rs | 5 + 8 files changed, 447 insertions(+), 31 deletions(-) create mode 100644 crates/server/src/proof/verifier.rs diff --git a/Cargo.lock b/Cargo.lock index c6721ce..3a3ead3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -358,7 +358,7 @@ dependencies = [ "alloy-rlp", "alloy-serde", "alloy-sol-types", - "itertools 0.14.0", + "itertools 0.13.0", "serde", "serde_json", "serde_with", @@ -1050,6 +1050,15 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bincode" version = "2.0.1" @@ -1296,6 +1305,38 @@ dependencies = [ "serde", ] +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.27", + "serde", + "serde_json", + "thiserror 2.0.18", +] + [[package]] name = "cc" version = "1.2.56" @@ -1329,7 +1370,7 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -1397,6 +1438,15 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "colored" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "compare_fields" version = "0.1.1" @@ -2145,7 +2195,7 @@ source = "git+https://github.com/eth-act/ere?tag=v0.8.0#54b00745fa5fabe008b037f6 dependencies = [ "anyhow", "auto_impl", - "bincode", + "bincode 2.0.1", "ere-codec 0.8.0", "ere-verifier-core 0.8.0", "indexmap 2.13.0", @@ -2161,7 +2211,7 @@ source = "git+https://github.com/eth-act/ere?tag=v0.8.1#653b406fa352f4c53161810c dependencies = [ "anyhow", "auto_impl", - "bincode", + "bincode 2.0.1", "ere-codec 0.8.1", "ere-verifier-core 0.8.1", "indexmap 2.13.0", @@ -2185,7 +2235,7 @@ name = "ere-server-client" version = "0.8.1" source = "git+https://github.com/eth-act/ere?tag=v0.8.1#653b406fa352f4c53161810c4ef078e79ec45b1b" dependencies = [ - "bincode", + "bincode 2.0.1", "ere-prover-core 0.8.1", "ere-server-api", "opentelemetry", @@ -2195,6 +2245,14 @@ dependencies = [ "twirp", ] +[[package]] +name = "ere-util-build" +version = "0.8.1" +source = "git+https://github.com/eth-act/ere?tag=v0.8.1#653b406fa352f4c53161810c4ef078e79ec45b1b" +dependencies = [ + "cargo_metadata", +] + [[package]] name = "ere-verifier-core" version = "0.8.0" @@ -2215,6 +2273,22 @@ dependencies = [ "serde", ] +[[package]] +name = "ere-verifier-zisk" +version = "0.8.1" +source = "git+https://github.com/eth-act/ere?tag=v0.8.1#653b406fa352f4c53161810c4ef078e79ec45b1b" +dependencies = [ + "bincode 2.0.1", + "bytemuck", + "ere-util-build", + "ere-verifier-core 0.8.1", + "proofman-util", + "proofman-verifier", + "serde", + "serde-big-array", + "thiserror 2.0.18", +] + [[package]] name = "errno" version = "0.3.14" @@ -2222,7 +2296,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -2675,6 +2749,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "fields" +version = "0.16.1" +source = "git+https://github.com/0xPolygonHermez/pil2-proofman.git?tag=v0.16.1#971209423e8fa53fa32dc747744d68c65aafa6c7" +dependencies = [ + "cfg-if", + "num-bigint", + "paste", + "serde", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -3262,7 +3347,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core", + "windows-core 0.62.2", ] [[package]] @@ -4090,13 +4175,22 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "ntapi" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" +dependencies = [ + "winapi", +] + [[package]] name = "nu-ansi-term" version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -4243,12 +4337,31 @@ dependencies = [ "objc2-encode", ] +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags", +] + [[package]] name = "objc2-encode" version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" +[[package]] +name = "objc2-io-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -4483,7 +4596,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -4810,6 +4923,30 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "proofman-util" +version = "0.16.1" +source = "git+https://github.com/0xPolygonHermez/pil2-proofman.git?tag=v0.16.1#971209423e8fa53fa32dc747744d68c65aafa6c7" +dependencies = [ + "bincode 1.3.3", + "bytemuck", + "colored", + "serde", + "sysinfo", +] + +[[package]] +name = "proofman-verifier" +version = "0.16.1" +source = "git+https://github.com/0xPolygonHermez/pil2-proofman.git?tag=v0.16.1#971209423e8fa53fa32dc747744d68c65aafa6c7" +dependencies = [ + "bytemuck", + "fields", + "proofman-util", + "rayon", + "tracing", +] + [[package]] name = "proptest" version = "1.10.0" @@ -4846,7 +4983,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.10.5", "proc-macro2", "quote", "syn 2.0.117", @@ -5960,7 +6097,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.12.1", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -6181,6 +6318,10 @@ name = "semver" version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] [[package]] name = "semver-parser" @@ -6201,6 +6342,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + [[package]] name = "serde_core" version = "1.0.228" @@ -6615,7 +6765,7 @@ dependencies = [ "alloy-rlp", "alloy-rpc-types-engine", "anyhow", - "bincode", + "bincode 2.0.1", "ere-prover-core 0.8.0", "guest", "once_cell", @@ -6749,6 +6899,20 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "sysinfo" +version = "0.35.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3ffa3e4ff2b324a57f7aeb3c349656c7b127c3c189520251a648102a92496e" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "windows", +] + [[package]] name = "system-configuration" version = "0.7.0" @@ -6786,7 +6950,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix 1.1.4", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -7745,6 +7909,41 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + [[package]] name = "windows-core" version = "0.62.2" @@ -7753,9 +7952,20 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", ] [[package]] @@ -7780,21 +7990,46 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + [[package]] name = "windows-registry" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-link", - "windows-result", - "windows-strings", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -7803,7 +8038,16 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -7812,7 +8056,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -7848,7 +8092,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -7873,7 +8117,7 @@ version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link", + "windows-link 0.2.1", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", @@ -7884,6 +8128,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -8252,6 +8505,8 @@ dependencies = [ "bytes", "clap", "ere-server-client", + "ere-verifier-core 0.8.1", + "ere-verifier-zisk", "futures", "lru 0.12.5", "metrics", diff --git a/Cargo.toml b/Cargo.toml index 4e7392c..dd5c46d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,6 +85,8 @@ stateless = { git = "https://github.com/paradigmxyz/stateless", rev = "ed189a519 # ere ere-server-client = { git = "https://github.com/eth-act/ere", tag = "v0.8.1" } +ere-verifier-core = { git = "https://github.com/eth-act/ere", tag = "v0.8.1" } +ere-verifier-zisk = { git = "https://github.com/eth-act/ere", tag = "v0.8.1" } # ere-guests ere-guests-stateless-validator-common = { git = "https://github.com/eth-act/ere-guests", tag = "v0.9.0", package = "stateless-validator-common" } diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index 3efa1bf..0b9f729 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -13,7 +13,7 @@ path = "src/bin/zkboost.rs" workspace = true [features] -default = [] +default = ["verifier-zisk"] otel = [ "dep:opentelemetry", "dep:opentelemetry-otlp", @@ -21,6 +21,7 @@ otel = [ "dep:tracing-opentelemetry", "ere-server-client/otel", ] +verifier-zisk = ["dep:ere-verifier-core", "dep:ere-verifier-zisk"] [dependencies] anyhow.workspace = true @@ -65,6 +66,8 @@ stateless.workspace = true # ere ere-server-client.workspace = true +ere-verifier-core = { workspace = true, optional = true } +ere-verifier-zisk = { workspace = true, optional = true } # ere-guests ere-guests-stateless-validator-common.workspace = true diff --git a/crates/server/src/config.rs b/crates/server/src/config.rs index 1d7b3b7..41d6914 100644 --- a/crates/server/src/config.rs +++ b/crates/server/src/config.rs @@ -125,6 +125,12 @@ impl Config { "proof_timeout_secs must be > 0 for {proof_type}" ); } + zkVMConfig::Verifier { program_vk_url, .. } => { + ensure!( + !program_vk_url.is_empty(), + "program_vk_url must be set for verifier-only zkvm {proof_type}" + ); + } } if let zkVMConfig::Mock { mock_proving_time, @@ -168,7 +174,8 @@ pub enum MockProvingTime { }, } -/// zkVM backend configuration, either a remote ere-server or a mock for testing. +/// zkVM backend configuration, either a remote ere-server, a mock, or an +/// in-process verifier-only backend (no proving). #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "kind", rename_all = "lowercase")] #[allow(non_camel_case_types)] @@ -200,13 +207,26 @@ pub enum zkVMConfig { #[serde(default)] mock_failure: bool, }, + /// In-process verifier-only backend. Verifies proofs received via HTTP + /// without running an `ere-server` or pre-loading prover circuits. + /// Returns an error on prove requests. + Verifier { + /// Proof type. + proof_type: ProofType, + /// URL or local path to the program verifying key file (.vk) for the + /// guest program of this proof type. Pre-computed and shipped in + /// `eth-act/ere-guests` releases alongside the .elf. + program_vk_url: String, + }, } impl zkVMConfig { /// Returns the proof type identifier for this configuration. pub fn proof_type(&self) -> ProofType { match self { - Self::Ere { proof_type, .. } | Self::Mock { proof_type, .. } => *proof_type, + Self::Ere { proof_type, .. } + | Self::Mock { proof_type, .. } + | Self::Verifier { proof_type, .. } => *proof_type, } } } diff --git a/crates/server/src/proof.rs b/crates/server/src/proof.rs index 86fea03..912bac2 100644 --- a/crates/server/src/proof.rs +++ b/crates/server/src/proof.rs @@ -2,6 +2,7 @@ //! (dispatched to per-zkVM worker), and completed (cached in LRU, broadcast via SSE). pub mod input; +pub mod verifier; pub mod worker; pub mod zkvm; diff --git a/crates/server/src/proof/verifier.rs b/crates/server/src/proof/verifier.rs new file mode 100644 index 0000000..8bbaac8 --- /dev/null +++ b/crates/server/src/proof/verifier.rs @@ -0,0 +1,94 @@ +//! In-process verifier-only backends. +//! +//! Wraps the per-zkVM `ere-verifier-*` crates so zkboost can verify proofs +//! without a remote `ere-server` (which loads the full prover circuit). Each +//! verifier is bound to a specific compiled guest program via its +//! `program_vk`, downloaded from the URL configured for that proof_type. + +use anyhow::Context; +use zkboost_types::ProofType; + +#[cfg(feature = "verifier-zisk")] +use ere_verifier_core::{PublicValues, codec::Decode, zkVMVerifier}; + +/// Per-zkVM verifier dispatch. Variants are feature-gated. +#[allow(non_camel_case_types)] +pub(crate) enum DynVerifier { + /// In-process ZisK verifier. + #[cfg(feature = "verifier-zisk")] + Zisk(ere_verifier_zisk::ZiskVerifier), +} + +impl std::fmt::Debug for DynVerifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + #[cfg(feature = "verifier-zisk")] + Self::Zisk(_) => f.write_str("DynVerifier::Zisk"), + #[cfg(not(any(feature = "verifier-zisk")))] + _ => f.write_str("DynVerifier::"), + } + } +} + +impl DynVerifier { + /// Construct a verifier for the given proof_type by downloading the + /// program verifying key from `url` and decoding it. + pub(crate) async fn from_url(proof_type: ProofType, url: &str) -> anyhow::Result { + let bytes = download_program_vk(url).await?; + Self::from_bytes(proof_type, &bytes) + } + + fn from_bytes(proof_type: ProofType, bytes: &[u8]) -> anyhow::Result { + match proof_type { + #[cfg(feature = "verifier-zisk")] + ProofType::EthrexZisk | ProofType::RethZisk => { + let program_vk = ere_verifier_zisk::ZiskProgramVk::decode_from_slice(bytes) + .with_context(|| format!("decode ZiskProgramVk for {proof_type}"))?; + Ok(Self::Zisk(ere_verifier_zisk::ZiskVerifier::new(program_vk))) + } + #[allow(unreachable_patterns)] + _ => anyhow::bail!( + "no in-process verifier compiled in for proof_type {proof_type}; \ + enable the matching `verifier-*` feature on `zkboost-server`" + ), + } + } + + /// Verify a serialized proof and return its public values. + pub(crate) async fn verify(&self, proof: &[u8]) -> anyhow::Result> { + match self { + #[cfg(feature = "verifier-zisk")] + Self::Zisk(verifier) => { + let proof = ere_verifier_zisk::ZiskProof::decode_from_slice(proof) + .context("decode ZiskProof")?; + let public_values: PublicValues = verifier + .verify(&proof) + .map_err(|error| anyhow::anyhow!("zisk verify failed: {error}"))?; + Ok(Vec::::from(public_values)) + } + } + } +} + +async fn download_program_vk(url: &str) -> anyhow::Result> { + if let Some(path) = url.strip_prefix("file://").or_else(|| { + if url.contains("://") { + None + } else { + Some(url) + } + }) { + return std::fs::read(path) + .with_context(|| format!("read program_vk from {path}")); + } + let bytes = reqwest::get(url) + .await + .with_context(|| format!("GET {url}"))? + .error_for_status() + .with_context(|| format!("status from {url}"))? + .bytes() + .await + .with_context(|| format!("body from {url}"))? + .to_vec(); + Ok(bytes) +} diff --git a/crates/server/src/proof/zkvm.rs b/crates/server/src/proof/zkvm.rs index f2c0131..2d07cf8 100644 --- a/crates/server/src/proof/zkvm.rs +++ b/crates/server/src/proof/zkvm.rs @@ -24,7 +24,7 @@ use zkboost_types::{ElKind, Hash256, ProofType}; use crate::{ config::{MockProvingTime, zkVMConfig}, - proof::input::NewPayloadRequestWithWitness, + proof::{input::NewPayloadRequestWithWitness, verifier::DynVerifier}, }; #[derive(Debug, thiserror::Error)] @@ -38,7 +38,7 @@ pub(crate) enum zkVMError { PublicValuesMismatch, } -/// zkVM instance, either a remote ere-server or a mock. +/// zkVM instance: remote ere-server, in-process mock, or in-process verifier-only. #[allow(non_camel_case_types)] #[derive(Clone, Debug)] pub(crate) enum zkVMInstance { @@ -60,6 +60,15 @@ pub(crate) enum zkVMInstance { /// Mock zkVM implementation. vm: MockzkVM, }, + /// In-process verifier-only backend. No `ere-server`, no prover circuit + /// loaded — just the lightweight `ere-verifier-*` for this proof type. + /// Returns an error on prove requests. + Verifier { + /// Proof type identifier. + proof_type: ProofType, + /// Verifier implementation, dispatched per proof_type. + verifier: Arc, + }, } impl zkVMInstance { @@ -106,6 +115,20 @@ impl zkVMInstance { *mock_failure, ), }), + zkVMConfig::Verifier { + proof_type, + program_vk_url, + } => { + let verifier = DynVerifier::from_url(*proof_type, program_vk_url) + .await + .with_context(|| { + format!("init in-process verifier for {proof_type} from {program_vk_url}") + })?; + Ok(Self::Verifier { + proof_type: *proof_type, + verifier: Arc::new(verifier), + }) + } } } @@ -119,6 +142,9 @@ impl zkVMInstance { .prove(new_payload_request_with_witness.stateless_input()) .await; } + if let Self::Verifier { proof_type, .. } = self { + anyhow::bail!("prove not supported for verifier-only zkvm {proof_type}"); + } let el_kind = self.proof_type().el_kind(); let input = new_payload_request_with_witness.to_zkvm_input(el_kind)?; @@ -127,7 +153,7 @@ impl zkVMInstance { let (_, proof, _) = client.prove(input).await?; Ok(proof.0) } - Self::Mock { .. } => unreachable!(), + Self::Mock { .. } | Self::Verifier { .. } => unreachable!(), } } @@ -137,7 +163,7 @@ impl zkVMInstance { new_payload_request_root: Hash256, proof: Vec, ) -> Result<(), zkVMError> { - let public_values = match self { + let public_values: PublicValues = match self { Self::Ere { client, .. } => client .verify(EncodedProof(proof)) .await @@ -146,6 +172,11 @@ impl zkVMInstance { .verify(&proof) .await .map_err(|error| zkVMError::VerificationFailed(error.to_string())), + Self::Verifier { verifier, .. } => verifier + .verify(&proof) + .await + .map(PublicValues::from) + .map_err(|error| zkVMError::VerificationFailed(error.to_string())), }?; let expected = expected_public_values(new_payload_request_root) @@ -166,14 +197,19 @@ impl zkVMInstance { /// Returns the proof type identifier for this instance. pub(crate) fn proof_type(&self) -> ProofType { match self { - Self::Ere { proof_type, .. } | Self::Mock { proof_type, .. } => *proof_type, + Self::Ere { proof_type, .. } + | Self::Mock { proof_type, .. } + | Self::Verifier { proof_type, .. } => *proof_type, } } /// Returns the proof timeout for this instance. + /// Verifier-only backends never prove, so the timeout is irrelevant — we + /// return the default to keep the signature uniform. pub(crate) fn proof_timeout(&self) -> Duration { match self { Self::Ere { proof_timeout, .. } | Self::Mock { proof_timeout, .. } => *proof_timeout, + Self::Verifier { .. } => Duration::from_secs(12), } } } diff --git a/crates/server/src/server.rs b/crates/server/src/server.rs index 63f1b75..f10431f 100644 --- a/crates/server/src/server.rs +++ b/crates/server/src/server.rs @@ -132,6 +132,11 @@ impl zkBoostServer { let mut worker_input_txs = HashMap::new(); for zkvm in self.zkvms.values() { + // Verifier-only backends don't prove, so they get no worker. Prove + // requests for those proof_types are dropped at the dispatch layer. + if matches!(zkvm, zkVMInstance::Verifier { .. }) { + continue; + } let (worker_input_tx, worker_input_rx) = mpsc::channel(CHANNEL_CAPACITY); worker_input_txs.insert(zkvm.proof_type(), worker_input_tx); handles.push(tokio::spawn(worker::run_worker( From 77e0158db8649dacca15ec4c0ece9d7336f73da4 Mon Sep 17 00:00:00 2001 From: han0110 Date: Wed, 6 May 2026 06:48:26 +0000 Subject: [PATCH 2/2] fix: fmt --- crates/server/src/proof/verifier.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/crates/server/src/proof/verifier.rs b/crates/server/src/proof/verifier.rs index 8bbaac8..faa8c0e 100644 --- a/crates/server/src/proof/verifier.rs +++ b/crates/server/src/proof/verifier.rs @@ -6,10 +6,9 @@ //! `program_vk`, downloaded from the URL configured for that proof_type. use anyhow::Context; -use zkboost_types::ProofType; - #[cfg(feature = "verifier-zisk")] use ere_verifier_core::{PublicValues, codec::Decode, zkVMVerifier}; +use zkboost_types::ProofType; /// Per-zkVM verifier dispatch. Variants are feature-gated. #[allow(non_camel_case_types)] @@ -71,15 +70,11 @@ impl DynVerifier { } async fn download_program_vk(url: &str) -> anyhow::Result> { - if let Some(path) = url.strip_prefix("file://").or_else(|| { - if url.contains("://") { - None - } else { - Some(url) - } - }) { - return std::fs::read(path) - .with_context(|| format!("read program_vk from {path}")); + if let Some(path) = url + .strip_prefix("file://") + .or_else(|| if url.contains("://") { None } else { Some(url) }) + { + return std::fs::read(path).with_context(|| format!("read program_vk from {path}")); } let bytes = reqwest::get(url) .await