Paul Gafni

So, you’ve realized the power of using verifiable, off-chain computation to scale blockchains.

You have a project you’d like to build, but you’re not sure where to start building. How should you evaluate your options?

This article will guide you through the key features you’ll need, and contextualize the state of ZK tooling today. We’ll consider the following questions:

- Why should you choose a zkVM?

- What are the essential features of zkVMs?

- Which zkVMs offer these essential features?

Two years ago, the primary workflow for ZK software development was to *write circuits by hand *using circom. The process of writing circuits is incredibly labor-intensive: circuits are difficult to write, update, audit, and maintain. The time and cost required to bring a circuit-based ZK project to market is on the order of 2 years and $100 million dollars.

Over the past two years, RISC Zero has demonstrated that rather than writing circuits directly, writing an application for a zkVM is a much faster/cheaper option for getting your project to market. zkVMs make ZK accessible to ordinary developers, and make it possible to bring complex applications to reality in the course of a weekend.

In early 2022, we unlocked the ability to prove correct execution of regular Rust code, including your favorite Rust crates. Suddenly, ZK builders were able to focus on building real applications, leveraging all the mature tooling of the Rust ecosystem.

Today, there are a number of options for zkVMs, which brings us to our next question…

There are four things you’ll definitely need in order to build anything interesting.

**Support for importing crates/packages.**

**Support for on-chain proof verification.**

**Support for unbounded computation, without ballooning costs for verification.**

**Support for proof composition.**

For the purposes of enabling the ZK future, these four features are mandatory. Keep reading to find out which zkVMs offer these features, and why they’re so important.

As of this writing, here’s the state of the zkVM industry.

For each of these features, let’s run through a quick explanation of:

- Why it matters

- Why it’s hard to implement

- RISC Zero’s approach

Without support for importing crates, software development is a nightmare. Allowing developers to import crates is essential for any complex application.

A couple years ago, ZK systems were so inefficient and hard-to-build that they could support a mature language like Rust or C++ seemed technologically out-of-reach. Today, the trend in zkVM development has moved from bespoke instruction sets to standard instruction sets like RISC-V, MIPS, and WASM.

In April 2022, RISC Zero released the first zkVM capable of making proofs about a high level language like Rust or C++. Today, we run nightly tests to check compatibility of the top 1000 Rust crates with our zkVM; currently 70% work out-of-the-box. Check out our examples directory to see examples of how to use Rust crates inside the zkVM.

Proof system design involves a fundamental tradeoff between prover complexity and verifier complexity. The current trend is that SNARKs based on hashing and error-correcting codes (aka STARKs) offer the best prover costs for zkVMs, while SNARKs based on elliptic curves offer better on-chain verification costs. zkVMs today typically include a merger of multiple proof systems in order to get the best of both worlds.

RISC Zero uses STARKs for efficient proving, and then *verifies the STARK proof inside a SNARK circuit* in order to “translate” the STARK into a SNARK. In August 2023, we posted and verified our first proof on Sepolia. Today, we support an on-chain verifier contract that *works for any zkVM application.*

If you want to prove the correct construction of an Ethereum block or an OP block, you’re going to need to prove a *very* large computation.

The naive approach to proving large computations doesn’t scale well – increasing the size of your computation by 2x will increase the computational complexity by more than 2x. In order to unlock unbounded computation size (without interfering with on-chain verification), we need two components, each of which is a major technical feat:

- The ability to split a large computation into chunks, to be proven separately

- The ability to aggregate these “segment proofs” into a single succinct proof.

RISC Zero introduced continuations to address the problem of generating proofs for computations of unbounded size – we prove each segment independently and then use *recursion* to aggregate the segment proofs. With this approach, RISC Zero manages to achieve *linear-time proving* with *constant verification costs.*

Proof composition (aka proof of proof) unlocks a wide variety of use cases, including more complex privacy applications, more modular zkVM applications, and proof aggregation (including proofs from RISC Zero and from other proof systems).

Making proof composition efficient is sufficiently challenging that no one besides RISC Zero has even mentioned the idea. Unlocking this feature requires not only a solution to the problem of recursion, but also requires building an API to allow developers to *call the recursive prover from inside the zkVM.*

Users can access proof composition by calling the `env::verify()` function inside the zkVM. This feature is new as of February of this year; learn more about proof composition in this blog and/or this study club session.

Three of these key features (on-chain verification, unbounded computation, and proof composition) rely on **recursion**. In the ZK world, recursion refers to *the ability to prove the correct verification of a proof. *In other words, you *run the verifier inside the prover.*

This may sound straight-forward, but building recursive circuits is notoriously complex. The RISC Zero zkVM is designed to be as easy-to-use as possible, but under the hood, we’re maintaining compatibility of *three *related but separate ZK circuits. At RISC Zero, we actually have *two STARK-based zkVMs*: we first use our RISC-V circuit to generate proofs of RISC-V execution, and then we use a separate recursion circuit to aggregate those proofs. And *then*, we feed the result into a SNARK circuit in order to enable on-chain verification.

The engineering required here is a serious endeavor – in order to support this effort, we’re building an MLIR-based language for building recursive circuits called Zirgen. To learn more about Zirgen, check out this talk from Julian Sutherland (Nethermind).

Performance seems to be the most natural axis for comparison, but unfortunately, benchmarking for ZK projects is still in its infancy. There are a number of benchmarking projects out there, but it turns out to be incredibly difficult to come up with a robust framework for apples-to-apples comparison.

Before comparing performance, make sure you’re looking at an apples-to-apples comparison in terms of capabilities. When a newer entrant announced their version of Zeth, they were quick to claim that their proofs of block construction is 30x faster than RISC Zero. Unfortunately, their Zeth proofs are also 1000x larger than ours. If you can’t get your proofs on-chain, does it really matter how fast you can generate proofs?

RISC Zero has been focused on getting a feature-complete zkVM ready for production use. Once we wrap up our audits and our trusted setup ceremony, and get our verifier deployed on mainnet, you can count on some serious performance improvements. For now, we recommend using the only feature-complete zkVM: RISC Zero.

A couple of other features worth mentioning are:

- Deterministic buildszkVMs natively prove correct execution of a given
*binary file*, but for most use cases, we’ll want to be able to prove correct execution of a given*Rust program*(or some other high level language. RISC Zero addresses this problem with our cargo risczero tool.

- Accelerator circuit support

When you identify a performance bottleneck in a zkVM application, it would be nice to be able to modify the zkVM in order to offer use-case-specific acceleration. For example, one might add a Keccak accelerator to support efficient proofs about Ethereum block construction. RISC Zero currently offers acceleration for big integer operations and SHA; check out Victor’s upcoming talk at zkSummit 11 to learn more about our plans to expand this functionality.

- Proof aggregation support

Proof aggregation refers to the ability to consolidate many proofs into a single proof. This feature is essential for making on-chain verification affordable. Proof composition enables this feature, but it’s worth noting that other systems may offer a solution to proof aggregation without fully solving the problem of proof composition.

If you’re ready to build, check out our Get Started guide and docs.