kkrt-labs
kakarot
Cairo

Kakarot is a zkEVM written in Cairo, leveraging the STARK proof system.

Last updated Jul 8, 2026
1.0k
Stars
312
Forks
35
Issues
0
Stars/day
Attention Score
83
Language breakdown
No language data available.
โ–ธ Files click to expand
README

Kakarot, the zkEVM written in Cairo.

GitHub Workflow Status GitHub GitHub contributors GitHub top language Telegram Contributions welcome GitHub Repo stars Twitter Follow Discord

Update

This repository - an EVM emulator on Starknet - is frozen at latest audited and tested commit: 5caaf28e6188ea8b3726a2db5d4940ecb5afd898. The team is working on keth, an Ethereum Prover. Contact us on Twitter or Discord if you would like to use the EVM emulator on Starknet in production.

Introduction

This repository contains the set of Cairo (Cairo compiler version Zero) programs that implement the core EVM logic of Kakarot zkEVM.

Kakarot is an EVM implementation in Cairo. Cairo being a high-level zero-knowledge domain specific language (zkDSL), Kakarot is provable by design. This allows for proving the execution of EVM transactions, and makes Kakarot a de facto so-called zkEVM.

We strongly believe the CairoVM will provide the best zero-knowledge toolbox in the coming years and that the Ethereum network effect will remain prevalent. We present to developers an abstraction layer they're familiar with: the EVM. Build and deploy as if you were working on Ethereum, be forward compatible with the future of zero-knowledge.

Kakarot presentations and talks around the world

Getting started โ€ข Build โ€ข Test โ€ข Report a bug

Supported opcodes

We support 100% of EVM opcodes and 9 out of 10 precompiles.

Documentation

Architecture

Here is a high-level architecture diagram of the entire Kakarot zkEVM system.

Kakarot high-level architecture

The set of Cairo programs in this repository are represented below:

Kakarot Core EVM diagram

  • โœ… Kakarot Core EVM is a set of Cairo programs
  • โœ… Kakarot can be packaged as a smart contract and deployed on any chain that
runs the CairoVM (StarknetOS chains, Starknet Appchains, Starknet clients).
  • โœ… Kakarot is an EVM implementation.
  • โš ๏ธ Kakarot Core EVM (the Cairo programs in this repository) is not a
blockchain by itself. Combined with an underlying CairoVM chain, an RPC layer, it forms an EVM runtime embedded inside a Starknet appchain.
  • โŒ Kakarot is not a compiler.

Getting started

To contribute and setup your development environment, please check out the contribution guide.

Build

The project uses uv to manage python dependencies and run commands. To install uv:

curl -LsSf https://astral.sh/uv/install.sh | sh

To setup the project and install all dependencies:

make setup

To build the CairoZero files:

make build

To build the test Solidity smart contracts:

# install foundry if you don't have it already

curl -L https://foundry.paradigm.xyz | bash

foundryup

make build-sol

Code style

The project uses trunk.io to run a comprehensive list of linters.

To install Trunk, run:

curl https://get.trunk.io -fsSL | bash

You can also add Trunk to VSCode with this extension.

Then, don't forget to select Trunk as your default formatter in VSCode (command palette > Format Document With > Trunk).

Once Trunk is installed, you can install a pre-push hook to run the linters before each push:

trunk git-hooks sync

Test

Kakarot tests

Kakarot tests uses pytest as test runner. Make sure to read the doc and get familiar with the tool to benefit from all of its features.

# Runs a local CairoVM client (or StarknetOS chain)
make run-nodes

Run all tests. This requires a Katana instance and an Anvil instance running in the background: make run-nodes

make test

Run only unit tests

make test-unit

Run only e2e tests

make test-end-to-end

Run a specific test file

pytest <PATHTOFILE>

Run a specific test mark (markers in pyproject.toml)

pytest -m <MARK>

Test architecture is the following:

  • tests/src contains cairo tests for each cairo function in the kakarot codebase
running either in plain cairo or with the starknet test runner;
  • tests/endtoend contains end-to-end tests running on an underlying
Starknet-like network (using the Starknet RPC), currently Katana. These end-to-end tests contain both raw bytecode execution tests and test on real solidity contracts.

The difference between the starknet test runner (when using contracts) and the plain cairo one is that the former emulate a whole starknet network and is as such much slower (~10x).

Consequently, when writing tests, don't use contracts unless it's really required. Actually, for tests requiring a Starknet devnet, prefer end-to-end relying only on a RPC endpoint and currently running on Katana.

For an example of the cairo test runner, see for example the RLP library tests. Especially, the cairo runner uses hints to communicate values and return outputs:

  • kwargs of cairorun are available in the programinput variable
  • values written in the output_ptr segment are returned, e.g.
segments.writearg(outputptr, [ids.x]) will return the list [x].

Both cairo and starknet tests can be used with the --profile-cairo flag to generate a profiling file (see the --profile_output flag of the cairo-run CLI). The file can then be used with pprof, for example:

go tool pprof --png <pathtofile.pb.gz>

The project also contains a regular forge project (./solidity_contracts) to generate real artifacts to be tested against. This project also contains some forge tests (e.g. PlainOpcodes.t.sol) which purpose is to test easily the solidity functions meant to be tested with kakarot, i.e. quickly making sure that they return the expected output so that we know that we focus on kakarot testing and not .sol testing. They are not part of the CI. Simply use forge test to run them.

EF tests

To run the Ethereum Foundation test suite, you need to pull locally the Kakarot ef-tests runner. To simplify the devX, you can create symlinks in the ef-tests repo pointing to your local changes. For example:

ln -s /Users/clementwalter/Documents/kkrt-labs/kakarot/blockchain-tests-skip.yml blockchain-tests-skip.yml
mkdir build && cd build
ln -s /Users/clementwalter/Documents/kkrt-labs/kakarot/build/ v0
ln -s /Users/clementwalter/Documents/kkrt-labs/kakarot/build/fixtures/ common

With this setting, you can run a given EF test against your local Kakarot build by running (in the ef test directory):

cargo test <test_name> --features v0 -- --nocapture

e.g. cargo test testsha3d7g0v0_Cancun --features v0 -- --nocapture

See this doc to learn how to debug a cairo trace when the CairoVM reverts.

Deploy

The following describes how to deploy the Kakarot as a Starknet smart contract on an underlying StarknetOS network.

It is not a description on how to deploy a solidity contract on the Kakarot EVM.

Note that the chosen chain_id when deploying is important:

  • To keep compatibility with metamask the max chain id is 4503599627370476 see
https://gist.github.com/rekmarks/a47bd5f2525936c4b8eee31a16345553
  • To be compatible with ledger the chain id needs to be inferior to 4 bytes see
https://github.com/kkrt-labs/kakarot/issues/1530

The deploy script relies on some env variables defined in a .env file located at the root of the project and loaded in the constant file. To get started, just

cp .env.example .env

The default file is self sufficient for using Kakarot with KATANA. If targeting other networks, make sure to fill the corresponding variables.

Furthermore, if you want to run the check-resources locally to check the steps usage of your local changes in the EF tests against main and other branches, you need to fill the following

GITHUBTOKEN=yourgithub_token

You can learn how to create this token from here, we would suggest using a fine-grained token with only read access.

By default, everything will run on a local katana (started with make run-katana). If you want to deploy to a given target, set the STARKNET_NETWORK env variable, for example:

make deploy # localhost
STARKNET_NETWORK=testnet make deploy
STARKNET_NETWORK=mainnet make deploy

Deployed contract addresses will be stored in ./deployments/{networks}/deployments.json.

A step by step description of the individual components and how they are deployed/configured can be found here.

Slither

To run slither against provided Kakarot solidity contracts, you need to install slither and run:

forge build --build-info --force
slither . --foundry-out-directory solidity_contracts/build --ignore-compile --include-paths "DualVmToken.sol|L1KakarotMessaging.sol|L2KakarotMessaging.sol" --checklist > report.md

Deeper dive

This deep dive was written by Zellic (Filippo Cremonese) as a result of their audit of Kakarot, as well as their preparation for the Code4rena competitive audit of the codebase. A more in-depth note can be found on Code4rena.

Kakarot consists of two major logical components: the core contract and the account contract.

Core contract

The core contract handles transaction parsing and implements the interpreter which executes EVM bytecode. Only one instance of this contract is deployed.

Account contract

As the name suggests, the account contract represents EVM accounts, both smart contracts and externally owner accounts (EOAs). Each EVM account is represented by a separate instance of the account contract (or more accurately, by an instance of a proxy contract, see the following section) which stores the state of the account, including the nonce, bytecode, and persistent storage. The account balance is not stored in the account contract, since Kakarot uses a Starknet ERC20 token as its EVM-native currency.

Note that while executing a transaction, information about the state of an account is usually read from the account contract and cached directly by the core contract. The account state is updated by the core contract only when required -- typically when a transaction has finished processing and changes to the account state need to be committed.

Account contract deployment

[^NOTE: some aspects of contract deployment changed since the code revision audited by Zellic. This description tries to match the current behavior]

One of the Kakarot design goals is to guarantee a deterministic Starknet address for each Kakarot account contract not influenced by the implementation of the account contract. This allows to upgrade the account contract implementation without affecting the Starknet address of a Kakarot EVM account, and to derive the Starknet address of an account contract before it is even deployed and/or off-chain.

It also allows the core contract to authenticate the source of a call and determine whether it originates from a legitimate Kakarot account contract.

To achieve this, Kakarot deploys an instance of a simple account proxy contract to represent each EVM account. When called, the proxy contract obtains the class hash of the actual account contract from the Kakarot core contract and performs a library call (essentially the equivalent of EVM delegatecall for Cairo).

The account proxy is always deployed by the core Kakarot contract, setting deployfromzero=FALSE. The constructor also receives the EVM address represented by the account contract. Therefore, the Starknet address of an account (proxy) contract depends on the following variables:

  • the class hash of the proxy contract
  • the address of the Kakarot core contract
  • the EVM address represented by the account contract

Transaction flow

Note: important details of the transaction flow changed since the code revision reviewed by Zellic. This includes changes to the account contract entrypoints and the separation of concerns between the core contract and account contract.

The flow of an EVM transaction into Kakarot is deep and could feel overwhelming at first. This section illustrates the execution path of a normal Ethereum transaction. Some simplifications and omissions needed to be made, but it should give you a good idea of the steps that are taken from the very entry point, right down to the EVM interpreter loop.

The journey starts with the account contract representing the EVM account sending the transaction; to be specific, the first entry point into Kakarot is the default function of the proxy account contract. The proxy retrieves from the core Kakarot contract the class hash of the actual account contract implementation, and library calls if (Starknet equivalent of delegatecalling) forwarding the original calldata. This allows to upgrade the implementation of all account contracts at once. The diagram below shows this flow:

sequenceDiagram
    actor U as User<br>(or paymaster)
    participant AP as AccountProxy
    participant EVM as Kakarot Core
    participant A as AccountContract

U ->> AP: Submit call note over AP: default handles all calls

AP ->> EVM: getaccountcontractclasshash() EVM ->> AP: Account contract class hash AP ->> A: library_call<br>Forwarding original calldata

In the case of the Kakarot Starknet deployment, the Starknet transaction typically be initiated by a paymaster account, which will fund the Starknet gas required to process the transaction. Note however that anyone can call the account proxy contract to submit an EVM transaction to Kakarot.

The entry point into the account contract is its executefromoutside function. This function performs several checks, including verification of the transaction signature, ensuring the transaction was signed by the private key associated to the public key represented by the account.

After verifying the transaction signature, the account contract calls the Kakarot core contract eth_rpc module, specifically the ethsendrawunsignedtx function. This function verifies several other properties of the transaction (nonce, chain ID, gas parameters, account balance), and invokes ethsendtransaction.

ethsendtransaction performs another critical check, verifying that the Starknet address of the caller matches the expected Starknet address of the sender of the EVM transaction. This guarantees that the caller is a legitimate Kakarot account contract, and therefore that (modulo critical bugs) the transaction signature was validated correctly.

Execution continues in the Kakarot core ethcall function, which retrieves the bytecode of the contract being called from the corresponding contract account.

Finally, execution reaches the actual virtual machine implementation. The interpreter module execute function initializes all the structures needed to store the execution state (Message, Stack, Memory, State, EVM).

The interpreter loop is implemented using tail-recursion by the run function, and the individual opcodes are handled by the aptly-named execopcode.

When execution ends (successfully or not) the state of the accounts involved in the transaction need to be updated. This is mostly handled by a call to Starknet.commit(...), which performs some finalization on the state structures and then updates the state persisted in the account contracts (e.g. updating their nonce or storage), and also performs the actual Starknet ERC20 transfers needed to transfer the native currency used by Kakarot between accounts.

The following diagram summarizes the flow of a transaction from account contract to the interpreter loop and back:

sequenceDiagram
    actor U as User

participant A as AccountContract

box Kakarot Core participant RPC as eth_rpc participant K as Kakarot participant I as Interpreter end

note over U: Note: proxy flow not represented

U ->> A: executefromoutside(...) note over A: Check EVM tx signature

A ->> RPC: ethsendrawunsignedtx(...) note over RPC: Decode tx<br>Check chain ID, nonce, gas params,<br>sender native balance, ...

RPC ->> RPC: ethsendtransaction(...) note over RPC: Verify caller address<br>(via safegetevm_address)

RPC ->> K: Kakarot.eth_call(...)

K ->> A: get_bytecode() A ->> K: Bytecode returned

K ->> I: Interpreter.execute(...)

note over I: Init state structs:<br>Message, EVM, stack, memory, ...<br>Init called account if needed

loop Interpreter loop note over I: exec_opcode(...) is the function handling individual opcodes end

note over I: State finalization:<br>squash memory dict, apply state balance changes, ...

I ->> K: EVM state:<br>result, stack, memory, gas_used, ...

rect rgb(240,240,240) K ->> K: Starknet.commit() note over K: Update accounts nonce<br>Commit accounts storage<br>Emit events<br>Perform ERC20 balance transfers end

K ->> A: returndata, success, gas used note over A: Emit transaction_executed event A ->> U: returndata

License

kakarot is released under the MIT.

Security

Kakarot follows good practices of security, but 100% security cannot be assured. Kakarot is provided "as is" without any warranty. Use at your own risk.

_For more information and to report security issues, please refer to our security documentation.

Contributing

First off, thanks for taking the time to contribute! Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make will benefit everybody else and are **greatly appreciated**.

Please read our contribution guidelines, and thank you for being involved!

Contributors

Abdel @ StarkWare
Abdel @ StarkWare

๐Ÿ’ป โš ๏ธ ๐Ÿ“– ๐Ÿš‡ ๐Ÿ“† ๐Ÿง‘โ€๐Ÿซ
Lucas
Lucas

๐Ÿ’ป โš ๏ธ ๐Ÿ“– ๐Ÿง‘โ€๐Ÿซ
Mentor Reka
Mentor Reka

๐Ÿ’ป โš ๏ธ ๐Ÿ“– ๐Ÿš‡
danilowhk
danilowhk

๐Ÿ’ป โš ๏ธ
Lenny
Lenny

๐Ÿ’ป โš ๏ธ
Florian Bellotti
Florian Bellotti

๐Ÿ’ป โš ๏ธ
Henri
Henri

๐Ÿ’ป โš ๏ธ
FreshPizza
FreshPizza

๐Ÿ’ป โš ๏ธ
Clรฉment Walter
Clรฉment Walter

๐Ÿ“– โš ๏ธ ๐Ÿ’ป
Rich Warner
Rich Warner

๐Ÿ’ป โš ๏ธ
pscott
pscott

๐Ÿ’ป โš ๏ธ
Elias Tazartes
Elias Tazartes

๐Ÿ’ป โš ๏ธ
Riad-Quadratic
Riad-Quadratic

๐Ÿ’ป โš ๏ธ
Tyler Smith
Tyler Smith

โš ๏ธ
Shahar Papini
Shahar Papini

๐Ÿง‘โ€๐Ÿซ ๐Ÿ’ป โš ๏ธ
Riad | Quadratic
Riad | Quadratic

๐Ÿ’ป
thomas-quadratic
thomas-quadratic

๐Ÿ’ป
Pedro Bergamini
Pedro Bergamini

๐Ÿ’ป
ptisserand
ptisserand

๐Ÿ’ป
TurcFort07
TurcFort07

๐Ÿ’ป
Mnemba Chambuya
Mnemba Chambuya

๐Ÿ’ป
Matthieu Auger
Matthieu Auger

๐Ÿง‘โ€๐Ÿซ โš ๏ธ ๐Ÿ’ป
ftupas
ftupas

๐Ÿ’ป
johann bestowrous
johann bestowrous

๐Ÿ’ป
Seshanth.S
Seshanth.S

๐Ÿ’ป
Flydexo
Flydexo

๐Ÿ’ป โš ๏ธ ๐Ÿ“–
Petar Calic
Petar Calic

๐Ÿ’ป โš ๏ธ
gaetbout
gaetbout

๐Ÿš‡
greged93
greged93

๐Ÿ’ป โš ๏ธ
Francisco Strambini
Francisco Strambini

๐Ÿ’ป โš ๏ธ
sparqet
sparqet

๐Ÿ’ป โš ๏ธ
omahs
omahs

๐Ÿ“–
ArnaudBD
ArnaudBD

๐Ÿ“–
Dragan Pilipovic
Dragan Pilipovic

๐Ÿ’ป โš ๏ธ
Harsh Bajpai
Harsh Bajpai

๐Ÿ’ป โš ๏ธ ๐Ÿ“–
Antoine
Antoine

๐Ÿ’ป
Bal7hazar @ Carbonable
Bal7hazar @ Carbonable

๐Ÿ“–
Daniel Bejarano
Daniel Bejarano

โš ๏ธ
JuMi231
JuMi231

๐Ÿ“–
Juan Rigada
Juan Rigada

๐Ÿ’ป
Mete Karasakal
Mete Karasakal

๐Ÿ“–
Ng Wei Han
Ng Wei Han

๐Ÿ’ป
etash
etash

๐Ÿ’ป
kasteph
kasteph

๐Ÿ“–
Lakhdar Slaim
Lakhdar Slaim

๐Ÿ’ป
mmsc2
mmsc2

๐Ÿ’ป
sarantapodarousa
sarantapodarousa

๐Ÿ’ป

๐Ÿ”— More in this category

ยฉ 2026 GitRepoTrend ยท kkrt-labs/kakarot ยท Updated daily from GitHub