How to build a zkVM for Move¶
The Move Virtual Machine¶
Move is designed to be cross-platform. Programs are compiled to bytecode and executed by the Move Virtual Machine (MoveVM).
MoveVM is a stack-based bytecode virtual machine composed of four main components:
- Interpreter — executes bytecode instructions sequentially
- Operand stack — holds intermediate computation values
- Local variable storage — stores function-local variables
- Global state — persistent on-chain storage
For simplicity, we refer to the stack, local variables, and global state collectively as memory.
The Move instruction set covers a broad range of operations:
- Stack push and pop
- Load and store of local variables
- Arithmetic and logical operations
- Type casting
- Control flow (branches, jumps)
- Function calls and returns
- Struct and vector operations
- Global state read/write
- Exception handling
Each instruction reads values from memory, applies the defined semantics, and writes the result back to memory.
How to Build a zkVM for Move¶
There are three main approaches to building a zkVM for Move, each with distinct trade-offs.
Approach 1: Run MoveVM on a RISC-V zkVM¶
Since MoveVM is implemented in Rust, its source code can be compiled to RISC-V. A RISC-V zkVM (such as RISC Zero or SP1) can then prove the correct execution of the resulting RISC-V binary.
- Advantage: No need to build custom circuits for MoveVM; most of the toolchain already exists.
- Disadvantage: The entire MoveVM is effectively "run inside" another virtual machine, resulting in a long execution path and poor performance.
Approach 2: Compiling Move Bytecode to RISC-V via move-llvm¶
Move bytecode can be compiled to RISC-V instructions using the move-llvm backend, bypassing the MoveVM interpreter entirely.
- Advantage: Better performance than Approach 1.
- Disadvantage: MoveVM and the Move language are tightly coupled — the bytecode relies on runtime safety checks that cannot be replicated in RISC-V. Compiling bytecode to RISC-V breaks these runtime guarantees. Proposed workarounds (e.g., having a trusted party compile Move bytecode to LLVM IR) compromise decentralization. [1]
Approach 3: Build a Dedicated Circuit for MoveVM (zkMove's Approach)¶
zkMove takes the third approach: building a custom circuit that directly verifies the execution of Move bytecode against the MoveVM semantics.
- Advantage: Achieves the best performance without sacrificing security. Because Move bytecode is executed directly on the zkVM, we can exploit the program's code structure for further optimizations.
- Disadvantage: Building a full circuit for MoveVM is a complex and time-intensive engineering effort.
Type safety and memory safety. Move's static type system and linear resource semantics eliminate entire classes of vulnerabilities at compile time — such as use-after-free errors, resource duplication, and accidental destruction. Its strict ownership rules and module encapsulation make classic reentrancy attacks extremely difficult or impossible in most cases.