美文网首页
Polygon zkEVM 递归证明过程

Polygon zkEVM 递归证明过程

作者: 雪落无留痕 | 来源:发表于2023-09-11 14:36 被阅读0次

    2022年12月21日,Polygon zkEVM 发布了第二个测试网,也是主网上线前最后一个测试网。此次升级主要在zkEVM 实现递归证明,实现Batch 聚合过程,并将每个Batch证明时间降低从原先的10min 降到 4min 以下,每个Batch的Gas limit 从 4 millon 增加到 10 milion, 进一步降低交易费用,增加吞吐量,并且还引入了EIP-155 (引入chain_id, 防止重入攻击) 的支持。

    recursive1

    生成recursive1证明需要两轮 stark->stark 证明,即 \pi_{batch}\rightarrow \pi_{c12a} \rightarrow \pi_{segment}, 皆定义在Goldilocks 域上。

    对于STARK 转换为STARK, 首先通过PIL2Circom 过程,生成circom 验证电路,用于验证STARK证明; 再将circom 电路编译成R1CS 之后,转换变Plonk 形式的电路,再生成PIL 的描述,通过这个过程,可以用于验证STARK 证明的PIL约束; 然后根据PIL, 可以生成新的STARK证明.

    因此recursive1 证明的实现过程如下:

    关于具体的解析过程,详见 STARK->SNARK 解析文档。

    生成\pi_{batch} 证时的Stark struct 结构为:

    {
                "nBits": 23,  // 基域
                "nBitsExt": 24,  // 扩域
                "nQueries": 128,  // FRI 查询点的个数
                "verificationHashType": "GL",  // Goldilocks 域
                "steps": [
                    {"nBits": 24},   // FRI各层域的位数 
                    {"nBits": 19},
                    {"nBits": 14},
                    {"nBits": 10},
                    {"nBits": 6}
                ]
    }
    

    生成 \pi_{C12a} 证明时的Stark struct 结构为:

    {
        "nBits": 22,
        "nBitsExt": 24,
        "nQueries": 64,
        "verificationHashType": "GL",
        "steps": [
            {"nBits": 24},
            {"nBits": 20},
            {"nBits": 15},
            {"nBits": 10},
            {"nBits": 5}
        ]
    }
    

    recursive1 验证\pi_b 的验证电路recursive1.circom为:

    pragma circom 2.1.0;
    pragma custom_templates;
    
    include "c12a.verifier.circom";
    
    template Main() {
        
        //publics 43个元素分别为:
        // 0-7: oldStateRoot; 8-15: OldAccInputHash; 16: oldBatchNum; 17: chainId, 
        // 18-25:newStateRoot; 26-33: newAccInputHash; 34-41: localExitRoot, 42: newBatchNum 
        signal input publics[43];         
        signal input rootC[4]; // 常量多项式对应的Merkle 根
    
        signal input root1[4]; // commit多项式对应的Merkle 根   
        signal input root2[4];  // plookup 多项式对应的Merkle 根
        signal input root3[4];  // plookup/permutation/connection Z 多项式对应的根
        signal input root4[4];  // q多项式 约束对应的Merkle 根
        signal input evals[94][3]; // 对应starkinfo 中 evMap中各个承诺多项式的值。
    
        signal input s0_vals1[64][12]; //FRI proof[0]: 64 表示查询点的个数,12表示commit多项式的个数(cm1_2ns)
        signal input s0_vals3[64][41]; 
        //FRI proof[0]: 64 表示查询点的个数,41表示plookup/permutation/connection Z多项式的个数
        
        signal input s0_vals4[64][12]; //FRI proof[0]: 64 表示查询点的个数,12表示 q多项式的个数(q_2ns)
        signal input s0_valsC[64][34]; //FRI proof[0]: 64 表示查询点的个数,34表示常量多项式的个数
        signal input s0_siblings1[64][24][4]; //s0_vals1对应的Merkle 路径,有24层,每个节点由4个Goldilocks 元素组成
        signal input s0_siblings3[64][24][4];
        signal input s0_siblings4[64][24][4];
        signal input s0_siblingsC[64][24][4];
    
        signal input s1_root[4]; // fri step 1 root
        signal input s2_root[4]; // fri step 2 root
        signal input s3_root[4]; // fri step 3 root
        signal input s4_root[4]; // fri step 4 root
    
        signal input s1_vals[64][48]; // fri 1 tree对应查询点的叶子节点,48为对应叶子width  
        signal input s1_siblings[64][20][4]; // fri 1 tree 查询点对应的Merkle路径
        signal input s2_vals[64][96];
        signal input s2_siblings[64][15][4];
        signal input s3_vals[64][96];
        signal input s3_siblings[64][10][4];
        signal input s4_vals[64][96];
        signal input s4_siblings[64][5][4];
    
        signal input finalPol[32][3]; // 最后一轮,每个都为宽度为3的值
    
    
    
        component vA = StarkVerifier();
    
        vA.publics <== publics;
        vA.root1 <== root1;
        vA.root2 <== root2;
        vA.root3 <== root3;
        vA.root4 <== root4;
        vA.evals <== evals;
        vA.s0_vals1 <== s0_vals1;
        vA.s0_vals3 <== s0_vals3;
        vA.s0_vals4 <== s0_vals4;
        vA.s0_valsC <== s0_valsC;
        vA.s0_siblings1 <== s0_siblings1;
        vA.s0_siblings3 <== s0_siblings3;
        vA.s0_siblings4 <== s0_siblings4;
        vA.s0_siblingsC <== s0_siblingsC;
        vA.s1_root <== s1_root;
        vA.s2_root <== s2_root;
        vA.s3_root <== s3_root;
        vA.s4_root <== s4_root;
        vA.s1_vals <== s1_vals;
        vA.s1_siblings <== s1_siblings;
        vA.s2_vals <== s2_vals;
        vA.s2_siblings <== s2_siblings;
        vA.s3_vals <== s3_vals;
        vA.s3_siblings <== s3_siblings;
        vA.s4_vals <== s4_vals;
        vA.s4_siblings <== s4_siblings;
        vA.finalPol <== finalPol;
    
    }
    
    component main {public [publics, rootC]}= Main(); // 公开输入为:publics 和 常量多项式根
    

    生成recursive1 证明时的的 Stark struct 为:

    {
        "nBits": 20,
        "nBitsExt": 24,
        "nQueries": 32,
        "verificationHashType": "GL",
        "steps": [
            {"nBits": 24},
            {"nBits": 19},
            {"nBits": 14},
            {"nBits": 9},
            {"nBits": 5}
        ]
    }
    

    recursive2

    通过合并两个recursive1证明的验证过程,生成recursive2 证明。

    recrsive2的验证电路recursive2.circom.ejs为, 其中包含了两个recursive1 证明的验证。

    注: 在进行ejs注入时,需要提供recursive1 常量根。

    pragma circom 2.1.0;
    pragma custom_templates;
    
    include "recursive1.verifier.circom";
    include "mux1.circom";
    include "iszero.circom";
    
    template Main() {
    
        var rootCSingle[4];
        rootCSingle[0] = <%- constRoot[0] %>;
        rootCSingle[1] = <%- constRoot[1] %>;
        rootCSingle[2] = <%- constRoot[2] %>;
        rootCSingle[3] = <%- constRoot[3] %>;
    
        signal input publics[43];
        signal input rootC[4];
    
        signal input a_publics[43];
    
        signal input a_root1[4];
        signal input a_root2[4];
        signal input a_root3[4];
        signal input a_root4[4];
    
        signal input a_evals[72][3];
    
        signal input a_s0_vals1[32][12];
        signal input a_s0_vals3[32][3];
        signal input a_s0_vals4[32][36];
        signal input a_s0_valsC[32][34];
        signal input a_s0_siblings1[32][24][4];
        signal input a_s0_siblings3[32][24][4];
        signal input a_s0_siblings4[32][24][4];
        signal input a_s0_siblingsC[32][24][4];
    
        signal input a_s1_root[4];
        signal input a_s2_root[4];
        signal input a_s3_root[4];
        signal input a_s4_root[4];
    
        signal input a_s1_vals[32][96];
        signal input a_s1_siblings[32][19][4];
        signal input a_s2_vals[32][96];
        signal input a_s2_siblings[32][14][4];
        signal input a_s3_vals[32][96];
        signal input a_s3_siblings[32][9][4];
        signal input a_s4_vals[32][48];
        signal input a_s4_siblings[32][5][4];
    
        signal input a_finalPol[32][3];
    
    
    
        signal input b_publics[43];
    
        signal input b_root1[4];
        signal input b_root2[4];
        signal input b_root3[4];
        signal input b_root4[4];
        signal input b_evals[72][3];
    
        signal input b_s0_vals1[32][12];
        signal input b_s0_vals3[32][3];
        signal input b_s0_vals4[32][36];
        signal input b_s0_valsC[32][34];
        signal input b_s0_siblings1[32][24][4];
        signal input b_s0_siblings3[32][24][4];
        signal input b_s0_siblings4[32][24][4];
        signal input b_s0_siblingsC[32][24][4];
    
        signal input b_s1_root[4];
        signal input b_s2_root[4];
        signal input b_s3_root[4];
        signal input b_s4_root[4];
    
        signal input b_s1_vals[32][96];
        signal input b_s1_siblings[32][19][4];
        signal input b_s2_vals[32][96];
        signal input b_s2_siblings[32][14][4];
        signal input b_s3_vals[32][96];
        signal input b_s3_siblings[32][9][4];
        signal input b_s4_vals[32][48];
        signal input b_s4_siblings[32][5][4];
    
        signal input b_finalPol[32][3];
    
        component vA = StarkVerifier();
    
        for (var i=0; i<43; i++) {
            vA.publics[i] <== a_publics[i];
        }
        vA.root1 <== a_root1;
        vA.root2 <== a_root2;
        vA.root3 <== a_root3;
        vA.root4 <== a_root4;
        vA.evals <== a_evals;
        vA.s0_vals1 <== a_s0_vals1;
        vA.s0_vals3 <== a_s0_vals3;
        vA.s0_vals4 <== a_s0_vals4;
        vA.s0_valsC <== a_s0_valsC;
        vA.s0_siblings1 <== a_s0_siblings1;
        vA.s0_siblings3 <== a_s0_siblings3;
        vA.s0_siblings4 <== a_s0_siblings4;
        vA.s0_siblingsC <== a_s0_siblingsC;
        vA.s1_root <== a_s1_root;
        vA.s2_root <== a_s2_root;
        vA.s3_root <== a_s3_root;
        vA.s4_root <== a_s4_root;
        vA.s1_vals <== a_s1_vals;
        vA.s1_siblings <== a_s1_siblings;
        vA.s2_vals <== a_s2_vals;
        vA.s2_siblings <== a_s2_siblings;
        vA.s3_vals <== a_s3_vals;
        vA.s3_siblings <== a_s3_siblings;
        vA.s4_vals <== a_s4_vals;
        vA.s4_siblings <== a_s4_siblings;
        vA.finalPol <== a_finalPol;
    
        component isOneBatchA = IsZero();
        isOneBatchA.in  <== a_publics[42] - a_publics[16] - 1;
        component a_muxRootC = MultiMux1(4);
        a_muxRootC.c[0] <== rootC;
        a_muxRootC.c[1] <== rootCSingle;
        a_muxRootC.s <== isOneBatchA.out;
    
        for (var i=0; i<4; i++) {
            vA.publics[43+i] <== rootC[i];
        }
        vA.rootC <== a_muxRootC.out;
    
        component vB = StarkVerifier();
    
        for (var i=0; i<43; i++) {
            vB.publics[i] <== b_publics[i];
        }
        vB.root1 <== b_root1;
        vB.root2 <== b_root2;
        vB.root3 <== b_root3;
        vB.root4 <== b_root4;
        vB.evals <== b_evals;
        vB.s0_vals1 <== b_s0_vals1;
        vB.s0_vals3 <== b_s0_vals3;
        vB.s0_vals4 <== b_s0_vals4;
        vB.s0_valsC <== b_s0_valsC;
        vB.s0_siblings1 <== b_s0_siblings1;
        vB.s0_siblings3 <== b_s0_siblings3;
        vB.s0_siblings4 <== b_s0_siblings4;
        vB.s0_siblingsC <== b_s0_siblingsC;
        vB.s1_root <== b_s1_root;
        vB.s2_root <== b_s2_root;
        vB.s3_root <== b_s3_root;
        vB.s4_root <== b_s4_root;
        vB.s1_vals <== b_s1_vals;
        vB.s1_siblings <== b_s1_siblings;
        vB.s2_vals <== b_s2_vals;
        vB.s2_siblings <== b_s2_siblings;
        vB.s3_vals <== b_s3_vals;
        vB.s3_siblings <== b_s3_siblings;
        vB.s4_vals <== b_s4_vals;
        vB.s4_siblings <== b_s4_siblings;
        vB.finalPol <== b_finalPol;
    
    
        component isOneBatchB = IsZero();
        isOneBatchB.in <== b_publics[42] - b_publics[16] - 1;
        component b_muxRootC = MultiMux1(4);
        b_muxRootC.c[0] <== rootC;
        b_muxRootC.c[1] <== rootCSingle;
        b_muxRootC.s <== isOneBatchB.out;
    
        for (var i=0; i<4; i++) {
            vB.publics[43+i] <== rootC[i];
        }
        vB.rootC <== b_muxRootC.out;
    
        // oldStateRoot
        for (var i=0; i<8; i++) {
            a_publics[i] === publics[i];
        }
    
        // oldAccInputHash
        for (var i=8; i<16; i++) {
            a_publics[i] === publics[i];
        }
    
        // oldBatchNum
        a_publics[16] === publics[16];
    
        // chainId
        a_publics[17] === publics[17];
    
        // midStateRoot
        for (var i=0; i<8; i++) {
            b_publics[i] === a_publics[18+i];
        }
    
        // midAccInputHash
        for (var i=8; i<16; i++) {
            b_publics[i] === a_publics[18+i];
        }
    
        // midBatchNum
        b_publics[16] === a_publics[18+24];
    
        // chainId
        b_publics[17] === publics[17];
    
    
        // newStateRoot
        for (var i=0; i<8; i++) {
            publics[18+i] === b_publics[18+i];
        }
    
        // newAccInputHash
        for (var i=8; i<16; i++) {
            publics[18+i] === b_publics[18+i];
        }
    
        // localExitRoot
        for (var i=16; i<24; i++) {
            publics[18+i] === b_publics[18+i];
        }
    
        // newBatchNum
        publics[18+24] === b_publics[18+24];
    
    }
    
    component main {public [publics, rootC]}= Main();
    
    

    注:publics 43个元素分别为: 0-7: oldStateRoot; 8-15: OldAccInputHash; 16: oldBatchNum; 17: chainId, 18-25:newStateRoot; 26-33: newAccInputHash; 34-41: localExitRoot, 42: newBatchNum.

    生成recursive2 证明时的的 Stark struct 和 recursive1的一致,皆为:

    {
        "nBits": 20,
        "nBitsExt": 24,
        "nQueries": 32,
        "verificationHashType": "GL",
        "steps": [
            {"nBits": 24},
            {"nBits": 19},
            {"nBits": 14},
            {"nBits": 9},
            {"nBits": 5}
        ]
    }
    

    由于recursive1.pil(生成recursive1 证明)和recursive2.pil(生成recursive2证明)完全一致,并且recursive1.verifier.circom(验证recursive1证明) 和recursive2.verifier.circom` (验证recursive2证明) 一致,

     "recursive_pil_check": ". ./pre.sh && F1=$BDIR/recursive1.pil && F2=$BDIR/recursive2.pil && diff $F1 $F2 || (echo \"ERROR: $F1 $F2 are different\"; exit 1)",
    "recursive_verifier_check": ". ./pre.sh && F1=$BDIR/recursive1.verifier.circom && F2=$BDIR/recursive2.verifier.circom && diff $F1 $F2 || (echo \"ERROR: $F1 $F2 are different\"; exit 1)",
    
    

    因此可以将一个recursive2 证明当作一个recursive1 证明, 可以再次将一个recursive2 证明和一个recursive1 证明,合并成一个新的recursive2 证明。

    recursivef

    在对recursivef.circom.ejs 进行 ejs 注入时,需要提供recursive1recursive2 的常量根:

        const template = await fs.promises.readFile(path.join(__dirname, "..", "recursive", "recursivef.circom.ejs"), "utf8");
    
        const obj = {
            constRoot1: constRoot1,
            constRoot2: constRoot2,
        };
    
        console.log(obj)
    
        const verifier = ejs.render(template ,  obj);
    

    recursivef.circom.ejs的实现过程为如下,主要是对一个STARK 证明的验证:

    pragma circom 2.1.0;
    pragma custom_templates;
    
    include "recursive2.verifier.circom";
    include "mux1.circom";
    include "iszero.circom";
    
    template Main() {
        signal input publics[43];
    
        signal input root1[4];
        signal input root2[4];
        signal input root3[4];
        signal input root4[4];
    
        signal input evals[72][3];
    
        signal input s0_vals1[32][12];
        signal input s0_vals3[32][3];
        signal input s0_vals4[32][36];
        signal input s0_valsC[32][34];
        signal input s0_siblings1[32][24][4];
        signal input s0_siblings3[32][24][4];
        signal input s0_siblings4[32][24][4];
        signal input s0_siblingsC[32][24][4];
    
        signal input s1_root[4];
        signal input s2_root[4];
        signal input s3_root[4];
        signal input s4_root[4];
    
        signal input s1_vals[32][96];
        signal input s1_siblings[32][19][4];
        signal input s2_vals[32][96];
        signal input s2_siblings[32][14][4];
        signal input s3_vals[32][96];
        signal input s3_siblings[32][9][4];
        signal input s4_vals[32][48];
        signal input s4_siblings[32][5][4];
    
        signal input finalPol[32][3];
    
        component sv = StarkVerifier();
    
        for (var i=0; i<43; i++) {
            sv.publics[i] <== publics[i];
        }
        sv.root1 <== root1;
        sv.root2 <== root2;
        sv.root3 <== root3;
        sv.root4 <== root4;
        sv.evals <== evals;
        sv.s0_vals1 <== s0_vals1;
        sv.s0_vals3 <== s0_vals3;
        sv.s0_vals4 <== s0_vals4;
        sv.s0_valsC <== s0_valsC;
        sv.s0_siblings1 <== s0_siblings1;
        sv.s0_siblings3 <== s0_siblings3;
        sv.s0_siblings4 <== s0_siblings4;
        sv.s0_siblingsC <== s0_siblingsC;
        sv.s1_root <== s1_root;
        sv.s2_root <== s2_root;
        sv.s3_root <== s3_root;
        sv.s4_root <== s4_root;
        sv.s1_vals <== s1_vals;
        sv.s1_siblings <== s1_siblings;
        sv.s2_vals <== s2_vals;
        sv.s2_siblings <== s2_siblings;
        sv.s3_vals <== s3_vals;
        sv.s3_siblings <== s3_siblings;
        sv.s4_vals <== s4_vals;
        sv.s4_siblings <== s4_siblings;
        sv.finalPol <== finalPol;
    
        component isOne = IsZero();
        isOne.in <== publics[42] -publics[16] -1;
        component muxKey = MultiMux1(4);
        muxKey.s <== isOne.out;
        muxKey.c[0][0] <== <%- constRoot2[0] %>;
        muxKey.c[0][1] <== <%- constRoot2[1] %>;
        muxKey.c[0][2] <== <%- constRoot2[2] %>;
        muxKey.c[0][3] <== <%- constRoot2[3] %>;
        muxKey.c[1][0] <== <%- constRoot1[0] %>;
        muxKey.c[1][1] <== <%- constRoot1[1] %>;
        muxKey.c[1][2] <== <%- constRoot1[2] %>;
        muxKey.c[1][3] <== <%- constRoot1[3] %>;
    
        sv.publics[43] <== <%- constRoot2[0] %>;
        sv.publics[44] <== <%- constRoot2[1] %>;
        sv.publics[45] <== <%- constRoot2[2] %>;
        sv.publics[46] <== <%- constRoot2[3] %>;
    
        sv.rootC[0] <== muxKey.out[0];
        sv.rootC[1] <== muxKey.out[1];
        sv.rootC[2] <== muxKey.out[2];
        sv.rootC[3] <== muxKey.out[3];
    
    }
    
    component main {public [publics]}= Main();
    

    生成 recursivef 证明的Stark struck 结构为:

    {
        "nBits": 19,
        "nBitsExt": 23,
        "nQueries": 32,
        "verificationHashType": "BN128",  // 定义在 BN128 标量域上
        "steps": [
            {"nBits": 23},
            {"nBits": 20},
            {"nBits": 16},
            {"nBits": 12},
            {"nBits": 8},
            {"nBits": 4}
        ]
    }
    

    final

    final.circom 电路主要用于验证recursivef 证明,生成最后的SNARK 证明。

    隐私输入为:aggregatorAddr, oldStateRoot, oldAcInputHash, oldBatchNum, chainId, newStateRoot, newAccInputHash, newLocalExitRoot, newBatchNum.

    公开输入:上述所有隐私输入变量拼接后计算得到的Hash值。

    pragma circom 2.1.0;
    
    /*
    aggregatorAddr -> 160   -> 160
    oldStateRoot -> 256     -> 416
    oldAccInputHash -> 256  -> 672
    oldBathcNum -> 64       -> 736
    chainId -> 64           -> 800
    newStateRoot -> 256     -> 1056
    newAccInputHash -> 256  -> 1312
    newLocalExitRoot -> 256 -> 1568
    newBatchNum -> 64       -> 1632
    
    Total: 1632
    */
    
    include "sha256/sha256.circom";
    include "bitify.circom";
    include "recursivef.verifier.circom";
    
    template Main() {
        signal output publicsHash;
    
        signal input aggregatorAddr;
    
        signal input publics[43];
        signal input root1;
        signal input root2;
        signal input root3;
        signal input root4;
    
        signal input evals[72][3];
    
        signal input s0_vals1[32][12];
        signal input s0_vals3[32][3];
        signal input s0_vals4[32][36];
        signal input s0_valsC[32][34];
    
        signal input s0_siblings1[32][6][16];
        signal input s0_siblings3[32][6][16];
        signal input s0_siblings4[32][6][16];
        signal input s0_siblingsC[32][6][16];
    
        signal input s1_root;
        signal input s2_root;
        signal input s3_root;
        signal input s4_root;
        signal input s5_root;
    
        signal input s1_vals[32][24];
        signal input s1_siblings[32][5][16];
        signal input s2_vals[32][48];
        signal input s2_siblings[32][4][16];
        signal input s3_vals[32][48];
        signal input s3_siblings[32][3][16];
        signal input s4_vals[32][48];
        signal input s4_siblings[32][2][16];
        signal input s5_vals[32][48];
        signal input s5_siblings[32][1][16];
    
        signal input finalPol[16][3];
    
    
        component sv = StarkVerifier();
        sv.publics <== publics;
        sv.root1 <== root1;
        sv.root2 <== root2;
        sv.root3 <== root3;
        sv.root4 <== root4;
    
        sv.evals <== evals;
    
        sv.s0_vals1 <== s0_vals1;
        sv.s0_vals3 <== s0_vals3;
        sv.s0_vals4 <== s0_vals4;
        sv.s0_valsC <== s0_valsC;
    
        sv.s0_siblings1 <== s0_siblings1;
        sv.s0_siblings3 <== s0_siblings3;
        sv.s0_siblings4 <== s0_siblings4;
        sv.s0_siblingsC <== s0_siblingsC;
    
        sv.s1_root <== s1_root;
        sv.s2_root <== s2_root;
        sv.s3_root <== s3_root;
        sv.s4_root <== s4_root;
        sv.s5_root <== s5_root;
    
        sv.s1_vals <== s1_vals;
        sv.s1_siblings <== s1_siblings;
        sv.s2_vals <== s2_vals;
        sv.s2_siblings <== s2_siblings;
        sv.s3_vals <== s3_vals;
        sv.s3_siblings <== s3_siblings;
        sv.s4_vals <== s4_vals;
        sv.s4_siblings <== s4_siblings;
        sv.s5_vals <== s5_vals;
        sv.s5_siblings <== s5_siblings;
    
        sv.finalPol <== finalPol;
    
        component publicsHasher = Sha256(1632);
    
        component n2bAggregatorAddr = Num2Bits(160);
        n2bAggregatorAddr.in <== aggregatorAddr;
        for (var i=0; i<160; i++) {
            publicsHasher.in[0 + 160 - 1 -i] <== n2bAggregatorAddr.out[i];
        }
    
        component n2bOldStateRoot[8];
        for (var i=0; i<8; i++) {
            n2bOldStateRoot[i] = Num2Bits(32);
            n2bOldStateRoot[i].in <== publics[0 + i];
            for (var j=0; j<32; j++) {
                publicsHasher.in[160 + 32*(8-i) - 1 -j] <== n2bOldStateRoot[i].out[j];
            }
        }
    
        component n2bOldAccInputHash[8];
        for (var i=0; i<8; i++) {
            n2bOldAccInputHash[i] = Num2Bits(32);
            n2bOldAccInputHash[i].in <== publics[8 + i];
            for (var j=0; j<32; j++) {
                publicsHasher.in[416 + 32*(8-i) - 1 -j] <== n2bOldAccInputHash[i].out[j];
            }
        }
    
        // Do 63 bits to avoid aliasing
        component n2bOldBatchNum = Num2Bits(63);
        n2bOldBatchNum.in <== publics[16];
        for (var i=0; i<63; i++) {
            publicsHasher.in[672 + 64 - 1 -i] <== n2bOldBatchNum.out[i];
        }
        publicsHasher.in[672] <== 0;
    
        component n2bChainId = Num2Bits(63);
        n2bChainId.in <== publics[17];
        for (var i=0; i<63; i++) {
            publicsHasher.in[736 + 64 - 1 -i] <== n2bChainId.out[i];
        }
        publicsHasher.in[736] <== 0;
    
        component n2bNewStateRoot[8];
        for (var i=0; i<8; i++) {
            n2bNewStateRoot[i] = Num2Bits(32);
            n2bNewStateRoot[i].in <== publics[18+i];
            for (var j=0; j<32; j++) {
                publicsHasher.in[800 + 32*(8-i) - 1 -j] <== n2bNewStateRoot[i].out[j];
            }
        }
    
        component n2bNewAccInputHash[8];
        for (var i=0; i<8; i++) {
            n2bNewAccInputHash[i] = Num2Bits(32);
            n2bNewAccInputHash[i].in <== publics[26+i];
            for (var j=0; j<32; j++) {
                publicsHasher.in[1056 + 32*(8-i) - 1 -j] <== n2bNewAccInputHash[i].out[j];
            }
        }
    
        component n2bNewLocalExitRoot[8];
        for (var i=0; i<8; i++) {
            n2bNewLocalExitRoot[i] = Num2Bits(32);
            n2bNewLocalExitRoot[i].in <== publics[34+i];
            for (var j=0; j<32; j++) {
                publicsHasher.in[1312 + 32*(8-i) - 1 -j] <== n2bNewLocalExitRoot[i].out[j];
            }
        }
    
        component n2bNewBatchNum = Num2Bits(63);
        n2bNewBatchNum.in <== publics[42];
        for (var i=0; i<63; i++) {
            publicsHasher.in[1568 + 64 - 1 -i] <== n2bNewBatchNum.out[i];
        }
        publicsHasher.in[1568] <== 0;
    
        component b2nPublicsHash = Bits2Num(256);
        for (var i = 0; i < 256; i++) {
            b2nPublicsHash.in[i] <== publicsHasher.out[255-i];
        }
    
        publicsHash <== b2nPublicsHash.out;
    }
    
    component main = Main();
    
    

    final.circom 编译为R1CS后,即可生成最后SNARK 证明,完成整个递归证明过程。在目前的c++/js 版本的zkevm-prover中,最终生成的还是Groth16证明。

    参考

    https://polygon.technology/blog/final-approach-last-testnet-for-an-upgraded-polygon-zkevm

    https://eips.ethereum.org/EIPS/eip-155

    https://github.com/0xPolygonHermez/zkevm-proverjs

    https://github.com/0xPolygonHermez/zkevm-prover

    相关文章

      网友评论

          本文标题:Polygon zkEVM 递归证明过程

          本文链接:https://www.haomeiwen.com/subject/xjwevdtx.html