u32 operations

Miden assembly provides a set of instructions which can perform operations on regular two-complement 32-bit integers. These instructions are described in the tables below.

For instructions where one or more operands can be provided as immediate parameters (e.g., u32wrapping_add and u32wrapping_add.b), we provide stack transition diagrams only for the non-immediate version. For the immediate version, it can be assumed that the operand with the specified name is not present on the stack.

In all the table below, the number of cycles it takes for the VM to execute each instruction is listed beneath the instruction.

Notes on Undefined Behavior

Most of the instructions documented below expect to receive operands whose values are valid u32 values, i.e. values in the range . Currently, the semantics of the instructions when given values outside of that range are undefined (as noted in the documented semantics for each instruction). The rule with undefined behavior generally speaking is that you can make no assumptions about what will happen if your program exhibits it.

For purposes of describing the effects of undefined behavior below, we will refer to values which are not valid for the input type of the affected operation, e.g. u32, as poison. Any use of a poison value propagates the poison state. For example, performing u32div with a poison operand, can be considered as producing a poison value as its result, for the purposes of discussing undefined behavior semantics.

With that in mind, there are two ways in which the effects of undefined behavior manifest:

Executor Semantics

From an executor perspective, currently, the semantics are completely undefined. An executor can do everything from terminate the program, panic, always produce 42 as a result, produce a random result, or something more principled.

In practice, the Miden VM, when executing an operation, will almost always trap on poison values. This is not guaranteed, but is currently the case for most operations which have niches of undefined behavior. To the extent that some other behavior may occur, it will generally be to truncate/wrap the poison value, but this is subject to change at any time, and is undocumented. You should assume that all operations will trap on poison.

The reason the Miden VM makes the choice to trap on poison, is to ensure that undefined behavior is caught close to the source, rather than propagated silently throughout the program. It also has the effect of ensuring you do not execute a program with undefined behavior, and produce a proof that is not actually valid, as we will describe in a moment.

Verifier Semantics

From the perspective of the verifier, the implementation details of the executor are completely unknown. For example, the fact that the Miden VM traps on poison values is not actually verified by constraints. An alternative executor implementation could choose not to trap, and thus appear to execute successfully. The resulting proof, however, as a result of the program exhibiting undefined behavior, is not a valid proof. In effect the use of poison values "poisons" the proof as well.

As a result, a program that exhibits undefined behavior, and executes successfully, will produce a proof that could pass verification, even though it should not. In other words, the proof does not prove what it says it does.

In the future, we may attempt to remove niches of undefined behavior in such a way that producing such invalid proofs is not possible, but for the time being, you must ensure that your program does not exhibit (or rely on) undefined behavior.

Conversions and tests

InstructionStack_inputStack_outputNotes
u32test
- (5 cycles)
[a, ...][b, a, ...]
u32testw
- (23 cycles)
[A, ...][b, A, ...]
u32assert
- (3 cycles)
[a, ...][a, ...]Fails if
u32assert2
- (1 cycle)
[b, a,...][b, a,...]Fails if or
u32assertw
- (6 cycles)
[A, ...][A, ...]Fails if
u32cast
- (2 cycles)
[a, ...][b, ...]
u32split
- (1 cycle)
[a, ...][c, b, ...],

The instructions u32assert, u32assert2 and u32assertw can also be parametrized with an error code which can be any 32-bit value specified either directly or via a named constant. For example:

u32assert.err=123
u32assert.err=MY_CONSTANT

If the error code is omitted, the default value of is assumed.

Arithmetic operations

InstructionStack_inputStack_outputNotes
u32overflowing_add
- (1 cycle)
u32overflowing_add.b
- (2-3 cycles)
[b, a, ...][d, c, ...]

Undefined if
u32wrapping_add
- (2 cycles)
u32wrapping_add.b
- (3-4 cycles)
[b, a, ...][c, ...]
Undefined if
u32overflowing_add3
- (1 cycle)
[c, b, a, ...][e, d, ...],

Undefined if
u32wrapping_add3
- (2 cycles)
[c, b, a, ...][d, ...],
Undefined if
u32overflowing_sub
- (1 cycle)
u32overflowing_sub.b
- (2-3 cycles)
[b, a, ...][d, c, ...]

Undefined if
u32wrapping_sub
- (2 cycles)
u32wrapping_sub.b
- (3-4 cycles)
[b, a, ...][c, ...]
Undefined if
u32overflowing_mul
- (1 cycle)
u32overflowing_mul.b
- (2-3 cycles)
[b, a, ...][d, c, ...]

Undefined if
u32wrapping_mul
- (2 cycles)
u32wrapping_mul.b
- (3-4 cycles)
[b, a, ...][c, ...]
Undefined if
u32overflowing_madd
- (1 cycle)
[b, a, c, ...][e, d, ...]

Undefined if
u32wrapping_madd
- (2 cycles)
[b, a, c, ...][d, ...]
Undefined if
u32div
- (2 cycles)
u32div.b
- (3-4 cycles)
[b, a, ...][c, ...]
Fails if
Undefined if
u32mod
- (3 cycles)
u32mod.b
- (4-5 cycles)
[b, a, ...][c, ...]
Fails if
Undefined if
u32divmod
- (1 cycle)
u32divmod.b
- (2-3 cycles)
[b, a, ...][d, c, ...]

Fails if
Undefined if

Bitwise operations

InstructionStack_inputStack_outputNotes
u32and
- (1 cycle)
u32and.b
- (2 cycles)
[b, a, ...][c, ...]Computes as a bitwise AND of binary representations of and .
Fails if
u32or
- (6 cycle)s
u32or.b
- (7 cycles)
[b, a, ...][c, ...]Computes as a bitwise OR of binary representations of and .
Fails if
u32xor
- (1 cycle)
u32xor.b
- (2 cycles)
[b, a, ...][c, ...]Computes as a bitwise XOR of binary representations of and .
Fails if
u32not
- (5 cycles)
u32not.a
- (6 cycles)
[a, ...][b, ...]Computes as a bitwise NOT of binary representation of .
Fails if
u32shl
- (18 cycles)
u32shl.b
- (3 cycles)
[b, a, ...][c, ...]
Undefined if or
u32shr
- (18 cycles)
u32shr.b
- (3 cycles)
[b, a, ...][c, ...]
Undefined if or
u32rotl
- (18 cycles)
u32rotl.b
- (3 cycles)
[b, a, ...][c, ...]Computes by rotating a 32-bit representation of to the left by bits.
Undefined if or
u32rotr
- (23 cycles)
u32rotr.b
- (3 cycles)
[b, a, ...][c, ...]Computes by rotating a 32-bit representation of to the right by bits.
Undefined if or
u32popcnt
- (33 cycles)
[a, ...][b, ...]Computes by counting the number of set bits in (hamming weight of ).
Undefined if
u32clz
- (42 cycles)
[a, ...][b, ...]Computes as a number of leading zeros of .
Undefined if
u32ctz
- (34 cycles)
[a, ...][b, ...]Computes as a number of trailing zeros of .
Undefined if
u32clo
- (41 cycles)
[a, ...][b, ...]Computes as a number of leading ones of .
Undefined if
u32cto
- (33 cycles)
[a, ...][b, ...]Computes as a number of trailing ones of .
Undefined if

Comparison operations

InstructionStack_inputStack_outputNotes
u32lt
- (3 cycles)
u32lt.b
- (4 cycles)
[b, a, ...][c, ...]
Undefined if
u32lte
- (5 cycles)
u32lte.b
- (6 cycles)
[b, a, ...][c, ...]
Undefined if
u32gt
- (4 cycles)
u32gt.b
- (5 cycles)
[b, a, ...][c, ...]
Undefined if
u32gte
- (4 cycles)
u32gte.b
- (5 cycles)
[b, a, ...][c, ...]
Undefined if
u32min
- (8 cycles)
u32min.b
- (9 cycles)
[b, a, ...][c, ...]
Undefined if
u32max
- (9 cycles)
u32max.b
- (10 cycles)
[b, a, ...][c, ...]
Undefined if