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.
In the context of the zkProver, these instructions are written as zk-Assembly (zkASM) codes, and stored in a ROM in JSON-format.
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.
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;
For a free input value of 7 7 7, the corresponding state transitions can be recorded in a table as follows;
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,Bfree7000A07710A′77100B0033B′0330
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,
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;
Rule for setters { setY } \{\texttt{setY}\} {setY}: Each setter setY \texttt{setY} setY is recorded;
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.
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 computational trace after executing Instruction 1 \texttt{Instruction}^{\texttt{1}} Instruction1 is as reflected in Table 3 below.
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,Bfree7000setB0101setA1011inFree1000selB0010selA0010A07710A′77100B0033B′0330
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.
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,Bfree7000const0300setB0101setA1011inFree1000selB0010selA0010A07710A′77100B0033B′0330
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⋅(selAi⋅Ai+selBi⋅Bi+inFreei⋅freei+consti−Ai),Bi+1=Bi+setBi⋅(selAi⋅Ai+selBi⋅Bi+inFreei⋅freei+consti−Bi).
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,B∈Zp[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.
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()}=>A−3=>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()}=>A−3=>B:ADD:JMPZ(5):ADD0=>A,Bfree700000A077441A′774410B00−3−3−3−3B′0−3−3−3−30
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()}=>A−3=>B:ADD:JMPZ(5)0=>A,Bfree30000A03300A′33000B00−3−3−3B′0−3−3−30
The first execution is done in 6 steps, while the second is in 5 steps.
Now, let us introduce a new model to manage a program that contains conditional jumps.
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:=selAi⋅Ai+selBi⋅Bi+inFreei⋅freei+consti.
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} a−1 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:=1−opi⋅(opi)−1,isZeroi⋅opi=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=a−1, 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} β=a−1 or β ≠ a − 1 \beta \neq a^{-1} β=a−1.
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. isZeroi⋅opi=0, isZeroi=1−opi⋅(opi)−1 → (1−opi⋅(opi)−1)⋅opi=0.
Let us introduce the following machinery to our setup in order to introduce jumps:
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:=selAi⋅Ai+selBi⋅Bi+inFreei⋅freei+consti,PCi+1=PCi+1+jmpzi⋅(1−opi⋅(opi)−1)⋅(addri−PCi−1),(1−opi⋅(opi)−1)⋅opi=0.
Observe that:
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()}=>A−3=>B:ADD:JMPZ(5):ADD0=>A,B,PCfree700000const0−30000addr000500jmpz000101setB010001setA101011inFree100000selB001010selA001010op7−34010invOp7−1(−3)−14−1010PC012345PC′123450A077441A′774410B00−3−3−3−3B′0−3−3−3−30
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()}=>A−3=>B:ADD:JMPZ(5)0=>A,Bfree30000const0−3000addr00050jmpz00011setB01001setA10101inFree10000selB00100selA00100op3−3000invOp3−1(−3)−1α00PC01235PC′12350A03330A′33000B00−3−3−3B′0−3−3−30
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.
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} −81000−71001−61010......−21110−11111000001000120010......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} −7p−7−6p−6......−2p−2−1p−1001122......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)∈{p−7,p−6,...,p−2,p−1,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()}=>A−3=>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)+26⋅addri+25⋅jmpzi+24⋅setBi+23⋅setAi+22⋅inFreei+2⋅selBi+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:=214⋅positioni+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()}=>A−3=>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()}=>A−3=>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()}=>A−3=>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.
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)⋅(1−op(x)⋅invOp(x))⋅(addr(x)−PC(x)−1),(1−op(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)+26⋅addr(x)+25⋅jmpz(x)+24⋅setB(x)+ 23⋅setA(x)+22⋅inFree(x)+2⋅selB(x)+selA(x),ROM(x):=214⋅position(x)+instruction(x),insTrace(x):=214⋅PC(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:
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).
While the only constant (preprocessed) polynomial is ROM ( x ) \textsf{ROM}(x) ROM(x).
[1] Polygon zkEVM Simple State Machine