Nexus zkVM Memory Checking
Since the external memory used by the Nexus Virtual Machine is assumed to be untrusted, the Nexus zkVM must ensure read-write consistency throughout the execution of a program. Informally, this requires that reading the contents of any cell of the memory should always return the value last written to that cell.
In order to enforce the consistency of read-write operations in the memory, the Nexus zkVM currently uses Merkle Trees [M87] together with the Poseidon hash function [GKR21]. In this method, the contents of the memory are first associated with leaves of a Merkle tree and then Merkle-hashed into a Merkle root. The latter Merkle root serves as a binding commitment to the memory and needs to be updated whenever the contents of the memory change.
Merkle Tree Setup
In the current version of Nexus VM, the memory size is set to bytes. Hence, we associate leaves to 256-bit-long strings (i.e., 32 bytes) and then use a Merkle binary tree with 17 levels to describe its contents, as in the figure below.
Initially, each memory cell is assumed to be the string. Hence, in order to compute the Merkle root for the initial memory, we first compute the default hashes for each level of the tree, starting with the leaves and ending with the Merkle root. For the leaves, the default value is simply the hash of the string. For any subsequent level, their default values then become the hash of the concatenation of two of the default values for the level below it.
Merkle Tree Updates and Proofs
After setting up the initial Merkle root for the memory, this value will be used or updated with each memory access, depending on whether the operation is a read or write.
Read Operations
For ease of illustration, let us assume the memory configuration shown in the figure below and consider the case of a read operation at address . Let be the value of the cell at memory address , and let be the 32-byte memory segment that contains .
In order to prove that is the correct value at address , the untrusted memory needs to provide not only , but also a Merkle opening proof that attests to the authenticity of the value . Let denote the path (highlighted in red in the figure above) from the leaf associated with to the Merkle root . Then the Merkle opening proof will consist of the memory segment along with all the siblings of the nodes in the aforementioned leaf-to-root path (highlighted with red boxes in the figure above). Note that, given and the nodes in the authentication path, one can easily recompute the value of the Merkle root in order to verify its correctness. Finally, given the segment , it is also possible to check that is the correct return value for this read operation.
Write Operations
Next, consider the case of a write operation at address , where a new value should replace the old value . In order to update the Merkle tree to match the new desired memory configuration, all the node values along the path from the leaf associated with to the Merkle root need to be recomputed. We highlight these values in blue in the figure below. To achieve this goal, the zkVM should proceed as follows:
- First perform a read operation to obtain along with a Merkle opening proof for it (highlighted by red boxes in the figure below);
- Next, update the value at to in the memory segment as well as all the nodes in the path starting from the leaf associated with ;
- Finally, keep the updated value as the new Merkle root.
Cost Profile
For a memory of size , read and write operations will respectively cost and hash computations. Since each hash operation translates to about 240 constraints using the Poseidon hash function, read and write operations will result in about and constraints, respectively.
References
[GKR21 (opens in a new tab)] Lorenzo Grassi, Dmitry Khovratovich, Christian Rechberger, Arnab Roy, and Markus Schofnegger. “Poseidon: A new hash function for Zero-Knowledge proof systems”. In: 30th USENIX Security Symposium (USENIX Security 21). 2021, pp. 519–535
[M87 (opens in a new tab)] Ralph C Merkle. “A digital signature based on a conventional encryption function”. In CRYPTO 1987.