We Investigated Adding an SP1 Backend. Here's Why We Didn't.
This project's HTTP server has a ProverBackend trait built specifically to support more than one proving backend. SP1 was the obvious first candidate to add. Here's what actually happened when we tried.
"Multi-VM router" is easy to claim and hard to actually build — most projects that say it either have one real backend and N stubs, or haven't tried adding the second one yet. Before writing that claim into this project's own docs, we tried adding SP1 as a real second backend, verified every API claim against SP1's actual source at a pinned version (not assumed from memory), and wrote down exactly why it didn't ship.
What actually checked out
SP1's Rust API is real and does what its docs say:
ProverClient::from_env()— confirmed against the real source, not guessedsetup()returns a singleSP1ProvingKey, not a(pk, vk)tuple — an earlier pasted integration draft claimed the tuple form and was wrong; the real signature only became clear from reading SP1's source at the exact tagprove()takesstdinby value, not by reference — same story, a plausible-looking draft got this backward
Both corrections came from reading the actual crate source at a pinned version, not from documentation summaries or memory — which is the same discipline applied throughout this repo: verify the exact API before writing code against it, or don't write the code yet.
What didn't check out
| Finding | What we measured |
|---|---|
| Dependency count for a bare hello-world SP1 program | 518 resolved crates — more than 3x this entire workspace's own dependency count |
| Native toolchain requirement | A Go-based FFI dependency (sp1-recursion-gnark-ffi) for Groth16 wrapping — a second language toolchain just to link the prover |
| Build time before reaching a working state | cargo check ran for roughly 4 minutes before failing on a missing system dependency (protoc) — before ever reaching the RISC-V toolchain step, let alone producing a proof |
The more fundamental mismatch
Even past the dependency weight, there's an architectural problem that no amount of patience with the build fixes: SP1 proves compiled RISC-V ELF binaries. This project's ISA is .zkasm — a custom, minimal instruction set with no RISC-V compatibility layer. Wiring SP1 in isn't "add a backend," it's "build a compiler from .zkasm to RISC-V first," which is a different, much larger project than a proving-backend integration.
That's the fork this investigation actually surfaced: keep extending .zkasm as its own ISA and own that stack end to end, or treat .zkasm as a demo fixture and make the router the real product, accepting whatever ISA a backend brings. This project chose the former — see docs/ROADMAP.md for the reasoning. The ProverBackend trait and ProverRouter stay in the codebase either way — future backends aren't ruled out — but they'd need to speak this ISA's semantics, not plug in as-is.
stark, this project's own Winterfell-based prover) and one honestly-labeled routing stub (mock-echo), which refuses to verify anything rather than faking success. GET /v1/backends reports exactly that — a checkable claim, not marketing copy.