Specs
Nexus Virtual Machine

Nexus Virtual Machine

The Nexus Virtual Machine (Nexus VM) is a reduced instruction set computer (RISC) with a word-addressable random-access memory and input tapes. This virtual machine abstraction is comparable to others used in the zero-knowledge research space, such as the TinyRAM architecture specification (opens in a new tab). The advantage of using such random-access machines is that they abstract away details of the underlying hardware or operating system and provide a convenient tool for generating claims and proofs about the correctness of a computation.

Nexus Virtual Machine Architecture

The Nexus Virtual Machine has a von Neumann architecture, storing instructions and data in the same read-write memory space. The machine has 32 registers and a read-write memory with addresses in the range {02321}\{0\ldots 2^{32}-1\}. The state of the machine is defined as a five-tuple, (pc;M;R;I;W)(pc;M;R;I;W), where

  • pcpc denotes the program counter register;
  • MM denotes the memory;
  • RR denotes the set of registers;
  • II is the public input;
  • WW is an auxiliary input, seen as a nondeterministic advice.

An abstraction of the Nexus Virtual Machine

Both MM and RR are finite maps. The keys of MM are addresses in the range {0,,2321}\{0,\ldots, 2^{32}-1\} and the keys of RR are register selectors from the set {x0x31}\{x_0\ldots x_{31}\}. By design, updates to register x0x_0 are ignored and the value of R[x0]R[x_0] is always zero.

The current implementation of the Nexus VM does not yet support public and auxiliary/private inputs, but this feature will soon be available. Also, we remark that specific implementations of the Nexus VM may choose memory sizes smaller than 2322^{32} for efficient reasons.

At initialization, all the general-purpose registers are set to 0. The program counter pcpc is set to 0x0000\mathtt{0x0000}. The input and auxiliary tapes, once supported, should contain the public and input auxiliary inputs for the program. Since pcpc is initially 0x0000\mathtt{0x0000}, the first instruction to be executed will be the one stored at the position 0x0000\mathtt{0x0000} of the memory. Since the program code resides in the same area as the data, the initial memory can contain not only the program code but also some initial input data for the program.

The program counter pcpc is always advanced by 8 bytes after the execution of each instruction, unless the instruction itself sets the value of pcpc. Moreover, the Nexus VM enforces 8-byte-memory alignment for the program counter by checking that pcpc is a multiple of 8 when reading an instruction.

Nexus Virtual Machine Instruction Set

The Nexus VM instruction set contains 30 instructions in total, as summarized in table below. Each instruction is specified via an opcode and takes three arguments, two register selectors and a full 32-bit immediate value. The exact format (opcode  rd    rs1  rs2  i)(\textbf{opcode}\;rd\;\;rs_1\;rs_2\;i) of each instruction is defined as follows:

  • opcode\textbf{opcode} is a string defining the instruction;
  • rdrd is a register selector specifying the destination register;
  • rs1rs_1 is a register selector specifying the first operand;
  • rs2rs_2 is a register selector specifying the second operand; and
  • ii is a full 32-bit immediate value.

Table: Summary of the Nexus Virtual Machine Instruction Set, where operations are mod 2322^{32}.

Instruction mnemonicArgumentsDescription of functionality
add\textbf{add}rdrd rs1rs_1 rs2rs_2 iisets rdrd to R[rs1]+(R[rs2]+i)R[rs_1] + (R[rs_2] + i)
sub\textbf{sub}rdrd rs1rs_1 rs2rs_2 iisets rdrd to R[rs1](R[rs2]+i)R[rs_1] - (R[rs_2] + i)
mul\textbf{mul}rdrd rs1rs_1 rs2rs_2 iisets rdrd to the least significant bits of R[rs1]×(R[rs2]+i)R[rs_1] \times (R[rs_2] + i)
div\textbf{div}rdrd rs1rs_1 rs2rs_2 iisets rdrd to the quotient of R[rs1]/(R[rs2]+i)R[rs_1] / (R[rs_2] + i)
slt\textbf{slt}rdrd rs1rs_1 rs2rs_2 iisets rdrd to (R[rs1]<(R[rs2]+i)(R[rs_1] < (R[rs_2] + i) (signed comparison)
sltu\textbf{sltu}rdrd rs1rs_1 rs2rs_2 iisets rdrd to (R[rs1]<(R[rs2]+i)(R[rs_1] < (R[rs_2] + i) (unsigned comparison)
sll\textbf{sll}rdrd rs1rs_1 rs2rs_2 iisets rdrd to R[rs1](R[rs2]+i)&0x1FR[rs_1] \ll (R[rs_2] + i) \mathbin{\&} \mathtt{0x1F}
slr\textbf{slr}rdrd rs1rs_1 rs2rs_2 iisets rdrd to R[rs1](R[rs2]+i)&0x1FR[rs_1] \gg (R[rs_2] + i) \mathbin{\&} \mathtt{0x1F}
sra\textbf{sra}rdrd rs1rs_1 rs2rs_2 iisets rdrd to R[rs1](R[rs2]+i)&0x1FR[rs_1] \gg (R[rs_2] + i) \mathbin{\&} \mathtt{0x1F} (R[rs1]R[rs_1] as integer)
xor\textbf{xor}rdrd rs1rs_1 rs2rs_2 iisets rdrd to the bitwise XOR of R[rs1]R[rs_1] and (R[rs2]+i)(R[rs_2] + i)
and\textbf{and}rdrd rs1rs_1 rs2rs_2 iisets rdrd to the bitwise AND of R[rs1]R[rs_1] and (R[rs2]+i)(R[rs_2] + i)
or\textbf{or}rdrd rs1rs_1 rs2rs_2 iisets rdrd to the bitwise OR of R[rs1]R[rs_1] and (R[rs2]+i)(R[rs_2] + i)
beq\textbf{beq}rs1rs_1 rs2rs_2 iibranches to pc+ipc+i if (R[rs1]=R[rs2])(R[rs_1] = R[rs_2]) (signed comparison)
bne\textbf{bne}rs1rs_1 rs2rs_2 iibranches to pc+ipc+i if (R[rs1]R[rs2])(R[rs_1] \not= R[rs_2]) (signed comparison)
blt\textbf{blt}rs1rs_1 rs2rs_2 iibranches to pc+ipc+i if (R[rs1]<R[rs2])(R[rs_1] < R[rs_2]) (signed comparison)
bge\textbf{bge}rs1rs_1 rs2rs_2 iibranches to pc+ipc+i if (R[rs1]R[rs2])(R[rs_1] \geq R[rs_2]) (signed comparison)
bltu\textbf{bltu}rs1rs_1 rs2rs_2 iibranches to pc+ipc+i if (R[rs1]<R[rs2])(R[rs_1] < R[rs_2]) (unsigned comparison)
bgeu\textbf{bgeu}rs1rs_1 rs2rs_2 iibranches to pc+ipc+i if (R[rs1]R[rs2])(R[rs_1] \geq R[rs_2]) (unsigned comparison)
lb\textbf{lb}rdrd rs1rs_1 rs2rs_2 iiloads the sign extension of the byte at M[R[rs1]+i]M[R[rs_1] + i] into rdrd
lh\textbf{lh}rdrd rs1rs_1 rs2rs_2 iiloads the sign extension of the half-word at M[R[rs1]+i]M[R[rs_1] + i] into rdrd
lw\textbf{lw}rdrd rs1rs_1 rs2rs_2 iiloads the sign extension of the word at M[R[rs1]+i]M[R[rs_1] + i] into rdrd
lbu\textbf{lbu}rdrd rs1rs_1 rs2rs_2 iiloads the zero extension of the byte at M[R[rs1]+i]M[R[rs_1] + i] into rdrd
lhu\textbf{lhu}rdrd rs1rs_1 rs2rs_2 iiloads the zero extension of the half-word at M[R[rs1]+i]M[R[rs_1] + i] into rdrd
sb\textbf{sb}rs1rs_1 rs2rs_2 iistores the first byte of R[rs2]R[rs_2] at M[R[rs1]+i]M[R[rs_1] + i]
sh\textbf{sh}rs1rs_1 rs2rs_2 iistores the first half-word of R[rs2]R[rs_2] at M[R[rs1]+i]M[R[rs_1] + i]
sw\textbf{sw}rs1rs_1 rs2rs_2 iistores R[rs2]R[rs_2] at M[R[rs1]+i]M[R[rs_1] + i]
jal\textbf{jal}rdrd rs1rs_1 iijumps to M[R[rs1]+i]M[R[rs_1] + i] and stores pc+8pc+8 into rdrd
nop\textbf{nop}no operation
halt\textbf{halt}rs1rs_1 iihalts execution with a return value (R[rs1]+i)(R[rs_1] + i), pcpc is not updated
sys\textbf{sys}system call

The Nexus VM also enforces 2-byte and 4-byte memory alignments for the instructions operating on half-words and words. In particular, one cannot read or write half-words and words to addresses which are not a multiple of 22 and 44, respectively.

Each instruction is encoded as a 64-bit-long string, starting with 8-bit-long opcode\textbf{opcode} string, followed by a 9-bit-long zero string, three 5-bit-long register selectors for rdrd, rs1rs_1, and rs1rs_1, and a 32-bit immediate value.

Table: Binary Encoding of Nexus Virtual Machine Instructions, where m*^m denotes any binary string of mm bits, and d\langle d \rangle, s1\langle s_1 \rangle, s2\langle s_2 \rangle, and i\langle i \rangle denote respectively the binary representation of the 5-bit-long register selectors rdrd, rs1rs_1, rs2rs_2, and the 32-bit-long immediate value ii.

Instruction mnemonicArgumentsBinary Encodings
nop\textbf{nop}0x015   5     5   32\begin{array}{llllll} \texttt{0x01} & \mathtt{*^5} \; \ & \mathtt{*^5} \; \ & \; \mathtt{*^5} \; \ & \mathtt{*^{32}}\end{array}
halt\textbf{halt}rs1rs_1 ii0x025   s1  5   i\begin{array}{llllll} \texttt{0x02} & \mathtt{*^5} \; \ & \langle s_1 \rangle & \; \mathtt{*^5} \; \ & \langle i \rangle \end{array}
sys\textbf{sys}0x035   5     5   32\begin{array}{llllll} \texttt{0x03} & \mathtt{*^5} \; \ & \mathtt{*^5} \; \ & \; \mathtt{*^5} \; \ & \mathtt{*^{32}}\end{array}
jal\textbf{jal}rdrd rs1rs_1 ii0x10ds1  5   i\begin{array}{llllll} \texttt{0x10} & \langle d \rangle & \langle s_1 \rangle & \; \mathtt{*^5} \; \ & \langle i \rangle\end{array}
beq\textbf{beq}rs1rs_1 rs2rs_2 ii0x115   s1s2i\begin{array}{llllll} \texttt{0x11} & \mathtt{*^5} \;\ & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
bne\textbf{bne}rs1rs_1 rs2rs_2 ii0x125   s1s2i\begin{array}{llllll} \texttt{0x12} & \mathtt{*^5} \; \ & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
blt\textbf{blt}rs1rs_1 rs2rs_2 ii0x135   s1s2i\begin{array}{llllll} \texttt{0x13} & \mathtt{*^5} \; \ & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
bge\textbf{bge}rs1rs_1 rs2rs_2 ii0x145   s1s2i\begin{array}{llllll} \texttt{0x14} & \mathtt{*^5} \; \ & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
bltu\textbf{bltu}rs1rs_1 rs2rs_2 ii0x155   s1s2i\begin{array}{llllll} \texttt{0x15} & \mathtt{*^5} \; \ & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
bgeu\textbf{bgeu}rs1rs_1 rs2rs_2 ii0x165   s1s2i\begin{array}{llllll} \texttt{0x16} & \mathtt{*^5} \; \ & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
lb\textbf{lb}rdrd rs1rs_1 ii0x20ds1  5   i\begin{array}{llllll} \texttt{0x20} & \langle d \rangle & \langle s_1 \rangle & \; \mathtt{*^5} \; \ & \langle i \rangle\end{array}
lh\textbf{lh}rdrd rs1rs_1 ii0x21ds1  5   i\begin{array}{llllll} \texttt{0x21} & \langle d \rangle & \langle s_1 \rangle & \; \mathtt{*^5} \; \ & \langle i \rangle\end{array}
lw\textbf{lw}rdrd rs1rs_1 ii0x22ds1  5   i\begin{array}{llllll} \texttt{0x22} & \langle d \rangle & \langle s_1 \rangle & \; \mathtt{*^5} \; \ & \langle i \rangle\end{array}
lbu\textbf{lbu}rdrd rs1rs_1 ii0x23ds1  5   i\begin{array}{llllll} \texttt{0x23} & \langle d \rangle & \langle s_1 \rangle & \; \mathtt{*^5} \; \ & \langle i \rangle\end{array}
lhu\textbf{lhu}rdrd rs1rs_1 ii0x24ds1  5   i\begin{array}{llllll} \texttt{0x24} & \langle d \rangle & \langle s_1 \rangle & \; \mathtt{*^5} \; \ & \langle i \rangle\end{array}
sb\textbf{sb}rs1rs_1 rs2rs_2 ii0x305   s1s2i\begin{array}{llllll} \texttt{0x30} & \mathtt{*^5} \;\ & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
sh\textbf{sh}rs1rs_1 rs2rs_2 ii0x315   s1s2i\begin{array}{llllll} \texttt{0x31} & \mathtt{*^5} \;\ & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
sw\textbf{sw}rs1rs_1 rs2rs_2 ii0x325   s1s2i\begin{array}{llllll} \texttt{0x32} & \mathtt{*^5} \;\ & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
add\textbf{add}rdrd rs1rs_1 rs2rs_2 ii0x40ds1s2i\begin{array}{llllll} \texttt{0x40} & \langle d \rangle & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
sub\textbf{sub}rdrd rs1rs_1 rs2rs_2 ii0x41ds1s2i\begin{array}{llllll} \texttt{0x41} & \langle d \rangle & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
slt\textbf{slt}rdrd rs1rs_1 rs2rs_2 ii0x42ds1s2i\begin{array}{llllll} \texttt{0x42} & \langle d \rangle & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
sltu\textbf{sltu}rdrd rs1rs_1 rs2rs_2 ii0x43ds1s2i\begin{array}{llllll} \texttt{0x43} & \langle d \rangle & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
sll\textbf{sll}rdrd rs1rs_1 rs2rs_2 ii0x44ds1s2i\begin{array}{llllll} \texttt{0x44} & \langle d \rangle & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
slr\textbf{slr}rdrd rs1rs_1 rs2rs_2 ii0x45ds1s2i\begin{array}{llllll} \texttt{0x45} & \langle d \rangle & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
sra\textbf{sra}rdrd rs1rs_1 rs2rs_2 ii0x46ds1s2i\begin{array}{llllll} \texttt{0x46} & \langle d \rangle & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
or\textbf{or}rdrd rs1rs_1 rs2rs_2 ii0x47ds1s2i\begin{array}{llllll} \texttt{0x47} & \langle d \rangle & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
and\textbf{and}rdrd rs1rs_1 rs2rs_2 ii0x48ds1s2i\begin{array}{llllll} \texttt{0x48} & \langle d \rangle & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
xor\textbf{xor}rdrd rs1rs_1 rs2rs_2 ii0x49ds1s2i\begin{array}{llllll} \texttt{0x49} & \langle d \rangle & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
mul\textbf{mul}rdrd rs1rs_1 rs2rs_2 ii0x4Ads1s2i\begin{array}{llllll} \texttt{0x4A} & \langle d \rangle & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}
div\textbf{div}rdrd rs1rs_1 rs2rs_2 ii0x4Bds1s2i\begin{array}{llllll} \texttt{0x4B} & \langle d \rangle & \langle s_1 \rangle & \langle s_2 \rangle & \langle i \rangle\end{array}

Compared to RISC-V, Nexus VM instructions are longer (64 bits versus 32 bits) and allow for an additional argument. One of the advantages of having an additional argument is that it allows for a reduced instruction set. In particular, as noted in the section describing the translation from RISC-V to Nexus VM, different RISC-V instructions can be emulated with a single Nexus VM instruction.

Similarly to the answer\textbf{answer} instruction in the TinyRAM architecture specification (opens in a new tab), the output produced by halt\textbf{halt} indicates whether the program halts in an accepting or rejecting state by setting R[rs1]+i=0R[rs_1] + i=0 or not.

The current architecture does not specify an output tape. Nevertheless, one can easily return arbitrary strings as output by encoding that string in some specific region of the memory before halting in an accepting state.

As we show in the next section, the RISC-V instruction set can be easily compiled to the instruction set of the Nexus VM, by applying a simple translation function to a subset of these instructions. As a result, the Nexus VM can effortlessly support the execution of programs written in high-level programming languages such as Rust and C++. In addition to that, as indicated further below, future versions of the Nexus VM will be able to be extended with custom instructions (e.g. SHA-256).

Translation from RISC-V to Nexus VM

The syntax of RISC-V instructions supported by the Nexus VM is the following:

i{0..2321}Immediate valuespc{0..2321}Program counterrd,rs1,rs2{x0..x31}Register selectorsalu=addsubmuldivsltsltusllsrlsraxorandorBinary operatorsbcc=beqbnebltbgebltubgeuBranch conditionsld=lblhlwlbulhuLoad operationsst=sbshswStore operationsoper=lui  rd  iLoad immediateauipc  rd  iLoad immediate + PCalu  rd    rs1  rs2ALU register-registeralu  rd    rs1  iALU register-immediateebreakBreakpointfenceMemory fencebranch=jal  rd  iJump and linkjalr  rd  rs1  iJump and link registerbcc  rs1  rs2  iConditional branchmemory=ld  rd  rs1  iLoad memoryst  rs1  rs2  iStore memoryinst=operOperationsbranchControl transfermemoryLoad and storeecallEnvironment callunimpUnimplemented\begin{align*} %\text{Binary Operators}\\ i \in&\: \{0..2^{32}-1\} &\text{Immediate values} \\ pc \in&\: \{0..2^{32}-1\} &\text{Program counter} \\ rd,rs_1,rs_2 \in&\: \{x_0 .. x_{31}\} &\text{Register selectors} \\ alu =&\: \textbf{add} \mid \textbf{sub} \mid \textbf{mul} \mid \textbf{div} \\ \mid&\: \textbf{slt} \mid \textbf{sltu} \mid \textbf{sll} \mid \textbf{srl} \mid \textbf{sra} \\ \mid&\: \textbf{xor} \mid \textbf{and} \mid \textbf{or} & \text{Binary operators} \\ bcc =&\: \textbf{beq} \mid \textbf{bne} \mid \textbf{blt} \mid \textbf{bge} \mid \textbf{bltu} \mid \textbf{bgeu} & \text{Branch conditions} \\ ld =&\: \textbf{lb} \mid \textbf{lh} \mid \textbf{lw} \mid \textbf{lbu} \mid \textbf{lhu} & \text{Load operations} \\ st =&\: \textbf{sb} \mid \textbf{sh} \mid \textbf{sw} & \text{Store operations} \\ oper =&\: \textbf{lui}\;rd\;i & \text{Load immediate} \\ \mid&\: \textbf{auipc}\;rd\;i & \text{Load immediate + PC} \\ \mid&\: alu\;rd\;\;rs_1\;rs_2 & \text{ALU register-register} \\ \mid&\: alu\;rd\;\;rs_1\;i & \text{ALU register-immediate} \\ \mid&\: \textbf{ebreak} & \text{Breakpoint} \\ \mid&\: \textbf{fence} & \text{Memory fence} \\ branch =&\: \textbf{jal}\;rd\;i & \text{Jump and link} \\ \mid&\: \textbf{jalr}\;rd\;rs_1\;i & \text{Jump and link register} \\ \mid&\: bcc\;rs_1\;rs_2\;i & \text{Conditional branch} \\ memory =&\: ld\;rd\;rs_1\;i & \text{Load memory} \\ \mid&\: st\;rs_1\;rs_2\;i & \text{Store memory} \\ inst =&\: oper & \text{Operations} \\ \mid&\: branch & \text{Control transfer} \\ \mid&\: memory & \text{Load and store} \\ \mid&\: \textbf{ecall} & \text{Environment call} \\ \mid&\: \textbf{unimp} & \text{Unimplemented} \\ \end{align*}

These RISC-V instructions can be easily converted to Nexus VM instructions according to:

C(lui  rd  i)=add  rd  x0  x0  iC(auipc  rd  i)=add  rd  x0  x0  (pc+i)C(alu  rd    rs1  rs2)=alu  rd  rs1  rs2  0C(alu  rd    rs1  i)=alu  rd  rs1  x0  iC(ebreak)=nopC(fence)=nopC(ecall)=sysC(unimp)=halt  x0  1C(bcc  rs1  rs2  i)=bcc  rs1  rs2  iC(ld  rs1  i)=ld  rs1  iC(st  rs1  rs2  i)=st  rs1  rs2  iC(jal  rd  i)=jal  rd  x0  iC(jalr  rd  rs1  i)=jal  rd  rs1  i\begin{align*} \mathcal{C}(\textbf{lui}\;rd\;i) =& \textbf{add}\;rd\;x_0\;x_0\;i \\ \mathcal{C}(\textbf{auipc}\;rd\;i) =& \textbf{add}\;rd\;x_0\;x_0\;(pc+i) \\ \mathcal{C}(alu\;rd\;\;rs_1\;rs_2) =& alu\;rd\;rs_1\;rs_2\;0 \\ \mathcal{C}(alu\;rd\;\;rs_1\;i) =& alu\;rd\;rs_1\;x_0\;i \\ \mathcal{C}(\textbf{ebreak}) =& \textbf{nop} \\ \mathcal{C}(\textbf{fence}) =& \textbf{nop} \\ \mathcal{C}(\textbf{ecall}) =& \textbf{sys} \\ \mathcal{C}(\textbf{unimp}) =& \textbf{halt}\;x_0\;1 \\ \mathcal{C}(bcc\;rs_1\;rs_2\;i) =& bcc\;rs_1\;rs_2\;i \\ \mathcal{C}(ld\;rs_1\;i) =& ld\;rs_1\;i \\ \mathcal{C}(st\;rs_1\;rs_2\;i) =& st\;rs_1\;rs_2\;i \\ \mathcal{C}(\textbf{jal}\;rd\;i) =& \textbf{jal}\;rd\;x_0\;i \\ \mathcal{C}(\textbf{jalr}\;rd\;rs_1\;i) =& \textbf{jal}\;rd\;rs_1\;i \\ \end{align*}

Note that the special RISC-V load immediate instructions (lui\textbf{lui} and auipc\textbf{auipc}) are a result of the fixed 32-bit encoding of instructions. The Nexus VM relaxes this constraint allowing for a reduced instruction set.

Both ebreak\textbf{ebreak} and fence\textbf{fence} are mapped to nop\textbf{nop} since they have no effect as we do not support debugging and our virtual machine only has one CPU core (a.k.a. Hart in RISC-V terminology),

unimp\textbf{unimp} is mapped to halt  x0  1\textbf{halt}\;x_0\;1 to indicate a failure condition.

Nexus Virtual Machine Initialization

Initially, the memory is assumed to only contain zero values and all the general-purpose registers are set to 0. The program counter pcpc is also set to 0x0000\mathtt{0x0000}. Although the current version of the Nexus VM does not yet support input and auxiliary tapes, these will be eventually implemented and initialized with the contents of the public and auxiliary inputs for the program. The program itself is provided to the Nexus VM via a file in a Executable and Linkable Format (ELF) encoded according to the RV32I Instruction Set in the Volume I, Unprivileged Specification version 20191213 in the The RISC-V Instruction Set Manual (opens in a new tab).

In order to load the ELF file into the Nexus VM memory, the RISC-V assembly code provided in the ELF file based on 32-bit-long RV32I instruction set is first translated to Nexus VM 64-bit-long instruction set following the translation process described in the previous section. Next, each instruction in the program is loaded one at a time into the memory starting at address 0x0000\mathtt{0x0000}.

Nexus Virtual Machine Extensions

While the universality of the current instruction set allows for executing any program on the Nexus VM, the translation process may yield inefficient programs due to the limited instruction set of the Nexus VM. As a result, proving the correctness of such computations within the Nexus zkVM may become infeasible for more complex programs. The cost of such an abstraction may be multiplied by more than a 10001000 factor for functions such as the SHA-256 circuit.

To deal with such scenarios, the Nexus Virtual Machine is being designed with extensability in mind in order to enable the addition of custom instructions for more complex functions, such as hashing and signature verification.

Currently, the Nexus Virtual Machine uses universal circuits to simulate the whole CPU and this unfortunately increases the complexity of the Nexus Proof System with each additional instruction.

Nevertheless, we will soon be switching to a non-uniform computation model based on recent advances in folding and accumulation techniques (e.g., [KS22], [BC23]), via the concept of zkVM precompiles. In the new model, the cost of proving custom precompile extensions of the NVM instruction set only occurs when that particular precompile is executed by the program.

nvm-architecture-coprocessors

The main advantage of using precompiles is that it maintains a developer-friendly CPU abstraction while efficiently allowing for the addition of more complex functions.

Though we first expect to implement these special functions as part of the Nexus VM instruction set, we do intend to eventually support user-defined precompiles written as as CCS circuits [STW23] that could be provided as input to the Nexus zkVM. we expect to first implement these special functions as part of the Nexus VM instruction set. CCS circuits are a generalization of R1CS [GGPR13], Plonkish [GWC19; CBBZ23], and AIR [BBHR19; Sta21; BCKL22].

References

[BBHR19 (opens in a new tab)] Eli Ben-Sasson, Iddo Bentov, Yinon Horesh, and Michael Riabzev. “Scalable zero knowledge with no trusted setup”. In CRYPTO 2019.

[BC23 (opens in a new tab)] Benedikt Bünz and Binyi Chen. “Protostar: Generic efficient accumulation/folding for special sound protocols”. In: Cryptology ePrint Archive (2023)

[BCKL22 (opens in a new tab)] Eli Ben-Sasson, Dan Carmon, Swastik Kopparty, and David Levit. “Scalable and transparent proofs over all large fields, via elliptic curves”. In: Electronic Colloquium on Computational Complexity, Report. Vol. 110. 2022, p. 2022

[CBBZ23 (opens in a new tab)] Binyi Chen, Benedikt Bünz, Dan Boneh, and Zhenfei Zhang. “Hyperplonk: Plonk with linear-time prover and high-degree custom gates”. In EUROCRYPT 2023.

[GGPR13 (opens in a new tab)] Rosario Gennaro, Craig Gentry, Bryan Parno, and Mariana Raykova. “Quadratic span programs and succinct NIZKs without PCPs”. In EUROCRYPT 2013.

[GWC19 (opens in a new tab)] Ariel Gabizon, Zachary J Williamson, and Oana Ciobotaru. “Plonk: Permutations over lagrange-bases for oecumenical noninteractive arguments of knowledge”. In: Cryptology ePrint Archive (2019)

[KS22 (opens in a new tab)] Abhiram Kothapalli and Srinath Setty. “SuperNova: Proving universal machine executions without universal circuits”. In: Cryptology ePrint Archive (2022)

[Sta21 (opens in a new tab)] StarkWare. ethSTARK Documentation. Cryptology ePrint Archive, Paper 2021/582.

[STW23 (opens in a new tab)] Srinath Setty, Justin Thaler, and Riad Wahby. “Customizable constraint systems for succinct arguments”. In: Cryptology ePrint Archive (2023)