前序博客有:
- Polygon zkEVM递归证明技术文档(1)【主要描述了相关工具 和 证明的组合、递归以及聚合】
- Polygon zkEVM递归证明技术文档(2)—— Polygon zkEVM架构设计
- Polygon zkEVM递归证明技术文档(3)——代码编译及运行
- Polygon zkEVM递归证明技术文档(4)—— C12 PIL Description
本文重点关注:
- 附录:借助SNARKjs和PIL-STARK实现proof composition。
7. 附录:借助SNARKjs和PIL-STARK实现proof composition
本节将展示当前SNARKjs和PIL-STARK工具栈的证明能力。尤其是演示如何实现某些类型的证明组合,从而超过SNARKjs和PIL-STARK原本的能力。
接下来,均以证明如下statement为例:
“I known a (secret) value a 1 = 1 a_1 = 1 a1=1 such that the ( 2 5 + 1 = ) (2^5 + 1 =) (25+1=) 33 33 33-th element of the Fibonacci sequence on (public) input a 0 = 1 a_0 = 1 a0=1 and a 1 a_1 a1 is equal to 3524578 3524578 3524578.”
本文前2小节,将展示如何生成(depth 0)proof。
7.1 Depth 0:Circom + SNARKjs
以Circom来表示上述statement,即意味着将Fibonacci序列计算以R1CS格式表示:
该电路特定实例(即
a
0
=
1
,
a
1
=
1
a_0=1,a_1=1
a0=1,a1=1)的execution trace为:
其中红色字体数字为仅对Prover已知的信息,而绿色字体数字为对Prover和Verifier都已知的信息。
在以Circom对该电路描述之后,可使用SNARKjs来为其生成有效的zk-SNARK证明:【当前SNARKjs支持Groth16、Fflonk和Plonk。为简化接下来都称为Plonk。】
- 1)编译电路:
$ mkdir -p build && circom src/fibonacci.circom --r1cs --wasm -o build
template instances: 1
non-linear constraints: 0
linear constraints: 0
public inputs: 1
public outputs: 1
private inputs: 1
private outputs: 0
wires: 3
labels: 35
- 2)在同一路径下,为该电路创建
input.json
输入文件:
$ cat <<EOT > input.json
{ "a0": 1, "a1": 1}
EOT
- 3)为该输入计算witness:
$ snarkjs wc build/fibonacci_js/fibonacci.wasm src/input.json build/fibonacci.wtns
out = 3524578
- 4)下载足够大的“powers of tau”文件:
$ wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_10.ptau -O build/powersOfTau.ptau
- 5)对该电路进行预处理:
$ snarkjs pks build/fibonacci.r1cs build/powersOfTau.ptau build/fibonacci.zkey
[INFO] snarkJS: Reading r1cs
[INFO] snarkJS: Plonk constraints: 2
[INFO] snarkJS: Setup Finished
- 6)导出proof verification的验证秘钥:
$ snarkjs zkev build/fibonacci.zkey build/fibonacci-vk.json
[INFO] snarkJS: EXPORT VERIFICATION KEY STARTED
[INFO] snarkJS: > Detected protocol: plonk
[INFO] snarkJS: EXPORT VERIFICATION KEY FINISHED
- 7)生成Plonk proof:
$ snarkjs pkp build/fibonacci.zkey build/fibonacci.wtns build/fibonacci.proof.json build/fibonacci.public.json
- 8)最终,验证该proof:
$ snarkjs pkv build/fibonacci-vk.json build/fibonacci.public.json build/fibonacci.proof.json
[ INFO ] snarkJS : OK!
7.2 Depth 0:PIL + PIL-STARK
以PIL来表示以上statement,即意味着需将Fibonacci序列的计算以AIR格式表示,即基于domain
G
=
<
g
>
G=<g>
G=<g>的一组多项式约束。此时,若对所有
x
∈
G
x\in G
x∈G,如下约束:
均满足,则原始statement为true。
此处:
- L 1 , L 32 L_1,L_{32} L1,L32为第一个和最后一个基于 G G G的Lagrange多项式
- a 0 , a 1 a_0,a_1 a0,a1定义为维护Finbonacci序列每个state转变值。
该状态机特定实例(即
a
0
(
g
)
=
1
,
a
1
(
g
)
=
1
a_0(g)=1,a_1(g)=1
a0(g)=1,a1(g)=1)的execution trace为:
在以PIL描述完电路之后,可使用pil-stark来为以上实例生成有效的eSTARK proof:
- 1)向execution trace中填充常量多项式:
$ mkdir -p build && node src/main_buildconst.js -o build/fibonacci.const
file Generated Correctly
- 2)向execution trace中填充committed多项式:
$ node src/main_buildcommit.js -i src/input.json -o build/fibonacci.commit
Result: 3524578
file Generated Correctly
- 3)验证前2步生成的execution trace是否有效:
$ node node_modules/pilcom/src/main_pilverifier.js build/fibonacci.commit -p src / fibonacci.pil -c build/fibonacci.const
PIL OK !!
- 4)在同一路径下,创建具有eSTARK参数的
starkstruct.json
文件:
$ cat << EOT > starkstruct.json
{
"nBits": 5,
"nBitsExt": 6,
"nQueries": 64,
"verificationHashType": "GL",
"steps": [
{ "nBits": 6},
{ "nBits": 4},
{ "nBits": 2}
]
}
EOT
- 5)根据
starkstruct.json
文件,生成,生成eSTARK所需的starkinfo.json
文件:
$ node node_modules/pil-stark/src/main_genstarkinfo.js -p src/fibonacci.pil -s src/starkstruct.json -i build/starkinfo.json
files Generated Correctly
- 6)预处理状态机:
$ node node_modules/pil-stark/src/main_buildconsttree.js -c build/fibonacci.const -p src/fibonacci.pil -s src/starkstruct.json -t build/fibonacci.consttree -v build/fibonacci.verkey.json
files Generated Correctly
- 7)生成eSTARK proof:
$ node node_modules/pil-stark/src/main_prover.js -m build/fibonacci.commit -c build/fibonacci.const -t build/fibonacci.consttree -p src/fibonacci.pil -s build/starkinfo.json -o build/fibonacci.proof.json -z build/fibonacci.zkin.json -b build/fibonacci.public.json
files Generated Correctly
- 8)最后验证该eSTARK proof:
$ node node_modules/pil-stark/src/main_verifier.js -p src/fibonacci.pil -s build/starkinfo.json -v build/fibonacci.verkey.json -o build/fibonacci.proof.json -b build/fibonacci.public.json
Verification Ok!!
7.3 Depth 0:Circom + PIL-STARK
本节将展示如何为以Circom直接编写的Fibonacci电路生成eSTARK proof:
- 1)编译电路:【指定采用Goldilocks域】
注意此处采用Goldilocks素数域,而不是(Circom中默认的)定义BN128椭圆曲线的素数域。原因在于,当前以PIL编写的状态机仅支持Goldilocks域。$ mkdir -p build && circom src/fibonacci.circom --O1 --prime goldilocks --r1cs --wasm -o build template instances: 1 non-linear constraints: 0 linear constraints: 31 public inputs: 1 public outputs: 1 private inputs: 1 private outputs: 0 wires: 34 labels: 35
- 2)在同一路径下,为该电路创建输入文件
input.json
:
$ cat << EOT > input.json
{ "a0": 1 , "a1": 1}
EOT
- 3)基于输入,计算witness:
$ snarkjs wc build/fibonacci_js/fibonacci.wasm src/input.json build/fibonacci.wtns
out = 3524578
- 4)目前已计算出witness(准确来说是R1CS witness),接下来需将电路的R1CS表示,转换为等价的同一电路的Plonk表示:
$ node node_modules/pil-stark/src/main_plonksetup.js -r build/fibonacci.r1cs -p build/fibonacci.pil -e build/fibonacci.exec -c build/fibonacci.const
files Generated Correctly
输出的fibonacci.pil
中,以PIL编写的状态机为:【该转换过程中还会生成一个包含constant多项式的文件fibonacci.const
。】
constant % N = 2**6;
namespace Global(%N);
pol constant L1 ;
pol constant L2 ;
namespace PlonkCircuit(%N) ;
pol constant S[3];
pol constant Qm, Ql, Qr, Qo, Qk;
pol commit a[3];
public pub0 = a[0](0) ;
public pub1 = a[0](1) ;
Global.L1 * (a[0] - :pub0) = 0;
Global.L2 * (a[0] - :pub1) = 0;
// Normal plonk ecuations
pol a01 = a[0]*a[1];
Qm*a01 + Ql*a[0] + Qr*a[1] + Qo*a[2] + Qk = 0;
// Connection equations
{a[0] , a[1] , a[2]} connect {S[0], S[1], S[2]};
- 5)将committed多项式填充到execution trace中:
$ node node_modules/pil-stark/src/main_plonkexec.js -w build/fibonacci.wtns -p build/fibonacci.pil -e build/fibonacci.exec -m build/fibonacci.commit
file Generated Correctly
- 6)验证之前2步所生成的execution trace是否有效:
$ node node_modules/pilcom/src/main_pilverifier.js build/fibonacci.commit -p build/fibonacci.pil -c build/fibonacci.const
PIL OK!!
- 7)在同一路径下创建具有eSTARK参数的
strakstruct.json
文件:
需注意,此处所需的nBits值需由5增加到6,因为将R1CS转换为Plonk的开销(具体可见上面的$ cat << EOT > starkstruct.json { "nBits": 6, "nBitsExt": 7, "nQueries": 64, "verificationHashType": "BN128", "steps": [ { "nBits": 7}, { "nBits": 5}, { "nBits": 3} ] } EOT
fibonacci.pil
状态机)。
接下来就是重复之前7.2节类似的流程来生成eSTARK proof了。 - 8)根据
starkstruct.json
文件,生成,生成eSTARK所需的starkinfo.json
文件:
$ node node_modules/pil-stark/src/main_genstarkinfo.js -p src/fibonacci.pil -s src/starkstruct.json -i build/starkinfo.json
files Generated Correctly
- 9)预处理状态机:
$ node node_modules/pil-stark/src/main_buildconsttree.js -c build/fibonacci.const -p src/fibonacci.pil -s src/starkstruct.json -t build/fibonacci.consttree -v build/fibonacci.verkey.json
files Generated Correctly
- 10)生成eSTARK proof:
$ node node_modules/pil-stark/src/main_prover.js -m build/fibonacci.commit -c build/fibonacci.const -t build/fibonacci.consttree -p src/fibonacci.pil -s build/starkinfo.json -o build/fibonacci.proof.json -z build/fibonacci.zkin.json -b build/fibonacci.public.json
files Generated Correctly
- 11)最后验证该eSTARK proof:
$ node node_modules/pil-stark/src/main_verifier.js -p src/fibonacci.pil -s build/starkinfo.json -v build/fibonacci.verkey.json -o build/fibonacci.proof.json -b build/fibonacci.public.json
Verification Ok!!
接下来的小节中,将使用"PIL-STARK + PIL-STARK" 或 “PIL-STARK + SNARKjs” 组合来展开之前的2个流程。
7.4 Depth 1:Circom + PIL-STARK + SNARKjs
接下来将展示,如何为,以Circom表示的statement的eSTARK proof有效,而生成的SNARK proof:
- 1)编译电路:
$ mkdir -p build && circom src/fibonacci.circom --O1 --prime goldilocks --r1cs --wasm -o build
Everything went okay, circom safe
- 2)在同一路径下,创建该电路的输入文件
input.json
:
$ cat << EOT > input.json
{ "a0": 1, "a1": 1}
EOT
- 3)基于该输入计算witness:
$ snarkjs wc build/fibonacci_js/fibonacci.wasm src/input.json build/fibonacci.wtns
out = 3524578
- 4)根据所计算的witness(准确来说是R1CS),将电路的R1CS表示,转换为同一电路等价的Plonk表示:
$ node node_modules/pil-stark/src/main_plonksetup.js -r build/fibonacci.r1cs -p build/fibonacci.pil -e build/fibonacci.exec -c build/fibonacci.const
files Generated Correctly
- 5)向execution trace填充committed多项式:
$ node node_modules/pil-stark/src/main_plonkexec.js -w build/fibonacci.wtns -p build/fibonacci.pil -e build/fibonacci.exec -m build/fibonacci.commit
file Generated Correctly
- 6)验证前2步所生成的execution trace是否有效:
$ node node_modules/pilcom/src/main_pilverifier.js build/fibonacci.commit -p build/fibonacci.pil -c build/fibonacci.const
PIL OK!!
- 7)在同一路径下创建具有eSTARK参数的
strakstruct.json
文件:
$ cat << EOT > starkstruct.json
{
"nBits": 6,
"nBitsExt": 7,
"nQueries": 64,
"verificationHashType": "BN128",
"steps": [
{ "nBits": 7},
{ "nBits": 5},
{ "nBits": 3}
]
}
EOT
- 8)根据
starkstruct.json
文件,生成,生成eSTARK proof所需的strakinfo.json
文件:
$ node node_modules/pil-stark/src/main_genstarkinfo.js -p build/fibonacci.pil -s src/starkstruct.json -i build/starkinfo.json
files Generated Correctly
- 9)预处理状态机:
$ node node_modules/pil-stark/src/main_buildconsttree.js -c build/fibonacci.const -p build/fibonacci.pil -s src/starkstruct.json -t build/fibonacci.consttree -v build/fibonacci.verkey.json
files Generated Correctly
- 10)生成eSTARK proof:
$ node node_modules/pil-stark/src/main_prover.js -m build/fibonacci.commit -c build/fibonacci.const -t build/fibonacci.consttree -p build/fibonacci.pil -s build/starkinfo.json -o build/fibonacci.proof.json -z build/fibonacci.zkin.json -b build/fibonacci.public.json --proverAddr 0x7BAbF98C66454aF8a3C366F893f99EBa26a15c66
files Generated Correctly
- 11)验证该eSTARK proof是否正确:
$ node node_modules/pil-stark/src/main_verifier.js -p build/fibonacci.pil -s build/starkinfo.json -v build/fibonacci.verkey.json -o build/fibonacci.proof.json -b build/fibonacci.public.json
Verification Ok!!
- 12)接下来,将eSTARK verifier生成为Circom电路:
此处支持递归性:若以之前生成的eSTARK proof为输入,生成了一个有效的SNARK,则可证明该eSTARK proof是有效的。$ node node_modules/pil-stark/src/main_pil2circom.js -p build/fibonacci.pil -s build/starkinfo.json -v build/fibonacci.verkey.json -o build/verifier.circom file Generated Correctly
- 13)需使用
circuits.gl
中的电路来编译该eSTARK verifier电路:
$ circom build/verifier circom --r1cs --wasm -l node_modules/pil-stark/circuits.bn128 -l node_modules/circomlib/circuits -o build
template instances: 465
non-linear constraints: 2123834
linear constraints: 0
public inputs: 0
public outputs: 1
private inputs: 14682
private outputs: 0
wires: 2125925
labels: 5010997
- 14)在同一路径下为该电路创建输入文件
input.json
:
$ cat << EOT > input.json
{ "a0": 1, "a1": 1}
EOT
- 15)基于输入计算witness:
$ snarkjs wc build/verifier_js/verifier.wasm build/fibonacci.zkin.json build/verifier.wtns
out = 3524578
- 16)下载足够大的“powers of tau”文件:
$ wget https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_16.ptau -O build/powersOfTau.ptau
- 17)预处理电路:
$ snarkjs pks build/verifier.r1cs build/powersOfTau.ptau build/fibonacci.zkey
[INFO] snarkJS: Reading r1cs
[INFO] snarkJS: Plonk constraints: 2
[INFO] snarkJS: Setup Finished
- 18)导出验证proof所需的验证密钥:
$ snarkjs zkev build/veirifer.zkey build/veirifer-vk.json
[INFO] snarkJS: EXPORT VERIFICATION KEY STARTED
[INFO] snarkJS: > Detected protocol: plonk
[INFO] snarkJS: EXPORT VERIFICATION KEY FINISHED
- 19)生成Plonk proof:
$ snarkjs pkp build/veirifer.zkey build/veirifer.wtns build/veirifer.proof.json build/veirifer.public.json
- 20)验证该Plonk proof:
$ snarkjs pkv build/veirifer-vk.json build/veirifer.public.json build/veirifer.proof.json
[INFO] snarkJS: OK!
7.5 unlimited depth with PIL-STARK
本节,将针对:
- 以PIL编写的Fibonacci序列
- 为其生成eSTARK proof
- 并为该eSTARK proof的有效性,生成eSTARK proof
以上相同的流程可不停重复,从而实现无限深度的proof composition。如之前各小节所示,无限的eSTARK composition最终以final SNARK结尾。
以下流程展示了PIL-STARK和SNARKjs工具栈的强大之处:
- 1)向execution trace中填充constant多项式:
$ mkdir -p build && node src/main_buildconst.js -o build/fibonacci.const
file Generated Correctly
- 2)向execution trace中填充committed多项式:
$ node src/main_buildcommit.js -i src/input.json -o build/fibonacci.commit
Result: 3524578
file Generated Correctly
- 3)验证前2步所生成的execution trace是否有效:
$ node node_modules/pilcom/src/main_pilverifier.js build/fibonacci.commit -p src/fibonacci.pil -c build/fibonacci.const
PIL OK!!
- 4)在同一路径下创建具有eSTARK参数的
strakstruct.json
文件:
$ cat << EOT > fibonacci.starkstruct.json
{
"nBits": 5,
"nBitsExt": 6,
"nQueries": 64,
"verificationHashType": "GL",
"steps": [
{ "nBits": 6},
{ "nBits": 4},
{ "nBits": 2}
]
}
EOT
- 5)基于
strakstruct.json
文件,生成,生成eSTARK proof所需的starkinfo.json
文件:
$ node node_modules/pil-stark/src/main_genstarkinfo.js -p src/fibonacci.pil -s src/fibonacci.starkstruct.json -i build/starkinfo.json
files Generated Correctly
- 6)预处理状态机:
$ node node_modules/pil-stark/src/main_buildconsttree.js -c build/fibonacci.const -p src/fibonacci.pil -s src/fibonacci.starkstruct.json -t build/fibonacci.consttree -v build/fibonacci.verkey.json
files Generated Correctly
- 7)生成eSTARK proof:
$ node node_modules/pil-stark/src/main_prover.js -m build/fibonacci.commit -c build/fibonacci.const -t build/fibonacci.consttree -p src/fibonacci.pil -s build/starkinfo.json -o build/fibonacci.proof.json -z build/fibonacci.zkin.json -b build/fibonacci.public.json
files Generated Correctly
- 8)验证该eSTARK proof是否正确:
$ node node_modules/pil-stark/src/main_verifier.js -p src/fibonacci.pil -s build/starkinfo.json -v build/fibonacci.verkey.json -o build/fibonacci.proof.json -b build/fibonacci.public.json
Verification Ok!!
- 9)为eSTARK verifier生成Circom电路:
$ node node_modules/pil-stark/src/main_pil2circom.js -p src/fibonacci.pil -s build/starkinfo.json -v build/fibonacci.verkey.json -o build/verifier.circom
Verification Ok!!
- 10)编译该verifier circom电路:
$ circom --O1 --prime goldilocks --r1cs --wasm build/verifier.circom -l node_modules/pil-stark/circuits.gl -o build
Verification Ok!!
- 11)基于输入计算witness
$ snarkjs wc build/verifier_js/verifier.wasm build/fibonacci.zkin.json build/verifier.wtns
out = 3524578
- 12)将所生成的verifier circom(r1cs)电路转换为状态机:
$ node node_modules/pil-stark/src/main_plonksetup.js -r build/verifier.r1cs -p build/verifier.pil -c build/verifier.const -e build/verifier.exec
files Generated Correctly
- 13)向execution trace中填充committed多项式:
$ node node_modules/pil-stark/src/main_plonkexec.js -w build/verifier.wtns -p build/verifier.pil -e build/verifier.exec -m build/verifier.commit
files Generated Correctly
- 14)验证前2步所生成的execution trace是否有效:
$ node node_modules/pilcom/src/main_pilverifier.js build/verifier.commit -p build/verifier.pil -c build/verifier.const
PIL OK!!
- 15)在同一路径下创建具有eSTARK参数的
verifier.starkstruct.json
文件:
至此,就可采用之前的流程来生成eSTARK proof。$ cat << EOT > verifier.starkstruct.json { "nBits": 16, "nBitsExt": 17, "nQueries": 64, "verificationHashType": "GL", "steps": [ { "nBits": 17}, { "nBits": 14}, { "nBits": 10}, { "nBits": 6} ] } EOT
- 16)根据
verifier.starkstruct.json
文件,生成,生成eSTARK proof所需的verifier.starkinfo.json
文件:
$ node node_modules/pil-stark/src/main_genstarkinfo.js -p build/verifier.pil -s src/verifier.starkstruct.json -i build/verifier.starkinfo.json
files Generated Correctly
- 17)预处理状态机
verifier.pil
:
$ node node_modules/pil-stark/src/main_buildconsttree.js -c build/verifier.const -p build/verifier.pil -s src/verifier.starkstruct.json -t build/verifier.consttree -v build/verifier.verkey.json
files Generated Correctly
- 18)生成eSTARK proof:
$ node node_modules/pil-stark/src/main_prover.js -m build/verifier.commit -c build/verifier.const -t build/verifier.consttree -p build/verifier.pil -s build/verifier.starkinfo.json -o build/verifier.proof.json -z build/verifier.zkin.json -b build/verifier.public.json
files Generated Correctly
- 19)验证该eSTARK proof:
$ node node_modules/pil-stark/src/main_verifier.js -p build/verifier.pil -s build/verifier.starkinfo.json -v build/verifier.verkey.json -o build/verifier.proof.json -b build/verifier.public.json
Verification Ok !!
正如之前所提及的,可为eSTARK verifier生成Circom电路,并遵循10-18步骤来重复以上流程,其中每次重复会创建一个starkstruct.json文件。
参考资料
[1] Polygon zkEVM技术文档 Recursion, aggregation and composition of proofs v.1.1
附录: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语法
- Polygon zkEVM可验证计算简单状态机示例
- Polygon zkEVM zkASM 与 以太坊虚拟机opcode 对应集合
- Polygon zkEVM zkROM代码解析(1)
- Polygon zkEVM zkASM中的函数集合
- Polygon zkEVM zkROM代码解析(2)
- Polygon zkEVM zkROM代码解析(3)
- Polygon zkEVM公式梳理
- Polygon zkEVM中的Merkle tree
- Polygon zkEVM中Goldilocks域元素circom约束
- Polygon zkEVM Merkle tree的circom约束
- Polygon zkEVM FFT和多项式evaluate计算的circom约束
- Polygon zkEVM R1CS与Plonk电路转换
- Polygon zkEVM中的子约束系统
- Polygon zkEVM交易解析
- Polygon zkEVM 审计及递归证明
- Polygon zkEVM发布公开测试网2.0
- Polygon zkEVM测试集——创建合约交易
- Polygon zkEVM中的Recursive STARKs
- Polygon zkEVM的gas定价
- Polygon zkEVM zkProver基本设计原则 以及 Storage状态机
- Polygon zkEVM bridge技术文档
- Polygon zkEVM Trustless L2 State Management 技术文档
- Polygon zkEVM中的自定义errors
- Polygon zkEVM RPC服务
- Polygon zkEVM Prover的 RPC功能
- Polygon zkEVM PIL技术文档
- Polygon zkEVM递归证明技术文档(1)【主要描述了相关工具 和 证明的组合、递归以及聚合】
- Polygon zkEVM递归证明技术文档(2)—— Polygon zkEVM架构设计
- Polygon zkEVM递归证明技术文档(3)——代码编译及运行
- Polygon zkEVM递归证明技术文档(4)—— C12 PIL Description