Original: A Developers Guide to the zkGalaxy
Last summer, Vitalik wrote a blog post outlining the different types of zkEVM (Zero-Knowledge Ethereum Virtual Machine). Vitalik defines and trades off performance and compatibility.
This is a very useful heuristic to differentiate zkEVM-enabled methods. However, zkEVM is a subset of all possible ways to build zero-knowledge applications. For programmers who want to take advantage of the unique properties of zk computation, namely simplicity, zero-knowledge, and correctness, zkEVM may not be the best choice. By illuminating the entire development toolset, this article hopes to provide a guide to help developers choose the appropriate zk stack during the decision-making process.
The Power of Abstract Complexity
In the past year or two, zk tooling has improved tremendously. Developers of ordinary software can take advantage of the powerful properties of zk without needing a deep understanding of the daunting underlying mathematics and engineering. On the other hand, there has been a proliferation of tools for advanced users, giving zk experts extremely fine-grained control over the zk stack.
Modern software is built on countless layers of abstraction to maximize the productivity of experts. Abstraction in engineering has many advantages that are somewhat intuitive -- web developers dont need a deep understanding of how an operating system works.
The key to building good, reusable abstraction layers is to encapsulate the complexity of one layer and then provide simple but expressive interfaces to higher layers in the stack. Done right, this enables developers with different areas of expertise and knowledge to build useful tools across the stack.
image description
Some examples of tools/techniques for zk stack and layers
Low level zk development
Arkworks-rs
Arkworks-rs is an ecosystem of Rust libraries that provide efficient and secure implementations of subcomponents of zkSNARK applications. Arkworks provides developers with the necessary interfaces to customize the software stack of zk applications without having to reimplement commonality with other existing libraries.
advantage
advantage
Flexibility through modularity
reduce duplication of code
Reduce engineering costs
Reduce audit/bug surface area
Upgrade any component without major refactoring
shortcoming
shortcoming
Requires in-depth knowledge of the full software stack
If not understood correctly, too much control can lead to footguns
Fine-grained control requires expertise at all levels of the stack.
Arkworks does provide some sensible defaults.
zk Domain Specific Language (DSL)
In order to create a proof about some computation, first the computation must be expressed in a form that a zkSNARK system can understand. Some domain-specific languages have created programming languages that allow application developers to express their computations in this way. These languages include Aztec Noir, Starknets Cairo, Circom, ZoKrates, and Aleos Leo, among others. The underlying proof system and mathematical details are generally not exposed to application developers.
developer experience
Developers of zkApps must be proficient in writing programs in domain-specific languages. Some of these languages look a lot like familiar programming languages, while others can be quite difficult to learn. Lets analyze a few of them.
Cairo - The Starkware DSL is necessary for building applications on Starknet. Compiled into Cairo-specific assembly language that can be interpreted by Cairo zkVM.
ZoKrates - ZoKrates is a toolkit for common SNARK needs, including a high-level language for writing circuits. ZoKrates also has some flexibility in terms of curves, proof schemes, and backends, allowing developers to hot swap via simple CLI arguments.
Circom — Circom is a specialized language for building electrical circuits. Currently, it is the actual language for producing circuits. The language is not particularly ergonomic, making the developer acutely aware that a circuit is being written.
Leo - Leo was developed as the language of the Aleo blockchain. Leo has some Rust-like syntax specifically for state transitions inside blockchains.
Noir - Rust-inspired syntax. Built around IR rather than the language itself, which means it can have an arbitrary front end.
for whom
Any application developer who wants to take advantage of zks unique properties in their applications.
advantage
advantage
Users do not need to understand the underlying zk details
With some production experience, you can use it today
verifiable on-chain
shortcoming
shortcoming
Users need to learn a new DSL
Tooling and support around these languages are siled
Little to no control over the underlying proof stack (for now).
zkEVMs
The main goal of zkEVM is to take Ethereum state transitions and prove their validity using succinct zero-knowledge correctness proofs. As mentioned in Vitaliks post, there are many ways to do this, with subtle differences and corresponding tradeoffs.
The main technical difference between all these approaches is where exactly in the language stack the computation is transformed into a form that can be used in the proof system (arithmeticization). In some zkEVMs, this happens in a high-level language (Solidity, Vyper, Yul), while others try to prove the EVM all the way down to the opcode level. The tradeoffs between these approaches are covered in depth in Vitaliks post, but Ill summarize it in one sentence. The lower the conversions/arithms happen on the stack, the bigger the performance penalty.
high operating costs
The main challenge in creating proofs for virtual machines is that the size of the circuit grows proportionally to the size of all possible instructions for each instruction executed. This is because the circuit does not know which instructions will be executed in each program, so it needs to support all of them.
In general-purpose circuits, the cost of each instruction executed is proportional to the sum of all supported instructions.
What this means in practice is that you pay (the performance cost) for the most expensive instruction, even if you are only executing the simplest instruction. This leads to a direct tradeoff between generality and performance - as you add more instructions for generality, you pay for every instruction you prove! This is the fundamental problem with general-purpose circuits.
But with new developments such as IVC (Incremental Verifiable Computing), this limitation can be improved by breaking the computation into smaller chunks, each with dedicated, smaller subcircuits.
Todays zkEVM implementations use different strategies to mitigate this problem...for example, zkSync removes more expensive operations (mostly cryptographic precompilations like hashes, and a few others)
Ideal customers for zkEVM are smart contract applications that need to be orders of magnitude cheaper than transactions on L1 Ethereum. These developers dont necessarily have the expertise or bandwidth to write zk applications from scratch. Therefore, it is preferable to write applications in a familiar higher-level language, such as Solidity.
Numerous development teams
Scaling Ethereum is currently the most in-demand application of zk technology.
developer experience
developer experience
The goal of zkEVM is to support a developer experience as close as possible to current Ethereum development. Full support for Solidity means teams dont have to build and maintain multiple codebases. This is somewhat impractical because zkEVM needs to trade some compatibility to be able to generate proofs of reasonable size in a reasonable amount of time.
zkSync and Scroll
The main difference between zkSync and Scroll is where/when they perform arithmetic operations on the stack -- that is, where they transition from normal EVM constructs to SNARK-friendly representations. For zkSync, this happens when they convert the YUL bytecode to their own custom zk instruction set. For Scroll, this happens at the end, when the actual execution trace is generated with the actual EVM opcodes.
So, for zkSync, everything is the same as interacting with the EVM, until the zk bytecode is generated. With Scroll, everything is the same until the actual bytecode is executed. This is a subtle difference that trades performance for support. For example, zkSync will not support EVM bytecode tools like the out-of-the-box debugger, because it is a completely different bytecode. While Scroll is hard to get good performance out of the instruction set, it wasnt designed for zk. Both strategies have pros and cons, and ultimately there are many exogenous factors that can affect their relative success.
zkLLVM circuit compiler
As discussed in detail, there are countless different options for developing zk applications, all with their own unique tradeoffs. This diagram will help summarize this decision matrix for choosing the best tool for the job, based on your level of zk expertise and performance needs. This is not a complete list and will be updated as zk develops.
zkLLVM is designed as an extension of the existing LLVM infrastructure, an industry-standard toolchain that supports many high-level languages such as Rust, C, C++, and more.
how to run
A user who wants to prove some calculation can simply implement the calculation in C++. zkLLVM takes high-level source code backed by its modified clang compiler (currently C++) and produces some intermediate representation of the circuit. At this point, the circuit is ready for verification, but the user may wish to verify the circuit against some dynamic input. To handle dynamic inputs, zkLLVM has an additional component called an allocator, which generates an allocation table containing all inputs and witnesses that are fully preprocessed and ready to be proved along with the circuit.
These two components are required to generate proofs. In theory, users could generate proofs themselves, but since this is a somewhat specialized computational task, it might cost someone else with the hardware to do it. For this counterparty discovery mechanism, =nil; the Foundation also builds a proof market where provers compete to prove computation for users who pay them. This free market dynamic will lead provers to optimize the most valuable proof tasks.
weigh the pros and cons
Since each computational task to be proved is unique and generates different circuits, the number of circuits that the prover needs to be able to handle is infinite. This forced generality makes the optimization of individual circuits difficult. The introduction of the proof market allows for the specialization of circuits that the market deems valuable. Without this market, it would be challenging to convince verifiers to optimize this circuit due to this natural cold-start problem.
advantage
advantage
Users can write code in a familiar high-level language
All zk internal structures are abstracted and are not affected by users
Does not rely on specific"virtual machine"shortcoming
shortcoming
Each program has a different circuit. Difficult to optimize. (proving that the market partly solves this problem)
Swapping/upgrading internal zk libraries is not trivial (requires forking)
zkVM
zkVM describes a superset of all zk virtual machines, while zkEVM is a specific type of zkVM that deserves a separate topic due to its popularity today. In addition to custom crypto VMs, there are several other projects working on building a more general ISA-based zkVM.
Rather than certifying the EVM, the system can certify a different instruction set architecture (ISA), such as RISC-V or WASM in the new VM. Two projects working on these general purpose zkVMs are RISC Zero and zkWASM.
image description
Risc Zero
High-Level Architecture for Risc Zero Proof Generation
RISC Zero is able to attest to any computation performed on the RISC-V architecture. RISC-V is an open-source instruction set architecture (ISA) standard that has grown in popularity. The idea of RISC (Reduced Instruction Set Computer) is to build an extremely simple instruction set with minimal complexity. This means that developers higher up in the stack end up with a larger load when implementing instructions using this architecture, while making hardware implementation simpler.
This philosophy also applies to computing in general, and ARM chips have been taking advantage of RISC-style instruction sets and are beginning to dominate the market for mobile chips. It turns out that simpler instruction sets are also more energy and chip area efficient.
This analogy applies quite well to the efficiency of generating zk proofs. As discussed earlier, when proving zks execution trajectory, you pay for the sum of the costs of all instructions for each item in the trajectory, so simpler, fewer total instructions are better.
how to work
From a developers perspective, using RISC Zero to handle zk proofs is a lot like using AWS Lambda functions to handle backend server architecture. Developers interact with RISC Zero or AWS Lambda by simply writing code, and the service handles all backend complexities.
For RISC Zero, developers write Rust or C++ (eventually anything targeting RISC-V). The system then accepts the ELF file produced during compilation as input code for the virtual machine circuit. Developers simply call proof, which returns a receipt (zk proof containing execution trace) object, and anyone can call `verify from anywhere. From a developers point of view, it is not necessary to understand how zk works, the underlying system handles all these complexities.
In order to support such a common interface, a lot of overhead (in terms of proof size and generation speed) is required.
Significant improvements to proof generation techniques are needed to enable broad support for existing libraries
Pre-built reusable circuits
For some basic and reusable circuits that are particularly useful for blockchain applications or elsewhere, the team may have built and optimized these circuits for you. You just provide input for your specific use case. For example, Merkle Proofs of Inclusion is something commonly needed in cryptocurrency applications (airdrop lists, Tornado Cash, etc.). As an application developer, you can always re-use these battle-tested contracts and just modify some layers on top to create a unique application.
For example, Tornado Cashs circuits could be repurposed for a private airdrop application or a private voting application. Manta and Semaphore are building a complete toolkit, including general-purpose circuit gadgets like this one, that can be used in Solidity contracts with little or no knowledge of the underlying zk moon math.
As discussed in detail, there are countless different options for developing zk applications, all with their own unique tradeoffs.
This diagram will help summarize this decision matrix for choosing the best tool for the job, based on your level of zk expertise and performance needs. This is not a complete list and will be updated as zk develops.
zkGalaxy Application Developers Guide
1. Low-level Snark library
Applicable scene
Requires fine-grained control over the entire proof stack
Avoid rebuilding common components
Try proving different combinations of schemes, curves, and other low-level primitives
Not applicable
Newbies looking for advanced proof interfaces
Optional tools
Arkworks-rs
2. zk DSLs
Applicable scene
want to use some tried and tested language
Minimal circuit size required, willingness to forego abstraction
Not applicable
Requires fine-grained control over proof backends (currently, backends can be swapped for some DSLs)
Optional tools
Circom
Aztec Noir
Cairo
ZoKrates
Leo
3. zk compiler
Applicable scene
Unwilling to incur the overhead of general purpose circuitry
Want to write circuits in a familiar language
Requires highly customized circuitry
Not applicable
want to control the underlying cryptographic primitives
requires an already highly optimized circuit
Optional tools
nil zkLLVM
4.zkEVM
Applicable scene
Have a dApp already running on the EVM
Need to offer cheaper deals to users
Want to minimize the effort required to deploy to a new chain
only care about the simplicity of zk (compression)
Not applicable
Requires perfect EVM equivalence
Privacy properties that require zk
There is a non-blockchain use case
Optional tools
zksync 2.0
Polygon zkEVM
Scroll
Starknet
5.zkVM
Applicable scene
Want to write code in a high-level language
Need to prove the correctness of the implementation
Need to hide some input information for this execution from the verifier
Little to no zk expertise
Not applicable
In a very low latency environment (its still slow).
There is a huge program (for now).
Optional tools
RISC Zero
zkWASM
6. Pre-built reusable circuits
Applicable scene
There is a smart contract application that relies on common zk building blocks, such as Merkle containment.
Little to no expertise on whats under the hood of zk
Not applicable
have highly specialized needs
Use case not supported by pre-built circuits
in conclusion
Manta Network
Semaphore
in conclusion
thank you
thank you
The compilation of this article has received support and feedback from the DAOrayaki community.
Original: A Developers Guide to the zkGalaxy