美文网首页
Polygon zkEVM Poseidon 状态机

Polygon zkEVM Poseidon 状态机

作者: 雪落无留痕 | 来源:发表于2023-09-13 00:10 被阅读0次

    基本介绍

    Poseidon 函数用来优化零知识证明中证明者和验证者的复杂度。Poseidon运算定义在有限域 \mathbb{F}_p 上,其中p = 2^{64}-2^{32}+1. Poseidon 置换的状态宽度为8 个域元素,其中 capacity 为 4 个域元素。

    Poseidon S盒 使用 7 次幂, 即:
    SB(x) = x^7,
    Poseidon full round 为 R_F=8, partial rounds R_P = 22

    POSEIDON SM 有12个内部的状态,即: in0, in1,... , in7, hashType, cap1, cap2, cap3 进行置换运算 \text{POSEIDON}^{\pi}.

    \text{POSEIDON}^{\pi} 运行30轮, 输出4个hash 值,即: hash0, hash1, hash2, hash3

    Poseidon算法实现过程为: https://github.com/0xPolygonHermez/zkevm-commonjs/blob/main/src/poseidon_opt.js

    常量多项式构建

    Poseidon 状态机的常量主要有: LAST, LATCH, C, LASTBLOCK.

    module.exports.buildConstants = async function (pols) {
        const N = pols.LAST.length;   // 总行数
    
        const maxHashes = Math.floor(N / (nRoundsF + nRoundsP + 1));  // 支持计算的最大Hash的个数
    
        for (let i=0; i<N; i++) {
            const iH = Math.floor(i/(nRoundsF + nRoundsP + 1));  // 所计算hash的编号
            const r = i%(nRoundsF + nRoundsP + 1);                // 单个Hash计算中的步数编号
            pols.LAST[i] = ((i == N-1) || (i % (nRoundsF + nRoundsP + 1)) == (nRoundsF + nRoundsP)) ? 1n : 0n;
            pols.LATCH[i] = ((iH<maxHashes) && (i % (nRoundsF + nRoundsP + 1) == 0)) ? 1n : 0n;
            pols.LASTBLOCK[i] = ((i % (nRoundsF + nRoundsP + 1)) == (nRoundsF + nRoundsP)) ? 1n : 0n;
            for (j=0; j<12; j++) {
                pols.C[j][i] = C[12*r + j]
            }
            pols.PARTIAL[i] = (r>=nRoundsF/2 && r<(nRoundsF/2 + nRoundsP)) ? 1n : 0n;
        }
    };
    

    其中:

    • LAST: 表示最后一行,或都每个Hash运算的最后一步;
    • LATCH: 表示每个Hash运算的第一行;
    • LASTBLOCK: 表示每个Hash运算的最后一步;
    • C 表示常量;
    • PARTIAL : 表示Partial Round.

    Main_executor

    在主状态机执行SLOADSSTORE 指令的时候,以如下zkASM代码为例:

    ;; Assert local exit root
            ; Read 'localExitRoot' variable from GLOBAL_EXIT_ROOT_MANAGER_L2 and check
            ; it is equal to the 'newLocalExitRoot' input
            %ADDRESS_GLOBAL_EXIT_ROOT_MANAGER_L2  => A
            %SMT_KEY_SC_STORAGE => B
            %LOCAL_EXIT_ROOT_STORAGE_POS => C
            $ => A                                          :SLOAD
    

    会生成PoseidonG Action, 如下所示:

         const keyI = poseidon(Kin0);
         required.PoseidonG.push([...Kin0, 0n, 0n, 0n, 0n, ...keyI]);
         const key = poseidon(Kin1, keyI);
         required.PoseidonG.push([...Kin1, ...keyI,  ...key]);
    

    STORAGE_executor

    存储状态机在执行Hash (Hash0或Hash1)指令的时候,以如下zkASM代码为例:

        ; NewRoot = Hash0( 0, NewRoot )
        0x0 => HASH_LEFT
        NEW_ROOT => HASH_RIGHT
        $ => NEW_ROOT                   :HASH0
    

    也会生成PoseidonG Action , 如下所示:

                // Call poseidon
                let rp = poseidon(fea, cap);
    
                // Get the calculated hash from the first 4 elements
                pols.free0[i] = rp[0];
                pols.free1[i] = rp[1];
                pols.free2[i] = rp[2];
                pols.free3[i] = rp[3];
    
                op[0] = fr.add(op[0],fr.mul(BigInt(rom.line[l].inFREE), pols.free0[i]));
                op[1] = fr.add(op[1],fr.mul(BigInt(rom.line[l].inFREE), pols.free1[i]));
                op[2] = fr.add(op[2],fr.mul(BigInt(rom.line[l].inFREE), pols.free2[i]));
                op[3] = fr.add(op[3],fr.mul(BigInt(rom.line[l].inFREE), pols.free3[i]));
    
                pols.iHash[i] = 1n;
    
                required.PoseidonG.push([fea[0],fea[1],fea[2],fea[3],fea[4],fea[5],fea[6],fea[7],cap[0],cap[1],cap[2],cap[3],rp[0],rp[1],rp[2],rp[3]]);
    
    

    PaddingPG

    当执行zkASM指令 hashP, hashPLen, hashPDigest 的时候,

    checkHashBytecodeLoop:
            %MAX_CNT_STEPS - STEP - 10 :JMPN(outOfCounters)
            B - 1 - HASHPOS                         :JMPN(checkHashBytecodeEnd) ; finish reading bytecode
            ${getBytecode(A, HASHPOS, 1)}           :HASHP(E) ; hash contract bytecode
                                                    :JMP(checkHashBytecodeLoop)
    
    checkHashBytecodeEnd:
            HASHPOS                         :HASHPLEN(E)
            $ => E                          :HASHPDIGEST(E)
    

    编译后的json 文件为:

      {
       "freeInTag": {
        "op": "functionCall",
        "funcName": "getBytecode",
        "params": [
         {
          "op": "getReg",
          "regName": "A"
         },
         {
          "op": "getReg",
          "regName": "HASHPOS"
         },
         {
          "op": "number",
          "num": "1"
         }
        ]
       },
       "inFREE": "1",
       "ind": 1,
       "indRR": 0,
       "offset": 0,
       "hashP": 1,
       "line": 469,
       "fileName": "process-tx.zkasm",
       "lineStr": "        ${getBytecode(A, HASHPOS, 1)}           :HASHP(E) ; hash contract bytecode"
      },
      {
       "JMP": 1,
       "JMPC": 0,
       "JMPN": 0,
       "offset": 1368,
       "line": 470,
       "offsetLabel": "checkHashBytecodeLoop",
       "fileName": "process-tx.zkasm",
       "lineStr": "                                                :JMP(checkHashBytecodeLoop)"
      },
      {
       "inHASHPOS": "1",
       "ind": 1,
       "indRR": 0,
       "offset": 0,
       "hashPLen": 1,
       "line": 473,
       "fileName": "process-tx.zkasm",
       "lineStr": "        HASHPOS                         :HASHPLEN(E)"
      },
      {
       "freeInTag": {
        "op": ""
       },
       "inFREE": "1",
       "setE": 1,
       "ind": 1,
       "indRR": 0,
       "offset": 0,
       "hashPDigest": 1,
       "line": 474,
       "fileName": "process-tx.zkasm",
       "lineStr": "        $ => E                          :HASHPDIGEST(E)"
      },
    

    hashP

    Main executor 中执行过程为:

            if (l.hashP) {
                if (typeof ctx.hashP[addr] === "undefined") ctx.hashP[addr] = { data: [], reads: {} };
                pols.hashP[i] = 1n;
                const size = fe2n(Fr, ctx.D[0], ctx);
                const pos = fe2n(Fr, ctx.HASHPOS, ctx);
                if ((size < 0) || (size > 32)) throw new Error(`Invalid size for hash: ${ctx.ln} at ${ctx.fileName}:${ctx.line}`);
                const a = fea2scalar(Fr, [op0, op1, op2, op3, op4, op5, op6, op7]);
                const maskByte = Scalar.e("0xFF");
                for (let k = 0; k < size; k++) {
                    const bm = Scalar.toNumber(Scalar.band(Scalar.shr(a, (size - k - 1) * 8), maskByte));
                    const bh = ctx.hashP[addr].data[pos + k];
                    if (typeof bh === "undefined") {
                        ctx.hashP[addr].data[pos + k] = bm;
                    } else if (bm != bh) {
                        throw new Error(`HashP do not match ${addr}:${pos + k} is ${bm} and should be ${bh}`)
                    }
                }
                const paddingA = Scalar.shr(a, size * 8);
                if (!Scalar.isZero(paddingA)) {
                    throw new Error(`Incoherent size (${size}) and data (0x${a.toString(16)}) padding (0x${paddingA.toString(16)}) for hashP (w=${step}): ${ctx.ln} at ${ctx.fileName}:${ctx.line}`);
                }
    
                if ((typeof ctx.hashP[addr].reads[pos] !== "undefined") &&
                    (ctx.hashP[addr].reads[pos] != size)) {
                    throw new Error(`HashP diferent read sizes in the same position ${addr}:${pos}`)
                }
                ctx.hashP[addr].reads[pos] = size;
                incHashPos = size;
            } else {
                pols.hashP[i] = 0n;
            }
    

    其主要将Poseidon hash的每个输入保存在data 字节数组中:

     ctx.hashP[addr].data[pos + k] = bm;
    

    将每个输入的长度保存在reads中:

    ctx.hashP[addr].reads[pos] = size;
    

    hashPLen

            if (l.hashPLen) {
                pols.hashPLen[i] = 1n;
                const lm = fe2n(Fr, op0, ctx);
                const lh = ctx.hashP[addr].data.length;
                if (lm != lh) throw new Error(`HashP length does not match ${addr}  is ${lm} and should be ${lh}`);
                if (typeof ctx.hashP[addr].digest === "undefined") {
                    // ctx.hashP[addr].digest = poseidonLinear(ctx.hash[addr].data);
                    ctx.hashP[addr].digest = await hashContractBytecode(byteArray2HexString(ctx.hashP[addr].data));
                    await db.setProgram(stringToH4(ctx.hashP[addr].digest), ctx.hashP[addr].data)
                }
            } else {
                pols.hashPLen[i] = 0n;
            }
    

    要是对ctx.hashP[addr].data 进行Hash运算,生成Poseidon hash, 保存在 ctx.hashP[addr].digets中。

    hashPDigest

            if (l.hashPDigest) {
                pols.hashPDigest[i] = 1n;
                const dg = fea2scalar(Fr, [op0, op1, op2, op3, op4, op5, op6, op7]);
                if (typeof ctx.hashP[addr] === "undefined") {
                    const k = scalar2h4(dg);
                    const data = await smt.db.getProgram(k);
    
                    ctx.hashP[addr] = {
                        data: data,
                        digest: dg
                    }
                }
                incCounter = Math.ceil((ctx.hashP[addr].data.length + 1) / 56);
                if (!Scalar.eq(Scalar.e(dg), Scalar.e(ctx.hashP[addr].digest))) {
                    throw new Error(`Digest doesn't match`);
                }
            } else {
                pols.hashPDigest[i] = 0n;
            }
    

    hashPDigest 主要是了获取计算的Poseidon hash值。

    Paddding PG action

    最后生成PaddingPG action.

        for (let i = 0; i < ctx.hashP.length; i++) {  //每个i,代表一次Poseidon的输入,
                                                       // 若是输入过长,每次输入需要多轮Poseidon运算
            const h = {
                data: ctx.hashP[i].data,
                reads: []
            }
            let p = 0;
            while (p < ctx.hashP[i].data.length) {
                if (ctx.hashP[i].reads[p]) {
                    h.reads.push(ctx.hashP[i].reads[p]);
                    p += ctx.hashP[i].reads[p];
                } else {
                    h.reads.push(1);
                    p += 1;
                }
            }
            if (p != ctx.hashP[i].data.length) {
                throw new Error(`Reading hashP out of limits: ${step}`);
            }
            required.PaddingPG.push(h);
        }
    

    PoseidonG action

    在执行PaddingPG executor 的时候,会将输入的数据填充为 BYTESPERBLOCK(7 * 8 = 56) 的整数倍,

    function prepareInput(input) {
        function hexToBytes(hex) {
            for (var bytes = [], c = 0; c < hex.length; c += 2)
                bytes.push(parseInt(hex.substr(c, 2), 16));
            return bytes;
        }
    
        for (let i=0; i<input.length; i++) {
            // TODO: check if test send information as string and order of bytes on data
            if (typeof input[i].data === 'string') {
                input[i].dataBytes = hexToBytes(input[i].data);
            } else {
                input[i].dataBytes = input[i].data;
            }
            input[i].realLen = BigInt(input[i].dataBytes.length);
    
            input[i].dataBytes.push(0x1);
    
            while (input[i].dataBytes.length % BYTESPERBLOCK) input[i].dataBytes.push(0);
    
            input[i].dataBytes[ input[i].dataBytes.length - 1] |= 0x80;
        }
    }
    

    BYTESPERBLOCK 数据作一次Poseidon 运算,也会生成PoseidonG Action.

                    required.PoseidonG.push([
                        pols.acc[0][p+1],
                        pols.acc[1][p+1],
                        pols.acc[2][p+1],
                        pols.acc[3][p+1],
                        pols.acc[4][p+1],
                        pols.acc[5][p+1],
                        pols.acc[6][p+1],
                        pols.acc[7][p+1],
                        pols.prevHash0[p],
                        pols.prevHash1[p],
                        pols.prevHash2[p],
                        pols.prevHash3[p],
                        pols.curHash0[p],
                        pols.curHash1[p],
                        pols.curHash2[p],
                        pols.curHash3[p]
                    ]);
    

    PoseidonG executor

    首先解析PoseidonG action的输入:

       let p=0;
        for (let i=0; i<input.length; i++) {
            pols.in0[p] = F.e(input[i][0]);
            pols.in1[p] = F.e(input[i][1]);
            pols.in2[p] = F.e(input[i][2]);
            pols.in3[p] = F.e(input[i][3]);
            pols.in4[p] = F.e(input[i][4]);
            pols.in5[p] = F.e(input[i][5]);
            pols.in6[p] = F.e(input[i][6]);
            pols.in7[p] = F.e(input[i][7]);
            pols.hashType[p] = F.e(input[i][8]);
            pols.cap1[p] = F.e(input[i][9]);
            pols.cap2[p] = F.e(input[i][10]);
            pols.cap3[p] = F.e(input[i][11]);
            pols.hash0[p] = F.e(input[i][12]);
            pols.hash1[p] = F.e(input[i][13]);
            pols.hash2[p] = F.e(input[i][14]);
            pols.hash3[p] = F.e(input[i][15]);
    

    对于每个action, 前12个值为输入,后4个值为输出,放于每个Hash运算的首行。

    然后对Poseidon初始状态赋值:

           p += 1;
            let state = [
                pols.in0[p-1],
                pols.in1[p-1],
                pols.in2[p-1],
                pols.in3[p-1],
                pols.in4[p-1],
                pols.in5[p-1],
                pols.in6[p-1],
                pols.in7[p-1],
                pols.hashType[p-1],
                pols.cap1[p-1],
                pols.cap2[p-1],
                pols.cap3[p-1]
            ];
    

    然后按行30轮运算:

            for (r=0; r<nRoundsF + nRoundsP; r++) {
                state = state.map((a, i) => F.add(a, C[r * t + i]));  // 常量运算
    
                if (r < nRoundsF / 2 || r >= nRoundsF / 2 + nRoundsP) {
                    state = state.map((a) => pow7(a));    // full round
                } else {
                    state[0] = pow7(state[0]);   // partial round
                }
                state = state.map((_, i) => state.reduce((acc, a, j) => F.add(acc, F.mul(M[i][j], a)), F.zero));
    
                pols.in0[p] = state[0];   //每一步的中间结查
                pols.in1[p] = state[1];
                pols.in2[p] = state[2];
                pols.in3[p] = state[3];
                pols.in4[p] = state[4];
                pols.in5[p] = state[5];
                pols.in6[p] = state[6];
                pols.in7[p] = state[7];
                pols.hashType[p] = state[8];
                pols.cap1[p] = state[9];
                pols.cap2[p] = state[10];
                pols.cap3[p] = state[11];
                pols.hash0[p] = input[i][12];  // hash 结果
                pols.hash1[p] = input[i][13];
                pols.hash2[p] = input[i][14];
                pols.hash3[p] = input[i][15];
                p+=1;
            }
    

    当所的PoseidonG action处理完之后,其余的行填充处理,如下所示:

        let st0 = [];
        st0[0] = [F.zero, F.zero, F.zero, F.zero, F.zero, F.zero, F.zero, F.zero, F.zero, F.zero, F.zero, F.zero];
    
        for (r=0; r<nRoundsF + nRoundsP; r++) {
            st0[r+1] = st0[r].map((a, i) => F.add(a, C[r * t + i]));
    
            if (r < nRoundsF / 2 || r >= nRoundsF / 2 + nRoundsP) {
                st0[r+1] = st0[r+1].map((a) => pow7(a));
            } else {
                st0[r+1][0] = pow7(st0[r+1][0]);
            }
            st0[r+1] = st0[r+1].map((_, i) => st0[r+1].reduce((acc, a, j) => F.add(acc, F.mul(M[i][j], a)), F.zero));
        }
    
        while (p<N) {
            pols.in0[p] = st0[p%(nRoundsP + nRoundsF + 1)][0];
            pols.in1[p] = st0[p%(nRoundsP + nRoundsF + 1)][1];
            pols.in2[p] = st0[p%(nRoundsP + nRoundsF + 1)][2];
            pols.in3[p] = st0[p%(nRoundsP + nRoundsF + 1)][3];
            pols.in4[p] = st0[p%(nRoundsP + nRoundsF + 1)][4];
            pols.in5[p] = st0[p%(nRoundsP + nRoundsF + 1)][5];
            pols.in6[p] = st0[p%(nRoundsP + nRoundsF + 1)][6];
            pols.in7[p] = st0[p%(nRoundsP + nRoundsF + 1)][7];
            pols.hashType[p] = st0[p%(nRoundsP + nRoundsF + 1)][8];
            pols.cap1[p] = st0[p%(nRoundsP + nRoundsF + 1)][9];
            pols.cap2[p] = st0[p%(nRoundsP + nRoundsF + 1)][10];
            pols.cap3[p] = st0[p%(nRoundsP + nRoundsF + 1)][11];
            pols.hash0[p] = st0[nRoundsP + nRoundsF][0];
            pols.hash1[p] = st0[nRoundsP + nRoundsF][1];
            pols.hash2[p] = st0[nRoundsP + nRoundsF][2];
            pols.hash3[p] = st0[nRoundsP + nRoundsF][3];
            p+=1;
        }
    

    PoseidonG PIL 约束

    namespace PoseidonG(%N);
    
        pol constant LAST;   // 0, 0, 0, ...0, 1,      0, ...., 0, 1, 0, ....
        pol constant LATCH;  // 1, 0, 0, 0, ..., 0,    1, 0, 0,
        pol constant LASTBLOCK;   // 0, 0, 0, ...0, 1,      0, ...., 0, 1, 0, ....
        pol constant PARTIAL;
        pol constant C[12];
        pol commit in0, in1, in2, in3, in4, in5, in6, in7, hashType, cap1, cap2, cap3;
        pol commit hash0, hash1, hash2, hash3;
    
        pol a0 = in0 + C[0];
        pol a1 = in1 + C[1];
        pol a2 = in2 + C[2];
        pol a3 = in3 + C[3];
        pol a4 = in4 + C[4];
        pol a5 = in5 + C[5];
        pol a6 = in6 + C[6];
        pol a7 = in7 + C[7];
        pol a8 = hashType + C[8];
        pol a9 = cap1 + C[9];
        pol a10 = cap2 + C[10];
        pol a11 = cap3 + C[11];
    
        pol x2_0 = a0 * a0;
        pol x4_0 = x2_0 * x2_0;
        pol x6_0 = x2_0 * x4_0;
        pol x7_0 = x6_0 * a0;
    
        pol x2_1 = a1 * a1;
        pol x4_1 = x2_1 * x2_1;
        pol x6_1 = x2_1 * x4_1;
        pol x7_1 = x6_1 * a1;
    
        pol x2_2 = a2 * a2;
        pol x4_2 = x2_2 * x2_2;
        pol x6_2 = x2_2 * x4_2;
        pol x7_2 = x6_2 * a2;
    
        pol x2_3 = a3 * a3;
        pol x4_3 = x2_3 * x2_3;
        pol x6_3 = x2_3 * x4_3;
        pol x7_3 = x6_3 * a3;
    
        pol x2_4 = a4 * a4;
        pol x4_4 = x2_4 * x2_4;
        pol x6_4 = x2_4 * x4_4;
        pol x7_4 = x6_4 * a4;
    
        pol x2_5 = a5 * a5;
        pol x4_5 = x2_5 * x2_5;
        pol x6_5 = x2_5 * x4_5;
        pol x7_5 = x6_5 * a5;
    
        pol x2_6 = a6 * a6;
        pol x4_6 = x2_6 * x2_6;
        pol x6_6 = x2_6 * x4_6;
        pol x7_6 = x6_6 * a6;
    
        pol x2_7 = a7 * a7;
        pol x4_7 = x2_7 * x2_7;
        pol x6_7 = x2_7 * x4_7;
        pol x7_7 = x6_7 * a7;
    
        pol x2_8 = a8 * a8;
        pol x4_8 = x2_8 * x2_8;
        pol x6_8 = x2_8 * x4_8;
        pol x7_8 = x6_8 * a8;
    
        pol x2_9 = a9 * a9;
        pol x4_9 = x2_9 * x2_9;
        pol x6_9 = x2_9 * x4_9;
        pol x7_9 = x6_9 * a9;
    
        pol x2_10 = a10 * a10;
        pol x4_10 = x2_10 * x2_10;
        pol x6_10 = x2_10 * x4_10;
        pol x7_10 = x6_10 * a10;
    
        pol x2_11 = a11 * a11;
        pol x4_11 = x2_11 * x2_11;
        pol x6_11 = x2_11 * x4_11;
        pol x7_11 = x6_11 * a11;
    
        pol b0 = x7_0;
        pol b1 = PARTIAL * (a1 - x7_1) + x7_1;
        pol b2 = PARTIAL * (a2 - x7_2) + x7_2;
        pol b3 = PARTIAL * (a3 - x7_3) + x7_3;
        pol b4 = PARTIAL * (a4 - x7_4) + x7_4;
        pol b5 = PARTIAL * (a5 - x7_5) + x7_5;
        pol b6 = PARTIAL * (a6 - x7_6) + x7_6;
        pol b7 = PARTIAL * (a7 - x7_7) + x7_7;
        pol b8 = PARTIAL * (a8 - x7_8) + x7_8;
        pol b9 = PARTIAL * (a9 - x7_9) + x7_9;
        pol b10 = PARTIAL * (a10 - x7_10) + x7_10;
        pol b11 = PARTIAL * (a11 - x7_11) + x7_11;
    
        pol  c0 = 25*b0 + 15*b1 + 41*b2 + 16*b3 +  2*b4 + 28*b5 + 13*b6 + 13*b7 + 39*b8 + 18*b9 + 34*b10 + 20*b11;
        pol  c1 = 20*b0 + 17*b1 + 15*b2 + 41*b3 + 16*b4 +  2*b5 + 28*b6 + 13*b7 + 13*b8 + 39*b9 + 18*b10 + 34*b11 ;
        pol  c2 = 34*b0 + 20*b1 + 17*b2 + 15*b3 + 41*b4 + 16*b5 +  2*b6 + 28*b7 + 13*b8 + 13*b9 + 39*b10 + 18*b11;
        pol  c3 = 18*b0 + 34*b1 + 20*b2 + 17*b3 + 15*b4 + 41*b5 + 16*b6 +  2*b7 + 28*b8 + 13*b9 + 13*b10 + 39*b11;
        pol  c4 = 39*b0 + 18*b1 + 34*b2 + 20*b3 + 17*b4 + 15*b5 + 41*b6 + 16*b7 +  2*b8 + 28*b9 + 13*b10 + 13*b11;
        pol  c5 = 13*b0 + 39*b1 + 18*b2 + 34*b3 + 20*b4 + 17*b5 + 15*b6 + 41*b7 + 16*b8 +  2*b9 + 28*b10 + 13*b11;
        pol  c6 = 13*b0 + 13*b1 + 39*b2 + 18*b3 + 34*b4 + 20*b5 + 17*b6 + 15*b7 + 41*b8 + 16*b9 +  2*b10 + 28*b11;
        pol  c7 = 28*b0 + 13*b1 + 13*b2 + 39*b3 + 18*b4 + 34*b5 + 20*b6 + 17*b7 + 15*b8 + 41*b9 + 16*b10 +  2*b11;
        pol  c8 =  2*b0 + 28*b1 + 13*b2 + 13*b3 + 39*b4 + 18*b5 + 34*b6 + 20*b7 + 17*b8 + 15*b9 + 41*b10 + 16*b11;
        pol  c9 = 16*b0 +  2*b1 + 28*b2 + 13*b3 + 13*b4 + 39*b5 + 18*b6 + 34*b7 + 20*b8 + 17*b9 + 15*b10 + 41*b11;
        pol c10 = 41*b0 + 16*b1 +  2*b2 + 28*b3 + 13*b4 + 13*b5 + 39*b6 + 18*b7 + 34*b8 + 20*b9 + 17*b10 + 15*b11;
        pol c11 = 15*b0 + 41*b1 + 16*b2 +  2*b3 + 28*b4 + 13*b5 + 13*b6 + 39*b7 + 18*b8 + 34*b9 + 20*b10 + 17*b11;
    
        (in0' - c0) * (1-LAST) = 0;  // 保证中间每一轮结果的正确性
        (in1' - c1) * (1-LAST) = 0;
        (in2' - c2) * (1-LAST) = 0;
        (in3' - c3) * (1-LAST) = 0;
        (in4' - c4) * (1-LAST) = 0;
        (in5' - c5) * (1-LAST) = 0;
        (in6' - c6) * (1-LAST) = 0;
        (in7' - c7) * (1-LAST) = 0;
        (hashType' - c8) * (1-LAST) = 0;
        (cap1' - c9) * (1-LAST) = 0;
        (cap2' - c10) * (1-LAST) = 0;
        (cap3' - c11) * (1-LAST) = 0;
    
        (hash0 - in0)*LASTBLOCK = 0;   // 保证最后一步Poseidon 计算结果的正确性 
        (hash1 - in1)*LASTBLOCK = 0;
        (hash2 - in2)*LASTBLOCK = 0;
        (hash3 - in3)*LASTBLOCK = 0;
    
        (hash0 - hash0')*(1-LAST) = 0;   // 保证Hash中间传递时的正确性
        (hash1 - hash1')*(1-LAST) = 0;
        (hash2 - hash2')*(1-LAST) = 0;
        (hash3 - hash3')*(1-LAST) = 0;
    
    
    

    主状态机约束

    主状态机通过Plonkup 约束·PoseidonG 计算的准确性,由此完成整个Poseidon 状态机约束系统的实现。

        (sRD + sWR) {
            C0, C1, C2, C3, C4, C5, C6, C7,
            0, 0, 0, 0,
            sKeyI[0], sKeyI[1], sKeyI[2], sKeyI[3]
        } in
        PoseidonG.LATCH {
            PoseidonG.in0,
            PoseidonG.in1,
            PoseidonG.in2,
            PoseidonG.in3,
            PoseidonG.in4,
            PoseidonG.in5,
            PoseidonG.in6,
            PoseidonG.in7,
            PoseidonG.hashType,
            PoseidonG.cap1,
            PoseidonG.cap2,
            PoseidonG.cap3,
            PoseidonG.hash0,
            PoseidonG.hash1,
            PoseidonG.hash2,
            PoseidonG.hash3
        };
    
        sRD + sWR {
            A0, A1, A2, A3, A4, A5, B0, B1,
            sKeyI[0], sKeyI[1], sKeyI[2], sKeyI[3],
            sKey[0], sKey[1], sKey[2], sKey[3]
        } in
        PoseidonG.LATCH {
            PoseidonG.in0,
            PoseidonG.in1,
            PoseidonG.in2,
            PoseidonG.in3,
            PoseidonG.in4,
            PoseidonG.in5,
            PoseidonG.in6,
            PoseidonG.in7,
            PoseidonG.hashType,
            PoseidonG.cap1,
            PoseidonG.cap2,
            PoseidonG.cap3,
            PoseidonG.hash0,
            PoseidonG.hash1,
            PoseidonG.hash2,
            PoseidonG.hash3
        };
    

    参考

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

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

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

    https://github.com/0xPolygonHermez/zkevm-storage-rom

    相关文章

      网友评论

          本文标题:Polygon zkEVM Poseidon 状态机

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