美文网首页
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 状态机设计原理

    Polygon zkEVM是兼容EVM的zkRollup Layer 2 方案。zkEVM 证明的第一步是构建交易...

  • Polygon zkEVM 整体架构

    Polygon zkEVM 是EVM的zkRollup方案,可以提供智能合约支持,用以提升以太坊的可扩展性。 架构...

  • Polygon zkEVM zkProver设计

    zkProver主要完成批量交易的证明,是Polygon zkEVM的关键组件。下图展示了zkProver和Nod...

  • Proof of Efficiency: zk-rollups

    PoE是Polygon Hermez 为zkEVM实现设计的一种新的共识机制 , 它基于之前的PoD(Proof ...

  • Hermez zkEVM

    本文主要对Hermez 2.0 zkEVM设计思路进行简单介绍。 Fibonacci 状态机 先从Fibonacc...

  • Poseidon

    Dodo、2017/6/25(Sun) Poseidon is one of the ‘‘Big Three G...

  • zkEVM 类型

    PSE: 第1种类型Polygon Hermez 和 Scroll : 第2或3种类型zkSync和MatterL...

  • [CSS][交互]断开的文字效果

    知识点: clip-path:polygon() code time clip-path polygon图形构建与...

  • cesium entity对象立体面的拉伸高度

    polygon高度的2个参数具体含义: height:是指polygon距离地面的高度 extrudedHeigh...

  • 设计模式-状态机

    对于一个状态机来说,需要分成2个部分来考虑状态机,一是状态机本身,二是状态机的实现。 状态机推演 只有状态机本身是...

网友评论

      本文标题:Polygon zkEVM Poseidon 状态机

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