Polygon zkEVM 状态机设计原理

Polygon zkEVM是兼容EVM的zkRollup Layer 2 方案。zkEVM 证明的第一步是构建交易的执行路径 (execution trace)。trace 是一个矩阵,每一列有一个名字,对每一列进行多项式插值,将执行路径的正确性归纳为多项式之间的恒等关系,这称算术化(arithmetization)。状态机主要提供了EVM证明的算术化过程。

Fibonacci 示例

Fibonacci State Machine

对于给定初始条件Fibonacci 序列,可以用两个寄存器A 和 B 构建状态机,如下图:

状态机初始条件为 , 并且有如下的关系:

将寄存器状态表示为多项式, 定义域在子群 , 即的8次单位根上,关系如下:

状态机的关系可以转为多项式的恒等关系:

但这些等式无法完全约束,例如:

  • 寄存器是非循环的,当在 计算等式关系的时候:

  • 其它的初始条件也能满足恒等关系,例如 (2, 4)。

为了解决上述问题,可以添加一个辅助寄存器(C):

此时 多项式 为:

新的多项式恒等关系为:

并且可以使用其它的初始条件, 修改多项式恒等关系为:

在上一个例子中,。

状态机证明

多项式承诺需要满足BindingHiding, 可以使用Kate 和 FRI 承诺。

Simple State Machine

首先展示一个简单状态机的算术化过程,如下图:

下列程序描述寄存器 A 和 B 接受输入的过程:

Instruction
${getInput()} => A
3 => B
: ADD
0 => A, B

上面的程序由汇编语言实现,通过executor 读入,生成执行路径。上面的代码,汇编指令分别表示为:

  • ${ getInput() } => A: 寻求自由输入,并保存在寄存器 A中。
  • 3 => B. 将3移入寄存器B 中;
  • :ADD 将寄存器 A 和 B的值加起来,作为寄存器A 的输出;
  • 0 => A, B 将0 移动到寄存器 A 和 B上。

例如,对于自由输入为7时,执行路径为:

\begin{array}{|l|c|c|c|c|c|} \hline \mathbf{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 & 10 & 3 & 3 \\ \hline \mathtt{0 => A,B} & 0 & 10 & 0 & 3 & 0 \\ \hline \end{array}
其中 为 寄存器 的下一个状态, 其中

为了创建合适的算术化约束条件,需要添加辅助的状态和选择子(selectors)表示寄存器 和 的关系:

其中 :

  • : 选择子,表示是否包含 在线性组合中;
  • : 选择子,表示是否将线性组合结果赋给;
  • : 包含的自由输入
  • : 包含一些固定的值

在引入辅助变量之后,可以得到下面的扩展表:
\scriptsize \begin{array}{|l|} \hline \mathbf{Instruction} \\ \hline \mathtt{\$\{getInput()\} => A} \\ \hline \mathtt{3 => B} \\ \hline \mathtt{:ADD} \\ \hline \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}
寄存器状态的关系可以用如下代数关系表示:
\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}
将寄存器的状态表示为多项式 , 定义域为子群上,
&\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)).
这个程序可以完全由常量多项式: , , , , 描述。

多项式 可以是公开的,或根据不同的初始条件 提前承诺。

程序的最终结果为

最后的指令重置寄存器的值到初始状态,形成一个循环。

条件语言跳转

下面引入指令 ,能够跳到指定的位置。在下面的程序中,当 值为0的时候, 将跳到 5 的位置:
\begin{array}{|c|l|} \hline \textbf{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} \\ \hline \end{array}
当引入条件跳转的时候,根据不同的输入值,执行路径长度是不一样的,如下所示:
\scriptsize \begin{array}{|l|c|c|c|c|c|} \hline \mathbf{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}

\scriptsize \begin{array}{|l|c|c|c|c|c|} \hline \mathbf{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}

上面的执行是6步,下面的执行是5步。

管理条件跳转

需要引入 新模型管理程序的条件跳转:

需要添加程序计数器, PC是一种特殊的寄存器,包含程序指令的执行位置。

下面使用 作为以下线性组合的简写:

若 为0, 将会跳转到指令 位置,首先需要检查操作在 中是否为0.

为了检查 中的数是否为0, 需要使用新的方法:若, 则 必然有一个乘法逆元:

下面添加 检查约束条件:

可以将两个方程变成一个约束条件:

引入下面的机制处理跳转:

添加选择子 , 通过下面的约束描述 的行为。
\begin{aligned} &\mathtt{op}^i := \mathtt{setA}^i \cdot \mathtt{A}^i + \mathtt{setB}^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}
当输入分别为7和3的时候,执行路径分别为:
\tiny \begin{array}{|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 \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{\color{blue!75!black} 4} & \mathbf{\color{blue!75!black} 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}

\tiny \begin{array}{|l|} \hline \mathbf{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{\color{blue!75!black} 0} & \mathbf{\color{blue!75!black} \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}

其中 用来表示 的逆。

目前,多项式是没有经过预处理的,因为表中的值不仅依赖自由输入,还需要验证正确的执行了程序。

证明正确的程序执行

为了检查执行了正确有的程序,我们提供一种指令常数值编码的方法,然后检查执行指令的编码确实在程序中指令的编码中。

假设采用4位符号整数(实际中为32位)进行编码指令中的常数值,如下所示:
\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}
去掉(8=-8), 编码余下的值为:
\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}
然后约束:

等价于:

对示例程序指令编码后的结果为:
\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 0111.0000.001100 \\ \hline 0100.0000.010000 \\ \hline 0111.0000.001011\\ \hline 0111.0101.100000 \\ \hline 0111.0000.001011 \\ \hline 0111.0000.111000 \\ \hline \end{array}
采用如下规则编码指令:
\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.
另外,需要检查 selectors 是二进制的, 是由4位组成, 即 .

对于, 指 , 表示没有使用常量。

为了证明程序,每个指令的编码和位置需要唯一识别,即:

可以唯一识别待验证的程序,如下所示:
\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 0111.0000.001100 \\ \hline 0100.0000.010000 \\ \hline 0111.0000.001011\\ \hline 0111.0101.100000 \\ \hline 0111.0000.001011 \\ \hline 0111.0000.111000 \\ \hline \end{array}
采用 编码程序的路径:
\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}

\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}

那么要如何有效检查执行了正确的程序呢,可以采用Plookup 协议, 即:

若指令路径包含在ROM 程序中,则表示执行了实际的程序。

证明执行路径的恒等关系

总而言之,可以采用如下的恒等关系定义程序:
\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}
其中 定义如下:

还需要进行如下的 Plookup 检查:
\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}
相关的定义如下:
\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}
最后,还需要检查 selectors 是二进制的,即:
\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}
关于状态机中的多项式,需要承诺: , , , 和 .

是 唯一可能预处理的不变多项式。

模块化设计

分而治之

若要添加更多运算到状态机,例如乘法,可以添加列到状态机中,但这会导致设计更加复杂,且难以处理,可以采用分而治之的策略:

  • zkEVM 架构 由不同的状态机相互连接组成;
  • 每个状态机去证明指定的任务;
  • 不同状态机相关的列可以使用包含证明 (plookup)。

下面通过一个32位算术运算的状态机和主状态机的包含证明展示这个过程。

算术状态机

算术状态机可以对32位元素执行加,减,乘,除的运算,使用如下5个寄存器:

可以用下多项式定义约束关系:

注意还需要检查 在 处的值为32 位。

我们将设计一种检查这些操作的机制:
\tiny \begin{array}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|} \hline \textbf{set}\mathcal{A} & \textbf{set}\mathcal{B} & \textbf{set}\mathcal{C} & \textbf{set}\mathcal{D} & \textbf{set}\mathcal{E} & \textbf{latch} & \textbf{freeIn} & \mathcal{A} & \mathcal{A'} & \mathcal{B} & \mathcal{B'} & \mathcal{C} & \mathcal{C'} & \mathcal{D} & \mathcal{D'} & \mathcal{E} & \mathcal{E'}\\ \hline 1 & 0 & 0 & 0 & 0 & 0 & 0x0003 & 0 & 0x003 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\ \hline 0 & 1 & 0 & 0 & 0 & 0 & 0x0002 & 0x0003 & 0x0003 & 0 & 0x0002 & 0 & 0 & 0 & 0 & 0 & 0\\ \hline 0 & 0 & 1 & 0 & 0 & 0 & 0x0004 & 0x0003 & 0x0003 & 0x0002 & 0x0002 & 0 & 0x0004 & 0 & 0 & 0 & 0\\ \hline 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0x0003 & 0x0003 & 0x0002 & 0x0002 & 0x0004 & 0x0004 & 0 & 0 & 0 & 0\\ \hline 0 & 0 & 0 & 0 & 1 & 0 & 0x000a & 0x0003 & 0x0003 & 0x0002 & 0x0002 & 0x0004 & 0x0004 & 0 & 0 & 0 & 0x000a\\ \hline 1 & 0 & 0 & 0 & 0 & \mathbf{1} & 0x1111 & \mathbf{0x0003} & 0x1111 & \mathbf{0x0002} & 0x0002 & \mathbf{0x0004} & 0x0004 & \mathbf{0} & 0 & \mathbf{0x000a} & 0x000a\\ \hline 0 & 1 & 0 & 0 & 0 & 0 & 0x2222 & {0x1111} & 0x1111 & {0x0002} & 0x2222 & {0x0004} & 0x0004 & {0} & 0 & {0x000a} & 0x000a\\ \hline 0 & 0 & 1 & 0 & 0 & 0 & 0x3333 & {0x1111} & 0x1111 & {0x2222} & 0x2222 & {0x0004} & 0x3333 & {0} & 0 & {0x000a} & 0x000a\\ \hline 0 & 0 & 0 & 1 & 0 & 0 & 0x0246 & {0x1111} & 0x1111 & {0x2222} & 0x2222 & {0x3333} & 0x3333 & {0} & 0x0246 & {0x000a} & 0x000a\\ \hline 0 & 0 & 0 & 0 & 1 & 0 & 0xb975 & {0x1111} & 0x1111 & {0x2222} & 0x2222 & {0x3333} & 0x3333 & {0x0246} & 0x0246 & {0x000a} & 0xb975\\ \hline 1 & 0 & 0 & 0 & 0 & \mathbf{1} & 0x7777 & \mathbf{0x1111} & 0x7777 & \mathbf{0x2222} & 0x2222 & \mathbf{0x3333} & 0x3333 & \mathbf{0x0246} & 0x0246 & \mathbf{0xb975} & 0xb975\\ \hline ... & ... & ... & ... & ... & ... & ... & ... & ... & ... & ... & ... & ... & ... & ... & ... & ...\\ \hline \end{array}
使用 来标记需要检查 寄存器 之间的约束关系。 , , , , 和 是不变的,即它们不依赖输入。

列的值需要承诺, 依赖 , 也需要承诺。

因此算术状态机多项式恒等关系为:
\begin{aligned} \mathcal{A'} &= \mathbf{sel}\mathcal{A}\cdot(\mathbf{freeIn}-\mathcal{A}) + \mathcal{A} \\ \mathcal{B'} &= \mathbf{sel}\mathcal{B}\cdot(\mathbf{freeIn}-\mathcal{B}) + \mathcal{B} \\ \mathcal{C'} &= \mathbf{sel}\mathcal{C}\cdot(\mathbf{freeIn}-\mathcal{C}) + \mathcal{C} \\ \mathcal{D'} &= \mathbf{sel}\mathcal{D}\cdot(\mathbf{freeIn}-\mathcal{D}) + \mathcal{D} \\ \mathcal{E'} &= \mathbf{sel}\mathcal{E}\cdot(\mathbf{freeIn}-\mathcal{E}) + \mathcal{E} \\ 0 &= [ \mathcal{A} \cdot \mathcal{B} + \mathcal{C} - (2^{32} \mathcal{D} + \mathcal{E}) ] \cdot \mathbf{latch} \\ \mathbf{freeIn} &\subset byte4\end{aligned}
下图展示了算术状态机的架构图:

扩展主状态机

对于主状态机,可以将其扩展到5 个寄存器,添加一个arith 标记,用来连接算术状态机。 当arith 为1 的时候,需要检查算术化操作。整个设计如下图所示:

下图展示如何连接主状态机和算术状态机,当arith 为1的时候,需要确何算术表中的latch 为1。

因此,需要保证如下的包含关系:
[arith \cdot A , arith \cdot B , arith \cdot C , arith \cdot D, arith \cdot op] \subset [latch \cdot \mathcal{A} , latch \cdot \mathcal{B} , latch \cdot \mathcal{C} , latch \cdot \mathcal{D} , latch \cdot \mathcal{E}]
注: 使用 用来表示它包寄存器 的值。

通过使用 Plookup作为总线,可以连接主状态机和其它具体的状态机:

由此可以设计一个模块化虚拟状态机,并通过零知识证明进行验证。

参考

https://docs.hermez.io/zkEVM/Basic-Concepts/introduction/

https://polygon.technology/solutions/polygon-zkevm

https://docs.hermez.io/

https://github.com/0xPolygonHermez/

https://blog.polygon.technology/the-future-is-now-for-ethereum-scaling-introducing-polygon-zkevm/?utm_source=ticker&utm_medium=website&utm_campaign=organic

https://ethresear.ch/t/proof-of-efficiency-a-new-consensus-mechanism-for-zk-rollups/11988

https://en.wikipedia.org/wiki/Fibonacci_number

你可能感兴趣的:(Polygon zkEVM 状态机设计原理)