Quick reference for all Aztec Virtual Machine (AVM) opcodes.
Before diving into the instruction set, familiarize yourself with these core concepts:
- Introduction: What is the AVM and why do we need it?
- State: World state (persistent) vs execution state (transient)
- Memory Model: Memory notation and tagged memory (
M[x]andT[x]) - Addressing Modes: Direct, indirect, and relative addressing along with their gas implications
- Execution Lifecycle: VM initialization, PC rules, halting, gas charging order
- Gas Metering: How L2 and DA gas costs are calculated and charged during instruction execution
- Errors: Error types, triggers, and gas/state behavior
- Wire Formats: How instructions are encoded in bytecode and why opcodes have variants like
ADD_8andADD_16
Click on an opcode name to view its detailed documentation.
- 🔗ADD: Addition (a + b)
- Opcodes
0x00-0x01(2 wire formats)
M[dstOffset] = M[aOffset] + M[bOffset]
- Opcodes
- 🔗SUB: Subtraction (a - b)
- Opcodes
0x02-0x03(2 wire formats)
M[dstOffset] = M[aOffset] - M[bOffset]
- Opcodes
- 🔗MUL: Multiplication (a * b)
- Opcodes
0x04-0x05(2 wire formats)
M[dstOffset] = M[aOffset] * M[bOffset]
- Opcodes
- 🔗DIV: Integer division (a / b)
- Opcodes
0x06-0x07(2 wire formats)
M[dstOffset] = M[aOffset] / M[bOffset]
- Opcodes
- 🔗FDIV: Field division (a / b)
- Opcodes
0x08-0x09(2 wire formats)
M[dstOffset] = M[aOffset] / M[bOffset]
- Opcodes
- 🔗EQ: Equality check (a == b)
- Opcodes
0x0A-0x0B(2 wire formats)
M[dstOffset] = (M[aOffset] == M[bOffset]) ? 1 : 0
- Opcodes
- 🔗LT: Less than (a < b)
- Opcodes
0x0C-0x0D(2 wire formats)
M[dstOffset] = (M[aOffset] < M[bOffset]) ? 1 : 0
- Opcodes
- 🔗LTE: Less than or equal (a <= b)
- Opcodes
0x0E-0x0F(2 wire formats)
M[dstOffset] = (M[aOffset] <= M[bOffset]) ? 1 : 0
- Opcodes
- 🔗AND: Bitwise AND (a & b)
- Opcodes
0x10-0x11(2 wire formats)
M[dstOffset] = M[aOffset] & M[bOffset]
- Opcodes
- 🔗OR: Bitwise OR (a | b)
- Opcodes
0x12-0x13(2 wire formats)
M[dstOffset] = M[aOffset] | M[bOffset]
- Opcodes
- 🔗XOR: Bitwise XOR (a ^ b)
- Opcodes
0x14-0x15(2 wire formats)
M[dstOffset] = M[aOffset] ^ M[bOffset]
- Opcodes
- 🔗NOT: Bitwise NOT (~a)
- Opcodes
0x16-0x17(2 wire formats)
M[dstOffset] = ~M[srcOffset]
- Opcodes
- 🔗SHL: Shift left (a << b)
- Opcodes
0x18-0x19(2 wire formats)
M[dstOffset] = M[aOffset] << M[bOffset]
- Opcodes
- 🔗SHR: Shift right (a >> b)
- Opcodes
0x1A-0x1B(2 wire formats)
M[dstOffset] = M[aOffset] >> M[bOffset]
- Opcodes
- 🔗CAST: Type cast memory value
- Opcodes
0x1C-0x1D(2 wire formats)
M[dstOffset] = M[srcOffset] as tag
- Opcodes
- 🔗GETENVVAR: Get environment variable
- Opcode
0x1E
M[dstOffset] = environmentVariable[varEnum]
- Opcode
- 🔗CALLDATACOPY: Copy calldata to memory
- Opcode
0x1F
M[dstOffset:dstOffset+M[copySizeOffset]] = calldata[M[cdStartOffset]:M[cdStartOffset]+M[copySizeOffset]]
- Opcode
- 🔗SUCCESSCOPY: Get success status of latest external call
- Opcode
0x20
M[dstOffset] = nestedCallSuccess ? 1 : 0
- Opcode
- 🔗RETURNDATASIZE: Get returndata size
- Opcode
0x21
M[dstOffset] = nestedReturndata.length
- Opcode
- 🔗RETURNDATACOPY: Copy returndata to memory
- Opcode
0x22
M[dstOffset:dstOffset+M[copySizeOffset]] = nestedReturndata[M[rdStartOffset]:M[rdStartOffset]+M[copySizeOffset]]
- Opcode
- 🔗JUMP: Unconditional jump
- Opcode
0x23
PC = jumpOffset
- Opcode
- 🔗JUMPI: Conditional jump
- Opcode
0x24
if M[condOffset] != 0 then PC = loc else PC = PC + instructionSize
- Opcode
- 🔗INTERNALCALL: Internal function call
- Opcode
0x25
internalCallStack.push({callPc: PC, returnPc: PC + instructionSize}); PC = loc
- Opcode
- 🔗INTERNALRETURN: Return from internal call
- Opcode
0x26
PC = internalCallStack.pop().returnPc
- Opcode
- 🔗SET: Set memory to immediate value
- Opcodes
0x27-0x2C(6 wire formats)
M[dstOffset] = value
- Opcodes
- 🔗MOV: Move value between memory locations
- Opcodes
0x2D-0x2E(2 wire formats)
M[dstOffset] = M[srcOffset]
- Opcodes
- 🔗SLOAD: Load value from public storage
- Opcode
0x2F
M[dstOffset] = storage[contractAddress][M[slotOffset]]
- Opcode
- 🔗SSTORE: Store value to public storage
- Opcode
0x30
storage[contractAddress][M[slotOffset]] = M[srcOffset]
- Opcode
- 🔗NOTEHASHEXISTS: Check existence of note hash
- Opcode
0x31
M[existsOffset] = noteHashTree.exists(M[noteHashOffset], M[leafIndexOffset]) ? 1 : 0
- Opcode
- 🔗EMITNOTEHASH: Emit note hash
- Opcode
0x32
noteHashes.append(M[noteHashOffset])
- Opcode
- 🔗NULLIFIEREXISTS: Check existence of nullifier
- Opcode
0x33
M[existsOffset] = nullifierTree.exists(M[addressOffset], M[nullifierOffset]) ? 1 : 0
- Opcode
- 🔗EMITNULLIFIER: Emit nullifier
- Opcode
0x34
nullifiers.append(M[nullifierOffset])
- Opcode
- 🔗L1TOL2MSGEXISTS: Check existence of L1-to-L2 message
- Opcode
0x35
M[existsOffset] = l1ToL2Messages.exists(M[msgHashOffset], M[msgLeafIndexOffset]) ? 1 : 0
- Opcode
- 🔗GETCONTRACTINSTANCE: Get contract instance information
- Opcode
0x36
M[dstOffset] = contractInstance.exists ? 1 : 0; M[dstOffset+1] = contractInstance[memberEnum]
- Opcode
- 🔗EMITUNENCRYPTEDLOG: Emit public log
- Opcode
0x37
unencryptedLogs.append(M[logOffset:logOffset+M[logSizeOffset]])
- Opcode
- 🔗SENDL2TOL1MSG: Send L2-to-L1 message
- Opcode
0x38
l2ToL1Messages.append({recipient: M[recipientOffset], content: M[contentOffset]})
- Opcode
- 🔗CALL: Call external contract
- Opcode
0x39
nestedCallResult = executeContract( /*address=*/M[addrOffset], /*args=*/M[argsOffset:argsOffset+M[argsSizeOffset]], {l2Gas: M[l2GasOffset], daGas: M[daGasOffset]} )
- Opcode
- 🔗STATICCALL: Static call to external contract
- Opcode
0x3A
nestedCallResult = executeContractStatic( /*address=*/M[addrOffset], /*args=*/M[argsOffset:argsOffset+M[argsSizeOffset]], {l2Gas: M[l2GasOffset], daGas: M[daGasOffset]} )
- Opcode
- 🔗RETURN: Return from call
- Opcode
0x3B
return M[returnOffset:returnOffset+M[returnSizeOffset]]; halt
- Opcode
- 🔗REVERT: Revert execution
- Opcodes
0x3C-0x3D(2 wire formats)
revert M[returnOffset:returnOffset+M[retSizeOffset]]; halt
- Opcodes
- 🔗DEBUGLOG: Output debug log
- Opcode
0x3E
debugLog(level, message, M[fieldsOffset:fieldsOffset+M[fieldsSizeOffset]])
- Opcode
- 🔗POSEIDON2: Poseidon2 permutation
- Opcode
0x3F
M[outputStateOffset:outputStateOffset+4] = poseidon2Permutation(/*input=*/M[inputStateOffset:inputStateOffset+4])
- Opcode
- 🔗SHA256COMPRESSION: SHA-256 compression
- Opcode
0x40
M[outputOffset:outputOffset+8] = sha256compress(/*state=*/M[stateOffset:stateOffset+8], /*inputs=*/M[inputsOffset:inputsOffset+16])
- Opcode
- 🔗KECCAKF1600: Keccak-f[1600] permutation
- Opcode
0x41
M[dstOffset:dstOffset+25] = keccakf1600(/*input=*/M[inputOffset:inputOffset+25])
- Opcode
- 🔗ECADD: Grumpkin elliptic curve addition
- Opcode
0x42
M[dstOffset:dstOffset+3] = grumpkinAdd( /*point1=*/{x: M[p1XOffset], y: M[p1YOffset], isInfinite: M[p1IsInfiniteOffset]}, /*point2=*/{x: M[p2XOffset], y: M[p2YOffset], isInfinite: M[p2IsInfiniteOffset]} )
- Opcode
- 🔗TORADIXBE: Convert to radix (big-endian)
- Opcode
0x43
M[dstOffset:dstOffset+M[numLimbsOffset]] = toRadixBE( /*value=*/M[srcOffset], /*radix=*/M[radixOffset], /*numLimbs=*/M[numLimbsOffset], /*outputBits=*/M[outputBitsOffset] )
- Opcode
← Previous: Wire Formats | Next: Tooling and Compilation →