Polygon zkEVM可验证计算简单状态机示例

Next we show the arithmetization process of a more complex but yet simple state machine. Unlike the Fibonacci state machine, our simple state machine transitions from one state to the next in response to certain external instructions. See Figure 1 below, for such a state machine, with registries A \texttt{A} A and B \texttt{B} B, and a state ( A i , B i ) \big(\texttt{A}^{\texttt{i}},\texttt{B}^{\texttt{i}}\big) (Ai,Bi) that changes to another state ( A i+2 , B i+2 ) \big(\texttt{A}^{\texttt{i+2}},\texttt{B}^{\texttt{i+2}}\big) (Ai+2,Bi+2) in accordance to two instructions, Instruction i \texttt{Instruction}^{\texttt{i}} Instructioni and Instruction i+1 \texttt{Instruction}^{\texttt{i+1}} Instructioni+1.

Polygon zkEVM可验证计算简单状态机示例_第1张图片

Figure 1: A State Machine Receiving Instructions

In the context of the zkProver, these instructions are written as zk-Assembly (zkASM) codes, and stored in a ROM in JSON-format.

State Machine Instructions

Suppose the above simple state machine receives an input, together with the following execution instruction, Instruction 1 \texttt{Instruction}^{\texttt{1}} Instruction1, written in Assembly.

Table 1: Instruction^1 written in zk-Assembly

  Instruction 1 line   1 $ { g e t I n p u t ( ) } = > A line   2 3 = > B line   3 : A D D line   4 0 = > A , B \begin{array}{|l|c|} \hline \texttt{ } & \texttt{Instruction}^{\texttt{1}} \\ \hline \texttt{line 1} & \mathtt{\$\{getInput()\} => A}\\ \hline \texttt{line 2} & \mathtt{3 => B} \\ \hline \texttt{line 3} & \mathtt{:ADD} \\ \hline \texttt{line 4} & \mathtt{0 => A,B} \\ \hline \end{array}  line 1line 2line 3line 4Instruction1${getInput()}=>A3=>B:ADD0=>A,B

In accordance with each line of Instruction 1 \texttt{Instruction}^{\texttt{1}} Instruction1, the state machine executor must;

  • line   1 \texttt{line 1} line 1: Get a free input value and move it into register A \texttt{A} A.
  • line   2 \texttt{line 2} line 2: Move the value 3 \mathtt{3} 3 into register B \mathtt{B} B.
  • line   3 \texttt{line 3} line 3: Compute the sum of registry values A \mathtt{A} A and B \mathtt{B} B, and save the output into register A \mathtt{A} A.
  • line   4 \texttt{line 4} line 4: Set the registers A \mathtt{A} A and B \mathtt{B} B to the value 0 \mathtt{0} 0.

For a free input value of 7 7 7, the corresponding state transitions can be recorded in a table as follows;

Table 2: Record of all State Changes

  Instruction 1 f r e e A A ′ B B ′ line   1 $ { g e t I n p u t ( ) } = > A 7 0 7 0 0 line   2 3 = > B 0 7 7 0 3 line   3 : A D D 0 7 10 3 3 line   4 0 = > A , B 0 10 0 3 0 \begin{array}{|l|c|c|c|c|c|c|} \hline \texttt{ } & \texttt{Instruction}^{\texttt{1}} & \mathtt{free} & \mathtt{A} & \mathtt{A'} & \mathtt{B} & \mathtt{B'} \\ \hline \texttt{line 1} & \mathtt{\$\{getInput()\} => A} & 7 & 0 & 7 & 0 & 0 \\ \hline \texttt{line 2} & \mathtt{3 => B} & 0 & 7 & 7 & 0 & 3 \\ \hline \texttt{line 3} & \mathtt{:ADD} & 0 & 7 & 10 & 3 & 3 \\ \hline \texttt{line 4} & \mathtt{0 => A,B} & 0 & 10 & 0 & 3 & 0 \\ \hline \end{array}  line 1line 2line 3line 4Instruction1${getInput()}=>A3=>B:ADD0=>A,Bfree7000A07710A77100B0033B0330

Note that A ′ \mathtt{A'} A and B ′ \mathtt{B'} B denote the next state of the registers A \mathtt{A} A and B \mathtt{B} B, respectively.

Observe also that, each line of Instruction 1 \texttt{Instruction}^{\texttt{1}} Instruction1 does not always affect all register values. Since every register is initialised to 0 \mathtt{0} 0 at the start, the state transitions are such that,

  • line   1 \texttt{line 1} line 1 only affects two registers; f r e e \mathtt{free} free and A ′ \mathtt{A'} A.
  • line   2 \texttt{line 2} line 2 affects the register B ′ \mathtt{B'} B alone. Any other state change is due to the rules and the logic of the state machine (i.e., changes in registers; f r e e \mathtt{free} free and A \mathtt{A} A).
  • line   3 \texttt{line 3} line 3 affects the register A ′ \mathtt{A'} A alone. Again, the state change in register B \mathtt{B} B is due to the state machine’s rules and logic.
  • line   4 \texttt{line 4} line 4 affects only two registers; A ′ \mathtt{A'} A and B ′ \mathtt{B'} B. The state change in register A \mathtt{A} A is also due to the rules and the logic of the state machine.

Computational Trace

Recall that the intention with developing these state machines is not only to carry out computations, but to also ensure that correctness of these computations is verifiable. In addition, verification must be achievable even by users with modest computer power. That said, keeping record of computations, as seen in Table 2 above, is not preferable for verification purposes, because the registry values can be very large for some state machines. And thus, defeating the ultimate purpose and aim of our rollup.

One therefore needs a way to keep track of all the computations and their correct execution, without requiring excessive memory. This is achieved by utilising the computational trace.

For our verification purposes, the computational trace does not capture the actual state values of each state transition, but uses selectors and setters to keep record of whether registry values have been altered (during each state transition) in a way that tallies with the received instructions.

Like switches that can either be ON or OFF, selectors and setters can also be either 1 \mathtt{1} 1 or 0 \mathtt{0} 0.

Rule for the inFree \texttt{inFree} inFree selector: Record inFree \texttt{inFree} inFree as 1 \mathtt{1} 1 only if the value of the register free \texttt{free} free is non-zero.

Rule for selectors { setX } \{\texttt{setX}\} {setX}: Each selector setX \texttt{setX} setX is recorded;

  • As the value 1 \mathtt{1} 1, if the value of the corresponding registry X \texttt{X} X was involved in (or contributed to) the computation,
  • Otherwise, selX \texttt{selX} selX is recorded as the value 0 \mathtt{0} 0.

Rule for setters { setY } \{\texttt{setY}\} {setY}: Each setter setY \texttt{setY} setY is recorded;

  • As the value 1 \mathtt{1} 1, if the corresponding registry value Y \texttt{Y} Y was altered by the instruction,
  • Or, as the value 0 \mathtt{0} 0, otherwise.

The computational trace therefore consists mostly of bits, instead of large registry values.

In the zkEVM context, the computational trace is stored as a lookup table in the ROM of the relevant state machine.

Example (Computational Trace)

Take as an example, Instruction 1 \texttt{Instruction}^{\texttt{1}} Instruction1 above. Set selectors selA \texttt{selA} selA, selB \texttt{selB} selB and inFree \texttt{inFree} inFree for the registers A \texttt{A} A, B \texttt{B} B and free \texttt{free} free, respectively. And, setters setA \texttt{setA} setA and setB \texttt{setB} setB for the registers A ′ \mathtt{A'} A and B ′ \mathtt{B'} B, respectively.

As discussed above;

  • The register values, f r e e \mathtt{free} free and A ′ \mathtt{A'} A, were changed in line   1 \texttt{line 1} line 1. Therefore, only selector inFree \texttt{inFree} inFree and setter setA \texttt{setA} setA are recorded as 1 \mathtt{1} 1.
  • The register values B ′ \mathtt{B'} B, f r e e \mathtt{free} free and A \mathtt{A} A were changed in line   2 \texttt{line 2} line 2. But, only setter setB \texttt{setB} setB is recorded as 1 \mathtt{1} 1 because it is the only change the instruction effected.
  • The register values A ′ \mathtt{A'} A and B \mathtt{B} B were changed in line   3 \texttt{line 3} line 3. So, setter setA \texttt{setA} setA is recorded as 1 \mathtt{1} 1. But since register values A \texttt{A} A and B \texttt{B} B were involved in the computation in line   3 \texttt{line 3} line 3, they are also recorded as 1 \mathtt{1} 1.
  • The register values A ′ \mathtt{A'} A, B ′ \mathtt{B'} B and A \mathtt{A} A were changed in line   4 \texttt{line 4} line 4. Consequently, only setters setA \texttt{setA} setA and setB \texttt{setB} setB are recorded as 1 \mathtt{1} 1.

The computational trace after executing Instruction 1 \texttt{Instruction}^{\texttt{1}} Instruction1 is as reflected in Table 3 below.

Table 3: Computational Trace for Instruction^1

  Instruction 1 f r e e setB setA inFree selB selA A A ′ B B ′ line   1 $ { g e t I n p u t ( ) } = > A 7 0 1 1 0 0 0 7 0 0 line   2 3 = > B 0 1 0 0 0 0 7 7 0 3 line   3 : A D D 0 0 1 0 1 1 7 10 3 3 line   4 0 = > A , B 0 1 1 0 0 0 10 0 3 0 \begin{array}{|l|c|c|c|c|c|c|c|c|c|c|c|} \hline \texttt{ } & \texttt{Instruction}^{\texttt{1}} & \mathtt{free} & \texttt{setB} & \texttt{setA} & \texttt{inFree} & \texttt{selB} & \texttt{selA} & \mathtt{A} & \mathtt{A'} & \mathtt{B} & \mathtt{B'} \\ \hline \texttt{line 1} & \mathtt{\$\{getInput()\} => A} & 7 & 0 & 1 & 1 & 0 & 0 & 0 & 7 & 0 & 0 \\ \hline \texttt{line 2} & \mathtt{3 => B} & 0 & 1 & 0 & 0 & 0 & 0 & 7 & 7 & 0 & 3 \\ \hline \texttt{line 3} & \mathtt{:ADD} & 0 & 0 & 1 & 0 & 1 & 1 & 7 & 10 & 3 & 3 \\ \hline \texttt{line 4} & \mathtt{0 => A,B} & 0 & 1 & 1 & 0 & 0 & 0 & 10 & 0 & 3 & 0 \\ \hline \end{array}  line 1line 2line 3line 4Instruction1${getInput()}=>A3=>B:ADD0=>A,Bfree7000setB0101setA1011inFree1000selB0010selA0010A07710A77100B0033B0330

Arithmetic Constraints

Next we create a proper set of arithmetic constraints required in proving correctness of execution. Similar to the Fibonacci SM, where each state had to conform to polynomial identities and each polynomial identity was nothing but an algebraic relation between two consecutive states, our executor SM also needs such algebraic relations. These algebraic relations are also called arithmetic constraints.

In order to fully express the relations between the next values of registries A \texttt{A} A and B \texttt{B} B as a linear combination of the current registry values, auxiliary registers and selectors need to be added.

This is shown in Figure 2 below, as an algebraic processor of sorts.

Polygon zkEVM可验证计算简单状态机示例_第2张图片

Figure 2: The State Machine as an Algebraic Processor

The notation used in Figure 2 is as follows,

a) i n F r e e i ∈ { 0 , 1 } \mathtt{inFree}^i \in \{0,1\} inFreei{0,1} indicates whether f r e e i \mathtt{free^i} freei is included in the linear combination or not.

b) s e t X i ∈ { 0 , 1 } \mathtt{setX}^i \in \{0,1\} setXi{0,1} indicates whether the result of the linear combination was moved into X i + 1 \mathtt{X^{i+1}} Xi+1 or not.

c) f r e e i \mathtt{free}^i freei carries inputs freely chosen in order to execute the program.

d) c o n s t i \mathtt{const}^i consti carries fixed values moved into specified registers as per instructions received.
  \text{ }  

Introducing new auxiliary registers results in the following extended table.

   Instruction 1 line   1 $ { g e t I n p u t ( ) } = > A line   2 3 = > B line   3 : A D D line   4 0 = > A , B free const setB setA inFree selB selA 7 0 0 1 1 0 0 0 3 1 0 0 0 0 0 0 0 1 0 1 1 0 0 1 1 0 0 0 A A ′ B B ′ 0 7 0 0 7 7 0 3 7 10 3 3 10 0 3 0 \begin{array}{|l|c|} \hline \texttt{ \ } & \texttt{Instruction}^{\texttt{1}}\\ \hline \texttt{line 1} & \mathtt{\$\{getInput()\} => A}\\\hline \texttt{line 2} & \mathtt{3 => B}\\\hline \texttt{line 3} & \mathtt{:ADD}\\\hline \texttt{line 4} & \mathtt{0 => A,B}\\\hline \end{array} \hspace{0.1cm} \begin{array}{|c|c|c|c|c|c|c|c|} \hline \texttt{free} & \texttt{const} & \texttt{setB} & \texttt{setA} & \texttt{inFree} & \texttt{selB} & \texttt{selA}\\\hline 7 & 0 & 0 & 1 & 1 & 0 & 0\\\hline 0 & 3 & 1 & 0 & 0 & 0 & 0\\\hline 0 & 0 & 0 & 1 & 0 & 1 & 1\\\hline 0 & 0 & 1 & 1 & 0 & 0 & 0\\\hline \end{array} \hspace{0.1cm} \begin{array}{|c|c|c|c|} \hline \mathtt{A} & \mathtt{A'} & \mathtt{B} & \mathtt{B'}\\\hline 0 & 7 & 0 & 0\\\hline 7 & 7 & 0 & 3\\\hline 7 & 10 & 3 & 3\\\hline 10 & 0 & 3 & 0\\\hline \end{array}   line 1line 2line 3line 4Instruction1${getInput()}=>A3=>B:ADD0=>A,Bfree7000const0300setB0101setA1011inFree1000selB0010selA0010A07710A77100B0033B0330

Henceforth, the relations between the states of the registries can be expressed algebraically as follows:

A i + 1 = A i + s e t A i ⋅ ( s e l A i ⋅ A i + s e l B i ⋅ B i + i n F r e e i ⋅ f r e e i + c o n s t i − A i ) , B i + 1 = B i + s e t B i ⋅ ( s e l A i ⋅ A i + s e l B i ⋅ B i + i n F r e e i ⋅ f r e e i + c o n s t i − B i ) . \begin{aligned} &\mathtt{A}^{i+1} = \mathtt{A}^i + \mathtt{setA}^i \cdot (\mathtt{selA}^i \cdot \mathtt{A}^i + \mathtt{selB}^i \cdot \mathtt{B^i} + \mathtt{inFree}^i \cdot \mathtt{free}^i + \mathtt{const}^i - \mathtt{A}^i), \\ &\mathtt{B}^{i+1} = \mathtt{B}^i + \mathtt{setB}^i \cdot (\mathtt{selA}^i \cdot \mathtt{A}^i + \mathtt{selB}^i \cdot \mathtt{B}^i + \mathtt{inFree}^i \cdot \mathtt{free}^i + \mathtt{const}^i - \mathtt{B}^i).\\ \end{aligned} Ai+1=Ai+setAi(selAiAi+selBiBi+inFreeifreei+constiAi),Bi+1=Bi+setBi(selAiAi+selBiBi+inFreeifreei+constiBi).

Polynomial Constraints

Let’s represent the states of these registries for four steps as polynomials A , B ∈ Z p [ x ] \mathtt{A}, \mathtt{B} \in \mathbb{Z}_p[x] A,BZp[x] evaluated on the subgroup H = { ω , ω 2 , ω 3 , ω 4 = 1 } H = \{\omega, \omega^2, \omega^3, \omega^4 = 1\} H={ω,ω2,ω3,ω4=1}, in order to produce a cyclic relation:

A ( x ω ) = A ( x ) + s e t A ( x ) ⋅ ( s e l A ( x ) ⋅ A ( x ) + s e l B ( x ) ⋅ B ( x ) + i n F r e e ( x ) ⋅ f r e e ( x ) + c o n s t ( x ) − A ( x ) ) , B ( x ω ) = B ( x ) + s e t B ( x ) ⋅ ( s e l A ( x ) ⋅ A ( x ) + s e l B ( x ) ⋅ B ( x ) + i n F r e e ( x ) ⋅ f r e e ( x ) + c o n s t ( x ) − B ( x ) ) . \begin{aligned} &\mathtt{A}(x\omega) = \mathtt{A}(x) + \mathtt{setA}(x) \cdot (\mathtt{selA}(x) \cdot \mathtt{A}(x) + \mathtt{selB}(x) \cdot \mathtt{B}(x) + \mathtt{inFree}(x) \cdot \mathtt{free}(x) + \mathtt{const}(x) - \mathtt{A}(x)), \\ &\mathtt{B}(x\omega) = \mathtt{B}(x) + \mathtt{setB}(x) \cdot (\mathtt{selA}(x) \cdot \mathtt{A}(x) + \mathtt{selB}(x) \cdot \mathtt{B}(x) + \mathtt{inFree}(x) \cdot \mathtt{free}(x) + \mathtt{const}(x) - \mathtt{B}(x)). \end{aligned} A(xω)=A(x)+setA(x)(selA(x)A(x)+selB(x)B(x)+inFree(x)free(x)+const(x)A(x)),B(xω)=B(x)+setB(x)(selA(x)A(x)+selB(x)B(x)+inFree(x)free(x)+const(x)B(x)).

Observe that the program is completely described by the constant (and public) polynomials s e l A ( x ) \mathtt{selA(x)} selA(x), s e l B ( x ) \mathtt{selB(x)} selB(x), s e t A ( x ) \mathtt{setA(x)} setA(x), s e t B ( x ) \mathtt{setB(x)} setB(x), i n F r e e ( x ) \mathtt{inFree(x)} inFree(x) and c o n s t ( x ) \mathtt{const(x)} const(x).

The polynomial f r e e ( x ) \mathtt{free}(x) free(x) can be public or committed and by changing this polynomial, we can proof different executions for different initial conditions for the same “program”.

In our previous program, we can provide a result of the execution by giving A ( ω 4 ) A(\omega^4) A(ω4).

Notice that the last instruction resets the states’ values and “glues” the last instruction with the first one, achieving a cycle.

Programs with Conditional Jumps

We are going to add the instruction J M P Z \mathtt{JMPZ} JMPZ to our assembly. J M P Z \mathtt{JMPZ} JMPZ jumps to a specified position in the program if the preceding state of the register A \mathtt{A} A is zero.

In the next program, J M P Z \mathtt{JMPZ} JMPZ will jump to position 5 5 5 if the previous result of A + B \mathtt{A + B} A+B (which is actually stored in the register A \mathtt{A} A) is 0 0 0:

Position Instruction 0 $ { g e t I n p u t ( ) } = > A 1 − 3 = > B 2 : A D D 3 : J M P Z ( 5 ) 4 : A D D 5 0 = > A , B \begin{array}{|c|l|} \hline \textbf{Position} & \texttt{Instruction} \\ \hline 0 & \mathtt{\$\{getInput()\} => A} \\ \hline 1 & \mathtt{-3 => B} \\ \hline 2 & \mathtt{:ADD} \\ \hline 3 & \mathtt{:JMPZ(5)} \\ \hline 4 & \mathtt{:ADD} \\ \hline 5 & \mathtt{0 => A, B} \\ \hline \end{array} Position012345Instruction${getInput()}=>A3=>B:ADD:JMPZ(5):ADD0=>A,B

Note: We will discuss later on how to introduce negative values into our program.

In programs with conditional jumps, our previous model will not work, because the flow of the program may vary depending on the values of the input.

As it can be seen next, with conditional jumps, the length of the execution trace is not constant (it depends on the free input):

Instruction f r e e A A ′ B B ′ $ { g e t I n p u t ( ) } = > A 7 0 7 0 0 − 3 = > B 0 7 7 0 − 3 : A D D 0 7 4 − 3 − 3 : J M P Z ( 5 ) 0 4 4 − 3 − 3 : A D D 0 4 1 − 3 − 3 0 = > A , B 0 1 0 − 3 0 \begin{array}{|l|c|c|c|c|c|} \hline \texttt{Instruction} & \mathtt{free} & \mathtt{A} & \mathtt{A'} & \mathtt{B} & \mathtt{B'} \\ \hline \mathtt{\$\{getInput()\} => A} & 7 & 0 & 7 & 0 & 0 \\ \hline \mathtt{-3 => B} & 0 & 7 & 7 & 0 & -3 \\ \hline \mathtt{:ADD} & 0 & 7 & 4 & -3 & -3 \\ \hline \mathtt{:JMPZ(5)} & 0 & 4 & 4 & -3 & -3 \\ \hline \mathtt{:ADD} & 0 & 4 & 1 & -3 & -3 \\ \hline \mathtt{0 => A, B} & 0 & 1 & 0 & -3 & 0 \\ \hline \end{array} Instruction${getInput()}=>A3=>B:ADD:JMPZ(5):ADD0=>A,Bfree700000A077441A774410B003333B033330

Instruction f r e e A A ′ B B ′ $ { g e t I n p u t ( ) } = > A 3 0 3 0 0 − 3 = > B 0 3 3 0 − 3 : A D D 0 3 0 − 3 − 3 : J M P Z ( 5 ) 0 0 0 − 3 − 3 0 = > A , B 0 0 0 − 3 0 \begin{array}{|l|c|c|c|c|c|} \hline \texttt{Instruction} & \mathtt{free} & \mathtt{A} & \mathtt{A'} & \mathtt{B} & \mathtt{B'} \\ \hline \mathtt{\$\{getInput()\} => A} & 3 & 0 & 3 & 0 & 0\\ \hline \mathtt{-3 => B} & 0 & 3 & 3 & 0 & -3\\ \hline \mathtt{:ADD} & 0 & 3 & 0 & -3 & -3\\ \hline \mathtt{:JMPZ(5)} & 0 & 0 & 0 & -3 & -3\\ \hline \mathtt{0 => A, B} & 0 & 0 & 0 & -3 & 0\\ \hline \end{array} Instruction${getInput()}=>A3=>B:ADD:JMPZ(5)0=>A,Bfree30000A03300A33000B00333B03330

The first execution is done in 6 steps, while the second is in 5 steps.

Managing Conditional Jumps

Now, let us introduce a new model to manage a program that contains conditional jumps.
Polygon zkEVM可验证计算简单状态机示例_第3张图片

To do this, we need to add the Program Counter (PC). The P C \mathtt{PC} PC is a special registry that contains the position of the instruction in the program being executed.

We use op i \texttt{op}^i opi as a shorthand for the linear combination of our state machine to simplify the forthcoming constraints:
o p i : = s e l A i ⋅ A i + s e l B i ⋅ B i + i n F r e e i ⋅ f r e e i + c o n s t i . \mathtt{op}^i :=\mathtt{selA}^i \cdot \mathtt{A}^i + \mathtt{selB}^i \cdot \mathtt{B^i} + \mathtt{inFree}^i \cdot \mathtt{free}^i + \mathtt{const}^i . opi:=selAiAi+selBiBi+inFreeifreei+consti.
Polygon zkEVM可验证计算简单状态机示例_第4张图片

The J M P Z \mathtt{JMPZ} JMPZ instruction will jump to the instruction addr i \texttt{addr}^i addri (specified by the J M P Z \mathtt{JMPZ} JMPZ instruction) if op i \texttt{op}^i opi is zero. Let us first develop some procedure to check if our operation is or not zero in Z p \mathbb{Z}_p Zp:

To check that a number in the field Z p \mathbb{Z}_p Zp is zero, we use the fact that a number a a a has a multiplicative inverse a − 1 a^{-1} a1 if and only if a ≠ 0 a \neq 0 a=0.

Using this fact, we use the following definition and constraint to do the i s Z e r o \mathtt{isZero} isZero check:

i s Z e r o i : = 1 − o p i ⋅ ( o p i ) − 1 , i s Z e r o i ⋅ o p i = 0. \begin{aligned} &\mathtt{isZero}^i := 1 - \mathtt{op}^i \cdot (\mathtt{op}^i)^{-1}, \\ &\mathtt{isZero}^i \cdot \mathtt{op}^i = 0. \end{aligned} isZeroi:=1opi(opi)1,isZeroiopi=0.

We can proof that the previous equations describe the desired check by case examination where a ≠ 0 a \neq 0 a=0
and α , β ∈ Z p \alpha, \beta \in \mathbb{Z}_p α,βZp:

o p i = 0 ,   ( o p i ) − 1 = α ,   i s Z e r o i = 1 \mathtt{op}^i = 0,~(\mathtt{op}^i)^{-1} = \alpha,~\mathtt{isZero}^i = 1 opi=0, (opi)1=α, isZeroi=1 passes the definition and constraint,

o p i = a ,   ( o p i ) − 1 = a − 1 ,   i s Z e r o i = 0 \mathtt{op}^i = a,~(\mathtt{op}^i)^{-1} = a^{-1},~\mathtt{isZero}^i = 0 opi=a, (opi)1=a1, isZeroi=0 passes the definition and constraint.

o p i = 0 ,   ( o p i ) − 1 = α ,   i s Z e r o i ≠ 1 \mathtt{op}^i = 0,~(\mathtt{op}^i)^{-1} = \alpha,~\mathtt{isZero}^i \neq 1 opi=0, (opi)1=α, isZeroi=1 does not pass the definition of i s Z e r o \mathtt{isZero} isZero.

o p i = a ,   ( o p i ) − 1 = β ,   i s Z e r o i ≠ 0 \mathtt{op}^i = a,~(\mathtt{op}^i)^{-1} = \beta,~\mathtt{isZero}^i \neq 0 opi=a, (opi)1=β, isZeroi=0 does not pass the definition and constraint,
either you consider β = 0 \beta = 0 β=0, β = a − 1 \beta = a^{-1} β=a1 or β ≠ a − 1 \beta \neq a^{-1} β=a1.

We can mix the two equations into just one constraint:
i s Z e r o i ⋅ o p i = 0 ,    i s Z e r o i = 1 − o p i ⋅ ( o p i ) − 1    →    ( 1 − o p i ⋅ ( o p i ) − 1 ) ⋅ o p i = 0. \mathtt{isZero}^i \cdot \mathtt{op}^i = 0,~~\mathtt{isZero}^i = 1 - \mathtt{op}^i \cdot (\mathtt{op}^i)^{-1}~~\rightarrow~~(1 - \mathtt{op}^i \cdot (\mathtt{op}^i)^{-1}) \cdot \mathtt{op}^i = 0. isZeroiopi=0,  isZeroi=1opi(opi)1    (1opi(opi)1)opi=0.

Let us introduce the following machinery to our setup in order to introduce jumps:
Polygon zkEVM可验证计算简单状态机示例_第5张图片

We add a selector jmpz i ∈ { 0 , 1 } \texttt{jmpz}^i \in \{0,1\} jmpzi{0,1} to our state machine to code the J M P Z \mathtt{JMPZ} JMPZ instruction and express the behaviour of the PC. Then, the set of constraints is the following:

o p i : = s e l A i ⋅ A i + s e l B i ⋅ B i + i n F r e e i ⋅ f r e e i + c o n s t i , P C i + 1 = P C i + 1 + j m p z i ⋅ ( 1 − o p i ⋅ ( o p i ) − 1 ) ⋅ ( a d d r i − P C i − 1 ) , ( 1 − o p i ⋅ ( o p i ) − 1 ) ⋅ o p i = 0. \begin{aligned} &\mathtt{op}^i := \mathtt{selA}^i \cdot \mathtt{A}^i + \mathtt{selB}^i \cdot \mathtt{B^i} + \mathtt{inFree}^i \cdot \mathtt{free}^i + \mathtt{const}^i , \\ &\mathtt{PC}^{i+1} = \mathtt{PC}^i + 1 + \mathtt{jmpz}^i \cdot (1 - \mathtt{op}^i \cdot (\mathtt{op}^i)^{-1}) \cdot (\mathtt{addr}^i - \mathtt{PC}^i - 1),\\ &(1 - \mathtt{op}^i \cdot (\mathtt{op}^i)^{-1}) \cdot \mathtt{op}^i = 0. \end{aligned} opi:=selAiAi+selBiBi+inFreeifreei+consti,PCi+1=PCi+1+jmpzi(1opi(opi)1)(addriPCi1),(1opi(opi)1)opi=0.

Observe that:

  1. If o p i ≠ 0 \mathtt{op}^i \neq 0 opi=0, then ( 1 − o p i ⋅ ( o p i ) − 1 ) = 0 (1 - \mathtt{op}^i \cdot (\mathtt{op}^i)^{-1}) = 0 (1opi(opi)1)=0 and hence P C i + 1 = P C i + 1 \mathtt{PC}^{i+1} = \mathtt{PC}^i + 1 PCi+1=PCi+1;
  2. If o p i = 0 \mathtt{op}^i = 0 opi=0, then ( 1 − o p i ⋅ ( o p i ) − 1 ) = 1 (1 - \mathtt{op}^i \cdot (\mathtt{op}^i)^{-1}) = 1 (1opi(opi)1)=1 and hence P C i + 1 = P C i + 1 + a d d r i − P C i − 1 = a d d r i \mathtt{PC}^{i+1} = \mathtt{PC}^i + 1 + \mathtt{addr}^i - \mathtt{PC}^i - 1 = \mathtt{addr}^i PCi+1=PCi+1+addriPCi1=addri.

This is exactly the wanted behaviour.

Next, we show the execution traces for the free inputs 7 and 3 respectively:

Instruction $ { g e t I n p u t ( ) } = > A − 3 = > B : A D D : J M P Z ( 5 ) : A D D 0 = > A , B , P C free const addr jmpz setB setA inFree selB selA op invOp 7 0 0 0 0 1 1 0 0 7 7 − 1 0 − 3 0 0 1 0 0 0 0 − 3 ( − 3 ) − 1 0 0 0 0 0 1 0 1 1 4 4 − 1 0 0 5 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1 1 0 0 0 1 1 1 0 0 0 0 0 P C P C ′ A A ′ B B ′ 0 1 0 7 0 0 1 2 7 7 0 − 3 2 3 7 4 − 3 − 3 3 4 4 4 − 3 − 3 4 5 4 1 − 3 − 3 5 0 1 0 − 3 0 \scriptsize \begin{array}{|l|} \hline \texttt{Instruction} \\ \hline \mathtt{\$\{getInput()\} => A} \\ \hline \mathtt{-3 => B} \\ \hline \mathtt{:ADD} \\ \hline \mathtt{:JMPZ(5)} \\ \hline \mathtt{:ADD} \\ \hline \mathtt{0 => A, B, PC} \\ \hline \end{array} \hspace{0.1cm} \begin{array}{|c|c|c|c|c|c|c|c|c|c|c|} \hline \texttt{free} & \textbf{const} & \texttt{addr} & \texttt{jmpz} & \texttt{setB} & \texttt{setA} & \texttt{inFree} & \texttt{selB} & \texttt{selA} & \texttt{op} & \texttt{invOp} \\ \hline 7 & 0 & 0 & 0 & 0 & 1 & 1 & 0 & 0 & 7 & 7^{-1} \\ \hline 0 & -3 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & -3 & (-3)^{-1} \\ \hline 0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 1 & \mathbf{4} & \mathbf{4^{-1}} \\ \hline 0 & 0 & 5 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ \hline 0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 1 & 1 & 1 \\ \hline 0 & 0 & 0 & 1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 \\ \hline \end{array} \hspace{0.1cm} \begin{array}{|c|c|c|c|c|c|} \hline \mathtt{PC} & \mathtt{PC'} & \mathtt{A} & \mathtt{A'} & \mathtt{B} & \mathtt{B'} \\ \hline 0 & 1 & 0 & 7 & 0 & 0\\ \hline 1 & 2 & 7 & 7 & 0 & -3\\ \hline 2 & 3 & 7 & 4 & -3 & -3\\ \hline 3 & 4 & 4 & 4 & -3 & -3\\ \hline 4 & 5 & 4 & 1 & -3 & -3\\ \hline 5 & 0 & 1 & 0 & -3 & 0\\ \hline \end{array} Instruction${getInput()}=>A3=>B:ADD:JMPZ(5):ADD0=>A,B,PCfree700000const030000addr000500jmpz000101setB010001setA101011inFree100000selB001010selA001010op734010invOp71(3)141010PC012345PC123450A077441A774410B003333B033330

Instruction $ { g e t I n p u t ( ) } = > A − 3 = > B : A D D : J M P Z ( 5 ) 0 = > A , B free const addr jmpz setB setA inFree selB selA op invOp 3 0 0 0 0 1 1 0 0 3 3 − 1 0 − 3 0 0 1 0 0 0 0 − 3 ( − 3 ) − 1 0 0 0 0 0 1 0 1 1 0 α 0 0 5 1 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 P C P C ′ A A ′ B B ′ 0 1 0 3 0 0 1 2 3 3 0 − 3 2 3 3 0 − 3 − 3 3 5 3 0 − 3 − 3 5 0 0 0 − 3 0 \scriptsize \begin{array}{|l|} \hline \texttt{Instruction} \\ \hline \mathtt{\$\{getInput()\} => A} \\ \hline \mathtt{-3 => B} \\ \hline \mathtt{:ADD} \\ \hline \mathtt{:JMPZ(5)} \\ \hline \mathtt{0 => A, B} \\ \hline \end{array} \hspace{0.1cm} \begin{array}{|c|c|c|c|c|c|c|c|c|c|c|c|} \hline \texttt{free} & \texttt{const} & \texttt{addr} & \texttt{jmpz} & \texttt{setB} & \texttt{setA} & \texttt{inFree} & \texttt{selB} & \texttt{selA} & \texttt{op} & \texttt{invOp} \\ \hline 3 & 0 & 0 & 0 & 0 & 1 & 1 & 0 & 0 & 3 & 3^{-1} \\ \hline 0 & -3 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & -3 & (-3)^{-1} \\ \hline 0 & 0 & 0 & 0 & 0 & 1 & 0 & 1 & 1 & \mathbf{ 0} & \mathbf{\alpha} \\ \hline 0 & 0 & 5 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ \hline 0 & 0 & 0 & 1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 \\ \hline \end{array} \hspace{0.1cm} \begin{array}{|c|c|c|c|c|c|} \hline \mathtt{PC} & \mathtt{PC'} & \mathtt{A} & \mathtt{A'} & \mathtt{B} & \mathtt{B'} \\ \hline 0 & 1 & 0 & 3 & 0 & 0\\ \hline 1 & 2 & 3 & 3 & 0 & -3\\ \hline 2 & 3 & 3 & 0 & -3 & -3\\ \hline 3 & 5 & 3 & 0 & -3 & -3\\ \hline 5 & 0 & 0 & 0 & -3 & 0\\ \hline \end{array} Instruction${getInput()}=>A3=>B:ADD:JMPZ(5)0=>A,Bfree30000const03000addr00050jmpz00011setB01001setA10101inFree10000selB00100selA00100op33000invOp31(3)1α00PC01235PC12350A03330A33000B00333B03330

Note that we use i n v O p \mathtt{invOp} invOp for the column containing the inverses of o p \mathtt{op} op.

Note also that the P C \mathtt{PC} PC turns to be an important registry when jumps are included in the set of possible instructions because jumps can modify the sequence of instructions that is executed also known as “the trace”.

Now, our polynomials are definitely not preprocessed, this is because the values of the table will not only depend on the program, but also on the free input values. Hence, we need to ensure that we are verifying the correct program.

Proving the Execution of the “Correct Program”

Up to now, we can prove that each instruction is correctly executed, but, how do we prove that we are executing the correct set of instructions, that is to say, that we are executing the “correct program”?
The solution seems obvious: Check that every executed instruction is some instruction in the program,
but how do we do this in a succinct manner?

To do so, we have to provide a codification for each instruction and then we will check that the codification of the execution’s instructions is included in the codification of the program’s instructions.

Let’s begin showing how to encode the constant values of our instructions. As a particular example, consider that we want to use signed integers of 4 bits (in the real machine, we will use an analogous 32 bits codification).
The four bit codification is shown next:

− 8 − 7 − 6 . . . − 2 − 1 0 1 2 . . . 6 7 8 1000 1001 1010 . . . 1110 1111 0000 0001 0010 . . . 0110 0111 1000 \begin{array}{|c|c|c|c|c|c|c|c|c|c|c|c|c|} \hline -8 & -7 & -6 & ... & -2 & -1 & 0 & 1 & 2 & ... & 6 & 7 & 8 \\ \hline 1000 & 1001 & 1010 & ... & 1110 & 1111 & 0000 & 0001 & 0010 & ... & 0110 & 0111 & 1000 \\ \hline \end{array} 810007100161010......2111011111000001000120010......601107011181000

Notice that with this arithmetic 8 = − 8 8=-8 8=8, which is a weird case that we discard, using only values from -7 to 7.
Then, we encode these values in elements of the field Z p \mathbb{Z}_p Zp:

− 7 − 6 . . . − 2 − 1 0 1 2 . . . 6 7 p − 7 p − 6 . . . p − 2 p − 1 0 1 2 . . . 6 7 \begin{array}{|c|c|c|c|c|c|c|c|c|c|c|} \hline -7 & -6 & ... & -2 & -1 & 0 & 1 & 2 & ...& 6 & 7 \\ \hline p-7 & p-6 & ... & p-2 & p-1 & 0 & 1 & 2 & ...& 6 & 7 \\ \hline \end{array} 7p76p6......2p21p1001122......6677

So, we have to enforce that c o n s t ( x ) ∈ { p − 7 , p − 6 , . . . , p − 2 , p − 1 , 0 , 1 , 2 , . . . , 6 , 7 } \mathsf{const}(x) \in \{p-7, p-6, ..., p-2, p-1, 0,1,2, ..., 6, 7\} const(x){p7,p6,...,p2,p1,0,1,2,...,6,7}.

We enforce the previous condition with the following equivalent inclusion:

c o n s t ( x ) + 7 ∈ { 0 , 1 , 2 , . . . , 14 } \mathsf{const}(x) + 7 \in \{0,1,2,...,14\} const(x)+7{0,1,2,...,14}

Hence, we will use c o n s t ( x ) + 7 \mathsf{const}(x) + 7 const(x)+7 in base 2 2 2 instead of c o n s t ( x ) \mathsf{const}(x) const(x) to encode our instruction, just to avoid the sum.

Let’s now explain how to encode every distinct instruction to be executed by the program:

I n s t r u c t i o n $ { g e t I n p u t ( ) } = > A − 3 = > B : A D D : J M P Z ( 5 ) : A D D 0 = > A , B , P C const+7 addr jmpz setB setA inFree selB selA instruction 7 0 0 0 1 1 0 0 0111.0000.001100 4 0 0 1 0 0 0 0 0100.0000.010000 7 0 0 0 1 0 1 1 0111.0000.001011 7 5 1 0 0 0 0 0 0111.0101.100000 7 0 0 0 1 0 1 1 0111.0000.001011 7 0 1 1 1 0 0 0 0111.0000.111000 \scriptsize \begin{array}{|c|l|} \hline \mathbf{Instruction} \\ \hline \mathtt{\$\{getInput()\} => A} \\ \hline \mathtt{-3 => B} \\ \hline \mathtt{:ADD} \\ \hline \mathtt{:JMPZ(5)} \\ \hline \mathtt{:ADD} \\ \hline \mathtt{0 => A, B, PC} \\ \hline \end{array} \hspace{0.1cm} \begin{array}{|c|c|c|c|c|c|c|c|c|c|c|} \hline \mathbf{\texttt{const+7}} & \texttt{addr} & \texttt{jmpz} & \texttt{setB} & \texttt{setA} & \texttt{inFree} & \texttt{selB} & \texttt{selA} & \texttt{instruction} \\ \hline \mathbf{ 7} & 0 & 0 & 0 & 1 & 1 & 0 & 0 & 0111.0000.001100 \\ \hline \mathbf{ 4} & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0100.0000.010000 \\ \hline \mathbf{ 7} & 0 & 0 & 0 & 1 & 0 & 1 & 1 & 0111.0000.001011\\ \hline \mathbf{ 7} & 5 & 1 & 0 & 0 & 0 & 0 & 0 & 0111.0101.100000 \\ \hline \mathbf{ 7} & 0 & 0 & 0 & 1 & 0 & 1 & 1 & 0111.0000.001011 \\ \hline \mathbf{ 7} & 0 & 1 & 1 & 1 & 0 & 0 & 0 & 0111.0000.111000 \\ \hline \end{array} Instruction${getInput()}=>A3=>B:ADD:JMPZ(5):ADD0=>A,B,PCconst+7747777addr000500jmpz000101setB010001setA101011inFree100000selB001010selA001010instruction0111.0000.0011000100.0000.0100000111.0000.0010110111.0101.1000000111.0000.0010110111.0000.111000

Observe that we have codified the instruction using the following rule:
instruction i : = 2 10 ⋅ ( const i + 7 ) + 2 6 ⋅ addr i + 2 5 ⋅ jmpz i + 2 4 ⋅ setB i + 2 3 ⋅ setA i + 2 2 ⋅ inFree i + 2 ⋅ selB i + selA i . \texttt{instruction}^i := 2^{10}\cdot(\texttt{const}^i + 7) + 2^6\cdot \texttt{addr}^i + 2^5\cdot \texttt{jmpz}^i + 2^4 \cdot \texttt{setB}^i + 2^3 \cdot \texttt{setA}^i + 2^2 \cdot \texttt{inFree}^i + 2 \cdot \texttt{selB}^i + \texttt{selA}^i. instructioni:=210(consti+7)+26addri+25jmpzi+24setBi+23setAi+22inFreei+2selBi+selAi.

That is, we are codifying it as the concatenated base 2 2 2 integer of all the values (in the order of appearance on the table).

Note that additionally, we will need to check that the selectors are binary and that addr \texttt{addr} addr is composed of 4 4 4 bits, i.e., addr i ∈ { 0 , 1 , … , 15 } \texttt{addr}^i \in \{0, 1, \dots, 15\} addri{0,1,,15}

Also observe that, when const i + 7 = 7 \texttt{const}^i+7 = 7 consti+7=7, this means that const i = 0 \texttt{const}^i = 0 consti=0, so the constant is not used in those cases.

Now, to prove the program, every instruction will be uniquely identified by its code and position in the program (we also use 4 bits in this example for the position).

We define the R O M \mathtt{ROM} ROM of the program as the sum between every instruction and the position in which it is defined:
ROM i : = 2 14 ⋅ position i + instruction i . \texttt{ROM}^i := 2^{14} \cdot \texttt{position}^i + \texttt{instruction}^i. ROMi:=214positioni+instructioni.

Observe that the R O M \mathtt{ROM} ROM uniquely identifies the program we want to verify and it is independent of the different possible executions.

The resulting R O M \mathtt{ROM} ROM of our program is the following:

position I n s t r u c t i o n 0 $ { g e t I n p u t ( ) } = > A 1 − 3 = > B 2 : A D D 3 : J M P Z ( 5 ) 4 : A D D 5 0 = > A , B , P C ROM 0000.0111.0000.001100 0001.0100.0000.010000 0010.0111.0000.001011 0011.0111.0101.100000 0100.0111.0000.001011 0101.0111.0000.111000 \begin{array}{|c|c|} \hline \texttt{position} & \mathbf{Instruction} \\ \hline 0 & \mathtt{\$\{getInput()\} => A} \\ \hline 1 & \mathtt{-3 => B} \\ \hline 2 & \mathtt{:ADD} \\ \hline 3 & \mathtt{:JMPZ(5)} \\ \hline 4 & \mathtt{:ADD} \\ \hline 5 & \mathtt{0 => A, B, PC} \\ \hline \end{array} \hspace{0.1cm} \begin{array}{|c|} \hline \texttt{ROM} \\ \hline 0000.0111.0000.001100 \\ \hline 0001.0100.0000.010000 \\ \hline 0010.0111.0000.001011\\ \hline 0011.0111.0101.100000 \\ \hline 0100.0111.0000.001011 \\ \hline 0101.0111.0000.111000 \\ \hline \end{array} position012345Instruction${getInput()}=>A3=>B:ADD:JMPZ(5):ADD0=>A,B,PCROM0000.0111.0000.0011000001.0100.0000.0100000010.0111.0000.0010110011.0111.0101.1000000100.0111.0000.0010110101.0111.0000.111000

We will encode the program trace using the PC:

P C 0 1 2 3 4 5 p o s i t i o n I n s t r u c t i o n 0 $ { g e t I n p u t ( ) } = > A 1 − 3 = > B 2 : A D D 3 : J M P Z ( 5 ) 4 : A D D 5 0 = > A , B , P C const+7 addr jmpz setB setA inFree selB selA 7 0 0 0 1 1 0 0 4 0 0 1 0 0 0 0 7 0 0 0 1 0 1 1 7 5 1 0 0 0 0 0 7 0 0 0 1 0 1 1 7 0 1 1 1 0 0 0 i n s T r a c e 0000.0111.0000.001100 0001.0100.0000.010000 0010.0111.0000.001011 0011.0111.0101.100000 0100.0111.0000.001011 0101.0111.0000.111000 \scriptsize \begin{array}{|c|c|c|c|c|c|} \hline \mathtt{PC} \\ \hline 0 \\ \hline 1 \\ \hline 2 \\ \hline 3 \\ \hline 4 \\ \hline 5 \\ \hline \end{array} \hspace{0.1cm} \begin{array}{|c|c|c|} \hline \mathtt{position} & \mathbf{Instruction} \\ \hline 0 & \mathtt{\$\{getInput()\} => A} \\ \hline 1 & \mathtt{-3 => B} \\ \hline 2 & \mathtt{:ADD} \\ \hline 3 & \mathtt{:JMPZ(5)} \\ \hline 4 & \mathtt{:ADD} \\ \hline 5 & \mathtt{0 => A, B, PC} \\ \hline \end{array} \hspace{0.1cm} \begin{array}{|c|c|c|c|c|c|c|c|c|} \hline \texttt{const+7} & \texttt{addr} & \texttt{jmpz} & \texttt{setB} & \texttt{setA} & \texttt{inFree} & \texttt{selB} & \texttt{selA} \\ \hline 7 & 0 & 0 & 0 & 1 & 1 & 0 & 0 \\ \hline 4 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ \hline 7 & 0 & 0 & 0 & 1 & 0 & 1 & 1 \\ \hline 7 & 5 & 1 & 0 & 0 & 0 & 0 & 0 \\ \hline 7 & 0 & 0 & 0 & 1 & 0 & 1 & 1 \\ \hline 7 & 0 & 1 & 1 & 1 & 0 & 0 & 0 \\ \hline \end{array} \hspace{0.1cm} \begin{array}{|c|c|c|c|c|c|} \hline \mathtt{insTrace} \\ \hline 0000.0111.0000.001100 \\ \hline 0001.0100.0000.010000 \\ \hline 0010.0111.0000.001011\\ \hline 0011.0111.0101.100000 \\ \hline 0100.0111.0000.001011 \\ \hline 0101.0111.0000.111000 \\ \hline \end{array} PC012345position012345Instruction${getInput()}=>A3=>B:ADD:JMPZ(5):ADD0=>A,B,PCconst+7747777addr000500jmpz000101setB010001setA101011inFree100000selB001010selA001010insTrace0000.0111.0000.0011000001.0100.0000.0100000010.0111.0000.0010110011.0111.0101.1000000100.0111.0000.0010110101.0111.0000.111000

P C 0 1 2 3 5 p o s i t i o n I n s t r u c t i o n 0 $ { g e t I n p u t ( ) } = > A 1 − 3 = > B 2 : A D D 3 : J M P Z ( 5 ) 4 0 = > A , B , P C const+7 addr jmpz setB setA inFree selB selA 7 0 0 0 1 1 0 0 4 0 0 1 0 0 0 0 7 0 0 0 1 0 1 1 7 5 1 0 0 0 0 0 7 0 1 1 1 0 0 0 i n s T r a c e 0000.0111.0000.001100 0001.0100.0000.010000 0010.0111.0000.001011 0011.0111.0101.100000 0101.0111.0000.111000 \scriptsize \begin{array}{|c|c|c|c|c|c|} \hline \mathtt{PC} \\ \hline 0 \\ \hline 1 \\ \hline 2 \\ \hline 3 \\ \hline 5 \\ \hline \end{array} \hspace{0.1cm} \begin{array}{|c|c|c|} \hline \mathtt{position} & \mathbf{Instruction} \\ \hline 0 & \mathtt{\$\{getInput()\} => A} \\ \hline 1 & \mathtt{-3 => B} \\ \hline 2 & \mathtt{:ADD} \\ \hline 3 & \mathtt{:JMPZ(5)} \\ \hline 4 & \mathtt{0 => A, B, PC} \\ \hline \end{array} \hspace{0.1cm} \begin{array}{|c|c|c|c|c|c|c|c|c|} \hline \texttt{const+7} & \texttt{addr} & \texttt{jmpz} & \texttt{setB} & \texttt{setA} & \texttt{inFree} & \texttt{selB} & \texttt{selA} \\ \hline 7 & 0 & 0 & 0 & 1 & 1 & 0 & 0 \\ \hline 4 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ \hline 7 & 0 & 0 & 0 & 1 & 0 & 1 & 1 \\ \hline 7 & 5 & 1 & 0 & 0 & 0 & 0 & 0 \\ \hline 7 & 0 & 1 & 1 & 1 & 0 & 0 & 0 \\ \hline \end{array} \hspace{0.1cm} \begin{array}{|c|c|c|c|c|c|} \hline \mathtt{insTrace} \\ \hline 0000.0111.0000.001100 \\ \hline 0001.0100.0000.010000 \\ \hline 0010.0111.0000.001011\\ \hline 0011.0111.0101.100000 \\ \hline 0101.0111.0000.111000 \\ \hline \end{array} PC01235position01234Instruction${getInput()}=>A3=>B:ADD:JMPZ(5)0=>A,B,PCconst+774777addr00050jmpz00011setB01001setA10101inFree10000selB00100selA00100insTrace0000.0111.0000.0011000001.0100.0000.0100000010.0111.0000.0010110011.0111.0101.1000000101.0111.0000.111000

Recall that our main question was: How do we actually check correctness in an efficient manner?

We can achieve it with the Plookup protocol. So, to check that the correct program is being executed, we simply have to use Plookup to determine if:

i n s T r a c e ( x ) ⊂ R O M ( x ) \mathsf{insTrace(x)} \subset \mathsf{ROM(x)} insTrace(x)ROM(x)

In words, the trace being executed is an execution of the actual program if the instruction trace is contained in the ROM of the program.

Identities to Prove an Execution Trace

As a summary, we have seen that the following set of identities are used to define our program:

A ( x ω ) = A ( x ) + s e t A ( x ) ⋅ ( o p ( x ) − A ( x ) ) , B ( x ω ) = B ( x ) + s e t B ( x ) ⋅ ( o p ( x ) − B ( x ) ) , P C ( x ω ) = P C ( x ) + 1 + j m p z ( x ) ⋅ ( 1 − o p ( x ) ⋅ i n v O p ( x ) ) ⋅ ( a d d r ( x ) − P C ( x ) − 1 ) , ( 1 − o p ( x ) ⋅ i n v O p ( x ) ) ⋅ o p ( x ) = 0. \begin{aligned} &\mathsf{A}(x\omega) = \mathsf{A}(x) + \mathsf{setA}(x) \cdot (\mathsf{op}(x) - \mathsf{A}(x)), \\ &\mathsf{B}(x\omega) = \mathsf{B}(x) + \mathsf{setB}(x) \cdot (\mathsf{op}(x) - \mathsf{B}(x)), \\ &\mathsf{PC}(x\omega) = \mathsf{PC}(x) + 1 + \mathsf{jmpz}(x) \cdot (1 - \mathsf{op}(x) \cdot \mathsf{invOp}(x)) \cdot (\mathsf{addr}(x) - \mathsf{PC}(x) - 1), \\ &(1 - \mathsf{op}(x) \cdot \mathsf{invOp}(x)) \cdot \mathsf{op}(x) = 0. \end{aligned} A(xω)=A(x)+setA(x)(op(x)A(x)),B(xω)=B(x)+setB(x)(op(x)B(x)),PC(xω)=PC(x)+1+jmpz(x)(1op(x)invOp(x))(addr(x)PC(x)1),(1op(x)invOp(x))op(x)=0.

With the following definition:
o p ( x ) : = s e l A ( x ) ⋅ A ( x ) + s e l B ( x ) ⋅ B ( x ) + i n F r e e ( x ) ⋅ f r e e ( x ) + c o n s t ( x ) . \mathsf{op}(x) := \mathsf{selA}(x) \cdot \mathsf{A}(x) + \mathsf{selB}(x) \cdot \mathsf{B}(x) + \mathsf{inFree}(x) \cdot \mathsf{free}(x) + \mathsf{const}(x). op(x):=selA(x)A(x)+selB(x)B(x)+inFree(x)free(x)+const(x).

Moreover, we should add the following Plookup checks:

const ( x ) + 7 ⊂ { 0 , 1 , … , 14 } , a d d r ( x ) ⊂ { 0 , 1 , … , 15 } , p o s i t i o n ( x ) ⊂ { 0 , 1 , … , 15 } , P C ( x ) ⊂ { 0 , 1 , … , 15 } , insTrace ( x ) ⊂ ROM ( x ) . \begin{aligned} &\textsf{const}(x) + 7 \subset \{0,1, \dots, 14\},\\ &\mathsf{addr}(x) \subset \{0,1, \dots, 15\},\\ &\mathsf{position}(x) \subset \{0,1, \dots, 15\},\\ &\mathsf{PC}(x) \subset \{0,1, \dots, 15\},\\ &\textsf{insTrace}(x) \subset \textsf{ROM}(x). \end{aligned} const(x)+7{0,1,,14},addr(x){0,1,,15},position(x){0,1,,15},PC(x){0,1,,15},insTrace(x)ROM(x).

With the following definitions:

instruction ( x ) : = 2 10 ⋅ ( const ( x ) + 7 ) + 2 6 ⋅ addr ( x ) + 2 5 ⋅ jmpz ( x ) + 2 4 ⋅ setB ( x ) +    2 3 ⋅ setA ( x ) + 2 2 ⋅ inFree ( x ) + 2 ⋅ selB ( x ) + selA ( x ) , ROM ( x ) : = 2 14 ⋅ position ( x ) + instruction ( x ) , insTrace ( x ) : = 2 14 ⋅ PC ( x ) + instruction ( x ) . \begin{aligned} &\textsf{instruction}(x) := 2^{10}\cdot(\textsf{const}(x) + 7) + 2^6\cdot \textsf{addr}(x) + 2^5\cdot \textsf{jmpz}(x) + 2^4 \cdot \textsf{setB}(x) + \\ &\qquad \qquad \qquad \quad~~2^3 \cdot \textsf{setA}(x) + 2^2 \cdot \textsf{inFree}(x) + 2 \cdot \textsf{selB}(x) + \textsf{selA}(x),\\ &\textsf{ROM}(x) := 2^{14} \cdot \textsf{position}(x) + \textsf{instruction}(x), \\ &\textsf{insTrace}(x) := 2^{14} \cdot \textsf{PC}(x) + \textsf{instruction}(x). \end{aligned} instruction(x):=210(const(x)+7)+26addr(x)+25jmpz(x)+24setB(x)+  23setA(x)+22inFree(x)+2selB(x)+selA(x),ROM(x):=214position(x)+instruction(x),insTrace(x):=214PC(x)+instruction(x).

Finally, it should be checked that the whole set of selectors are, in fact, binary:

s e l A ( x ) ⋅ ( s e l A ( x ) − 1 ) = 0 , s e t A ( x ) ⋅ ( s e t A ( x ) − 1 ) = 0 , s e l B ( x ) ⋅ ( s e l B ( x ) − 1 ) = 0 , s e t B ( x ) ⋅ ( s e t B ( x ) − 1 ) = 0 , i n F r e e ( x ) ⋅ ( i n F r e e ( x ) − 1 ) = 0 , j m p z ( x ) ⋅ ( j m p z ( x ) − 1 ) = 0. \begin{aligned} &\mathsf{selA}(x) \cdot (\mathsf{selA}(x) - 1) = 0, \quad \mathsf{setA}(x) \cdot (\mathsf{setA}(x) - 1) = 0, \quad\\ &\mathsf{selB}(x) \cdot (\mathsf{selB}(x)- 1) = 0, \quad \mathsf{setB}(x) \cdot (\mathsf{setB}(x) - 1) = 0, \quad\\ &\mathsf{inFree}(x) \cdot (\mathsf{inFree}(x) - 1) = 0, \quad \mathsf{jmpz}(x) \cdot (\mathsf{jmpz}(x) - 1) = 0. \end{aligned} selA(x)(selA(x)1)=0,setA(x)(setA(x)1)=0,selB(x)(selB(x)1)=0,setB(x)(setB(x)1)=0,inFree(x)(inFree(x)1)=0,jmpz(x)(jmpz(x)1)=0.

Regarding the polynomials, in this state machine:

  1. We have to commit inFree ( x ) , selA ( x ) , selB ( x ) , setA ( x ) , setB ( x ) \textsf{inFree}(x), \textsf{selA}(x), \textsf{selB}(x), \textsf{setA}(x), \textsf{setB}(x) inFree(x),selA(x),selB(x),setA(x),setB(x) A ( x ) , B ( x ) , const ( x ) , \textsf{A}(x), \textsf{B}(x), \textsf{const}(x), A(x),B(x),const(x), jmpz ( x ) , \textsf{jmpz}(x), jmpz(x), invOp ( x ) \textsf{invOp}(x) invOp(x), addr ( x ) \textsf{addr}(x) addr(x), free ( x ) \textsf{free}(x) free(x), position ( x ) \textsf{position}(x) position(x) and PC ( x ) \textsf{PC}(x) PC(x).

  2. While the only constant (preprocessed) polynomial is ROM ( x ) \textsf{ROM}(x) ROM(x).

参考资料

[1] Polygon zkEVM Simple State Machine

附录:Polygon Hermez 2.0 zkEVM系列博客

  • ZK-Rollups工作原理
  • Polygon zkEVM——Hermez 2.0简介
  • Polygon zkEVM网络节点
  • Polygon zkEVM 基本概念
  • Polygon zkEVM Prover
  • Polygon zkEVM工具——PIL和CIRCOM
  • Polygon zkEVM节点代码解析
  • Polygon zkEVM的pil-stark Fibonacci状态机初体验
  • Polygon zkEVM的pil-stark Fibonacci状态机代码解析
  • Polygon zkEVM PIL编译器——pilcom 代码解析
  • Polygon zkEVM Arithmetic状态机
  • Polygon zkEVM中的常量多项式
  • Polygon zkEVM Binary状态机
  • Polygon zkEVM Memory状态机
  • Polygon zkEVM Memory Align状态机
  • Polygon zkEVM zkASM编译器——zkasmcom
  • Polygon zkEVM哈希状态机——Keccak-256和Poseidon
  • Polygon zkEVM zkASM语法

你可能感兴趣的:(zkVM,零知识证明)