- A virtual machine is a software simulation of a computer system that provides an execution environment for programs. It can simulate various hardware devices, allowing programs to run in a controlled and compatible environment. The Ethereum Virtual Machine (EVM) is a stack-based virtual machine used to execute Ethereum smart contracts.
- zkEVM is an EVM that integrates zero-knowledge proofs/validity proofs. It allows the use of zero-knowledge proofs to verify the execution process of the EVM without requiring all validators to re-execute the EVM. There are various zkEVM products on the market, each with its own methods and designs.
- The need for zkEVM arises from the demand for a virtual machine that supports smart contract execution on Layer 2. In addition, some projects choose to use zkEVM to leverage the wide user ecosystem of the EVM and design an instruction set that is more friendly to zero-knowledge proofs.
- Kakarot is a zkEVM implemented on Starknet using the Cairo language. It simulates the stack, memory, execution, and other aspects of the EVM in the form of Cairo smart contracts. Kakarot faces challenges such as compatibility with the Starknet account system, cost optimization, and stability, as the Cairo language is still in the experimental stage.
- Warp is a converter that translates Solidity code into Cairo code, providing compatibility at the high-level language level. On the other hand, Kakarot provides compatibility at the EVM level by implementing EVM opcodes and precompiles.
What is a Virtual Machine?
To understand what a virtual machine is, we must first explain the execution process of computers under the mainstream von Neumann architecture. Various programs running on a computer are usually transformed from high-level languages through multiple layers to machine-readable machine code for execution. Depending on the method of transformation into machine code, high-level languages can be roughly divided into compiled languages and interpreted languages.
Compiled languages refer to languages that, after the code is written, need to be processed by a compiler to transform high-level language code into machine code, generating executable files. Compilation can be done once and executed multiple times with higher efficiency. The advantages of compiled languages are that they execute quickly because the code is converted into machine code during compilation. They can also run programs without the compiler, making it user-friendly without the need to install additional software. Common compiled languages include C, C++, Go, etc.
- After FTX’s collapse caused the crash of SOL, what new changes will Solana have in 2023?
- New Project Outlook | Davos Protocol Providing an Inflation-Resistant Stablecoin
- Coinbase In-depth Analysis Why We Support Staking
It should be emphasized that languages do not fundamentally distinguish between compiled and interpreted. It’s just a tendency in the initial design. C/C++ is mostly compiled, but it can also be interpreted (Cint, Cling). Many traditionally interpreted languages are now compiled into intermediate code and executed on a virtual machine (Python, Lua).
Now that we know the execution process of a physical machine, let’s talk about virtual machines.
A virtual machine typically provides a virtual computing environment by simulating different hardware devices. Different virtual machines may simulate different hardware devices, but they usually include CPU, memory, hard disk, network interface, etc.
Take the Ethereum Virtual Machine (EVM) as an example. EVM is a stack-based virtual machine used for executing Ethereum smart contracts. EVM provides a virtual computing environment by simulating hardware devices such as CPU, memory, storage, and stack.
Specifically, EVM is a stack-based virtual machine that uses a stack to store data and execute instructions. EVM’s instruction set includes various opcodes, such as arithmetic operations, logical operations, storage operations, jump operations, etc. These instructions can be executed on the stack of EVM to complete the execution of smart contracts.
The memory and storage simulated by EVM are devices used to store the state and data of smart contracts. EVM treats memory and storage as two separate areas, and it can access the state and data of smart contracts by reading and writing to memory and storage.
The stack simulated by EVM is used to store the operands and results of instructions. Most instructions in EVM’s instruction set are stack-based, meaning they read operands from the stack and push results back to the stack.
In summary, EVM provides a virtual computing environment by simulating hardware devices such as CPU, memory, storage, and stack. It can execute instructions of smart contracts and store the state and data of smart contracts. In actual operation, EVM loads the bytecode of smart contracts into memory and executes the logic of smart contracts by executing the instruction set. EVM effectively replaces the operating system + hardware part in the diagram.
The design process of EVM is obviously bottom-up. First, the simulated hardware environment (stack, memory) is determined, and then a set of assembly instruction set (Opcode) and bytecode is designed based on the corresponding environment. Although the assembly instruction set is for human reading, it involves a lot of low-level knowledge and requires high demands on developers. It is also cumbersome to develop, so a high-level language is needed to shield the obscure and cumbersome low-level calls and provide a better experience for developers. Due to the customized design of its assembly instruction set, EVM is difficult to directly use traditional high-level languages, so a new high-level language is designed to adapt to this virtual machine. In order to improve the execution efficiency of EVM, the Ethereum community has designed two compiled high-level languages – Solidity and Vyper. Solidity is self-explanatory, while Vyper is an EVM high-level language designed by Vitalik to improve some of the deficiencies in Solidity. However, it has not gained high adoption in the community and gradually faded out of the historical stage.
What is zkEVM
Simply put, zkEVM is an EVM that utilizes zero-knowledge proofs/validity proofs to efficiently and cost-effectively validate the execution process of the EVM without requiring all validators to re-execute the EVM.
There are many zkEVM products in the market, and the competition is fierce. The main players include Starknet, zkSync, Scroll, Taiko, Linea, Polygon zkEVM (formerly Polygon Hermez), etc. Vitalik has categorized them into 5 types (1, 2, 2.5, 3, 4). For more detailed information, please refer to Vitalik’s blog.
Why do we need zkEVM
This question needs to be looked at from two perspectives.
Initially, zk Rollup attempts could only achieve simple transfer and transaction functions, such as zkSync Lite, Loopring, etc. However, once people get used to the Turing-complete EVM on Ethereum and are unable to create diverse applications through programming, they began to call for a virtual machine on Layer 2. The demand for writing smart contracts is one reason.
Due to certain designs in the EVM that are not friendly to generating zero-knowledge proofs/validity proofs, some players chose to use instruction sets that are friendly to zero-knowledge proofs/validity proofs at the underlying level, such as Starknet’s Cairo Assembly and zkSync’s Zinc Instruction. However, everyone is also unwilling to give up the extensive user ecosystem of the EVM, so they choose to be compatible with the EVM at the upper layer, which falls into the categories of 3 and 4 zkEVM. Some players still adhere to the traditional instruction set Opcode of the EVM and focus on generating more efficient proofs for Opcode, which falls into the categories of 1 and 2 zkEVM. The extensive ecosystem of the EVM is another reason.
Kakarot: A virtual machine on a virtual machine?
Why is it possible to have another virtual machine on top of a virtual machine? This is commonplace for computer professionals, but it may not be so obvious to users who are not familiar with computers. It is actually quite easy to understand. It’s like building with building blocks. As long as the lower layer is solid enough (with a Turing-complete execution environment), you can stack building blocks endlessly. However, no matter how many layers are built, the final execution still needs to be handled by the physical hardware at the lowest level, so increasing the number of layers will reduce efficiency. At the same time, as different building blocks have different designs (different virtual machine designs), the higher the stack of building blocks, the greater the possibility of collapse (runtime errors), which requires higher technical expertise to support.
The technical challenges of Kakarot zkEVM are that the protocol exists as a contract on Starknet, which brings two key issues:
- Compatibility: Starknet uses a completely different account system from Ethereum. In Ethereum, accounts are divided into EOA (Externally Owned Accounts) and CA (Contract Accounts), but Starknet supports native account abstraction, where all accounts are contract accounts. Also, due to the use of different cryptographic algorithms, users cannot generate the same addresses in Starknet using the same entropy as in Ethereum.
- Cost: Since Kakarot zkEVM exists as a contract on the chain, there are high requirements for code implementation. It needs to be optimized for Gas as much as possible to reduce interaction costs.
- Stability: Unlike traditional high-level languages such as Golang, Rust, Python, etc., the Cairo language is still in the experimental stage. From Cairo 0 to Cairo 1 and then to Cairo 2 (or Cairo 1 version 2 if you prefer), the official team is constantly modifying language features. At the same time, the Cairo VM has not undergone sufficient testing, and the possibility of large-scale rewrites in the future cannot be ruled out.
The Kakarot protocol consists of five main components (the GitHub documentation states four, excluding EOA, this article has been adjusted for the convenience of readers’ understanding):
- Kakarot (Core): Responsible for executing Ethereum-style transactions and providing corresponding Starknet accounts for Ethereum users
- Contract Accounts: CA in the Ethereum sense, responsible for storing contract bytecode and variable states in the contract
- Externally Owned Accounts: EOA in the Ethereum sense, responsible for forwarding Ethereum transactions to Kakarot Core
- Account Registry: Stores the correspondence between Ethereum accounts and Starknet accounts
- Blockhash Registry: As a special opcode, Blockhash requires past block data, but Kakarot cannot directly obtain data on the chain. This component stores the mapping relationship between block_number and block_hash, which is written by the administrator and provided to Kakarot Core.
According to Kakarot CEO Elias Tazartes, in the latest version of the team, the design of Account Registry has been abandoned, and a mapping from a 31-byte Starknet address to a 20-digit EVM address is directly used to save the correspondence. In the future, in order to improve interoperability and allow Starknet contracts to register their own EVM addresses, the design of Account Registry may be reintroduced.
Compatibility of EVM on Starknet: What are the differences between Warp and Kakarot
According to Vitalik’s definition of zkEVM types, Warp belongs to Type-4, while Kakarot currently belongs to Type-2.5.
Warp is a transpiler that converts Solidity code into Cairo code. The reason why it is not called a compiler is probably because the output Cairo code is still a high-level language. With Warp, Solidity developers can maintain their original development state without having to learn a new language like Cairo. For many projects, Warp lowers the barrier to entry into the Starknet ecosystem as it eliminates the need to rewrite a large amount of engineering code in Cairo.
Although the idea of transpiling is simple, compatibility is also the worst. Some Solidity code cannot be translated well into Cairo. Code logic related to account systems, cryptographic algorithms, and other aspects may require modification of the source code to complete the migration. Specific unsupported features can be found in the Warp documentation. For example, many projects differentiate the execution logic between externally owned accounts (EOA) and contract accounts, but in Starknet, all accounts are contract accounts, so this part of the code needs to be modified before transpilation can take place.
Warp focuses on compatibility at the high-level language level, while Kakarot focuses on compatibility at the EVM level.
By rewriting the entire EVM, implementing opcodes and pre-compiles one by one, Kakarot achieves higher native compatibility. After all, executing in the same virtual machine (EVM) is always more compatible than executing in different virtual machines (Cairo VM). Account Registry and Blockhash Registry cleverly shield the differences between different systems, minimizing migration friction for users.
Thanks to the Kakarot team for their valuable insights into this article, especially Elias Tazartes. Thank you, sir!