---
# System prepended metadata

title: Thoughts on integrating zkVM with the client

---

# Thoughts on integrating zkVM with the client

Date: 2025-04-28
By: Jun Song

---

Yesterday, Justin provided some updates on zkVMs, along with a few implementation tips. Here's the list:

- a) isolate your STF (e.g. in a separate module/library/crate/repo)
- b) minimise STF dependencies (e.g. avoid loading heavy libraries)
- c) use stateless reads and writes (the full consensus state should never be loaded in memory for snarkification—use Merkle proofs for state access)
- d) kick the tyres of various zkVMs


The Ream team is on track with each item.

- a, b) [`ream-consensus`](https://github.com/ReamLabs/ream/tree/master/crates/common/consensus) crate contains STF for Electra
- c) For this, partially updating SSZ object is necessary, and @unnawut-eth is working on.
- d) We have bare PoCs on [SP1](https://github.com/ReamLabs/consensp1us) and [Risc0](https://github.com/ReamLabs/consenzero-bench).

This note is a set of unorganized memos for the next step: integrating zkVM with [Ream](https://github.com/ReamLabs/ream) repo.

### 1. Separation of Engine API usage.

zkVMs [doesn't support](https://dev.risczero.com/api/zkvm/zkvm-specification#the-zkvm-execution-model) asynchronous behavior: it is considered as a single-threaded environment. However, for the STF of status quo, we need to call the connected execution client via Engine API while processing the `ExecutionPayload`.

```python!
def process_block(state: BeaconState, block: BeaconBlock) -> None:
    process_block_header(state, block)
    process_withdrawals(state, block.body.execution_payload)
    process_execution_payload(state, block.body, EXECUTION_ENGINE) # We should verify and notify new execution payload via Engine API
    process_randao(state, block.body)
    process_eth1_data(state, block.body)
    process_operations(state, block.body) 
    process_sync_aggregate(state, block.body.sync_aggregate)
```

As `process_execution_payload` is the only part that should be asynchronous, I tried to separate it with `state_transition`. However, separating `process_execution_payload` from `state_transition` is challenging because multiple `BeaconState` fields are interdependent. For example, `latest_execution_payload_header` is updated upon validation and reused for subsequent block validations. Also, `process_randao` mutates `randao_mixes`, and `process_execution_payload` contains validation logic w.r.t the randao mix value.

To execute the entire STF for new block on zkVMs, we need some clever way to decouple those highly coupled state transitions. For initial demonstrations, it could be fine to add new `state_transition_sync` function that **assumes** the result of validating `execution_payload`.

### 2. Rough architecture for real-time proving

> Super open to feedback!

Here's a rough overview for the client. For simplicity, I divided critical components as services.

![image](https://hackmd.io/_uploads/HkYNuzpkle.png)

- **Core** service are mainly responsible for state transition. **Validator** service performs some duties, but in this architecture I'd like to focus on the block producing part.
- **Prover** service are responsible for generating proofs and submitting them to a certain network. It works as a consumer-service, while services like Validator & Core service feed newly generated blocks through `mpsc` channels.
    - As Ream client won't depend on a single zkVM vendor, **Prover** service should be modular: User can choose which zkVM to use via command flags.
- Proof Network could range from a simple, centralized verifier to a more complex, distributed P2P verification network. The exact structure needs more exploration.


### 3. [WIP] Continuation

As Justin mentioned, there are currently 8 zkVMs supporting **continuation**, each with features such as [Proof Composition](https://dev.risczero.com/api/zkvm/composition) for Risc Zero and [Proof Aggregation](https://docs.succinct.xyz/docs/sp1/writing-programs/proof-aggregation) for SP1. Continuations could help split large STFs into manageable chunks, potentially enabling parallel execution. However, given the current complexity and linear nature of Beacon chain STF, effective parallelization remains unclear and requires further investigation.

## To-do list

- We do have STF, but lack the way to process from given state. The Core Service should handle this.
    - Potentially implement an RPC in a debug namespace accepting SSZ-encoded Beacon states and blocks, returning computed state transitions.
- Further explore continuation features and practical implications for STF.
- Figure out for handling asynchronous behavior of current STF.
- Try other zkVMs:  [OpenVM](https://github.com/openvm-org/openvm), [Pico](https://github.com/brevis-network/pico), [zkEngine](https://github.com/ICME-Lab/zkEngine_dev), [ZisK](https://github.com/0xPolygonHermez/zisk), [zkMIPS](https://github.com/zkMIPS/zkm), [zkWASM](https://github.com/DelphinusLab/zkWasm)

