1. 引言
前序博客有:
Binary状态机为Polygon zkEVM的六个二级状态机之一,该状态机内包含:
- executor part:sm_binary.js:负责生成execution trace,为常量多项式和隐私多项式赋值。
- 验证规则集PIL:binary.pil:定义了约束系统。
相应的test vectors见:binary_test.js:包含了所支持的各类计算的测试集。
Polygon zkEVM Binary状态机针对的是256-bit字符串的二进制运算,当前支持的二进制运算有:
Operation Name \textbf{Operation Name} Operation Name | Mnemonic \textbf{Mnemonic} Mnemonic | Symbol \textbf{Symbol} Symbol | BinOpCode \textbf{BinOpCode} BinOpCode |
---|---|---|---|
Addition \text{Addition} Addition | A D D \mathrm{ADD} ADD | + + + | 0 0 0 |
Subtraction \text{Subtraction} Subtraction | S U B \mathrm{SUB} SUB | − - − | 1 1 1 |
Less Than \text{Less Than} Less Than | L T \mathrm{LT} LT | < < < | 2 2 2 |
Signed Less Than \text{Signed Less Than} Signed Less Than | S L T \mathrm{SLT} SLT | < < < | 3 3 3 |
Equal To \text{Equal To} Equal To | E Q \mathrm{EQ} EQ | = = = | 4 4 4 |
Bitwise AND \text{Bitwise AND} Bitwise AND | A N D \mathrm{AND} AND | ∧ \wedge ∧ | 5 5 5 |
Bitwise OR \text{Bitwise OR} Bitwise OR | O R \mathrm{OR} OR | ∨ \vee ∨ | 6 6 6 |
Bitwise XOR \text{Bitwise XOR} Bitwise XOR | X O R \mathrm{XOR} XOR | ⊕ \oplus ⊕ | 7 7 7 |
No Operation \text{No Operation} No Operation | N O P \mathrm{NOP} NOP | N O P \mathrm{NOP} NOP | ⋆ \star ⋆ |
相应的运算定义可参见zkasmcom中的zkasm_parser.jison
中:
| ADD
{
$$ = { bin: 1, binOpcode: 0}
}
| SUB
{
$$ = { bin: 1, binOpcode: 1}
}
| LT
{
$$ = { bin: 1, binOpcode: 2}
}
| SLT
{
$$ = { bin: 1, binOpcode: 3}
}
| EQ
{
$$ = { bin: 1, binOpcode: 4}
}
| AND
{
$$ = { bin: 1, binOpcode: 5}
}
| OR
{
$$ = { bin: 1, binOpcode: 6}
}
| XOR
{
$$ = { bin: 1, binOpcode: 7}
}
2. 将256位字符串编码为有符号位和无符号位整数
在理解以上运算规则的工作原理之前,需首先了解zkEVM是如何将256位字符串编码为signed integers和unsigned integers。
以3-bit字符串为例,相应的uint和int编码表示为:【可很容易将其扩展至256-bit字符串】【对于int表示,需注意-4和4具有相同的编码方式。】
ADD和SUB可逐bit运算,如以3-bit string 0b001和0b101(0b表示二进制)为例,逐bit add为:
-
初始 c a r r y = 0 carry=0 carry=0,最低有效位相加有: 1 + 1 + c a r r y = 1 + 1 + 0 = 0 1+1+carry=1+1+0=0 1+1+carry=1+1+0=0,因此,下一carry值为 c a r r y ′ = 1 carry'=1 carry′=1。
-
其次,将次低有效位相加,并与前一carry相加,有 0 + 0 + c a r r y = 0 + 0 + 1 = 1 0+0+carry = 0+0+1 = 1 0+0+carry=0+0+1=1,此时,下一carry值为 c a r r y ′ = 0 carry'=0 carry′=0。
-
最后,将最高有效位相加,并与前一carry相加,有 0 + 1 + c a r r y = 0 + 1 + 0 = 1 0+1+carry=0+1+0=1 0+1+carry=0+1+0=1,最终carry值为 c a r r y ′ = 0 carry'=0 carry′=0。
-
最终结果为: 0 b 001 + 0 b 101 = 0 b 110 \mathtt{0b001}+\mathtt{0b101} = \mathtt{0b110} 0b001+0b101=0b110 with c a r r y = 0 carry=0 carry=0。
不过LT(less than)与 SLT(unsigned less than)有所不同,LT按正常顺序直接比较即可,而SLT:
- 1)若最高有效位相同,则按正常顺序直接比较,如101<110,即-3<-2。
- 2)若最高有效位不同,则顺序相反(以0为最高有效位的值更大),如110<001,即-2<1。
而AND/OR/XOR/NOT运算均为bit-wise运算,即可逐位计算,且无需考虑进位(carry)情况:
注意,zkEVM中未单独设置NOT运算符,因NOT运算可看成是与0xff…ff的XOR运算。
3. polygon zkEVM Binary状态机设计思想
polygon zkEVM Binary状态机的executor part:sm_binary.js,负责记录状态机内的每个computation trace,该computation trace可用于证明计算的正确性。
execution trace通常以256-bit字符串来表示,每个正确的execution trace必须满足相应的多项式约束,这些多项式约束定义在PIL代码文件中。
3.1 internal Byte Plookups
Binary状态机内部使用plookups of bytes来表达所有二进制运算。
在其plookups table中,包含了所有可能的input bytes和output byte组合:
byte
i
n
0
⋆
byte
i
n
1
=
byte
o
u
t
,
\text{byte}_{in_0} \star \text{byte}_{in_1} = \text{byte}_{out},
bytein0⋆bytein1=byteout,
其中
⋆
\star
⋆表示所有可能的运算。
当对256-bit字符串进行二进制运算时,某execution trace可 以cycles of 32 steps 来实现一个运算。(因32*8=256)
在每一个step,对应为byte-wise操作 和 ‘carries’ 或其它任何辅助值信息,来构成computation trace。
此外,每个256-bit字符串(2个输入、1个输出)使用8个 32-bit的寄存器来表示。
3.2 Main状态机与Binary状态机的连接
Polygon zkEVM的Main状态机的execution trace 与 Binary状态机的execution trace 之间的约束是通过一个Plookup来连接的——即,当cycle结束(即名为RESET的寄存器为1)时,会对Binary状态机execution trace中的每一行进行运算。该Plookup会检查相应的operation code、输入和输出的256-bit字符串的寄存器 以及 最终的carry。
4. Byte-wise运算
由于Polygon zkEVM Binary状态机选用byte plookups,因此接下来将256-bit运算转换为了byte-wise运算。
将
256
256
256-bit整数
a
\mathbf{a}
a表示为:
(
a
31
,
…
,
a
1
,
a
0
)
(a_{31}, \dots, a_1, a_0)
(a31,…,a1,a0),即:
a
=
a
31
⋅
(
2
8
)
31
+
a
30
⋅
(
2
8
)
30
+
⋯
+
a
1
⋅
2
8
+
a
0
=
∑
i
=
31
0
a
i
⋅
(
2
8
)
i
,
\mathbf{a} = a_{31}\cdot (2^8)^{31} + a_{30}\cdot (2^8)^{30} + \cdots + a_1\cdot2^8 + a_0 = \sum_{i = {31}}^{0} a_i \cdot (2^8)^i,
a=a31⋅(28)31+a30⋅(28)30+⋯+a1⋅28+a0=i=31∑0ai⋅(28)i,
其中每个
a
i
a_i
ai为一个字节,其取值范围为
0
0
0到
2
8
−
1
2^8 - 1
28−1。
如 a = 29967 \mathbf{a} = 29967 a=29967,将其按byte分解表示为 a = ( 0 x 75 , 0 x 0 F ) \mathbf{a} = (\mathtt{0x75}, \mathtt{0x0F}) a=(0x75,0x0F),因 a = 29967 = 117 ⋅ 2 8 + 15 \mathbf{a} = 29967 = 117 \cdot 2^8 + 15 a=29967=117⋅28+15,以16进制表示为: 117 ↦ 0 x 75 117 \mapsto \mathtt{0x75} 117↦0x75 以及 15 ↦ 0 x 0 F 15 \mapsto \mathtt{0x0F} 15↦0x0F。
4.1 ADD加法运算
将讲述如何将2个256位数字的加法运算 reduce为 a byte-by-byte加法运算,然后使用byte-wise Plookup table。
观察2个byte
a
,
b
a,b
a,b的加法运算,即
a
,
b
a,b
a,b为
[
0
,
2
8
−
1
]
[0,2^8-1]
[0,28−1]集合中的成员,二者之和
c
c
c可能无法以一个字节来表示。
如
a
=
0
x
F
F
a = \mathtt{0xFF}
a=0xFF,
b
=
0
x
01
b = \mathtt{0x01}
b=0x01 则:
a
+
b
=
0
x
F
F
+
0
x
01
=
0
x
100
.
a + b = \mathtt{0xFF} + \mathtt{0x01} = \mathtt{0x100}.
a+b=0xFF+0x01=0x100.
以字节形式表示,
c
=
0
x
00
c=\mathtt{0x00}
c=0x00 且
c
a
r
r
y
′
=
1
carry'=1
carry′=1。即在处理byte add时,需考虑进位。
接下来,考虑2个byte的加法:
如
a
=
(
a
1
,
a
0
)
=
(
0
x
F
F
,
0
x
01
)
\mathbf{a} = (a_1, a_0) = (\mathtt{0xFF}, \mathtt{0x01})
a=(a1,a0)=(0xFF,0x01) and
b
=
(
b
1
,
b
0
)
=
(
0
x
F
0
,
0
x
F
F
)
\mathbf{b} = (b_1, b_0) = (\mathtt{0xF0}, \mathtt{0xFF})
b=(b1,b0)=(0xF0,0xFF):
- 首先对低有效字节相加:
a 1 + b 1 = 0 x 01 + 0 x F F = c 1 = 0 x 00 , c a r r y 1 = 1. \begin{aligned} a_1 + b_1 &= \mathtt{0x01} + \mathtt{0xFF} = c_1 = \mathtt{0x00}, \\ carry_1 &= 1. \end{aligned} a1+b1carry1=0x01+0xFF=c1=0x00,=1. - 然后对次有效字节相加:
a 2 + b 2 + c a r r y 1 = 0 x F F + 0 x F 0 = c 2 = 0 x F 0 , c a r r y 2 = 1. \begin{aligned} a_2 + b_2 + carry_1 &= \mathtt{0xFF} + \mathtt{0xF0} = c_2 = \mathtt{0xF0}, \\ carry_2 &= 1. \end{aligned} a2+b2+carry1carry2=0xFF+0xF0=c2=0xF0,=1.
2字节相加时,对应有如下情况需区分对待:
-
1)若 a 1 + b 1 < 2 8 a_1 + b_1 < 2^8 a1+b1<28 且 a 2 + b 2 < 2 8 a_2 + b_2 < 2^8 a2+b2<28,则 a + b \mathbf{a} + \mathbf{b} a+b之和可简单表示为:
a + b = ( a 2 + b 2 , a 1 + b 1 ) . \mathbf{a} + \mathbf{b} = (a_2 + b_2, a_1 + b_1). a+b=(a2+b2,a1+b1). -
2)若 a 1 + b 1 < 2 8 a_1 + b_1 < 2^8 a1+b1<28 但 a 2 + b 2 ≥ 2 8 a_2 + b_2 \geq 2^8 a2+b2≥28, 则 a 2 + b 2 a_2 + b_2 a2+b2 无法以单一字节来表示,从而可将 a 2 a_2 a2 和 b 2 b_2 b2 之和表示为:
a 2 + b 2 = 1 ⋅ 2 8 + c 2 , a_2 + b_2 = 1 \cdot 2^8 + c_2, a2+b2=1⋅28+c2,
a + b \mathbf{a} + \mathbf{b} a+b之和表示为:
a + b = ( 1 , c 2 , a 1 + b 1 ) . \mathbf{a} + \mathbf{b} = (1, c_2, a_1 + b_1). a+b=(1,c2,a1+b1). -
3)若 a 1 + b 1 ≥ 2 8 a_1 + b_1 \geq 2^8 a1+b1≥28,则有:
a 1 + b 1 = 1 ⋅ 2 8 + c 1 , a_1 + b_1 = 1 \cdot 2^8 + c_1, a1+b1=1⋅28+c1,
从而有:
a + b = ( a 2 + b 2 + 1 ) ⋅ 2 8 + c 1 . \mathbf{a} + \mathbf{b} = (a_2 + b_2 + 1) \cdot 2^8 + c_1. a+b=(a2+b2+1)⋅28+c1.- 3.a)若
a
2
+
b
2
+
1
≥
2
8
a_2 + b_2 + 1 \geq 2^8
a2+b2+1≥28,则有:
a 2 + b 2 + 1 = 1 ⋅ 2 8 + c 2 . a_2 + b_2 + 1 = 1 \cdot 2^8 + c_2. a2+b2+1=1⋅28+c2.
最终 a + b \mathbf{a} + \mathbf{b} a+b之和表示为:
a + b = ( 1 , c 2 , c 1 ) . \mathbf{a} + \mathbf{b} = (1, c_2, c_1). a+b=(1,c2,c1). - 3.b)若
a
2
+
b
2
+
1
<
2
8
a_2 + b_2 + 1 < 2^8
a2+b2+1<28,则
a
+
b
\mathbf{a} + \mathbf{b}
a+b之和表示为:
a + b = ( c 2 , c 1 ) . \mathbf{a} + \mathbf{b} = (c_2, c_1). a+b=(c2,c1).
- 3.a)若
a
2
+
b
2
+
1
≥
2
8
a_2 + b_2 + 1 \geq 2^8
a2+b2+1≥28,则有:
对于 256 256 256-bit数字加法,可reduce为类似以上byte-level计算。
4.2 SUB减法运算
减法比加法更具技巧。
如
a
=
0
x
0101
\mathbf{a} = \mathtt{0x0101}
a=0x0101,
b
=
0
x
00
F
F
\mathbf{b} = \mathtt{0x00FF}
b=0x00FF,相应的减法表示为:
a
−
b
=
(
0
x
01
−
0
x
00
)
⋅
2
8
+
(
0
x
01
−
0
x
F
F
)
=
(
0
x
01
−
0
x
00
)
⋅
2
8
−
2
8
+
2
8
+
(
0
x
01
−
0
x
F
F
)
=
(
0
x
01
−
0
x
00
−
0
x
01
)
⋅
2
8
+
0
x
F
F
+
0
x
01
+
0
x
01
−
0
x
F
F
=
(
0
x
00
)
⋅
2
8
+
0
x
02
\begin{aligned} \mathbf{a} - \mathbf{b} & = (\mathtt{0x01} - \mathtt{0x00}) \cdot 2^8 + (\mathtt{0x01} - \mathtt{0xFF}) \\ & = (\mathtt{0x01} - \mathtt{0x00}) \cdot 2^8 - 2^8 + 2^8 + (\mathtt{0x01} - \mathtt{0xFF}) \\ & = (\mathtt{0x01} - \mathtt{0x00 - 0x01}) \cdot 2^8 + \mathtt{0xFF + 0x01} + \mathtt{0x01} - \mathtt{0xFF} \\ & = ( \mathtt{0x00} ) \cdot 2^8 + \mathtt{0x02} \end{aligned}
a−b=(0x01−0x00)⋅28+(0x01−0xFF)=(0x01−0x00)⋅28−28+28+(0x01−0xFF)=(0x01−0x00−0x01)⋅28+0xFF+0x01+0x01−0xFF=(0x00)⋅28+0x02
即最终结果以byte形式表示为:
c
=
(
c
1
,
c
0
)
=
(
0
x
00
,
0
x
02
)
\mathbf{c} = (c_1, c_0) = (\mathtt{0x00}, \mathtt{0x02})
c=(c1,c0)=(0x00,0x02)
byte-wise减法运算只需考虑如下2种场景:
- 若 a i − carry ≥ b i a_i - \texttt{carry} \geq b_i ai−carry≥bi,则 a i − b i − carry a_i - b_i - \texttt{carry} ai−bi−carry提供了 a − b a-b a−b的第 i i i个byte结果表达。
- 若
a
i
−
carry
<
b
i
a_i - \texttt{carry} < b_i
ai−carry<bi,则a-b
的第
的第
的第i$个byte结果表示为:
2 8 − b i + a i − carry = 255 − b i + a i − carry + 1. 2^8 - b_i + a_i - \texttt{carry} = 255 - b_i + a_i - \texttt{carry} + 1. 28−bi+ai−carry=255−bi+ai−carry+1.
以
a
=
0
x
0001
F
E
a = \mathtt{0x0001FE}
a=0x0001FE,
b
=
0
x
F
E
F
F
F
F
b = \mathtt{0xFEFFFF}
b=0xFEFFFF为例,
a
−
b
a-b
a−b结果表示为:
c
=
(
0
x
01
,
0
x
01
,
0
x
F
F
)
=
0
x
01
⋅
2
16
+
0
x
01
⋅
2
8
+
0
x
F
F
.
c = (\mathtt{0x01}, \mathtt{0x01}, \mathtt{0xFF}) = \mathtt{0x01} \cdot 2^{16} + \mathtt{0x01} \cdot 2^8 + \mathtt{0xFF}.
c=(0x01,0x01,0xFF)=0x01⋅216+0x01⋅28+0xFF.
4.3 Less Than小于运算
Less Than小于运算是指:
- 若 a < b a<b a<b,则结果 c = 1 c=1 c=1;
- 若 a ≥ b a\geq b a≥b,则结果 c = 0 c=0 c=0。
以 a = 0 x F F A E 09 a = \mathtt{0xFF AE 09} a=0xFFAE09, b = 0 x F F A E 02 b = \mathtt{0x FF AE 02} b=0xFFAE02为例,直观上来说,是直接从最高有效byte开始比较,但polygon zkEVM的实际实现是必须从最低有效byte开始,因此,需分以下三种情况来分析:
- 1)若 a i < b i a_i < b_i ai<bi,则设置 c a r r y = 1 \mathtt{carry}=1 carry=1,若当前为最高有效byte,则直接输出结果为 c = 1 c=1 c=1。
- 2)若 a i = b i a_i = b_i ai=bi,则 c a r r y \mathtt{carry} carry保持与之前的一致不变,若当前为最高有效byte,则直接输出结果为 c = c a r r y c=\mathtt{carry} c=carry。
- 3)若 a i > b i a_i > b_i ai>bi,则设置 c a r r y = 0 \mathtt{carry}=0 carry=0,若当前为最高有效byte,则直接输出结果为 c = 0 c=0 c=0。
4.4 Signed Less Than有符号小于运算
计算机科学中常使用two’s implement来表示有符号整数。对于有符号整数,其最高有效位若为1,则表示其为负数。
对于
N
N
N-bit系统,负数
x
x
x的two’s implement二进制表示为:
2
N
−
x
2^N-x
2N−x,即若
x
=
−
1
,
N
=
4
x=-1,N=4
x=−1,N=4,则:
10000
−
0001
=
1111
10000-0001=1111
10000−0001=1111
即
−
1
=
1111
-1=1111
−1=1111。
Polygon zkEVM中采用byte-wise有符号整数比较方式。
将256-bit有符号整数
a
,
b
a,b
a,b表示为:
a
=
(
a
31
,
a
30
,
…
,
a
0
)
a = (a_{31}, a_{30}, \dots, a_0)
a=(a31,a30,…,a0)
b
=
(
b
31
,
b
30
,
…
,
b
0
)
b = (b_{31}, b_{30}, \dots, b_0)
b=(b31,b30,…,b0)
a
a
a的最高有效位为
sgn
(
a
)
=
a
31
,
7
\texttt{sgn}(a) = a_{31, 7}
sgn(a)=a31,7,其中:
a
31
=
∑
i
=
0
7
a
31
,
i
⋅
2
i
a_{31} = \sum_{i = 0}^7 a_{31, i} \cdot 2^i
a31=i=0∑7a31,i⋅2i
为
a
31
a_{31}
a31的二进制表示。
同理定义
sgn
(
b
)
=
b
31
,
7
\texttt{sgn}(b) = b_{31, 7}
sgn(b)=b31,7。
分以下3种场景:
- 1)若 sgn ( a ) = 1 \texttt{sgn}(a) = 1 sgn(a)=1, sgn ( b ) = 0 \texttt{sgn}(b) = 0 sgn(b)=0,则 a < b a < b a<b,输出结果 c = 1 c=1 c=1。
- 2)若 sgn ( a ) = 0 \texttt{sgn}(a) = 0 sgn(a)=0, sgn ( b ) = 1 \texttt{sgn}(b) = 1 sgn(b)=1,则 a > b a > b a>b,输出结果 c = 0 c=0 c=0。
- 3)若
sgn
(
a
)
=
sgn
(
b
)
\texttt{sgn}(a) = \texttt{sgn}(b)
sgn(a)=sgn(b),则按如下顺序由最低有效byte开始比较:
- 3.1)首先比较最低有效byte
a
0
a_0
a0和
b
0
b_0
b0:
* 3.1.a)若 a 0 < b 0 a_0 < b_0 a0<b0,则设置 carry = 1 \texttt{carry} = 1 carry=1。- 3.1.b)否则,设置 carry = 0 \texttt{carry} = 0 carry=0.
- 3.2)对于所有的
0
<
i
<
31
0 < i < 31
0<i<31,比较
a
i
a_i
ai和
b
i
b_i
bi:
- 3.2.a)若 a i < b i a_i < b_i ai<bi,则设置 carry = 1 \texttt{carry} = 1 carry=1。
- 3.2.b)若 a i = b i a_i = b_i ai=bi,则 carry \texttt{carry} carry与前一步值一致保持不变。
- 3.2.c)否则,设置 carry = 0 \texttt{carry} = 0 carry=0。
- 3.3)比较最高有效byte
a
31
a_{31}
a31和
b
31
b_{31}
b31:
- 3.3.a)若 a 31 < b 31 a_{31} < b_{31} a31<b31,从而有 a < b a<b a<b,输出结果 c = 1 c=1 c=1
- 3.3.b)若 a 31 = b 31 a_{31} = b_{31} a31=b31,则输出结果为上一步的 carry \texttt{carry} carry,即保留最近的判定结果。
- 3.3.c)否则, a ≮ b a \not < b a<b.,输出结果 c = 0 c=0 c=0。
- 3.1)首先比较最低有效byte
a
0
a_0
a0和
b
0
b_0
b0:
4.5 Equality等价性运算
Equality等价性运算是指:
- 若 a = b a=b a=b,则 c = 1 c=1 c=1;
- 否则, c = 0 c=0 c=0。
byte-wise等价性运算就是逐byte判断是否相等,引入carry来标记未找到不同的byte(即,若 carry = 0 \texttt{carry}=0 carry=0,则表示 a , b a,b a,b不同)。
将256-bit整数
a
,
b
a,b
a,b表示为:
a
=
(
a
31
,
a
30
,
…
,
a
0
)
a = (a_{31}, a_{30}, \dots, a_0)
a=(a31,a30,…,a0)
b
=
(
b
31
,
b
30
,
…
,
b
0
)
b = (b_{31}, b_{30}, \dots, b_0)
b=(b31,b30,…,b0)
其逐byte等价性比较流程为:
- 1)首先,设置 carry = 1 \texttt{carry}=1 carry=1。
- 2)开始比较
a
0
a_0
a0和
b
0
b_0
b0:
- 2.a)若 a 0 = b 0 a_0=b_0 a0=b0,则保持 carry = 1 \texttt{carry}=1 carry=1不变。
- 2.b)若 a 0 ≠ b 0 a_0 \neq b_0 a0=b0,则设置 carry = 0 \texttt{carry}=0 carry=0,表示 a ≠ b a \neq b a=b。则直接返回,输出结果 c = 0 c=0 c=0。
- 3)对于
0
<
i
≤
31
0 < i \leq 31
0<i≤31,比较
a
i
a_i
ai和
b
i
b_i
bi:
- 3.a)若 a i = b i 且 carry = 1 a_i = b_i \textbf{ 且 } \texttt{carry} = 1 ai=bi 且 carry=1,则保持 carry = 1 \texttt{carry}=1 carry=1不变,若 i = 31 i = 31 i=31则输出结果 c = 1 c=1 c=1因 a = b a = b a=b。
- 3.b)若 a i ≠ b i a_i \neq b_i ai=bi,则设置 carry = 0 \texttt{carry} = 0 carry=0,应不做后续比较,直接跳出返回,输出结果 c = 0 c=0 c=0。
4.6 Bitwise位运算
Bitwise位运算相对要简单很多,无需考虑进位情况。
对于
a
=
(
a
31
,
a
30
,
…
,
a
0
)
a = (a_{31}, a_{30}, \dots, a_{0})
a=(a31,a30,…,a0) and
b
=
(
b
31
,
b
30
,
…
,
b
0
)
b = (b_{31}, b_{30}, \dots, b_{0})
b=(b31,b30,…,b0),其中
a
i
,
b
i
∈
{
0
,
1
}
a_i, b_i \in \{0, 1\}
ai,bi∈{0,1},则位运算定义为:
a
⋆
b
=
(
a
i
⋆
b
i
)
i
=
(
a
31
⋆
b
31
,
a
30
⋆
b
30
,
…
,
a
0
⋆
b
0
)
a \star b = (a_i \star b_i)_i = (a_{31} \star b_{31}, a_{30} \star b_{30}, \dots, a_0 \star b_0)
a⋆b=(ai⋆bi)i=(a31⋆b31,a30⋆b30,…,a0⋆b0)
其中
⋆
\star
⋆ 可为
∧
,
∨
\land, \lor
∧,∨ 或
⊕
\oplus
⊕.
如
a
=
0
x
C
B
=
0
b
11001011
a = \mathtt{0xCB} = \mathtt{0b11001011}
a=0xCB=0b11001011,
b
=
0
x
E
A
=
0
b
11101010
b = \mathtt{0xEA} = \mathtt{0b11101010}
b=0xEA=0b11101010,则:
a
∧
b
=
0
b
11001010
=
0
x
C
A
,
a
∨
b
=
0
b
11101011
=
0
x
E
B
,
a
⊕
b
=
0
b
00100001
=
0
x
21
.
\begin{aligned} a \land b &= \mathtt{0b11001010} = \mathtt{0xCA},\\ a \lor b &= \mathtt{0b11101011} = \mathtt{0xEB},\\ a \oplus b &= \mathtt{0b00100001} = \mathtt{0x21}. \end{aligned}
a∧ba∨ba⊕b=0b11001010=0xCA,=0b11101011=0xEB,=0b00100001=0x21.
5. Binary状态机内的约束系统
Binary状态机内的常量多项式见:Polygon zkEVM中的常量多项式 中“binary.pil中的常量多项式”。
Binary状态机内的隐私多项式有:
// ############################################################
// COMMIT POLINOMIALS
// ############################################################
// opcode = (2 bits) Operation code
// ============================================================
// a0-a7, a0-a7, a0-a7
// 256 bits operations -> 32 Bytes / 4 Bytes (per registry) ->
// 8 Registries
// ============================================================
// freeInA, freeInB, freeInC -> 1 Byte input
// ============================================================
// cIn -> Carry In ; cOut -> Carry Out ; lCIn -> Latch Carry in
// ============================================================
pol commit freeInA, freeInB, freeInC;
pol commit a0, a1, a2, a3, a4, a5, a6, a7;
pol commit b0, b1, b2, b3, b4, b5, b6, b7;
pol commit c0, c1, c2, c3, c4, c5, c6, c7;
pol commit opcode;
pol commit cIn, cOut;
pol commit lCout,lOpcode;
pol commit last;
pol commit useCarry;
binary.pil的结果为要么pass要么fail。
Binary状态机内的约束系统表达有:【其中useCarry
和c0Temp
用于管理更新和赋值,特别是对于布尔运算,使得输出c0
的值要么为TRUE=1
或FALSE=0
。对于非布尔运算,useCarry
的默认值为0,c0'=c0 * (1 - RESET) + freeInC * FACTOR[0];
就与其它ci'
的更新逻辑一样了。】
- 1)opcode、cIn、lCout、lOpcode的transition约束为:
opcode' * ( 1 - RESET' ) = opcode * ( 1 - RESET' ); cIn' * ( 1 - RESET' ) = cOut * ( 1 - RESET' ); lCout' = cOut; lOpcode' = opcode;
- 2)plookup约束有:
{last, opcode, freeInA, freeInB , cIn, useCarry ,freeInC, cOut} in {P_LAST, P_OPCODE, P_A, P_B, P_CIN, P_USE_CARRY, P_C, P_COUT};
- 3)a0-a7、b0-b7、c0-c7的transition约束为:
a0' = a0 * (1 - RESET) + freeInA * FACTOR[0]; a1' = a1 * (1 - RESET) + freeInA * FACTOR[1]; a2' = a2 * (1 - RESET) + freeInA * FACTOR[2]; a3' = a3 * (1 - RESET) + freeInA * FACTOR[3]; a4' = a4 * (1 - RESET) + freeInA * FACTOR[4]; a5' = a5 * (1 - RESET) + freeInA * FACTOR[5]; a6' = a6 * (1 - RESET) + freeInA * FACTOR[6]; a7' = a7 * (1 - RESET) + freeInA * FACTOR[7]; b0' = b0 * (1 - RESET) + freeInB * FACTOR[0]; b1' = b1 * (1 - RESET) + freeInB * FACTOR[1]; b2' = b2 * (1 - RESET) + freeInB * FACTOR[2]; b3' = b3 * (1 - RESET) + freeInB * FACTOR[3]; b4' = b4 * (1 - RESET) + freeInB * FACTOR[4]; b5' = b5 * (1 - RESET) + freeInB * FACTOR[5]; b6' = b6 * (1 - RESET) + freeInB * FACTOR[6]; b7' = b7 * (1 - RESET) + freeInB * FACTOR[7]; pol c0Temp = c0 * (1 - RESET) + freeInC * FACTOR[0]; c0' = useCarry * (cOut - c0Temp ) + c0Temp; c1' = c1 * (1 - RESET) + freeInC * FACTOR[1]; c2' = c2 * (1 - RESET) + freeInC * FACTOR[2]; c3' = c3 * (1 - RESET) + freeInC * FACTOR[3]; c4' = c4 * (1 - RESET) + freeInC * FACTOR[4]; c5' = c5 * (1 - RESET) + freeInC * FACTOR[5]; c6' = c6 * (1 - RESET) + freeInC * FACTOR[6]; pol c7Temp = c7 * (1 - RESET) + freeInC * FACTOR[7]; c7' = (1 - useCarry) * c7Temp;
参考资料
附录: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中的常量多项式