Skip to main content
Version: 0.11 (stable)

Stack operation constraints

In addition to the constraints described in the previous section, we need to impose constraints to check that each VM operation is executed correctly.

For this purpose the VM exposes a set of operation-specific flags. These flags are set to 11 when a given operation is executed, and to 00 otherwise. The naming convention for these flags is fopnamef_{opname}. For example, fdupf_{dup} would be set to 11 when DUP operation is executed, and to 00 otherwise. Operation flags are discussed in detail in the section below.

To describe how operation-specific constraints work, let's use an example with DUP operation. This operation pushes a copy of the top stack item onto the stack. The constraints we need to impose for this operation are as follows:

fdup(s0s0)=0fdup(si+1si)=0  for i[0,15)f_{dup} \cdot (s'_0 - s_0) = 0 f_{dup} \cdot (s'_{i+1} - s_i) = 0 \ \text{ for } i \in [0, 15)

The first constraint enforces that the top stack item in the next row is the same as the top stack item in the current row. The second constraint enforces that all stack items (starting from item 00) are shifted to the right by 11. We also need to impose all the constraints discussed in the previous section, be we omit them here.

Let's write similar constraints for DUP1 operation, which pushes a copy of the second stack item onto the stack:

fdup1(s0s1)=0fdup1(si+1si)=0  for i[0,15)f_{dup1} \cdot (s'_0 - s_1) = 0 f_{dup1} \cdot (s'_{i+1} - s_i) = 0 \ \text{ for } i \in [0, 15)

It is easy to notice that while the first constraint changed, the second constraint remained the same - i.e., we are still just shifting the stack to the right.

In fact, for most operations it makes sense to make a distinction between constraints unique to the operation vs. more general constraints which enforce correct behavior for the stack items not affected by the operation. In the subsequent sections we describe in detail only the former constraints, and provide high-level descriptions of the more general constraints. Specifically, we indicate how the operation affects the rest of the stack (e.g., shifts right starting from position 00).

Operation flags

As mentioned above, operation flags are used as selectors to enforce operation-specific constraints. That is, they turn on relevant constraints for a given operation. In total, the VM provides 8888 unique operations, and thus, there are 8888 operation flags (not all of them currently used).

Operation flags are mutually exclusive. That is, if one flag is set to 11, all other flags are set to 00. Also, one of the flags is always guaranteed to be set to 11.

To compute values of operation flags we use op bits registers located in the decoder. These registers contain binary representations of operation codes (opcodes). Each opcode consists of 77 bits, and thus, there are 77 op bits registers. We denote these registers as b0,...,b6b_0, ..., b_6. The values are computed by multiplying the op bit registers in various combinations. Notice that binary encoding down below is showed in big-endian order, so the flag bits correspond to the reverse order of the op bits registers, from b6b_6 to b0b_0.

For example, the value of the flag for NOOP, which is encoded as 0000000, is computed as follows:

fnoop=(1b6)(1b5)(1b4)(1b3)(1b2)(1b1)(1b0)f_{noop} = (1 - b_6) \cdot (1 - b_5) \cdot (1 - b_4) \cdot (1 - b_3) \cdot (1 - b_2) \cdot (1 - b_1) \cdot (1 - b_0)

While the value of the DROP operation, which is encoded as 0101001 is computed as follows:

fdrop=(1b6)b5(1b4)b3(1b2)(1b1)b0f_{drop} = (1 - b_6) \cdot b_5 \cdot (1 - b_4) \cdot b_3 \cdot (1 - b_2) \cdot (1 - b_1) \cdot b_0

As can be seen from above, the degree for both of these flags is 77. Since degree of constraints in Miden VM can go up to 99, this means that operation-specific constraints cannot exceed degree 22. However, there are some operations which require constraints of higher degree (e.g., 33 or even 55). To support such constraints, we adopt the following scheme.

We organize the operations into 44 groups as shown below and also introduce two extra registers e0e_0 and e1e_1 for degree reduction:

b6b_6b5b_5b4b_4b3b_3b2b_2b1b_1b0b_0e0e_0e1e_1# of opsdegree
0xxxxxx00647
100xxx-0086
101xxxx10165
11xxx--0184

In the above:

  • Operation flags for operations in the first group (with prefix 0), are computed using all 77 op bits, and thus their degree is 77.
  • Operation flags for operations in the second group (with prefix 100), are computed using only the first 66 op bits, and thus their degree is 66.
  • Operation flags for operations in the third group (with prefix 101), are computed using all 77 op bits. We use the extra register e0e_0 (which is set to b6(1b5)b4b_6 \cdot (1-b_5) \cdot b_4) to reduce the degree by 22. Thus, the degree of op flags in this group is 55.
  • Operation flags for operations in the fourth group (with prefix 11), are computed using only the first 55 op bits. We use the extra register e1e_1 (which is set to b6b5b_6 \cdot b_5) to reduce the degree by 11. Thus, the degree of op flags in this group is 44.

How operations are distributed between these 44 groups is described in the sections below.

No stack shift operations

This group contains 3232 operations which do not shift the stack (this is almost all such operations). Since the op flag degree for these operations is 77, constraints for these operations cannot exceed degree 22.

OperationOpcode valueBinary encodingOperation groupFlag degree
NOOP00000_0000System ops77
EQZ 11000_0001Field ops77
NEG22000_0010Field ops77
INV33000_0011Field ops77
INCR44000_0100Field ops77
NOT55000_0101Field ops77
FMPADD66000_0110System ops77
MLOAD77000_0111I/O ops77
SWAP88000_1000Stack ops77
CALLER99000_1001System ops77
MOVUP21010000_1010Stack ops77
MOVDN21111000_1011Stack ops77
MOVUP31212000_1100Stack ops77
MOVDN31313000_1101Stack ops77
ADVPOPW1414000_1110I/O ops77
EXPACC1515000_1111Field ops77
MOVUP41616001_0000Stack ops77
MOVDN41717001_0001Stack ops77
MOVUP51818001_0010Stack ops77
MOVDN51919001_0011Stack ops77
MOVUP62020001_0100Stack ops77
MOVDN62121001_0101Stack ops77
MOVUP72222001_0110Stack ops77
MOVDN72323001_0111Stack ops77
SWAPW2424001_1000Stack ops77
EXT2MUL2525001_1001Field ops77
MOVUP82626001_1010Stack ops77
MOVDN82727001_1011Stack ops77
SWAPW22828001_1100Stack ops77
SWAPW32929001_1101Stack ops77
SWAPDW3030001_1110Stack ops77
EMIT3131001_1111System ops77

Left stack shift operations

This group contains 1616 operations which shift the stack to the left (i.e., remove an item from the stack). Most of left-shift operations are contained in this group. Since the op flag degree for these operations is 77, constraints for these operations cannot exceed degree 22.

OperationOpcode valueBinary encodingOperation groupFlag degree
ASSERT3232010_0000System ops77
EQ3333010_0001Field ops77
ADD3434010_0010Field ops77
MUL3535010_0011Field ops77
AND3636010_0100Field ops77
OR3737010_0101Field ops77
U32AND3838010_0110u32 ops77
U32XOR3939010_0111u32 ops77
FRIE2F44040010_1000Crypto ops77
DROP4141010_1001Stack ops77
CSWAP4242010_1010Stack ops77
CSWAPW4343010_1011Stack ops77
MLOADW4444010_1100I/O ops77
MSTORE4545010_1101I/O ops77
MSTOREW4646010_1110I/O ops77
FMPUPDATE4747010_1111System ops77

Right stack shift operations

This group contains 1616 operations which shift the stack to the right (i.e., push a new item onto the stack). Most of right-shift operations are contained in this group. Since the op flag degree for these operations is 77, constraints for these operations cannot exceed degree 22.

OperationOpcode valueBinary encodingOperation groupFlag degree
PAD4848011_0000Stack ops77
DUP4949011_0001Stack ops77
DUP15050011_0010Stack ops77
DUP25151011_0011Stack ops77
DUP35252011_0100Stack ops77
DUP45353011_0101Stack ops77
DUP55454011_0110Stack ops77
DUP65555011_0111Stack ops77
DUP75656011_1000Stack ops77
DUP95757011_1001Stack ops77
DUP115858011_1010Stack ops77
DUP135959011_1011Stack ops77
DUP156060011_1100Stack ops77
ADVPOP6161011_1101I/O ops77
SDEPTH6262011_1110I/O ops77
CLK6363011_1111System ops77

u32 operations

This group contains 88 u32 operations. These operations are grouped together because all of them require range checks. The constraints for range checks are of degree 55, however, since all these operations require them, we can define a flag with common prefix 100 to serve as a selector for the range check constraints. The value of this flag is computed as follows:

fu32rc=b6(1b5)(1b4)f_{u32rc} = b_6 \cdot (1 - b_5) \cdot (1 - b_4)

The degree of this flag is 33, which is acceptable for a selector for degree 55 constraints.

OperationOpcode valueBinary encodingOperation groupFlag degree
U32ADD6464100_0000u32 ops66
U32SUB6666100_0010u32 ops66
U32MUL6868100_0100u32 ops66
U32DIV7070100_0110u32 ops66
U32SPLIT7272100_1000u32 ops66
U32ASSERT27474100_1010u32 ops66
U32ADD37676100_1100u32 ops66
U32MADD7878100_1110u32 ops66

As mentioned previously, the last bit of the opcode is not used in computation of the flag for these operations. We force this bit to always be set to 00 with the following constraint:

b6(1b5)(1b4)b0=0 | degree=4b_6 \cdot (1 - b_5) \cdot (1 - b_4) \cdot b_0 = 0 \text{ | degree} = 4

Putting these operations into a group with flag degree 66 is important for two other reasons:

  • Constraints for the U32SPLIT operation have degree 33. Thus, the degree of the op flag for this operation cannot exceed 66.
  • Operations U32ADD3 and U32MADD shift the stack to the left. Thus, having these two operations in this group and putting them under the common prefix 10011 allows us to create a common flag for these operations of degree 55 (recall that the left-shift flag cannot exceed degree 55).

High-degree operations

This group contains operations which require constraints with degree up to 33. All 77 operation bits are used for these flags. The extra e0e_0 column is used for degree reduction of the three high-degree bits.

OperationOpcode valueBinary encodingOperation groupFlag degree
HPERM8080101_0000Crypto ops55
MPVERIFY8181101_0001Crypto ops55
PIPE8282101_0010I/O ops55
MSTREAM8383101_0011I/O ops55
SPLIT8484101_0100Flow control ops55
LOOP8585101_0101Flow control ops55
SPAN8686101_0110Flow control ops55
JOIN8787101_0111Flow control ops55
DYN8888101_1000Flow control ops55
HORNEREXT8989101_1001Crypto ops55
<unused>9090101_101055
PUSH9191101_1011I/O ops55
DYNCALL9292101_1100Flow control ops55
EVALCIRCUIT9393101_1101Crypto ops55
<unused>9494101_111055
<unused>9595101_111155

Note that the SPLIT and LOOP operations are grouped together under the common prefix 101010, and thus can have a common flag of degree 44 (using e0e_0 for degree reduction). This is important because both of these operations shift the stack to the left.

Also, we need to make sure that extra register e0e_0, which is used to reduce the flag degree by 22, is set to 11 when b6=1b_6 = 1, b5=0b_5 = 0, and b4=1b_4 = 1:

e0b6(1b5)b4=0 | degree=3e_0 - b_6 \cdot (1 - b_5) \cdot b_4 = 0 \text{ | degree} = 3

Very high-degree operations

This group contains operations which require constraints with degree up to 55.

OperationOpcode valueBinary encodingOperation groupFlag degree
MRUPDATE9696110_0000Crypto ops44
HORNERBASE100100110_0100Crypto ops44
SYSCALL104104110_1000Flow control ops44
CALL108108110_1100Flow control ops44
END112112111_0000Flow control ops44
REPEAT116116111_0100Flow control ops44
RESPAN120120111_1000Flow control ops44
HALT124124111_1100Flow control ops44

As mentioned previously, the last two bits of the opcode are not used in computation of the flag for these operations. We force these bits to always be set to 00 with the following constraints:

b6b5b0=0 | degree=3b_6 \cdot b_5 \cdot b_0 = 0 \text{ | degree} = 3 b6b5b1=0 | degree=3b_6 \cdot b_5 \cdot b_1 = 0 \text{ | degree} = 3

Also, we need to make sure that extra register e1e_1, which is used to reduce the flag degree by 11, is set to 11 when both b6b_6 and b5b_5 columns are set to 11:

e1b6b5=0 | degree=2e_1 - b_6 \cdot b_5 = 0 \text{ | degree} = 2

Composite flags

Using the operation flags defined above, we can compute several composite flags which are used by various constraints in the VM.

Shift right flag

The right-shift flag indicates that an operation shifts the stack to the right. This flag is computed as follows:

fshr=(1b6)b5b4+fu32split+fpush | degree=6f_{shr} = (1 - b_6) \cdot b_5 \cdot b_4 + f_{u32split} + f_{push} \text{ | degree} = 6

In the above, (1b6)b5b4(1 - b_6) \cdot b_5 \cdot b_4 evaluates to 11 for all right stack shift operations described previously. This works because all these operations have a common prefix 011. We also need to add in flags for other operations which shift the stack to the right but are not a part of the above group (e.g., PUSH operation).

Shift left flag

The left-shift flag indicates that a given operation shifts the stack to the left. To simplify the description of this flag, we will first compute the following intermediate variables:

A flag which is set to 11 when fu32add3=1f_{u32add3} = 1 or fu32madd=1f_{u32madd} = 1:

fadd3_madd=b6(1b5)(1b4)b3b2 | degree=5f_{add3\_madd} = b_6 \cdot (1 - b_5) \cdot (1 - b_4) \cdot b_3 \cdot b_2 \text{ | degree} = 5

A flag which is set to 11 when fsplit=1f_{split} = 1 or floop=1f_{loop} = 1:

fsplit_loop=e0(1b3)b2(1b1) | degree=4f_{split\_loop} = e_0 \cdot (1 - b_3) \cdot b_2 \cdot (1 - b_1) \text{ | degree} = 4

Using the above variables, we compute left-shift flag as follows:

fshl=(1b6)b5(1b4)+fadd3_madd+fsplit_loop+frepeat+fendh5 | degree=5f_{shl} = (1 - b_6) \cdot b_5 \cdot (1 - b_4) + f_{add3\_madd} + f_{split\_loop} + f_{repeat} + f_{end} \cdot h_5 \text{ | degree} = 5

In the above:

  • (1b6)b5(1b4)(1 - b_6) \cdot b_5 \cdot (1 - b_4) evaluates to 11 for all left stack shift operations described previously. This works because all these operations have a common prefix 010.
  • h5h_5 is the helper register in the decoder which is set to 11 when we are exiting a LOOP block, and to 00 otherwise.

Thus, similarly to the right-shift flag, we compute the value of the left-shift flag based on the prefix of the operation group which contains most left shift operations, and add in flag values for other operations which shift the stack to the left but are not a part of this group.

Control flow flag

The control flow flag fctrlf_{ctrl} is set to 11 when a control flow operation is being executed by the VM, and to 00 otherwise. Naively, this flag can be computed as follows:

fctrl=fjoin+fsplit+floop+frepeat+fspan+frespan+fcall+fsyscall+fend+fhalt | degree=6f_{ctrl} = f_{join} + f_{split} + f_{loop} + f_{repeat} + f_{span} + f_{respan} + f_{call} + f_{syscall} + f_{end} + f_{halt} \text{ | degree} = 6

However, this can be computed more efficiently via the common operation prefixes for the two groups of control flow operations as follows.

fspan,join,split,loop=e0(1b3)b2 | degree=3f_{span,join,split,loop} = e_0 \cdot (1 - b_3) \cdot b_2 \text{ | degree} = 3 fend,repeat,respan,halt=e1b4 | degree=2f_{end,repeat,respan,halt} = e_1 \cdot b_4 \text{ | degree} = 2 fctrl=fspan,join,split,loop+fend,repeat,respan,halt+fdyn+fcall+fsyscall | degree=5f_{ctrl} = f_{span,join,split,loop} + f_{end,repeat,respan,halt} + f_{dyn} + f_{call} + f_{syscall} \text{ | degree} = 5

Immediate value flag

The immediate value flag fimmf_{imm} is set to 1 when an operation has an immediate value, and 0 otherwise:

fimm=fpush | degree=5f_{imm} = f_{push} \text{ | degree} = 5

Note that the ASSERT, MPVERIFY and other operations have immediate values too. However, these immediate values are not included in the MAST digest, and hence are not considered for the fimmf_{imm} flag.