diff --git a/assets/design/decoder/decoder_dyn_block_decoding.png b/assets/design/decoder/decoder_dyn_block_decoding.png new file mode 100644 index 0000000000..955d88bdba Binary files /dev/null and b/assets/design/decoder/decoder_dyn_block_decoding.png differ diff --git a/assets/design/decoder/decoder_dyn_operation.png b/assets/design/decoder/decoder_dyn_operation.png new file mode 100644 index 0000000000..93426e0d31 Binary files /dev/null and b/assets/design/decoder/decoder_dyn_operation.png differ diff --git a/design/decoder/constraints.html b/design/decoder/constraints.html index cbdfacb02c..a3e13897d3 100644 --- a/design/decoder/constraints.html +++ b/design/decoder/constraints.html @@ -183,6 +183,7 @@
SPAN
RESPAN
DYN
CALL
SYSCALL
END
We also use the control flow flag exposed by the VM, which is set when any one of the above control flow operations is being executed. It has degree .
-As described previously, the general idea of the decoder is that the prove provides the program to the VM by populating some of cells in the trace non-deterministically. Values in these are then used to update virtual tables (represented via multiset checks) such as block hash table, block stack table etc. Transition constraints are used to enforce that the tables are updates correctly, and we also apply boundary constraints to enforce the correct initial and final states of these tables. One of these boundary constraints binds the execution trace to the hash of the program being executed. Thus, if the virtual tables were updated correctly and boundary constraints hold, we can be convinced that the prover executed the claimed program on the VM.
+We also use the control flow flag exposed by the VM, which is set when any one of the above control flow operations is being executed. It has degree .
+As described previously, the general idea of the decoder is that the prover provides the program to the VM by populating some of cells in the trace non-deterministically. Values in these are then used to update virtual tables (represented via multiset checks) such as block hash table, block stack table etc. Transition constraints are used to enforce that the tables are updates correctly, and we also apply boundary constraints to enforce the correct initial and final states of these tables. One of these boundary constraints binds the execution trace to the hash of the program being executed. Thus, if the virtual tables were updated correctly and boundary constraints hold, we can be convinced that the prover executed the claimed program on the VM.
In the sections below, we describe constraints according to their logical grouping. However, we start out with a set of general constraints which are applicable to multiple parts of the decoder.
When SPLIT
or LOOP
operation is executed, the top of the operand stack must contain a binary value:
+
When a DYN
operation is executed, the hasher registers must all be set to :
++
When REPEAT
operation is executed, the value at the top of the operand stack must be :
@@ -232,11 +237,11 @@
Gener
When the value in in_span
column is set to , control flow operations cannot be executed on the VM, but when in_span
flag is , only control flow operations can be executed on the VM:
-+
As described previously, when the VM starts executing a new block, it also initiates computation of the block's hash. There are two separate methodologies for computing block hashes.
-For join, split, and loop blocks, the hash is computed directly from the hashes of the block's children. The prover provides these child hashes non-deterministically by populating registers . The hasher is initialized using the hash chiplet, and we use the address of the hasher as the block's ID. The result of the hash is available rows down in the hasher table (i.e., at row with index equal to block ID plus ). We read the result from the hasher table at the time the END
operation is executed for a given block.
For join, split, and loop blocks, the hash is computed directly from the hashes of the block's children. The prover provides these child hashes non-deterministically by populating registers . For dyn, the hasher registers are populated with zeros, so the resulting hash is a constant value. The hasher is initialized using the hash chiplet, and we use the address of the hasher as the block's ID. The result of the hash is available rows down in the hasher table (i.e., at row with index equal to block ID plus ). We read the result from the hasher table at the time the END
operation is executed for a given block.
For span blocks, the hash is computed by absorbing a linear sequence of instructions (organized into operation groups and batches) into the hasher and then returning the result. The prover provides operation batches non-deterministically by populating registers . Similarly to other blocks, the hasher is initialized using the hash chiplet at the start of the block, and we use the address of the hasher as the ID of the first operation batch in the block. As we absorb additional operation batches into the hasher (by executing RESPAN
operation), the batch address is incremented by . This moves the "pointer" into the hasher table rows down with every new batch. We read the result from the hasher table at the time the END
operation is executed for a given block.
The decoder communicates with the hash chiplet via the chiplets bus. This works by dividing values of the multiset check column by the values of operations providing inputs to or reading outputs from the hash chiplet. A constraint to enforce this would look as , where is the value which defines the operation.
@@ -253,12 +258,12 @@
In the above, represents the address value in the decoder which corresponds to the hasher chiplet address at which the hasher was initialized (or the last absorption took place). As such, corresponds to the hasher chiplet address at which the result is returned.
-+
In the above, is set to when a control flow operation that signifies the initialization of a control block is being executed on the VM. Otherwise, it is set to . An exception is made for the SYSCALL
operation. Although it also signifies the initialization of a control block, it must additionally send a procedure access request to the kernel ROM chiplet via the chiplets bus. Therefore, it is excluded from this flag and its communication with the chiplets bus is handled separately.
In the above, represents the opcode value of the opcode being executed on the virtual machine. It is calculated via a bitwise combination of the op bits. We leverage the opcode value to achieve domain separation when hashing control blocks. This is done by populating the second capacity register of the hasher with the value via the term when initializing the hasher.
Using the above variables, we define operation values as described below.
-When a control block initializer operation (JOIN
, SPLIT
, LOOP
, CALL
, SYSCALL
) is executed, a new hasher is initialized and the contents of are absorbed into the hasher. As mentioned above, the opcode value is populated in the second capacity resister via the term.
When a control block initializer operation (JOIN
, SPLIT
, LOOP
, DYN
, CALL
, SYSCALL
) is executed, a new hasher is initialized and the contents of are absorbed into the hasher. As mentioned above, the opcode value is populated in the second capacity resister via the term.
As mentioned previously, the value sent by the SYSCALL
operation is defined separately, since in addition to communicating with the hash chiplet it must also send a kernel procedure access request to the kernel ROM chiplet. This value of this kernel procedure request is described by .
@@ -287,7 +292,7 @@
END
operation, the situation is reversed: is the ID of the ending block, and is the ID of the parent block. For RESPAN
operation, refers to the ID of the current operation batch, refers to the ID of the next batch, and the parent ID for both batches is set by the prover non-deterministically in register .
When JOIN
operation is executed, row is added to the block stack table:
-
When SPLIT
operation is executed, row added to the block stack table:
When SPLIT
operation is executed, row is added to the block stack table:
When LOOP
operation is executed, row is added to the block stack table if the value at the top of the operand stack is , and row is added to the block stack table if the value at the top of the operand stack is :
@@ -295,17 +300,19 @@
When RESPAN
operation is executed, row is removed from the block stack table, and row is added to the table. The prover sets the value of register at the next row to the ID of the parent block:
+
When a DYN
operation is executed, row is added to the block stack table:
When END
operation is executed, row is removed from the block span table. Register contains the is_loop
flag:
Using the above definitions, we can describe the constraint for updating the block stack table as follows:
-+
We need to add and subtract the sum of the relevant operation flags from each side to ensure that when none of the flags is set to , the above constraint reduces to .
The degree of this constraint is .
In addition to the above transition constraint, we also need to impose boundary constraints against the column to make sure the first and the last value in the column is set to . This enforces that the block stack table starts and ends in an empty state.
As described previously, when the VM starts executing a new program block, it adds hashes of the block's children to the block hash table. And when the VM finishes executing a block, it removes the block's hash from the block hash table. This means that the block hash tables gets updated when we execute JOIN
, SPLIT
, LOOP
, REPEAT
, and END
operations (executing SPAN
operation does not affect the block hash table because a span block has no children).
As described previously, when the VM starts executing a new program block, it adds hashes of the block's children to the block hash table. And when the VM finishes executing a block, it removes the block's hash from the block hash table. This means that the block hash table gets updated when we execute the JOIN
, SPLIT
, LOOP
, REPEAT
, DYN
, and END
operations (executing SPAN
operation does not affect the block hash table because a span block has no children).
Adding and removing entries to/from the block hash table is accomplished as follows:
(prnt_id, block_hash, is_first_child, is_loop_body)
. A constraint to enforce this would look as , where is the value representing the row to be added.When REPEAT
operation is executed, hash of loop body is added to the block hash table. We add term to indicate that the child is a body of a loop:
+
When the DYN
operation is executed, the hash of the dynamic child is added to the block hash table. Since the child is dynamically specified by the top four elements of the stack, the value representing the dyn block's child must be computed based on the stack rather than from the decoder's hasher registers:
+
When END
operation is executed, hash of the completed block is removed from the block hash table. However, we also need to differentiate between removing the first and the second child of a join block. We do this by looking at the next operation. Specifically, if the next operation is neither END
nor REPEAT
we know that another block is about to be executed, and thus, we have just finished executing the first child of a join block. Thus, if the next operation is neither END
nor REPEAT
we need to set the term for coefficient to as shown below:
Using the above definitions, we can describe the constraint for updating the block hash table as follows:
-+
We need to add and subtract the sum of the relevant operation flags from each side to ensure that when none of the flags is set to , the above constraint reduces to .
The degree of this constraint is .
diff --git a/design/decoder/main.html b/design/decoder/main.html index b58e69c4cf..714efa6cac 100644 --- a/design/decoder/main.html +++ b/design/decoder/main.html @@ -193,6 +193,7 @@REPEAT
SPAN
RESPAN
DYN
CALL
SYSCALL
END
group_count
register by .op_index
register to .Before a DYN
operation is executed by the VM, the prover populates registers with as shown in the diagram below.
In the above diagram, blk
is the ID of the dyn block which is about to be executed. blk
is also the address of the hasher row in the auxiliary hasher table. prnt
is the ID of the block's parent.
When the VM executes a DYN
operation, it does the following:
(blk, prnt, 0)
to the block stack table.dynamic_block_hash
from the top four elements of the stack.(blk, dynamic_block_hash, 0, 0)
to the block hash table.blk
as row address in the auxiliary hashing table and as input values.Before an END
operation is executed by the VM, the prover populates registers with the hash of the block which is about to end. The prover also sets values in and registers as follows:
If the top of the stack is , the VM still executes the LOOP
operation. But unlike in the case when we need to enter the loop, the VM sets is_loop
flag to in the block stack table, and does not add any rows to the block hash table. The last point means that the only possible operation to be executed after the LOOP
operation is the END
operation. This is illustrated in the diagram below.
Moreover, since we've set the is_loop
flag to , executing the END
operation does not remove any items from the stack.
When decoding a dyn bock, the VM first executes a DYN
operation, then executes the child block dynamically specified by the top of the stack. Once the child of the dyn block has been executed, the VM executes an END
operation. This is illustrated in the diagram below.
As described previously, when the VM executes a DYN
operation, the hash of the child is added to the block hash table. This hash is removed only when the END
operation for the child block is executed. Thus, until the child block corresponding to the dynamically specified target is executed, the block hash table is not cleared.
As described here, a span block can contain one or more operation batches, each batch containing up to operation groups. At the high level, decoding of a span block is done as follows:
After the body of the loop is executed, the VM checks the top of the stack again. If the top of the stack is , the body is executed again, if the top of the stack is , the loop is exited. If the top of the stack is neither nor , the execution fails.
A loop block must always have one child, and thus, cannot be a leaf node in the tree.
+A dyn block is used to describe a node whose target is specified dynamically via the stack. When the VM encounters a dyn block, it executes a program which hashes to the target specified by the top of the stack. Thus, it has a dynamic target rather than a hardcoded target. In order to execute a dyn block, the VM must be aware of a program with the hash value that is specified by the top of the stack. Otherwise, the execution fails.
+ +A dyn block must always have one (dynamically-specified) child. Thus, it cannot be a leaf node in the tree.
A call block is used to describe a function call which is executed in a user context. When the VM encounters a call block, it creates a new user context, then executes a program which hashes to the target specified by the call block in the new context. Thus, in order to execute a call block, the VM must be aware of a program with the specified hash. Otherwise, the execution fails. At the end of the call block, execution returns to the previous context.
When executing a call block, the VM does the following:
@@ -206,10 +210,6 @@A syscall block does not have any children. Thus, it must be leaf node in the tree.
-A dyn block is used to describe a node whose target is specified dynamically via the stack. When the VM encounters a dyn block, it executes a program which hashes to the target specified by the top of the stack. Thus, it has a dynamic target rather than a hardcoded target. In order to execute a dyn block, the VM must be aware of a program with the hash value that is specified by the top of the stack. Otherwise, the execution fails.
- -A dyn block must always have one (dynamically-specified) child. Thus, it cannot be a leaf node in the tree.
A span block is used to describe a linear sequence of operations. When the VM encounters a span block, it breaks the sequence of operations into batches and groups according to the following rules:
[ZERO, ZERO, ZERO, ZERO]
) using a domain value of DYN_DOMAIN
, where DYN_DOMAIN
is the op code of the Dyn
operation.[ZERO, ZERO, ZERO, ZERO]
) using a domain value of DYN_DOMAIN
, where DYN_DOMAIN
is the op code of the Dyn
operation.NOOPs
are appended to the end of the last batch to ensure that the number of operations in the batch is always equal to .LOOP
101_0101
SPAN
101_0110
JOIN
101_0111
<unused>
101_1000
DYN
101_1000
<unused>
101_1001
<unused>
101_1010
<unused>
101_1011
However, this can be computed more efficiently via the common operation prefixes for the two groups of control flow operations as follows.
-
+
diff --git a/print.html b/print.html index bd5b00668b..7706a5b347 100644 --- a/print.html +++ b/print.html @@ -1344,6 +1344,10 @@
After the body of the loop is executed, the VM checks the top of the stack again. If the top of the stack is , the body is executed again, if the top of the stack is , the loop is exited. If the top of the stack is neither nor , the execution fails.
A loop block must always have one child, and thus, cannot be a leaf node in the tree.
+A dyn block is used to describe a node whose target is specified dynamically via the stack. When the VM encounters a dyn block, it executes a program which hashes to the target specified by the top of the stack. Thus, it has a dynamic target rather than a hardcoded target. In order to execute a dyn block, the VM must be aware of a program with the hash value that is specified by the top of the stack. Otherwise, the execution fails.
+ +A dyn block must always have one (dynamically-specified) child. Thus, it cannot be a leaf node in the tree.
A call block is used to describe a function call which is executed in a user context. When the VM encounters a call block, it creates a new user context, then executes a program which hashes to the target specified by the call block in the new context. Thus, in order to execute a call block, the VM must be aware of a program with the specified hash. Otherwise, the execution fails. At the end of the call block, execution returns to the previous context.
When executing a call block, the VM does the following:
@@ -1364,10 +1368,6 @@A syscall block does not have any children. Thus, it must be leaf node in the tree.
-A dyn block is used to describe a node whose target is specified dynamically via the stack. When the VM encounters a dyn block, it executes a program which hashes to the target specified by the top of the stack. Thus, it has a dynamic target rather than a hardcoded target. In order to execute a dyn block, the VM must be aware of a program with the hash value that is specified by the top of the stack. Otherwise, the execution fails.
- -A dyn block must always have one (dynamically-specified) child. Thus, it cannot be a leaf node in the tree.
A span block is used to describe a linear sequence of operations. When the VM encounters a span block, it breaks the sequence of operations into batches and groups according to the following rules:
[ZERO, ZERO, ZERO, ZERO]
) using a domain value of DYN_DOMAIN
, where DYN_DOMAIN
is the op code of the Dyn
operation.[ZERO, ZERO, ZERO, ZERO]
) using a domain value of DYN_DOMAIN
, where DYN_DOMAIN
is the op code of the Dyn
operation.NOOPs
are appended to the end of the last batch to ensure that the number of operations in the batch is always equal to .REPEAT
SPAN
RESPAN
DYN
CALL
SYSCALL
END
group_count
register by .op_index
register to .Before a DYN
operation is executed by the VM, the prover populates registers with as shown in the diagram below.
In the above diagram, blk
is the ID of the dyn block which is about to be executed. blk
is also the address of the hasher row in the auxiliary hasher table. prnt
is the ID of the block's parent.
When the VM executes a DYN
operation, it does the following:
(blk, prnt, 0)
to the block stack table.dynamic_block_hash
from the top four elements of the stack.(blk, dynamic_block_hash, 0, 0)
to the block hash table.blk
as row address in the auxiliary hashing table and as input values.Before an END
operation is executed by the VM, the prover populates registers with the hash of the block which is about to end. The prover also sets values in and registers as follows:
If the top of the stack is , the VM still executes the LOOP
operation. But unlike in the case when we need to enter the loop, the VM sets is_loop
flag to in the block stack table, and does not add any rows to the block hash table. The last point means that the only possible operation to be executed after the LOOP
operation is the END
operation. This is illustrated in the diagram below.
Moreover, since we've set the is_loop
flag to , executing the END
operation does not remove any items from the stack.
When decoding a dyn bock, the VM first executes a DYN
operation, then executes the child block dynamically specified by the top of the stack. Once the child of the dyn block has been executed, the VM executes an END
operation. This is illustrated in the diagram below.
As described previously, when the VM executes a DYN
operation, the hash of the child is added to the block hash table. This hash is removed only when the END
operation for the child block is executed. Thus, until the child block corresponding to the dynamically specified target is executed, the block hash table is not cleared.
As described here, a span block can contain one or more operation batches, each batch containing up to operation groups. At the high level, decoding of a span block is done as follows:
SPAN
RESPAN
DYN
CALL
SYSCALL
END
We also use the control flow flag exposed by the VM, which is set when any one of the above control flow operations is being executed. It has degree .
-As described previously, the general idea of the decoder is that the prove provides the program to the VM by populating some of cells in the trace non-deterministically. Values in these are then used to update virtual tables (represented via multiset checks) such as block hash table, block stack table etc. Transition constraints are used to enforce that the tables are updates correctly, and we also apply boundary constraints to enforce the correct initial and final states of these tables. One of these boundary constraints binds the execution trace to the hash of the program being executed. Thus, if the virtual tables were updated correctly and boundary constraints hold, we can be convinced that the prover executed the claimed program on the VM.
+We also use the control flow flag exposed by the VM, which is set when any one of the above control flow operations is being executed. It has degree .
+As described previously, the general idea of the decoder is that the prover provides the program to the VM by populating some of cells in the trace non-deterministically. Values in these are then used to update virtual tables (represented via multiset checks) such as block hash table, block stack table etc. Transition constraints are used to enforce that the tables are updates correctly, and we also apply boundary constraints to enforce the correct initial and final states of these tables. One of these boundary constraints binds the execution trace to the hash of the program being executed. Thus, if the virtual tables were updated correctly and boundary constraints hold, we can be convinced that the prover executed the claimed program on the VM.
In the sections below, we describe constraints according to their logical grouping. However, we start out with a set of general constraints which are applicable to multiple parts of the decoder.
When SPLIT
or LOOP
operation is executed, the top of the operand stack must contain a binary value:
+
When a DYN
operation is executed, the hasher registers must all be set to :
++
When REPEAT
operation is executed, the value at the top of the operand stack must be :
@@ -1937,11 +1958,11 @@
Gener
When the value in in_span
column is set to , control flow operations cannot be executed on the VM, but when in_span
flag is , only control flow operations can be executed on the VM:
-+
As described previously, when the VM starts executing a new block, it also initiates computation of the block's hash. There are two separate methodologies for computing block hashes.
-For join, split, and loop blocks, the hash is computed directly from the hashes of the block's children. The prover provides these child hashes non-deterministically by populating registers . The hasher is initialized using the hash chiplet, and we use the address of the hasher as the block's ID. The result of the hash is available rows down in the hasher table (i.e., at row with index equal to block ID plus ). We read the result from the hasher table at the time the END
operation is executed for a given block.
For join, split, and loop blocks, the hash is computed directly from the hashes of the block's children. The prover provides these child hashes non-deterministically by populating registers . For dyn, the hasher registers are populated with zeros, so the resulting hash is a constant value. The hasher is initialized using the hash chiplet, and we use the address of the hasher as the block's ID. The result of the hash is available rows down in the hasher table (i.e., at row with index equal to block ID plus ). We read the result from the hasher table at the time the END
operation is executed for a given block.
For span blocks, the hash is computed by absorbing a linear sequence of instructions (organized into operation groups and batches) into the hasher and then returning the result. The prover provides operation batches non-deterministically by populating registers . Similarly to other blocks, the hasher is initialized using the hash chiplet at the start of the block, and we use the address of the hasher as the ID of the first operation batch in the block. As we absorb additional operation batches into the hasher (by executing RESPAN
operation), the batch address is incremented by . This moves the "pointer" into the hasher table rows down with every new batch. We read the result from the hasher table at the time the END
operation is executed for a given block.
The decoder communicates with the hash chiplet via the chiplets bus. This works by dividing values of the multiset check column by the values of operations providing inputs to or reading outputs from the hash chiplet. A constraint to enforce this would look as , where is the value which defines the operation.
@@ -1958,12 +1979,12 @@
In the above, represents the address value in the decoder which corresponds to the hasher chiplet address at which the hasher was initialized (or the last absorption took place). As such, corresponds to the hasher chiplet address at which the result is returned.
-+
In the above, is set to when a control flow operation that signifies the initialization of a control block is being executed on the VM. Otherwise, it is set to . An exception is made for the SYSCALL
operation. Although it also signifies the initialization of a control block, it must additionally send a procedure access request to the kernel ROM chiplet via the chiplets bus. Therefore, it is excluded from this flag and its communication with the chiplets bus is handled separately.
In the above, represents the opcode value of the opcode being executed on the virtual machine. It is calculated via a bitwise combination of the op bits. We leverage the opcode value to achieve domain separation when hashing control blocks. This is done by populating the second capacity register of the hasher with the value via the term when initializing the hasher.
Using the above variables, we define operation values as described below.
-When a control block initializer operation (JOIN
, SPLIT
, LOOP
, CALL
, SYSCALL
) is executed, a new hasher is initialized and the contents of are absorbed into the hasher. As mentioned above, the opcode value is populated in the second capacity resister via the term.
When a control block initializer operation (JOIN
, SPLIT
, LOOP
, DYN
, CALL
, SYSCALL
) is executed, a new hasher is initialized and the contents of are absorbed into the hasher. As mentioned above, the opcode value is populated in the second capacity resister via the term.
As mentioned previously, the value sent by the SYSCALL
operation is defined separately, since in addition to communicating with the hash chiplet it must also send a kernel procedure access request to the kernel ROM chiplet. This value of this kernel procedure request is described by .
@@ -1992,7 +2013,7 @@
END
operation, the situation is reversed: is the ID of the ending block, and is the ID of the parent block. For RESPAN
operation, refers to the ID of the current operation batch, refers to the ID of the next batch, and the parent ID for both batches is set by the prover non-deterministically in register .
When JOIN
operation is executed, row is added to the block stack table:
-
When SPLIT
operation is executed, row added to the block stack table:
When SPLIT
operation is executed, row is added to the block stack table:
When LOOP
operation is executed, row is added to the block stack table if the value at the top of the operand stack is , and row is added to the block stack table if the value at the top of the operand stack is :
@@ -2000,17 +2021,19 @@
When RESPAN
operation is executed, row is removed from the block stack table, and row is added to the table. The prover sets the value of register at the next row to the ID of the parent block:
+
When a DYN
operation is executed, row is added to the block stack table:
When END
operation is executed, row is removed from the block span table. Register contains the is_loop
flag:
Using the above definitions, we can describe the constraint for updating the block stack table as follows:
-+
We need to add and subtract the sum of the relevant operation flags from each side to ensure that when none of the flags is set to , the above constraint reduces to .
The degree of this constraint is .
In addition to the above transition constraint, we also need to impose boundary constraints against the column to make sure the first and the last value in the column is set to . This enforces that the block stack table starts and ends in an empty state.
As described previously, when the VM starts executing a new program block, it adds hashes of the block's children to the block hash table. And when the VM finishes executing a block, it removes the block's hash from the block hash table. This means that the block hash tables gets updated when we execute JOIN
, SPLIT
, LOOP
, REPEAT
, and END
operations (executing SPAN
operation does not affect the block hash table because a span block has no children).
As described previously, when the VM starts executing a new program block, it adds hashes of the block's children to the block hash table. And when the VM finishes executing a block, it removes the block's hash from the block hash table. This means that the block hash table gets updated when we execute the JOIN
, SPLIT
, LOOP
, REPEAT
, DYN
, and END
operations (executing SPAN
operation does not affect the block hash table because a span block has no children).
Adding and removing entries to/from the block hash table is accomplished as follows:
(prnt_id, block_hash, is_first_child, is_loop_body)
. A constraint to enforce this would look as , where is the value representing the row to be added.When REPEAT
operation is executed, hash of loop body is added to the block hash table. We add term to indicate that the child is a body of a loop:
+
When the DYN
operation is executed, the hash of the dynamic child is added to the block hash table. Since the child is dynamically specified by the top four elements of the stack, the value representing the dyn block's child must be computed based on the stack rather than from the decoder's hasher registers:
+
When END
operation is executed, hash of the completed block is removed from the block hash table. However, we also need to differentiate between removing the first and the second child of a join block. We do this by looking at the next operation. Specifically, if the next operation is neither END
nor REPEAT
we know that another block is about to be executed, and thus, we have just finished executing the first child of a join block. Thus, if the next operation is neither END
nor REPEAT
we need to set the term for coefficient to as shown below:
Using the above definitions, we can describe the constraint for updating the block hash table as follows:
-+
We need to add and subtract the sum of the relevant operation flags from each side to ensure that when none of the flags is set to , the above constraint reduces to .
The degree of this constraint is .
@@ -2522,7 +2548,7 @@LOOP
101_0101
SPAN
101_0110
JOIN
101_0111
<unused>
101_1000
DYN
101_1000
<unused>
101_1001
<unused>
101_1010
<unused>
101_1011
However, this can be computed more efficiently via the common operation prefixes for the two groups of control flow operations as follows.
-
+
In this section we describe the AIR constraints for Miden VM system operations.
diff --git a/searchindex.js b/searchindex.js index 5d41144f22..e8eb521501 100644 --- a/searchindex.js +++ b/searchindex.js @@ -1 +1 @@ -Object.assign(window.search, {"doc_urls":["intro/main.html#introduction","intro/main.html#status-and-features","intro/main.html#feature-highlights","intro/main.html#planned-features","intro/main.html#structure-of-this-document","intro/main.html#license","intro/overview.html#miden-vm-overview","intro/overview.html#writing-programs","intro/overview.html#inputs-and-outputs","intro/overview.html#stack-depth-restrictions","intro/overview.html#nondeterministic-inputs","intro/usage.html#usage","intro/usage.html#cli-interface","intro/usage.html#compiling-miden-vm","intro/usage.html#controlling-parallelism","intro/usage.html#gpu-acceleration","intro/usage.html#running-miden-vm","intro/usage.html#inputs","intro/usage.html#fibonacci-example","intro/performance.html#performance","intro/performance.html#single-core-prover-performance","intro/performance.html#multi-core-prover-performance","tools/main.html#development-tools-and-resources","tools/debugger.html#miden-debugger","tools/repl.html#miden-repl","tools/repl.html#miden-assembly-instruction","tools/repl.html#help","tools/repl.html#program","tools/repl.html#stack","tools/repl.html#mem","tools/repl.html#memaddr","tools/repl.html#undo","user_docs/main.html#user-documentation","user_docs/assembly/main.html#miden-assembly","user_docs/assembly/main.html#terms-and-notations","user_docs/assembly/main.html#design-goals","user_docs/assembly/code_organization.html#code-organization","user_docs/assembly/code_organization.html#procedures","user_docs/assembly/code_organization.html#modules","user_docs/assembly/code_organization.html#constants","user_docs/assembly/code_organization.html#comments","user_docs/assembly/execution_contexts.html#execution-contexts","user_docs/assembly/execution_contexts.html#procedure-invocation-semantics","user_docs/assembly/execution_contexts.html#kernels","user_docs/assembly/execution_contexts.html#memory-layout","user_docs/assembly/execution_contexts.html#example","user_docs/assembly/flow_control.html#flow-control","user_docs/assembly/flow_control.html#conditional-execution","user_docs/assembly/flow_control.html#counter-controlled-loops","user_docs/assembly/flow_control.html#condition-controlled-loops","user_docs/assembly/field_operations.html#field-operations","user_docs/assembly/field_operations.html#assertions-and-tests","user_docs/assembly/field_operations.html#arithmetic-and-boolean-operations","user_docs/assembly/field_operations.html#comparison-operations","user_docs/assembly/field_operations.html#extension-field-operations","user_docs/assembly/u32_operations.html#u32-operations","user_docs/assembly/u32_operations.html#conversions-and-tests","user_docs/assembly/u32_operations.html#arithmetic-operations","user_docs/assembly/u32_operations.html#bitwise-operations","user_docs/assembly/u32_operations.html#comparison-operations","user_docs/assembly/stack_manipulation.html#stack-manipulation","user_docs/assembly/stack_manipulation.html#conditional-manipulation","user_docs/assembly/io_operations.html#input--output-operations","user_docs/assembly/io_operations.html#constant-inputs","user_docs/assembly/io_operations.html#environment-inputs","user_docs/assembly/io_operations.html#nondeterministic-inputs","user_docs/assembly/io_operations.html#random-access-memory","user_docs/assembly/cryptographic_operations.html#cryptographic-operations","user_docs/assembly/cryptographic_operations.html#hashing-and-merkle-trees","user_docs/stdlib/main.html#miden-standard-library","user_docs/stdlib/main.html#terms-and-notations","user_docs/stdlib/main.html#organization-and-usage","user_docs/stdlib/main.html#available-modules","user_docs/stdlib/collections.html#collections","user_docs/stdlib/collections.html#merkle-mountain-range","user_docs/stdlib/collections.html#sparse-merkle-tree-64","user_docs/stdlib/collections.html#sparse-merkle-tree-256","user_docs/stdlib/crypto/fri.html#fri-verification-procedures","user_docs/stdlib/crypto/fri.html#fri-extension-2-fold-4","user_docs/stdlib/crypto/hashes.html#cryptographic-hashes","user_docs/stdlib/crypto/hashes.html#blake3","user_docs/stdlib/crypto/hashes.html#sha256","user_docs/stdlib/math/u64.html#unsigned-64-bit-integer-operations","user_docs/stdlib/math/u64.html#arithmetic-operations","user_docs/stdlib/math/u64.html#comparison-operations","user_docs/stdlib/math/u64.html#bitwise-operations","user_docs/stdlib/mem.html#memory-procedures","user_docs/stdlib/sys.html#system-procedures","design/main.html#design","design/main.html#vm-components","design/main.html#vm-execution-trace","design/programs.html#programs-in-miden-vm","design/programs.html#code-blocks","design/programs.html#join-block","design/programs.html#split-block","design/programs.html#loop-block","design/programs.html#call-block","design/programs.html#syscall-block","design/programs.html#dyn-block","design/programs.html#span-block","design/programs.html#program-example","design/programs.html#program-hash-computation","design/decoder/main.html#miden-vm-program-decoder","design/decoder/main.html#program-execution","design/decoder/main.html#decoder-structure","design/decoder/main.html#decoder-trace","design/decoder/main.html#program-block-hashing","design/decoder/main.html#control-flow-tables","design/decoder/main.html#control-flow-operation-semantics","design/decoder/main.html#program-decoding","design/decoder/main.html#join-block-decoding","design/decoder/main.html#split-block-decoding","design/decoder/main.html#loop-block-decoding","design/decoder/main.html#span-block-decoding","design/decoder/main.html#program-decoding-example","design/decoder/constraints.html#miden-vm-decoder-air-constraints","design/decoder/constraints.html#general-constraints","design/decoder/constraints.html#block-hash-computation-constraints","design/decoder/constraints.html#chiplets-bus-constraints","design/decoder/constraints.html#block-stack-table-constraints","design/decoder/constraints.html#block-hash-table-constraints","design/decoder/constraints.html#span-block","design/decoder/constraints.html#in-span-column-constraints","design/decoder/constraints.html#block-address-constraints","design/decoder/constraints.html#group-count-constraints","design/decoder/constraints.html#op-group-decoding-constraints","design/decoder/constraints.html#op-index-constraints","design/decoder/constraints.html#op-batch-flags-constraints","design/decoder/constraints.html#op-group-table-constraints","design/stack/main.html#operand-stack","design/stack/main.html#stack-representation","design/stack/main.html#overflow-table","design/stack/main.html#right-shift","design/stack/main.html#left-shift","design/stack/main.html#air-constraints","design/stack/main.html#stack-overflow-flag","design/stack/main.html#stack-depth-constraints","design/stack/main.html#overflow-table-constraints","design/stack/main.html#boundary-constraints","design/stack/op_constraints.html#stack-operation-constraints","design/stack/op_constraints.html#operation-flags","design/stack/op_constraints.html#no-stack-shift-operations","design/stack/op_constraints.html#left-stack-shift-operations","design/stack/op_constraints.html#right-stack-shift-operations","design/stack/op_constraints.html#u32-operations","design/stack/op_constraints.html#high-degree-operations","design/stack/op_constraints.html#very-high-degree-operations","design/stack/op_constraints.html#composite-flags","design/stack/op_constraints.html#shift-right-flag","design/stack/op_constraints.html#shift-left-flag","design/stack/op_constraints.html#control-flow-flag","design/stack/system_ops.html#system-operations","design/stack/system_ops.html#noop","design/stack/system_ops.html#assert","design/stack/system_ops.html#fmpadd","design/stack/system_ops.html#fmpupdate","design/stack/system_ops.html#clk","design/stack/field_ops.html#field-operations","design/stack/field_ops.html#add","design/stack/field_ops.html#neg","design/stack/field_ops.html#mul","design/stack/field_ops.html#inv","design/stack/field_ops.html#incr","design/stack/field_ops.html#not","design/stack/field_ops.html#and","design/stack/field_ops.html#or","design/stack/field_ops.html#eq","design/stack/field_ops.html#eqz","design/stack/field_ops.html#expacc","design/stack/field_ops.html#ext2mul","design/stack/u32_ops.html#u32-operations","design/stack/u32_ops.html#range-checks","design/stack/u32_ops.html#checking-element-validity","design/stack/u32_ops.html#u32split","design/stack/u32_ops.html#u32assert2","design/stack/u32_ops.html#u32add","design/stack/u32_ops.html#u32add3","design/stack/u32_ops.html#u32sub","design/stack/u32_ops.html#u32mul","design/stack/u32_ops.html#u32madd","design/stack/u32_ops.html#u32div","design/stack/u32_ops.html#u32and","design/stack/u32_ops.html#u32xor","design/stack/stack_ops.html#stack-manipulation","design/stack/stack_ops.html#pad","design/stack/stack_ops.html#drop","design/stack/stack_ops.html#dupn","design/stack/stack_ops.html#swap","design/stack/stack_ops.html#swapw","design/stack/stack_ops.html#swapw2","design/stack/stack_ops.html#swapw3","design/stack/stack_ops.html#swapdw","design/stack/stack_ops.html#movupn","design/stack/stack_ops.html#movdnn","design/stack/stack_ops.html#cswap","design/stack/stack_ops.html#cswapw","design/stack/io_ops.html#input--output-operations","design/stack/io_ops.html#push","design/stack/io_ops.html#sdepth","design/stack/io_ops.html#advpop","design/stack/io_ops.html#advpopw","design/stack/io_ops.html#memory-access-operations","design/stack/io_ops.html#mloadw","design/stack/io_ops.html#mload","design/stack/io_ops.html#mstorew","design/stack/io_ops.html#mstore","design/stack/io_ops.html#mstream","design/stack/crypto_ops.html#cryptographic-operations","design/stack/crypto_ops.html#hperm","design/stack/crypto_ops.html#mpverify","design/stack/crypto_ops.html#mrupdate","design/stack/crypto_ops.html#frie2f4","design/range.html#range-checker","design/range.html#8-bit-range-checks","design/range.html#a-better-construction","design/range.html#16-bit-range-checks","design/range.html#miden-approach","design/range.html#requirements","design/range.html#capabilities","design/range.html#execution-trace","design/range.html#execution-trace-constraints","design/range.html#communication-bus","design/chiplets/main.html#chiplets","design/chiplets/main.html#chiplets-module-trace","design/chiplets/main.html#chiplets-order","design/chiplets/main.html#additional-requirements-for-stacking-execution-traces","design/chiplets/main.html#operation-labels","design/chiplets/main.html#chiplets-module-constraints","design/chiplets/main.html#chiplet-constraints","design/chiplets/main.html#chiplet-selector-constraints","design/chiplets/main.html#chiplets-bus","design/chiplets/main.html#chiplets-bus-constraints","design/chiplets/main.html#chiplets-virtual-table","design/chiplets/main.html#chiplets-virtual-table-constraints","design/chiplets/hasher.html#hash-chiplet","design/chiplets/hasher.html#chiplet-trace","design/chiplets/hasher.html#instruction-flags","design/chiplets/hasher.html#computation-examples","design/chiplets/hasher.html#single-permutation","design/chiplets/hasher.html#simple-2-to-1-hash","design/chiplets/hasher.html#linear-hash-of-n-elements","design/chiplets/hasher.html#verify-merkle-path","design/chiplets/hasher.html#update-merkle-root","design/chiplets/hasher.html#air-constraints","design/chiplets/hasher.html#selector-columns-constraints","design/chiplets/hasher.html#node-index-constraints","design/chiplets/hasher.html#hasher-state-constraints","design/chiplets/hasher.html#multiset-check-constraints","design/chiplets/bitwise.html#bitwise-chiplet","design/chiplets/bitwise.html#example","design/chiplets/bitwise.html#constraints","design/chiplets/bitwise.html#selectors","design/chiplets/bitwise.html#input-decomposition","design/chiplets/bitwise.html#output-aggregation","design/chiplets/bitwise.html#chiplets-bus-constraints","design/chiplets/memory.html#memory-chiplet","design/chiplets/memory.html#alternative-designs","design/chiplets/memory.html#read-write-memory","design/chiplets/memory.html#non-contiguous-memory","design/chiplets/memory.html#context-separation","design/chiplets/memory.html#miden-approach","design/chiplets/memory.html#air-constraints","design/chiplets/kernel_rom.html#kernel-rom-chiplet","design/chiplets/kernel_rom.html#kernel-rom-trace","design/chiplets/kernel_rom.html#constraints","design/chiplets/kernel_rom.html#chiplets-bus-constraints","design/chiplets/kernel_rom.html#kernel-procedure-table-constraints","design/lookups/main.html#lookup-arguments-in-miden-vm","design/lookups/main.html#virtual-tables-in-miden-vm","design/lookups/main.html#communication-buses-in-miden-vm","design/lookups/main.html#length-of-auxiliary-columns-for-lookup-arguments","design/lookups/main.html#cost-of-auxiliary-columns-for-lookup-arguments","design/lookups/multiset.html#multiset-checks","design/lookups/multiset.html#running-product-columns","design/lookups/multiset.html#virtual-tables","design/lookups/multiset.html#computing-a-virtual-tables-trace-column","design/lookups/multiset.html#virtual-tables-in-miden-vm","design/lookups/multiset.html#communication-buses-via-multiset-checks","design/lookups/multiset.html#communication-bus-constraints","design/lookups/multiset.html#communication-buses-in-miden-vm","design/lookups/logup.html#logup-multivariate-lookups-with-logarithmic-derivatives","design/lookups/logup.html#usage-in-miden-vm","design/lookups/logup.html#constraints","design/lookups/logup.html#extending-the-construction-to-multiple-components","design/lookups/logup.html#extending-the-construction-with-flags","background.html#background-material"],"index":{"documentStore":{"docInfo":{"0":{"body":34,"breadcrumbs":2,"title":1},"1":{"body":53,"breadcrumbs":3,"title":2},"10":{"body":115,"breadcrumbs":4,"title":2},"100":{"body":200,"breadcrumbs":4,"title":2},"101":{"body":239,"breadcrumbs":5,"title":3},"102":{"body":131,"breadcrumbs":7,"title":4},"103":{"body":209,"breadcrumbs":5,"title":2},"104":{"body":45,"breadcrumbs":5,"title":2},"105":{"body":183,"breadcrumbs":5,"title":2},"106":{"body":298,"breadcrumbs":6,"title":3},"107":{"body":516,"breadcrumbs":6,"title":3},"108":{"body":814,"breadcrumbs":7,"title":4},"109":{"body":91,"breadcrumbs":5,"title":2},"11":{"body":72,"breadcrumbs":3,"title":1},"110":{"body":59,"breadcrumbs":6,"title":3},"111":{"body":54,"breadcrumbs":6,"title":3},"112":{"body":227,"breadcrumbs":6,"title":3},"113":{"body":1070,"breadcrumbs":6,"title":3},"114":{"body":292,"breadcrumbs":6,"title":3},"115":{"body":302,"breadcrumbs":10,"title":5},"116":{"body":137,"breadcrumbs":7,"title":2},"117":{"body":144,"breadcrumbs":9,"title":4},"118":{"body":447,"breadcrumbs":8,"title":3},"119":{"body":306,"breadcrumbs":9,"title":4},"12":{"body":0,"breadcrumbs":4,"title":2},"120":{"body":403,"breadcrumbs":9,"title":4},"121":{"body":26,"breadcrumbs":7,"title":2},"122":{"body":135,"breadcrumbs":8,"title":3},"123":{"body":70,"breadcrumbs":8,"title":3},"124":{"body":184,"breadcrumbs":8,"title":3},"125":{"body":225,"breadcrumbs":9,"title":4},"126":{"body":132,"breadcrumbs":8,"title":3},"127":{"body":141,"breadcrumbs":9,"title":4},"128":{"body":349,"breadcrumbs":9,"title":4},"129":{"body":120,"breadcrumbs":5,"title":2},"13":{"body":62,"breadcrumbs":5,"title":3},"130":{"body":80,"breadcrumbs":5,"title":2},"131":{"body":172,"breadcrumbs":5,"title":2},"132":{"body":172,"breadcrumbs":5,"title":2},"133":{"body":114,"breadcrumbs":5,"title":2},"134":{"body":59,"breadcrumbs":5,"title":2},"135":{"body":58,"breadcrumbs":6,"title":3},"136":{"body":51,"breadcrumbs":6,"title":3},"137":{"body":132,"breadcrumbs":6,"title":3},"138":{"body":27,"breadcrumbs":5,"title":2},"139":{"body":181,"breadcrumbs":8,"title":3},"14":{"body":18,"breadcrumbs":4,"title":2},"140":{"body":312,"breadcrumbs":7,"title":2},"141":{"body":216,"breadcrumbs":8,"title":3},"142":{"body":129,"breadcrumbs":9,"title":4},"143":{"body":133,"breadcrumbs":9,"title":4},"144":{"body":167,"breadcrumbs":7,"title":2},"145":{"body":159,"breadcrumbs":8,"title":3},"146":{"body":113,"breadcrumbs":9,"title":4},"147":{"body":13,"breadcrumbs":7,"title":2},"148":{"body":41,"breadcrumbs":8,"title":3},"149":{"body":93,"breadcrumbs":8,"title":3},"15":{"body":48,"breadcrumbs":4,"title":2},"150":{"body":37,"breadcrumbs":8,"title":3},"151":{"body":8,"breadcrumbs":7,"title":2},"152":{"body":34,"breadcrumbs":6,"title":1},"153":{"body":33,"breadcrumbs":6,"title":1},"154":{"body":35,"breadcrumbs":6,"title":1},"155":{"body":31,"breadcrumbs":6,"title":1},"156":{"body":30,"breadcrumbs":6,"title":1},"157":{"body":14,"breadcrumbs":7,"title":2},"158":{"body":30,"breadcrumbs":6,"title":1},"159":{"body":28,"breadcrumbs":6,"title":1},"16":{"body":118,"breadcrumbs":5,"title":3},"160":{"body":30,"breadcrumbs":6,"title":1},"161":{"body":34,"breadcrumbs":6,"title":1},"162":{"body":28,"breadcrumbs":6,"title":1},"163":{"body":41,"breadcrumbs":5,"title":0},"164":{"body":46,"breadcrumbs":5,"title":0},"165":{"body":46,"breadcrumbs":5,"title":0},"166":{"body":56,"breadcrumbs":6,"title":1},"167":{"body":54,"breadcrumbs":6,"title":1},"168":{"body":85,"breadcrumbs":6,"title":1},"169":{"body":71,"breadcrumbs":6,"title":1},"17":{"body":151,"breadcrumbs":3,"title":1},"170":{"body":17,"breadcrumbs":7,"title":2},"171":{"body":111,"breadcrumbs":7,"title":2},"172":{"body":113,"breadcrumbs":8,"title":3},"173":{"body":95,"breadcrumbs":6,"title":1},"174":{"body":76,"breadcrumbs":6,"title":1},"175":{"body":83,"breadcrumbs":6,"title":1},"176":{"body":85,"breadcrumbs":6,"title":1},"177":{"body":83,"breadcrumbs":6,"title":1},"178":{"body":98,"breadcrumbs":6,"title":1},"179":{"body":114,"breadcrumbs":6,"title":1},"18":{"body":63,"breadcrumbs":4,"title":2},"180":{"body":70,"breadcrumbs":6,"title":1},"181":{"body":74,"breadcrumbs":6,"title":1},"182":{"body":77,"breadcrumbs":6,"title":1},"183":{"body":9,"breadcrumbs":7,"title":2},"184":{"body":28,"breadcrumbs":6,"title":1},"185":{"body":35,"breadcrumbs":6,"title":1},"186":{"body":62,"breadcrumbs":6,"title":1},"187":{"body":30,"breadcrumbs":6,"title":1},"188":{"body":33,"breadcrumbs":6,"title":1},"189":{"body":36,"breadcrumbs":6,"title":1},"19":{"body":124,"breadcrumbs":3,"title":1},"190":{"body":36,"breadcrumbs":6,"title":1},"191":{"body":33,"breadcrumbs":6,"title":1},"192":{"body":71,"breadcrumbs":6,"title":1},"193":{"body":70,"breadcrumbs":6,"title":1},"194":{"body":60,"breadcrumbs":6,"title":1},"195":{"body":62,"breadcrumbs":6,"title":1},"196":{"body":24,"breadcrumbs":9,"title":3},"197":{"body":34,"breadcrumbs":7,"title":1},"198":{"body":37,"breadcrumbs":7,"title":1},"199":{"body":38,"breadcrumbs":7,"title":1},"2":{"body":253,"breadcrumbs":3,"title":2},"20":{"body":207,"breadcrumbs":6,"title":4},"200":{"body":49,"breadcrumbs":7,"title":1},"201":{"body":73,"breadcrumbs":9,"title":3},"202":{"body":90,"breadcrumbs":7,"title":1},"203":{"body":95,"breadcrumbs":7,"title":1},"204":{"body":90,"breadcrumbs":7,"title":1},"205":{"body":102,"breadcrumbs":7,"title":1},"206":{"body":100,"breadcrumbs":7,"title":1},"207":{"body":54,"breadcrumbs":7,"title":2},"208":{"body":118,"breadcrumbs":6,"title":1},"209":{"body":169,"breadcrumbs":6,"title":1},"21":{"body":106,"breadcrumbs":6,"title":4},"210":{"body":204,"breadcrumbs":6,"title":1},"211":{"body":281,"breadcrumbs":6,"title":1},"212":{"body":65,"breadcrumbs":5,"title":2},"213":{"body":213,"breadcrumbs":7,"title":4},"214":{"body":86,"breadcrumbs":5,"title":2},"215":{"body":130,"breadcrumbs":7,"title":4},"216":{"body":7,"breadcrumbs":5,"title":2},"217":{"body":34,"breadcrumbs":4,"title":1},"218":{"body":32,"breadcrumbs":4,"title":1},"219":{"body":64,"breadcrumbs":5,"title":2},"22":{"body":59,"breadcrumbs":5,"title":3},"220":{"body":35,"breadcrumbs":6,"title":3},"221":{"body":174,"breadcrumbs":5,"title":2},"222":{"body":98,"breadcrumbs":3,"title":1},"223":{"body":121,"breadcrumbs":5,"title":3},"224":{"body":101,"breadcrumbs":4,"title":2},"225":{"body":137,"breadcrumbs":7,"title":5},"226":{"body":121,"breadcrumbs":4,"title":2},"227":{"body":0,"breadcrumbs":5,"title":3},"228":{"body":75,"breadcrumbs":4,"title":2},"229":{"body":116,"breadcrumbs":5,"title":3},"23":{"body":212,"breadcrumbs":5,"title":2},"230":{"body":123,"breadcrumbs":4,"title":2},"231":{"body":52,"breadcrumbs":5,"title":3},"232":{"body":65,"breadcrumbs":5,"title":3},"233":{"body":86,"breadcrumbs":6,"title":4},"234":{"body":313,"breadcrumbs":6,"title":2},"235":{"body":331,"breadcrumbs":6,"title":2},"236":{"body":266,"breadcrumbs":6,"title":2},"237":{"body":0,"breadcrumbs":6,"title":2},"238":{"body":73,"breadcrumbs":6,"title":2},"239":{"body":84,"breadcrumbs":8,"title":4},"24":{"body":55,"breadcrumbs":5,"title":2},"240":{"body":143,"breadcrumbs":8,"title":4},"241":{"body":197,"breadcrumbs":7,"title":3},"242":{"body":215,"breadcrumbs":7,"title":3},"243":{"body":30,"breadcrumbs":6,"title":2},"244":{"body":98,"breadcrumbs":7,"title":3},"245":{"body":148,"breadcrumbs":7,"title":3},"246":{"body":105,"breadcrumbs":7,"title":3},"247":{"body":559,"breadcrumbs":7,"title":3},"248":{"body":227,"breadcrumbs":6,"title":2},"249":{"body":180,"breadcrumbs":5,"title":1},"25":{"body":55,"breadcrumbs":6,"title":3},"250":{"body":24,"breadcrumbs":5,"title":1},"251":{"body":24,"breadcrumbs":5,"title":1},"252":{"body":117,"breadcrumbs":6,"title":2},"253":{"body":86,"breadcrumbs":6,"title":2},"254":{"body":114,"breadcrumbs":7,"title":3},"255":{"body":66,"breadcrumbs":6,"title":2},"256":{"body":139,"breadcrumbs":6,"title":2},"257":{"body":228,"breadcrumbs":7,"title":3},"258":{"body":147,"breadcrumbs":7,"title":3},"259":{"body":230,"breadcrumbs":6,"title":2},"26":{"body":8,"breadcrumbs":4,"title":1},"260":{"body":418,"breadcrumbs":6,"title":2},"261":{"body":253,"breadcrumbs":6,"title":2},"262":{"body":38,"breadcrumbs":8,"title":3},"263":{"body":54,"breadcrumbs":8,"title":3},"264":{"body":103,"breadcrumbs":6,"title":1},"265":{"body":85,"breadcrumbs":8,"title":3},"266":{"body":101,"breadcrumbs":9,"title":4},"267":{"body":144,"breadcrumbs":7,"title":4},"268":{"body":44,"breadcrumbs":7,"title":4},"269":{"body":117,"breadcrumbs":7,"title":4},"27":{"body":25,"breadcrumbs":4,"title":1},"270":{"body":53,"breadcrumbs":8,"title":5},"271":{"body":42,"breadcrumbs":8,"title":5},"272":{"body":17,"breadcrumbs":7,"title":2},"273":{"body":72,"breadcrumbs":8,"title":3},"274":{"body":105,"breadcrumbs":7,"title":2},"275":{"body":58,"breadcrumbs":10,"title":5},"276":{"body":40,"breadcrumbs":9,"title":4},"277":{"body":111,"breadcrumbs":10,"title":5},"278":{"body":105,"breadcrumbs":8,"title":3},"279":{"body":35,"breadcrumbs":9,"title":4},"28":{"body":57,"breadcrumbs":4,"title":1},"280":{"body":113,"breadcrumbs":9,"title":5},"281":{"body":28,"breadcrumbs":7,"title":3},"282":{"body":83,"breadcrumbs":5,"title":1},"283":{"body":40,"breadcrumbs":8,"title":4},"284":{"body":45,"breadcrumbs":7,"title":3},"285":{"body":117,"breadcrumbs":4,"title":2},"29":{"body":48,"breadcrumbs":4,"title":1},"3":{"body":69,"breadcrumbs":3,"title":2},"30":{"body":24,"breadcrumbs":4,"title":1},"31":{"body":110,"breadcrumbs":4,"title":1},"32":{"body":57,"breadcrumbs":4,"title":2},"33":{"body":165,"breadcrumbs":6,"title":2},"34":{"body":79,"breadcrumbs":6,"title":2},"35":{"body":160,"breadcrumbs":6,"title":2},"36":{"body":53,"breadcrumbs":8,"title":2},"37":{"body":128,"breadcrumbs":7,"title":1},"38":{"body":237,"breadcrumbs":7,"title":1},"39":{"body":98,"breadcrumbs":7,"title":1},"4":{"body":78,"breadcrumbs":3,"title":2},"40":{"body":37,"breadcrumbs":7,"title":1},"41":{"body":96,"breadcrumbs":8,"title":2},"42":{"body":205,"breadcrumbs":9,"title":3},"43":{"body":90,"breadcrumbs":7,"title":1},"44":{"body":138,"breadcrumbs":8,"title":2},"45":{"body":274,"breadcrumbs":7,"title":1},"46":{"body":26,"breadcrumbs":8,"title":2},"47":{"body":69,"breadcrumbs":8,"title":2},"48":{"body":49,"breadcrumbs":9,"title":3},"49":{"body":93,"breadcrumbs":9,"title":3},"5":{"body":4,"breadcrumbs":2,"title":1},"50":{"body":53,"breadcrumbs":8,"title":2},"51":{"body":38,"breadcrumbs":8,"title":2},"52":{"body":118,"breadcrumbs":9,"title":3},"53":{"body":70,"breadcrumbs":8,"title":2},"54":{"body":75,"breadcrumbs":9,"title":3},"55":{"body":112,"breadcrumbs":8,"title":2},"56":{"body":50,"breadcrumbs":8,"title":2},"57":{"body":263,"breadcrumbs":8,"title":2},"58":{"body":221,"breadcrumbs":8,"title":2},"59":{"body":156,"breadcrumbs":8,"title":2},"6":{"body":148,"breadcrumbs":5,"title":3},"60":{"body":235,"breadcrumbs":8,"title":2},"61":{"body":56,"breadcrumbs":8,"title":2},"62":{"body":120,"breadcrumbs":10,"title":3},"63":{"body":68,"breadcrumbs":9,"title":2},"64":{"body":64,"breadcrumbs":9,"title":2},"65":{"body":449,"breadcrumbs":9,"title":2},"66":{"body":348,"breadcrumbs":10,"title":3},"67":{"body":13,"breadcrumbs":8,"title":2},"68":{"body":243,"breadcrumbs":9,"title":3},"69":{"body":59,"breadcrumbs":8,"title":3},"7":{"body":58,"breadcrumbs":4,"title":2},"70":{"body":79,"breadcrumbs":7,"title":2},"71":{"body":47,"breadcrumbs":7,"title":2},"72":{"body":100,"breadcrumbs":7,"title":2},"73":{"body":25,"breadcrumbs":7,"title":1},"74":{"body":144,"breadcrumbs":9,"title":3},"75":{"body":177,"breadcrumbs":10,"title":4},"76":{"body":202,"breadcrumbs":10,"title":4},"77":{"body":7,"breadcrumbs":9,"title":3},"78":{"body":210,"breadcrumbs":11,"title":5},"79":{"body":9,"breadcrumbs":8,"title":2},"8":{"body":150,"breadcrumbs":4,"title":2},"80":{"body":83,"breadcrumbs":7,"title":1},"81":{"body":83,"breadcrumbs":7,"title":1},"82":{"body":125,"breadcrumbs":11,"title":5},"83":{"body":493,"breadcrumbs":8,"title":2},"84":{"body":595,"breadcrumbs":8,"title":2},"85":{"body":373,"breadcrumbs":8,"title":2},"86":{"body":124,"breadcrumbs":8,"title":2},"87":{"body":58,"breadcrumbs":8,"title":2},"88":{"body":187,"breadcrumbs":2,"title":1},"89":{"body":151,"breadcrumbs":3,"title":2},"9":{"body":44,"breadcrumbs":5,"title":3},"90":{"body":103,"breadcrumbs":4,"title":3},"91":{"body":48,"breadcrumbs":5,"title":3},"92":{"body":0,"breadcrumbs":4,"title":2},"93":{"body":27,"breadcrumbs":4,"title":2},"94":{"body":41,"breadcrumbs":4,"title":2},"95":{"body":67,"breadcrumbs":4,"title":2},"96":{"body":82,"breadcrumbs":4,"title":2},"97":{"body":85,"breadcrumbs":4,"title":2},"98":{"body":54,"breadcrumbs":4,"title":2},"99":{"body":196,"breadcrumbs":4,"title":2}},"docs":{"0":{"body":"Miden VM is a zero-knowledge virtual machine written in Rust. For any program executed on Miden VM, a STARK-based proof of execution is automatically generated. This proof can then be used by anyone to verify that the program was executed correctly without the need for re-executing the program or even knowing the contents of the program.","breadcrumbs":"Introduction » Introduction","id":"0","title":"Introduction"},"1":{"body":"Miden VM is currently on release v0.7. In this release, most of the core features of the VM have been stabilized, and most of the STARK proof generation has been implemented. While we expect to keep making changes to the VM internals, the external interfaces should remain relatively stable, and we will do our best to minimize the amount of breaking changes going forward. At this point, Miden VM is good enough for experimentation, and even for real-world applications, but it is not yet ready for production use. The codebase has not been audited and contains known and unknown bugs and security flaws.","breadcrumbs":"Introduction » Status and features","id":"1","title":"Status and features"},"10":{"body":"The advice provider component is responsible for supplying nondeterministic inputs to the VM. These inputs only need to be known to the prover (i.e., they do not need to be shared with the verifier). The advice provider consists of three components: Advice stack which is a one-dimensional array of field elements. Being a stack, the VM can either push new elements onto the advice stack, or pop the elements from its top. Advice map which is a key-value map where keys are words and values are vectors of field elements. The VM can copy values from the advice map onto the advice stack as well as insert new values into the advice map (e.g., from a region of memory). Merkle store which contain structured data reducible to Merkle paths. Some examples of such structures are: Merkle tree, Sparse Merkle Tree, and a collection of Merkle paths. The VM can request Merkle paths from the Merkle store, as well as mutate it by updating or merging nodes contained in the store. The prover initializes the advice provider prior to executing a program, and from that point on the advice provider is manipulated solely by executing operations on the VM.","breadcrumbs":"Introduction » Overview » Nondeterministic inputs","id":"10","title":"Nondeterministic inputs"},"100":{"body":"Consider the following program, where a0,...,ai, b0,...,bj etc. represent individual operations: a_0, ..., a_i\nif.true b_0, ..., b_j\nelse c_0, ..., c_k while.true d_0, ..., d_n end e_0, ..., e_m\nend\nf_0, ..., f_l A MAST for this program would look as follows: mast_of_program Execution of this program would proceed as follows: The VM will start execution at the root of the program which is block B5. Since, B5 is a join block , the VM will attempt to execute block B4 first, and only after that execute block f. Block B4 is also a join block , and thus, the VM will execute block a by executing operations a0,...,ai in sequence, and then execute block B3. Block B3 is a split block , and thus, the VM will pop the value off the top of the stack. If the popped value is 1, operations from block b will be executed in sequence. If the popped value is 0, then the VM will attempt to execute block B2. B2 is a join block , thus, the VM will try to execute block B1 first, and then execute operations from block e. Block B1 is also a join_block , and thus, the VM will first execute all operations in block c, and then will attempt to execute block B0. Block B0 is a loop block, thus, the VM will pop the value off the top of the stack. If the pooped value is 1, the VM will execute the body of the loop defined by block d. If the popped value is 0, the VM will not execute block d and instead will move up the tree executing first block e, then f. If the VM does enter the loop, then after operation dn is executed, the VM will pop the value off the top of the stack again. If the popped value is 1, the VM will execute block d again, and again until the top of the stack becomes 0. Once the top of the stack becomes 0, the VM will exit the loop and will move up the tree executing first block e, then f.","breadcrumbs":"Design » Programs » Program example","id":"100","title":"Program example"},"101":{"body":"Every Miden VM program can be reduced to a unique hash value. Specifically, it is infeasible to find two Miden VM programs with distinct semantics which hash to the same value. Padding a program with NOOPs does not change a program's execution semantics, and thus, programs which differ only in the number and/or placement of NOOPs may hash to the same value, although in most cases padding with NOOP should not affect program hash. To prevent program hash collisions we implement domain separation across the variants of control blocks. We define the domain value to be the opcode of the operation that initializes the control block. Below we denote hash to be an arithmetization-friendly hash function with 4-element output and capable of absorbing 8 elements in a single permutation. The hash domain is specified as the subscript of the hash function and its value is used to populate the second capacity register upon initialization of control block hashing - hashdomain(a,b). The hash of a join block is computed as hashjoin(a,b), where a and b are hashes of the code block being joined. The hash of a split block is computed as hashsplit(a,b), where a is a hash of a code block corresponding to the true branch of execution, and b is a hash of a code block corresponding to the false branch of execution. The hash of a loop block is computed as hashloop(a,0), where a is a hash of a code block corresponding to the loop body. The hash of a call block is computed as hashcall(a,0), where a is a hash of a program of which the VM is aware. The hash of a syscall block is computed as hashsyscall(a,0), where a is a hash of a program belonging to the kernel against which the code was compiled. The hash of a dyn block is set to a constant, so it is the same for all dyn blocks. It does not depend on the hash of the dynamic child. This constant is computed as the RPO hash of two empty words ([ZERO, ZERO, ZERO, ZERO]) using a domain value of DYN_DOMAIN, where DYN_DOMAIN is the op code of the Dyn operation. The hash of a span block is computed as hash(a1,...,ak), where ai is the ith batch of operations in the span block. Each batch of operations is defined as containing 8 field elements, and thus, hashing a k-batch span block requires k absorption steps. In cases when the number of operations is insufficient to fill the last batch entirely, NOOPs are appended to the end of the last batch to ensure that the number of operations in the batch is always equal to 8.","breadcrumbs":"Design » Programs » Program hash computation","id":"101","title":"Program hash computation"},"102":{"body":"Miden VM program decoder is responsible for ensuring that a program with a given MAST root is executed by the VM. As the VM executes a program, the decoder does the following: Decodes a sequence of field elements supplied by the prover into individual operation codes (or opcodes for short). Organizes the sequence of field elements into code blocks, and computes the hash of the program according to the methodology described here . At the end of program execution, the decoder outputs the computed program hash. This hash binds the sequence of opcodes executed by the VM to a program the prover claims to have executed. The verifier uses this hash during the STARK proof verification process to verify that the proof attests to a correct execution of a specific program (i.e., the prover didn't claim to execute program A while in fact executing a different program B). The sections below describe how Miden VM decoder works. Throughout these sections we make the following assumptions: An opcode requires 7 bits to represent. An immediate value requires one full field element to represent. A NOOP operation has a numeric value of 0, and thus, can be encoded as seven zeros. Executing a NOOP operation does not change the state of the VM, but it does advance operation counter, and may affect program hash.","breadcrumbs":"Design » Program decoder » Miden VM Program decoder","id":"102","title":"Miden VM Program decoder"},"103":{"body":"Miden VM programs consist of a set of code blocks organized into a binary tree. The leaves of the tree contain linear sequences of instructions, and control flow is defined by the internal nodes of the tree. Managing control flow in the VM is accomplished by executing control flow operations listed in the table below. Each of these operations require exactly one VM cycle to execute. Operation Description JOIN Initiates processing of a new Join block . SPLIT Initiates processing of a new Split block . LOOP Initiates processing of a new Loop block . REPEAT Initiates a new iteration of an executing loop. SPAN Initiates processing of a new Span block . RESPAN Initiates processing of a new operation batch within a span block. CALL Initiates processing of a new Call block . SYSCALL Initiates processing ofa new Syscall block . END Marks the end of a program block. HALT Marks the end of the entire program. Let's consider a simple program below: begin> !mem\n7: [1, 2, 0, 3]\n8: [5, 7, 3, 32]\n9: [9, 10, 2, 0] If the memory is not yet been initialized: >> !mem\nThe memory has not been initialized yet","breadcrumbs":"Development tooling » REPL » !mem","id":"29","title":"!mem"},"3":{"body":"In the coming months we plan to finalize the design of the VM and implement support for the following features: Recursive proofs. Miden VM will soon be able to verify a proof of its own execution. This will enable infinitely recursive proofs, an extremely useful tool for real-world applications. Better debugging. Miden VM will provide a better debugging experience including the ability to place breakpoints, better source mapping, and more complete program analysis info. Faulty execution. Miden VM will support generating proofs for programs with faulty execution (a notoriously complex task in ZK context). That is, it will be possible to prove that execution of some program resulted in an error.","breadcrumbs":"Introduction » Planned features","id":"3","title":"Planned features"},"30":{"body":"The !mem[addr] command prints out memory contents at the address specified by addr. If the addr has been initialized: >> !mem[9]\n9: [9, 10, 2, 0] If the addr has not been initialized: >> !mem[87]\nMemory at address 87 is empty","breadcrumbs":"Development tooling » REPL » !mem[addr]","id":"30","title":"!mem[addr]"},"31":{"body":"The !undo command reverts to the previous state of the stack and memory by dropping off the last executed assembly instruction from the program. One could use !undo as often as they want to restore the state of a stack and memory n instructions ago (provided there are n instructions in the program). The !undo command will result in an error if no remaining instructions are left in the Miden program. >> push.1 push.2 push.3\n>> push.4\n>> !stack\n4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 >> push.5\n>> !stack\n5 4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 >> !undo\n4 3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 >> !undo\n3 2 1 0 0 0 0 0 0 0 0 0 0 0 0 0","breadcrumbs":"Development tooling » REPL » !undo","id":"31","title":"!undo"},"32":{"body":"In the following sections, we provide developer-focused documentation useful to those who want to develop on Miden VM or build compilers from higher-level languages to Miden VM. This documentation consists of two high-level sections: Miden assembly which provides a detailed description of Miden assembly language, which is the native language of Miden VM. Miden Standard Library which provides descriptions of all procedures available in Miden Standard Library. For info on how to run programs on Miden VM, please refer to the usage section in the introduction.","breadcrumbs":"User Documentation » User Documentation","id":"32","title":"User Documentation"},"33":{"body":"Miden assembly is a simple, low-level language for writing programs for Miden VM. It stands just above raw Miden VM instruction set, and in fact, many instructions of Miden assembly map directly to raw instructions of Miden VM. Before Miden assembly can be executed on Miden VM, it needs to be compiled into a Program MAST (Merkelized Abstract Syntax Tree) which is a binary tree of code blocks each containing raw Miden VM instructions. assembly_to_VM As compared to raw Miden VM instructions, Miden assembly has several advantages: Miden assembly is intended to be a more stable external interface for the VM. That is, while we plan to make significant changes to the underlying VM to optimize it for stability, performance etc., we intend to make very few breaking changes to Miden assembly. Miden assembly natively supports control flow expressions which the assembler automatically transforms into a program MAST. This greatly simplifies writing programs with complex execution logic. Miden assembly supports macro instructions . These instructions expand into short sequences of raw Miden VM instructions making it easier to encode common operations. Miden assembly supports procedures . These are stand-alone blocks of code which the assembler inlines into program MAST at compile time. This improves program modularity and code organization. The last two points also make Miden assembly much more concise as compared to the raw program MAST. This may be important in the blockchain context where pubic programs need to be stored on chain.","breadcrumbs":"User Documentation » Miden Assembly » Miden Assembly","id":"33","title":"Miden Assembly"},"34":{"body":"In this document we use the following terms and notations: p is the modulus of the VM's base field which is equal to 264−232+1. A binary value means a field element which is either 0 or 1. Inequality comparisons are assumed to be performed on integer representations of field elements in the range [0,p). Throughout this document, we use lower-case letters to refer to individual field elements (e.g., a). Sometimes it is convenient to describe operations over groups of elements. For these purposes we define a word to be a group of four elements. We use upper-case letters to refer to words (e.g., A). To refer to individual elements within a word, we use numerical subscripts. For example, a0 is the first element of word A, b3 is the last element of word B, etc.","breadcrumbs":"User Documentation » Miden Assembly » Terms and notations","id":"34","title":"Terms and notations"},"35":{"body":"The design of Miden assembly tries to achieve the following goals: Miden assembly should be an easy compilation target for high-level languages. Programs written in Miden assembly should be readable, even if the code is generated by a compiler from a high-level language. Control flow should be easy to understand to help in manual inspection, formal verification, and optimization. Compilation of Miden assembly into Miden program MAST should be as straight-forward as possible. Serialization of Miden assembly into a binary representation should be as compact and as straight-forward as possible. In order to achieve the first goal, Miden assembly exposes a set of native operations over 32-bit integers and supports linear read-write memory. Thus, from the stand-point of a higher-level language compiler, Miden VM can be viewed as a regular 32-bit stack machine with linear read-write memory. In order to achieve the second and third goals, Miden assembly facilitates flow control via high-level constructs like while loops, if-else statements, and function calls with statically defined targets. Thus, for example, there are no explicit jump instructions. In order to achieve the fourth goal, Miden assembly retains direct access to the VM stack rather than abstracting it away with higher-level constructs and named variables. Lastly, in order to achieve the fifth goal, each instruction of Miden assembly can be encoded using a single byte. The resulting byte-code is simply a one-to-one mapping of instructions to their binary values.","breadcrumbs":"User Documentation » Miden Assembly » Design goals","id":"35","title":"Design goals"},"36":{"body":"A Miden assembly program is just a sequence of instructions each describing a specific directive or an operation. You can use any combination of whitespace characters to separate one instruction from another. In turn, Miden assembly instructions are just keywords which can be parameterized by zero or more parameters. The notation for specifying parameters is keyword.param1.param2 - i.e., the parameters are separated by periods. For example, push.123 instruction denotes a push operation which is parameterized by value 123. Miden assembly programs are organized into procedures. Procedures, in turn, can be grouped into modules.","breadcrumbs":"User Documentation » Miden Assembly » Code Organization » Code organization","id":"36","title":"Code organization"},"37":{"body":"A procedure can be used to encapsulate a frequently-used sequence of instructions which can later be invoked via a label. A procedure must start with a proc.