A zkVM Survey for the Nomos Coordination Layer

The Nomos research team carried out a survey of the top zkVMs earlier this year, and the results are summarised in this article.

A zkVM Survey for the Nomos Coordination Layer

The complexity of the cryptography underlying zero knowledge proof (ZKP) systems has long been a barrier to the widespread adoption of ZKP technology. One solution to the difficulty of constructing ZKPs is a Zero Knowledge Virtual Machine (zkVM), which is a virtual machine that generates zero knowledge proofs. As virtual machines, zkVMs are able to execute arbitrary programs written in their general-purpose environment, and as zero knowledge circuits they create proofs that these programs were executed correctly.

In recent years, a wide variety of zkVMs have been developed based on the most cutting-edge research, and the competition for the title of “best zkVM” has become fierce. The Nomos research team carried out a survey of some of the top candidates earlier this year, and the result of our research will be summarised in this article.

A zkVM for the Nomos Coordination Layer

The Coordination Layer, or CL for short, is one of the three basic components of the Nomos network architecture, along with the Base Layer (BL) and the zones. Some of the main responsibilities of the CL are:

  1. The CL verifies zero knowledge proofs sent to it from the zones, which are generated by Zone Executors. This ensures the validity of each zone’s state transitions, without requiring validators to process the state transition functions themselves.
  2. The CL also ensures that transfers of information (known as notes) between zones are valid. It does this by verifying proofs that the notes being removed from one zone have the same value as the notes being created in another zone. If the zones are proven to be “balanced” in this way, then the note transfer is considered correct.
  3. Additionally, the CL provides support for synchronous composability across zones. Synchronous composability is a property of transactions and more general contract calls that involve multiple zones but are executed within a single block. Due to the complexity of these transactions, the CL uses more advanced techniques to match user intents and ensure their validity and synchronicity.

In addition to these responsibilities, the CL is the part of the Nomos architecture that deals with zone management, which includes zone creation and keeping track of existing zones. The CL also verifies proofs of leadership (the current block proposer) and proofs of validator.

Because of the large volumes of proofs and commitments being created and verified via the CL, it is imperative for us to choose a way to handle these proofs in the most efficient manner possible. This basic requirement will be our guiding principle throughout this survey.

Why a zkVM?

Before we dive into our analysis of zkVMs, we should note that there is another option for generating ZKPs. Creating custom ZK circuits is also a possibility, which involves writing circuits in a low-level language from scratch rather than relying on a zkVM to generate these circuits for us. A major advantage of this approach is that custom circuits can be created in a tailored way that is optimised for a specific use case, potentially unlocking much more efficient performance than using a zkVM for the same application.

However, custom ZK circuits have many limitations which make them less than ideal for most production applications. For starters, writing correct and optimised zk circuits directly is a very niche skill, requiring deep knowledge of cryptography and domain-specific languages like Circom. Because of the difficulty of writing custom ZK circuits, as well as the fact that special-purpose circuits typically cannot reuse general purpose code, the development process is much slower and more costly than using a zkVM. The complexity of this process is also more likely to produce vulnerabilities, and therefore require specialised cryptographic audits that can be expensive and time-consuming.

zkVMs, by contrast, are well-audited as a consequence of their broader user base. They allow developers to focus on writing their applications in higher-level languages, with the zkVM taking care of the cryptographic details. In the end, we decided to avoid writing custom ZK circuits for the most part, foregoing the efficiency advantage in favour of the more robust security and easier development cycle of zkVMs. However, a few light and commonly-used circuits will still be written by hand to improve performance.

Evaluation Criteria

Our survey of zkVMs for the Nomos CL focused on evaluating two main criteria. These criteria were chosen because they were determined to be decisive for our particular scenario - whether because the CL requires them to function properly, or in order to maximally take advantage of zkVMs’ benefits for the development process. These criteria are:

  1. Performance
  2. Versatility

Performance

As mentioned earlier, the zkVM to be used for CL should be able to efficiently handle creating and verifying large volumes of commitments and proofs. These include proofs of membership and proofs of non-membership in Merkle trees, the verification of which involves many calculations of hashes of concatenations of previously-hashed data. To evaluate this area of performance in a consistent way across zkVMs, we measured the time it took to generate a proof for 100 hashes of 100-128 bits using the best hash function in each zkVM’s proof system. We also took a look at whether the zkVM provided support for using GPUs to accelerate its performance.

Another requirement for our project was that the proofs must be small enough to be verified on-chain. In practice, this has restricted our choices to zkVMs that wrap their proofs in the Groth16 ZKP to create constant-size proofs, or can at least generate proofs small enough to be wrapped with Groth16 in our implementation of the CL. Our research indicates that the best zkVMs for our purposes use a type of wrapping called STARK-to-SNARK proving, which takes a large STARK proof and wraps it to create a shorter SNARK proof.

Versatility

The versatility of a zkVM describes the extent to which it provides support for common programming languages and cryptographic primitives. A zkVM that supports programs compiled from code written in languages familiar to our engineering team is much easier to develop for than one with a custom instruction set. This quality also allows for simple code reuse, enabling developers to leverage existing libraries in their applications. The versatility of a zkVM is therefore important not only for the Nomos engineering team working on the CL, but also for every developer building on a Nomos Native Zone. With this fact in mind, zone creators can benefit from the results of this survey as well.

Due to the CL’s extensive use of cryptographic operations, we have prioritised those VMs that provide support for cryptographic primitives such as elliptic curve operations, finite field arithmetic, and a variety of hash functions. Some zkVMs also integrate application-specific accelerator circuits for these primitives, enhancing their performance.

Analysis

The Nomos research team chose a broad group of 11 key zkVMs for our analysis, not all of which satisfied all of the criteria required for our use case. Despite this, it was decided to survey a large amount of zkVMs to get a better idea of the current state of zkVM development and the tradeoffs that different implementations chose. However, all of the VMs surveyed were those that meet the criteria to be considered a true zkVM, as contrasted to zk-rollup platforms or other kinds of verifiable operating systems that may erroneously be referred to as “zkVMs”. This topic is explained in greater detail in this blog post by the Vac team.

The zkVMs analysed in this article are Risc0, SP1, Valida, Jolt, Nexus, Cairo-VM, Miden, Scroll zkevm, Hermez, Eigen zkVM, and zkWasm.

Testing Equipment

As mentioned above, our main metric for measuring performance is the time it takes to generate a proof for 100 hashes of 100-128 bits using the best hash function in each zkVM’s proof system. To produce performance benchmarks that can be compared across zkVMs, we used the same machine with the following specifications for all tests:

  • Operating System: Ubuntu 22.04.4 LTS 64 bits
  • Memory: 32.0 GiB
  • Processor: Intel® Core™ i7-10850H CPU @ 2.70GHz × 12
  • Rust version: 1.79

Top Candidates

In the introduction to this section, we noted that not all of the 11 zkVMs we surveyed were actually relevant for our purposes. Since we require a general-purpose zkVM for the CL, the Scroll zkEVM and Hermez zkEVM, capable of proving only Ethereum blocks, were obviously not candidates for consideration. Eigen zkVM gave script errors when we tested it, and zkWasm produced out of memory errors for elementary programs like a Fibonacci calculator. Hermez also required a huge amount of space to install (115 GB), preventing us from testing it. The remaining zkVMs will be described in greater detail below.

Risc0

Risc0 is the zkVM built by the company of the same name. It works by splitting large computations into smaller segments and producing FRI-based proofs of each segment. These proofs are aggregated into a single STARK with a 217.4 KB proof size, and finally wrapped into an even smaller Groth16 proof. Risc0 generates proofs fairly quickly, and its built-in Groth16 wrapper has a consistent wrapping time of around 94 seconds. It also provides broad programming language support, including for C, Wasm, and Rust, making it easy to use for developers. It also supports GPU acceleration and has some built-in accelerator circuits for common hash functions and elliptic curve operations. However, Risc0 is not the fastest of the zkVMs we surveyed, and, while it claims to support 71% of top Rust crates, there is no way to know if a particular Rust crate is compatible without actually testing it.

SP1

SP1, created by Succinct Labs, proves program execution using the recently-released Plonky3 prover together with STARK recursion. It wraps up this proof via Plonk, resulting in a smaller SNARK proof. SP1 was built with high performance in mind, taking just 22.07 seconds to generate proofs for 100 hashes on a CPU. It also includes accelerator circuits for hash functions and cryptographic signature verification, speeding up performance even further. Conveniently for developers, it can support any program that compiles to LLVM. However, its use of Plonk as a wrapper results in bigger proofs (at most 656 B) than those produced by Groth16 (192 B using BLS12-381), and it requires a lot of RAM to generate proofs.

Valida

Valida, developed by the Lita Foundation, is a recent STARK-based zkVM that was designed to maximise prover performance. Like SP1, it uses Plonky3, but it has smaller proofs despite not including a wrapper at the time of writing. Valida uses a custom instruction set, but includes a C and Rust compiler to make development easier. Despite claims of extremely fast proof times, our survey showed that their time to prove 100 hashes was actually among the worst, at 43.1 seconds. Valida is also still in its early stages of development, and does not include a wrapper, making it suboptimal for the Nomos CL.

Jolt

Jolt is a zkVM developed by a16z. It is an original VM that uses a totally different architecture to the other VMs on our list, using the Lasso proving system to generate SNARKs without a STARK stage. Jolt’s architecture is built around binary fields like Binius, allowing for the efficient implementation of common cryptographic algorithms, especially those that benefit from SNARKs’ succinctness. Jolt’s proof time is good, at 17.33 seconds, and it supports programs compiled from Rust code. It also has a high security level of 128 bits. However, Jolt does not use a wrapper at the time of writing, resulting in larger proof sizes. It also does not support GPU acceleration and requires a lot of RAM. Jolt is currently still in alpha and is not ready for use in production. According to the Jolt book, Jolt also does not have true zero knowledge on its own, requiring modifications to achieve this property.

Nexus

Nexus is the zkVM developed by the company of the same name. It has a unique architecture and uses the Nova folding scheme, which is particularly effective for recursive Spartan SNARK proof generation. This efficient generation of recursive proofx is done at the expense of having large proof sizes. Nexus has several custom precompiled circuits for cryptographic operations, enhancing both versatility and performance. It currently also supports programs compiled from Rust and C++ code. Unfortunately, the compressed Nexus proofs are still very large (69.7 MB in our tests), and no wrapper exists. It also takes a lot of time and RAM to set up the prover.

Cairo-VM

Cairo-VM is a zkVM created by StarkWare that is specifically tailored for fast and efficient cryptographic operations. Cairo-VM supports multiple STARK provers, including StarkWare’s Stone, which are compatible with cryptographic primitives like Rescue and Poseidon. It uses their unique Cairo programming language, but can also execute Solidity code by integrating the Kakarot zkEVM. At the moment, there is no wrapper available for the Cairo-VM.

The Nomos research team investigated the possibility of constructing a wrapper for Stwo to reduce proof sizes. What we found is that many of the same optimisations that Stwo uses to reduce the proof size increase the computations required by the verifier. Additionally, Stwo is not compatible “as-is” with our use case due to factors like its use of the M31 field and the general complexity of Circle STARK verification. The additional work required to modify Stwo to suit our needs was deemed to not be worth the effort.

Miden

Miden, created by Polygon, uses STARK-based recursion to achieve very fast proof generation. Hash functions like Rescue and Merkle operations are implemented as single assembly opcodes, further speeding up proof generation. In our tests, Miden generated a proof for 100 hashes in less than 1 second! Miden’s proof sizes are also relatively small compared to some other zkVMs we surveyed. Unfortunately, Miden does not include a wrapper or any compilers, and the Miden assembly language is hard to develop in.

Evaluation Table

Below is a table summarising the relevant properties for each of the surveyed zkVMs, as well as our results for proof sizes and hash generation times.

Our Choice: Risc0

In the end, we decided to use Risc0 as our zkVM for the Nomos Coordination Layer. Its proof times, while not the best, are fairly good, and it has a built-in Groth16 wrapper that produces constant-size proofs. It provides very broad support for major programming languages and widely-used cryptographic primitives, making it perfect for general-purpose uses. Risc0 also supports GPU acceleration, which is a welcome feature.

By contrast, SP1, Jolt, and Nexus’ large proof sizes and RAM requirements, as well as their lack of suitable Groth16 or Plonk wrappers, made them unsuitable for our use case. Jolt also has suboptimal zero-knowledge privacy, which is a priority for the Nomos project. Cairo-VM and Valida had worse-than-average proof times, and Cairo-VM and Miden use custom languages that make them difficult to use for developers. Many of these zkVMs were also not production-ready at the time of writing.

Ultimately, however, it should be noted that these results are valid for the snapshot in time and specific VM version in which the survey was conducted. Due to the rapidly-evolving nature of zero knowledge cryptography and technology, and especially with many of the zkVMs surveyed being still in active development, these metrics will surely change in the future. Recognising this, we see Risc0 as a tentative choice, to be potentially replaced by any zkVM that proves more suitable for the needs of the ever-advancing Nomos project.

Sources and Further Reading

Notes

  1. Date evaluated: 12/08/24. Version: risc 1.0.5
  2. Date evaluated: 12/08/24. Version: 1.1.1
  3. Date evaluated: 13/08/24, LLVM compiler version: v0.3.0-alpha
  4. Date evaluated: 12/08/24
  5. Version evaluated: Nexus zkVM v0.2.1
  6. Date evaluated: 05/09/24
  7. Version evaluated: 0.10.3
  8. Version evaluated: 0.12
  9. Version evaluated: 6.0.2
  10. Version evaluated: 0.0.5
  11. Date evaluated: 20/08/24