Instruction Set
This page lists all of the instructions supported by the Aztec Virtual Machine (AVM).
The following notes are relevant to the table and sections below:
M[offset]
notation is shorthand forcontext.machineState.memory[offset]
S[slot]
notation is shorthand for an access to the specified slot in the current contract's public storage (context.worldState.publicStorage
) after the slot has been siloed by the contract address (hash(context.environment.address, slot)
)- Any instruction whose description does not mention a program counter change simply increments it:
context.machineState.pc++
- All instructions update
context.machineState.*GasLeft
as detailed in "Gas limits and tracking" - Any instruction can lead to an exceptional halt as specified in "Exceptional halting"
- The term
hash
used in expressions below represents a Poseidon hash operation. - Type structures used in world state tracing operations are defined in "Type Definitions"
Instructions Table
Click on an instruction name to jump to its section.
Instructions
ADD
Addition (a + b)
- Opcode: 0x00
- Category: Compute - Arithmetic
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The tag/size to check inputs against and tag the destination with.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's left input
- bOffset: memory offset of the operation's right input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[aOffset] + M[bOffset] mod 2^k
- Details: Wraps on overflow
- Tag checks:
T[aOffset] == T[bOffset] == inTag
- Tag updates:
T[dstOffset] = inTag
- Bit-size: 128
SUB
Subtraction (a - b)
- Opcode: 0x01
- Category: Compute - Arithmetic
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The tag/size to check inputs against and tag the destination with.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's left input
- bOffset: memory offset of the operation's right input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[aOffset] - M[bOffset] mod 2^k
- Details: Wraps on undeflow
- Tag checks:
T[aOffset] == T[bOffset] == inTag
- Tag updates:
T[dstOffset] = inTag
- Bit-size: 128
MUL
Multiplication (a * b)
- Opcode: 0x02
- Category: Compute - Arithmetic
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The tag/size to check inputs against and tag the destination with.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's left input
- bOffset: memory offset of the operation's right input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[aOffset] * M[bOffset] mod 2^k
- Details: Wraps on overflow
- Tag checks:
T[aOffset] == T[bOffset] == inTag
- Tag updates:
T[dstOffset] = inTag
- Bit-size: 128
DIV
Unsigned integer division (a / b)
- Opcode: 0x03
- Category: Compute - Arithmetic
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The tag/size to check inputs against and tag the destination with.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's left input
- bOffset: memory offset of the operation's right input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[aOffset] / M[bOffset]
- Details: If the input is a field, it will be interpreted as an integer
- Tag checks:
T[aOffset] == T[bOffset] == inTag
- Tag updates:
T[dstOffset] = inTag
- Bit-size: 128
FDIV
Field division (a / b)
- Opcode: 0x04
- Category: Compute - Arithmetic
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's left input
- bOffset: memory offset of the operation's right input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[aOffset] / M[bOffset]
- Tag checks:
T[aOffset] == T[bOffset] == field
- Tag updates:
T[dstOffset] = field
- Bit-size: 120
EQ
Equality check (a == b)
- Opcode: 0x05
- Category: Compute - Comparators
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The tag/size to check inputs against and tag the destination with.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's left input
- bOffset: memory offset of the operation's right input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[aOffset] == M[bOffset] ? 1 : 0
- Tag checks:
T[aOffset] == T[bOffset] == inTag
- Tag updates:
T[dstOffset] = u8
- Bit-size: 128
LT
Less-than check (a < b)
- Opcode: 0x06
- Category: Compute - Comparators
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The tag/size to check inputs against and tag the destination with.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's left input
- bOffset: memory offset of the operation's right input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[aOffset] < M[bOffset] ? 1 : 0
- Tag checks:
T[aOffset] == T[bOffset] == inTag
- Tag updates:
T[dstOffset] = u8
- Bit-size: 128
LTE
Less-than-or-equals check (a <= b)
- Opcode: 0x07
- Category: Compute - Comparators
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The tag/size to check inputs against and tag the destination with.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's left input
- bOffset: memory offset of the operation's right input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[aOffset] <= M[bOffset] ? 1 : 0
- Tag checks:
T[aOffset] == T[bOffset] == inTag
- Tag updates:
T[dstOffset] = u8
- Bit-size: 128
AND
Bitwise AND (a & b)
- Opcode: 0x08
- Category: Compute - Bitwise
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The tag/size to check inputs against and tag the destination with.
field
type is NOT supported for this instruction.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's left input
- bOffset: memory offset of the operation's right input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[aOffset] AND M[bOffset]
- Tag checks:
T[aOffset] == T[bOffset] == inTag
- Tag updates:
T[dstOffset] = inTag
- Bit-size: 128
OR
Bitwise OR (a | b)
- Opcode: 0x09
- Category: Compute - Bitwise
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The tag/size to check inputs against and tag the destination with.
field
type is NOT supported for this instruction.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's left input
- bOffset: memory offset of the operation's right input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[aOffset] OR M[bOffset]
- Tag checks:
T[aOffset] == T[bOffset] == inTag
- Tag updates:
T[dstOffset] = inTag
- Bit-size: 128
XOR
Bitwise XOR (a ^ b)
- Opcode: 0x0a
- Category: Compute - Bitwise
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The tag/size to check inputs against and tag the destination with.
field
type is NOT supported for this instruction.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's left input
- bOffset: memory offset of the operation's right input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[aOffset] XOR M[bOffset]
- Tag checks:
T[aOffset] == T[bOffset] == inTag
- Tag updates:
T[dstOffset] = inTag
- Bit-size: 128
NOT
Bitwise NOT (inversion)
- Opcode: 0x0b
- Category: Compute - Bitwise
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The tag/size to check inputs against and tag the destination with.
field
type is NOT supported for this instruction.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = NOT M[aOffset]
- Tag checks:
T[aOffset] == inTag
- Tag updates:
T[dstOffset] = inTag
- Bit-size: 96
SHL
Bitwise leftward shift (a << b)
- Opcode: 0x0c
- Category: Compute - Bitwise
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The tag/size to check inputs against and tag the destination with.
field
type is NOT supported for this instruction.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's left input
- bOffset: memory offset of the operation's right input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[aOffset] << M[bOffset]
- Tag checks:
T[aOffset] == inTag
,T[bOffset] == u8
- Tag updates:
T[dstOffset] = inTag
- Bit-size: 128
SHR
Bitwise rightward shift (a >> b)
- Opcode: 0x0d
- Category: Compute - Bitwise
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The tag/size to check inputs against and tag the destination with.
field
type is NOT supported for this instruction.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of the operation's left input
- bOffset: memory offset of the operation's right input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[aOffset] >> M[bOffset]
- Tag checks:
T[aOffset] == inTag
,T[bOffset] == u8
- Tag updates:
T[dstOffset] = inTag
- Bit-size: 128
CAST
Type cast
- Opcode: 0x0e
- Category: Type Conversions
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - dstTag: The tag/size to tag the destination with but not to check inputs against.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of word to cast
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = cast<dstTag>(M[aOffset])
- Details: Cast a word in memory based on the
dstTag
specified in the bytecode. Truncates (M[dstOffset] = M[aOffset] mod 2^dstsize
) when casting to a smaller type, left-zero-pads when casting to a larger type. See here for more details. - Tag updates:
T[dstOffset] = dstTag
- Bit-size: 96
ADDRESS
Get the address of the currently executing l2 contract
- Opcode: 0x0f
- Category: Execution Environment
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = context.environment.address
- Tag updates:
T[dstOffset] = field
- Bit-size: 56
SENDER
Get the address of the sender (caller of the current context)
- Opcode: 0x10
- Category: Execution Environment
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = context.environment.sender
- Tag updates:
T[dstOffset] = field
- Bit-size: 56
TRANSACTIONFEE
Get the computed transaction fee during teardown phase, zero otherwise
- Opcode: 0x11
- Category: Execution Environment
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = context.environment.transactionFee
- Tag updates:
T[dstOffset] = field
- Bit-size: 56
CHAINID
Get this rollup's L1 chain ID
- Opcode: 0x12
- Category: Execution Environment - Globals
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = context.environment.globals.chainId
- Tag updates:
T[dstOffset] = field
- Bit-size: 56
VERSION
Get this rollup's L2 version ID
- Opcode: 0x13
- Category: Execution Environment - Globals
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = context.environment.globals.version
- Tag updates:
T[dstOffset] = field
- Bit-size: 56
BLOCKNUMBER
Get this L2 block's number
- Opcode: 0x14
- Category: Execution Environment - Globals
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = context.environment.globals.blocknumber
- Tag updates:
T[dstOffset] = field
- Bit-size: 56
TIMESTAMP
Get this L2 block's timestamp
- Opcode: 0x15
- Category: Execution Environment - Globals
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = context.environment.globals.timestamp
- Tag updates:
T[dstOffset] = u64
- Bit-size: 56
FEEPERL2GAS
Get the fee to be paid per "L2 gas" - constant for entire transaction
- Opcode: 0x16
- Category: Execution Environment - Globals - Gas
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = context.environment.globals.feePerL2Gas
- Tag updates:
T[dstOffset] = field
- Bit-size: 56
FEEPERDAGAS
Get the fee to be paid per "DA gas" - constant for entire transaction
- Opcode: 0x17
- Category: Execution Environment - Globals - Gas
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = context.environment.globals.feePerDaGas
- Tag updates:
T[dstOffset] = field
- Bit-size: 56
CALLDATACOPY
Copy calldata into memory
- Opcode: 0x18
- Category: Execution Environment - Calldata
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- cdOffset: offset into calldata to copy from
- copySize: number of words to copy
- dstOffset: memory offset specifying where to copy the first word to
- Expression:
M[dstOffset:dstOffset+copySize] = context.environment.calldata[cdOffset:cdOffset+copySize]
- Details: Calldata is read-only and cannot be directly operated on by other instructions. This instruction moves words from calldata into memory so they can be operated on normally.
- Tag updates:
T[dstOffset:dstOffset+copySize] = field
- Bit-size: 120
L2GASLEFT
Remaining "L2 gas" for this call (after this instruction)
- Opcode: 0x19
- Category: Machine State - Gas
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = context.MachineState.l2GasLeft
- Tag updates:
T[dstOffset] = u32
- Bit-size: 56
DAGASLEFT
Remaining "DA gas" for this call (after this instruction)
- Opcode: 0x1a
- Category: Machine State - Gas
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = context.machineState.daGasLeft
- Tag updates:
T[dstOffset] = u32
- Bit-size: 56
JUMP
Jump to a location in the bytecode
- Opcode: 0x1b
- Category: Machine State - Control Flow
- Args:
- loc: target location to jump to
- Expression:
context.machineState.pc = loc
- Details: Target location is an immediate value (a constant in the bytecode).
- Bit-size: 48
JUMPI
Conditionally jump to a location in the bytecode
- Opcode: 0x1c
- Category: Machine State - Control Flow
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- loc: target location conditionally jump to
- condOffset: memory offset of the operations 'conditional' input
- Expression:
context.machineState.pc = M[condOffset] > 0 ? loc : context.machineState.pc
- Details: Target location is an immediate value (a constant in the bytecode).
T[condOffset]
is not checked because the greater-than-zero suboperation is the same regardless of type. - Bit-size: 88
INTERNALCALL
Make an internal call. Push the current PC to the internal call stack and jump to the target location.
- Opcode: 0x1d
- Category: Machine State - Control Flow
- Args:
- loc: target location to jump/call to
- Expression:
context.machineState.internalCallStack.push(context.machineState.pc)
context.machineState.pc = loc
- Details: Target location is an immediate value (a constant in the bytecode).
- Bit-size: 48
INTERNALRETURN
Return from an internal call. Pop from the internal call stack and jump to the popped location.
- Opcode: 0x1e
- Category: Machine State - Control Flow
- Expression:
context.machineState.pc = context.machineState.internalCallStack.pop()
- Bit-size: 16
SET
Set a memory word from a constant in the bytecode
- Opcode: 0x1f
- Category: Machine State - Memory
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
. - inTag: The type/size to check inputs against and tag the destination with.
field
type is NOT supported for SET.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- const: an N-bit constant value from the bytecode to store in memory (any type except
field
) - dstOffset: memory offset specifying where to store the constant
- const: an N-bit constant value from the bytecode to store in memory (any type except
- Expression:
M[dstOffset] = const
- Details: Set memory word at
dstOffset
toconst
's immediate value.const
's bit-size (N) can be 8, 16, 32, 64, or 128 based oninTag
. It cannot be 254 (field
type)! - Tag updates:
T[dstOffset] = inTag
- Bit-size: 64+N
MOV
Move a word from source memory location to destination
- Opcode: 0x20
- Category: Machine State - Memory
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- srcOffset: memory offset of word to move
- dstOffset: memory offset specifying where to store that word
- Expression:
M[dstOffset] = M[srcOffset]
- Tag updates:
T[dstOffset] = T[srcOffset]
- Bit-size: 88
CMOV
Move a word (conditionally chosen) from one memory location to another (d \= cond \> 0 ? a : b
)
- Opcode: 0x21
- Category: Machine State - Memory
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- aOffset: memory offset of word 'a' to conditionally move
- bOffset: memory offset of word 'b' to conditionally move
- condOffset: memory offset of the operations 'conditional' input
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = M[condOffset] > 0 ? M[aOffset] : M[bOffset]
- Details: One of two source memory locations is chosen based on the condition.
T[condOffset]
is not checked because the greater-than-zero suboperation is the same regardless of type. - Tag updates:
T[dstOffset] = M[condOffset] > 0 ? T[aOffset] : T[bOffset]
- Bit-size: 152
SLOAD
Load a word from this contract's persistent public storage. Zero is loaded for unwritten slots.
- Opcode: 0x22
- Category: World State - Public Storage
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- slotOffset: memory offset of the storage slot to load from
- dstOffset: memory offset specifying where to store operation's result
- Expression:
M[dstOffset] = S[M[slotOffset]]
- Details:
// Expression is shorthand for
leafIndex = hash(context.environment.address, M[slotOffset])
exists = context.worldState.publicStorage.has(leafIndex) // exists == previously-written
if exists:
value = context.worldState.publicStorage.get(leafIndex: leafIndex)
else:
value = 0
M[dstOffset] = value
- World State access tracing:
context.worldStateAccessTrace.publicStorageReads.append(
TracedStorageRead {
callPointer: context.environment.callPointer,
slot: M[slotOffset],
exists: exists, // defined above
value: value, // defined above
counter: ++context.worldStateAccessTrace.accessCounter,
}
)
- Triggers downstream circuit operations: Storage slot siloing (hash with contract address), public data tree membership check
- Tag updates:
T[dstOffset] = field
- Bit-size: 88
SSTORE
Write a word to this contract's persistent public storage
- Opcode: 0x23
- Category: World State - Public Storage
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- srcOffset: memory offset of the word to store
- slotOffset: memory offset containing the storage slot to store to
- Expression:
S[M[slotOffset]] = M[srcOffset]
- Details:
// Expression is shorthand for
context.worldState.publicStorage.set({
leafIndex: hash(context.environment.address, M[slotOffset]),
leaf: M[srcOffset],
})
- World State access tracing:
context.worldStateAccessTrace.publicStorageWrites.append(
TracedStorageWrite {
callPointer: context.environment.callPointer,
slot: M[slotOffset],
value: M[srcOffset],
counter: ++context.worldStateAccessTrace.accessCounter,
}
)
- Triggers downstream circuit operations: Storage slot siloing (hash with contract address), public data tree update
- Bit-size: 88
NOTEHASHEXISTS
Check whether a note hash exists in the note hash tree (as of the start of the current block)
- Opcode: 0x24
- Category: World State - Notes & Nullifiers
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- noteHashOffset: memory offset of the note hash
- leafIndexOffset: memory offset of the leaf index
- existsOffset: memory offset specifying where to store operation's result (whether the note hash leaf exists)
- Expression:
exists = context.worldState.noteHashes.has({
leafIndex: M[leafIndexOffset]
leaf: hash(context.environment.address, M[noteHashOffset]),
})
M[existsOffset] = exists
- World State access tracing:
context.worldStateAccessTrace.noteHashChecks.append(
TracedNoteHashCheck {
callPointer: context.environment.callPointer,
leafIndex: M[leafIndexOffset]
noteHash: M[noteHashOffset],
exists: exists, // defined above
counter: ++context.worldStateAccessTrace.accessCounter,
}
)
- Triggers downstream circuit operations: Note hash siloing (hash with storage contract address), note hash tree membership check
- Tag updates:
T[existsOffset] = u8
- Bit-size: 120
EMITNOTEHASH
Emit a new note hash to be inserted into the note hash tree
- Opcode: 0x25
- Category: World State - Notes & Nullifiers
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- noteHashOffset: memory offset of the note hash
- Expression:
context.worldState.noteHashes.append(
hash(context.environment.address, M[noteHashOffset])
)
- World State access tracing:
context.worldStateAccessTrace.noteHashes.append(
TracedNoteHash {
callPointer: context.environment.callPointer,
noteHash: M[noteHashOffset], // unsiloed note hash
counter: ++context.worldStateAccessTrace.accessCounter,
}
)
- Triggers downstream circuit operations: Note hash siloing (hash with contract address), note hash tree insertion.
- Bit-size: 56
NULLIFIEREXISTS
Check whether a nullifier exists in the nullifier tree (including nullifiers from earlier in the current transaction or from earlier in the current block)
- Opcode: 0x26
- Category: World State - Notes & Nullifiers
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- nullifierOffset: memory offset of the unsiloed nullifier
- addressOffset: memory offset of the storage address
- existsOffset: memory offset specifying where to store operation's result (whether the nullifier exists)
- Expression:
exists = pendingNullifiers.has(M[addressOffset], M[nullifierOffset]) || context.worldState.nullifiers.has(
hash(M[addressOffset], M[nullifierOffset])
)
M[existsOffset] = exists
- World State access tracing:
context.worldStateAccessTrace.nullifierChecks.append(
TracedNullifierCheck {
callPointer: context.environment.callPointer,
nullifier: M[nullifierOffset],
address: M[addressOffset],
exists: exists, // defined above
counter: ++context.worldStateAccessTrace.accessCounter,
}
)
- Triggers downstream circuit operations: Nullifier siloing (hash with storage contract address), nullifier tree membership check
- Tag updates:
T[existsOffset] = u8
- Bit-size: 120
EMITNULLIFIER
Emit a new nullifier to be inserted into the nullifier tree
- Opcode: 0x27
- Category: World State - Notes & Nullifiers
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- nullifierOffset: memory offset of nullifier
- Expression:
context.worldState.nullifiers.append(
hash(context.environment.address, M[nullifierOffset])
)
- World State access tracing:
context.worldStateAccessTrace.nullifiers.append(
TracedNullifier {
callPointer: context.environment.callPointer,
nullifier: M[nullifierOffset], // unsiloed nullifier
counter: ++context.worldStateAccessTrace.accessCounter,
}
)
- Triggers downstream circuit operations: Nullifier siloing (hash with contract address), nullifier tree non-membership-check and insertion.
- Bit-size: 56
L1TOL2MSGEXISTS
Check if a message exists in the L1-to-L2 message tree
- Opcode: 0x28
- Category: World State - Messaging
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- msgHashOffset: memory offset of the message hash
- msgLeafIndexOffset: memory offset of the message's leaf index in the L1-to-L2 message tree
- existsOffset: memory offset specifying where to store operation's result (whether the message exists in the L1-to-L2 message tree)
- Expression:
exists = context.worldState.l1ToL2Messages.has({
leafIndex: M[msgLeafIndexOffset], leaf: M[msgHashOffset]
})
M[existsOffset] = exists
- World State access tracing:
context.worldStateAccessTrace.l1ToL2MessagesChecks.append(
L1ToL2Message {
callPointer: context.environment.callPointer,
leafIndex: M[msgLeafIndexOffset],
msgHash: M[msgHashOffset],
exists: exists, // defined above
}
)
- Triggers downstream circuit operations: L1-to-L2 message tree membership check
- Tag updates:
T[existsOffset] = u8,
- Bit-size: 120
GETCONTRACTINSTANCE
Copies contract instance data to memory
- Opcode: 0x29
- Category: Other
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- addressOffset: memory offset of the contract instance address
- dstOffset: location to write the contract instance information to
- Expression:
M[dstOffset:dstOffset+CONTRACT_INSTANCE_SIZE+1] = [
instance_found_in_address,
instance.salt ?? 0,
instance.deployer ?? 0,
instance.contractClassId ?? 0,
instance.initializationHash ?? 0,
instance.portalContractAddress ?? 0,
instance.publicKeysHash ?? 0,
]
- Additional AVM circuit checks: TO-DO
- Triggers downstream circuit operations: TO-DO
- Tag updates: T[dstOffset:dstOffset+CONTRACT_INSTANCE_SIZE+1] = field
- Bit-size: 88
EMITUNENCRYPTEDLOG
Emit an unencrypted log
- Opcode: 0x2a
- Category: Accrued Substate - Logging
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- logOffset: memory offset of the data to log
- logSizeOffset: memory offset to number of words to log
- Expression:
context.accruedSubstate.unencryptedLogs.append(
UnencryptedLog {
address: context.environment.address,
log: M[logOffset:logOffset+M[logSizeOffset]],
}
)
- Bit-size: 88
SENDL2TOL1MSG
Send an L2-to-L1 message
- Opcode: 0x2b
- Category: Accrued Substate - Messaging
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- recipientOffset: memory offset of the message recipient
- contentOffset: memory offset of the message content
- Expression:
context.accruedSubstate.sentL2ToL1Messages.append(
SentL2ToL1Message {
address: context.environment.address,
recipient: M[recipientOffset],
message: M[contentOffset]
}
)
- Bit-size: 88
CALL
Call into another contract
- Opcode: 0x2c
- Category: Control Flow - Contract Calls
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- gasOffset: offset to two words containing
{l2GasLeft, daGasLeft}
: amount of gas to provide to the callee - addrOffset: address of the contract to call
- argsOffset: memory offset to args (will become the callee's calldata)
- argsSizeOffset: memory offset for the number of words to pass via callee's calldata
- retOffset: destination memory offset specifying where to store the data returned from the callee
- retSize: number of words to copy from data returned by callee
- successOffset: destination memory offset specifying where to store the call's success (0: failure, 1: success)
- gasOffset: offset to two words containing
- Expression:
// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize }
chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=false)
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)
- Details: Creates a new (nested) execution context and triggers execution within that context. Execution proceeds in the nested context until it reaches a halt at which point execution resumes in the current/calling context. A non-existent contract or one with no code will return success. "Nested contract calls" provides a full explanation of this instruction along with the shorthand used in the expression above. The explanation includes details on charging gas for nested calls, nested context derivation, world state tracing, and updating the parent context after the nested call halts.
- Tag checks:
T[gasOffset] == T[gasOffset+1] == T[gasOffset+2] == u32
- Tag updates:
T[successOffset] = u8
T[retOffset:retOffset+retSize] = field
- Bit-size: 248
STATICCALL
Call into another contract, disallowing World State and Accrued Substate modifications
- Opcode: 0x2d
- Category: Control Flow - Contract Calls
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- gasOffset: offset to two words containing
{l2GasLeft, daGasLeft}
: amount of gas to provide to the callee - addrOffset: address of the contract to call
- argsOffset: memory offset to args (will become the callee's calldata)
- argsSizeOffset: memory offset for the number of words to pass via callee's calldata
- retOffset: destination memory offset specifying where to store the data returned from the callee
- retSize: number of words to copy from data returned by callee
- successOffset: destination memory offset specifying where to store the call's success (0: failure, 1: success)
- gasOffset: offset to two words containing
- Expression:
// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize }
chargeGas(context,
l2GasCost=M[instr.args.gasOffset],
daGasCost=M[instr.args.gasOffset+1])
traceNestedCall(context, instr.args.addrOffset)
nestedContext = deriveContext(context, instr.args, isStaticCall=true
execute(nestedContext)
updateContextAfterNestedCall(context, instr.args, nestedContext)
- Details: Same as
CALL
, but disallows World State and Accrued Substate modifications. "Nested contract calls" provides a full explanation of this instruction along with the shorthand used in the expression above. The explanation includes details on charging gas for nested calls, nested context derivation, world state tracing, and updating the parent context after the nested call halts. - Tag checks:
T[gasOffset] == T[gasOffset+1] == T[gasOffset+2] == u32
- Tag updates:
T[successOffset] = u8
T[retOffset:retOffset+retSize] = field
- Bit-size: 248
RETURN
Halt execution within this context (without revert), optionally returning some data
- Opcode: 0x2e
- Category: Control Flow - Contract Calls
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- retOffset: memory offset of first word to return
- retSize: number of words to return
- Expression:
context.contractCallResults.output = M[retOffset:retOffset+retSize]
halt
- Details: Return control flow to the calling context/contract. Caller will accept World State and Accrued Substate modifications. See "Halting" to learn more. See "Nested contract calls" to see how the caller updates its context after the nested call halts.
- Bit-size: 88
REVERT
Halt execution within this context as reverted
, optionally returning some data
- Opcode: 0x2f
- Category: Control Flow - Contract Calls
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- retOffset: memory offset of first word to return
- retSize: number of words to return
- Expression:
context.contractCallResults.output = M[retOffset:retOffset+retSize]
context.contractCallResults.reverted = true
halt
- Details: Return control flow to the calling context/contract. Caller will reject World State and Accrued Substate modifications. See "Halting" to learn more. See "Nested contract calls" to see how the caller updates its context after the nested call halts.
- Bit-size: 88
TORADIXLE
Convert a word to an array of limbs in little-endian radix form
- Opcode: 0x30
- Category: Conversions
- Flags:
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
M[M[offset]]
instead of the more standardM[offset]
.
- indirect: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like
- Args:
- srcOffset: memory offset of word to convert.
- dstOffset: memory offset specifying where the first limb of the radix-conversion result is stored.
- radix: the maximum bit-size of each limb.
- numLimbs: the number of limbs the word will be converted into.
- Expression: TBD: Storage of limbs and if T[dstOffset] is constrained to U8
- Details: The limbs will be stored in a contiguous memory block starting at
dstOffset
. - Tag checks:
T[srcOffset] == field
- Bit-size: 152