Building a performant and modular zkVM framework with OpenVM
EthCC[8] · 30 Jun 2025 · 14:32
Yi Sun introduces OpenVM’s modular zero-knowledge virtual-machine framework. The presentation discusses customization, extensibility and the applications enabled by its architecture.
Speakers
Topics
From EthCC[8], hosted by Ethereum France.
Transcript
Um, hey everyone. So, my name is Ye, one of the founders of Axiom and I'm here to tell you about OpenVM, which is the ZKVM framework uh that we've been building. Um, so first off to just give some motivation for what ZKVMs are good for and why they've gained some interest in the past couple years. Traditionally, the development model of ZK has required that developers take a program they're interested in proving in ZK and kind of manually translate that program into some systems of polinomial equations called circuits. And of course the problem with this is that this translation is quite laborious and can also be errorprone. Uh I think the previous talk referenced quite a bit of
security issues that can occur in this process. Um so the premise of ZKVMs is that instead of doing this developers can just write normal programs and it's on the ZK framework to address uh the translation. And so concretely how that works is that instead of writing a ZK circuit for every program, a ZKVM is nothing more than a ZK circuit for a very special program or family of programs that is an interpreter for all programs written in a certain ISA. And so the flow here now changes where the developer will take a normal computer program, compile it normally to a binary and then the ZKVM will prove that the
interpretation of this binary by the interpreter was executed correctly. And so this separates concerns between the application developer and the ZK developer with the idea that we can hyperoptimize this uh interpreter circuit. Now it does provide present some trade-offs and broadly speaking I would say that the trade-off is between performance and usability. So if we try to plot out the spectrum between the traditional approach of custom circuits and the spectrum of ZKVMs, I would say that custom circuits are still going to be the most performant. Uh but they obviously have this developer experience issue. And when you go to ZK VMland, you have a couple choices. The first is that
you could make your ISA a custom ISA that is tailored for ZK. Uh this will still have a bit of performance overhead over custom circuits. Uh but I might it might be more performant than adopting an existing ISA. Now the trade-off is that if you create a ZK adapted ISA, you still have to rewrite all your programs in this ZK adapted ISA. And so it's probably a better developer experience than custom circuits, but it's definitely not as good as reusing a traditional ISA, which will allow you to directly reuse traditional compiler tool chains and maybe even existing programs.
And so our starting point at OpenVM was that these trade-offs sort of result from committing to a fixed choice of ISA. And so the premise of OpenVM is to try to remove this trade-off by using a more modular approach to an ISA supported by a VM. And so what is OpenVM? It's a modular and performant ZKVM which is built to be customized and extended from the ground up. And so in particular, it allows developers to prove arbitrary Rust programs. It has a totally modular ISA structure through a concept we call VM extensions. And all of this is enabled
by a new approach to VM architecture which we call the no CPU architecture. And so for the rest of the this talk, just wanted to talk through these aspects. So first of all, what is a VM extension? Well, in OpenVM, we don't commit to a specific ISA that's verified in the ZKVM. Instead, we allow developers to construct their own ISAs from what we call extensions. So these are groups of op codes that interoperate over common address spaces. And these address spaces can have types. For example, in address spaces attended for risk 5 or similar architectures, it's an invariant that all field elements are bytes. On the
other hand, we have native address spaces where all um field elements are interpreted as full field elements. And so, OpenVM ships with some default extensions, for example, for risk 5, for recursion, and for all the pre-ompiles you might expect when trying to handle something like Ethereum. And so, in this way, we're actually able to support multiple tool chains in the same program. So uh today we support a Rust tool chain through compilation to RV32 and we also support what we call a native ISA that's intended for recursion. Um one particular feature is that we enable developers to mix and
match these ISAs. So it's actually possible to invoke the native ISA from within a Rust program. And further down the tool chain, OpenVM supports um continuations and proving of arbitrary length Rust programs through aggregation. Now the modular design of OpenVM means that it's actually built extension first. What that means is that all functionality in the system is supported through extensions and in particular developers can write their own extensions without forking OpenVM. uh it's possible to just import the core OpenVM library and define your own extension for a front end or pre-ompile
you might want to add. One feature I want to highlight that might be interesting is this gives developers the ability to iteratively optimize their program. Um so we support a flow where a developer can write a program that works well out of the box just using the default extensions. if they prefer to further optimize, they can write their own custom circuits and really isolate the part of their workload that takes the most time. And then finally, there's uh Powder Labs recently built some experimental work to automate the synthesis of pre-ompiles and extensions um which might eliminate this trade-off and the need for
developers to write their own circuits. And so we believe this offers a pretty good trade-off between the custom circuit approach which is going to be the most performant and the full CKVM approach which offers the best developer experience. And so you can think of this as the analog of handwriting assembly in a C++ program. Okay. So how does OpenVM support this modular approach? Well, our approach to VM design was to observe that most existing ZKVMs are what we call skuorphic, meaning they essentially emulate the design of a physical processor. And in particular,
usually you'll find a central CPU circuit that simply contains a list of all op codes that were invoked in the execution trace of the program. And so we introduced something we call the no CPU architecture which eliminates this CPU chip and instead constrains execution consistency through an interaction check across different op code chips. And so what that means is that actually even in the VM circuit the chips corresponding to different op codes only interact through a uh global logup argument. And that makes it much easier for us to offer this modularity feature for developers.
A second place where we deviate from existing physical chips is that most CKVMs have a fixed word size simply because physical memory has an actual word size. Um, and what that means is that if you want to access larger chunks of contiguous memory, you have to read those chunks word by word. Um this actually is not necessary in ZK. Um and so as a result in OpenVM we use um offline memory checking for memory consistency with a variable word size.
So that means that um if a chip wants to read a larger contiguous block of memory, it can do so with a single invocation of offline memory checking and reading and writing larger chunks of memory simultaneously will result in a lower cost. And we're able to allow conversion between these chunks using what we call length adapters which simply on demand convert between a larger block and two smaller blocks. Okay, so just to briefly summarize what OpenVM can do today, uh we're able to prove Ethereum mainet. Uh these numbers are from our initial production release a couple months ago where we have uh you
know about 8 minutes average proving time on a single CPU machine and we can parallelize to achieve under 90 seconds on CPU. Uh and OpenVM is actually deployed live today to verify scroll mainet. Um to give a more up-to-date uh view on the performance of OpenVM, um we initially released OpenVM at the end of December. Uh you can see the performance was not great. Uh since then we've been continuously pushing on both the proving cost and latency. So today we're under you know 0.04 cents per transaction on a test block and we can achieve a parallel latency of close to 1 minute on CPU
machines. Okay, so what's next? Uh, we're continuing to push on cost and latency. Uh, we have a GPU prover which will be released in the next month. Um, and also we're following some of the pioneering work by for example the ZIS team on native execution and we're going to push on that which is the main source of our latency bottleneck today. In addition, we're excited to explore adding different ISAs to the front end for OpenVM. So things like risk 564 and web assembly we believe can be supported on a homogeneous back-end system. Um and
we think that that work might have some interactions with doing program uh specific circuit synthesis to further optimize for specific workloads. The idea here would be to incorporate uh different op codes that are specific to a program within an ISA that is custom designed for that program. And finally, last month we released the Axiom proving API, which is just a hosted API for proof generation on Axiom's cloud infrastructure. Uh next month we're going to roll out uh distributed GPU proving on the API.
All right. So, you can check out more about OpenVM on our developer docs at the book and GitHub. Uh, and if you're interested in working more closely with the Axiom team, uh, we have an interest form for collaborations with us on implementations. Um, yeah, happy to take any questions. Any questions? Yes, thanks for the talk. Uh I have just a quick question regarding the um when you say that you can mix different kind
of isa uh how do you handle the fact that they might not share the same registers? Um so the question is what happens if different ESAs don't share the same registers? Uh the answer is that it's actually we allow developers to specify the extent to which the op codes can interoperate. So there's two options here. One is that your op codes can interoperate on the same what we call address spaces. So we have different address spaces for different types of memory. Um so if you have for example a catch pre-ompile it can read directly from risk 5 memory and write directly to risk 5 memory. Uh the second op second option we offer is for a new op code to use a different segment of memory. Uh
for you might want to do this for example for stark recursion within a rust program. And so we implement this akin in a way that's akin to a GPU kernel. So in Rust developers can invoke um a function call that simply triggers execution within a totally independent address space. Does that answer the question? When you run a the trace you need to record the state of the register registration and depending of the instruction set they might not be have the same registers or you may miss some or they might not be updated the same.
So that was my my question not not how you address memory. Yes. So so we actually emulate registers with rewrite memory. So there's not really uh so so we have a specific address space address space one that's dedicated just for uh for example risk five registers. Um so if you were to implement a I say where the register structure is different it would be on the developer to you know do the same emulation in their own address space. Any other questions?
All right. Well, then let's give an applause.