Polygon zkEVM Poseidon 狀態(tài)機(jī)

基本介紹

Poseidon 函數(shù)用來優(yōu)化零知識證明中證明者和驗(yàn)證者的復(fù)雜度。Poseidon運(yùn)算定義在有限域 \mathbb{F}_p 上澄惊,其中p = 2^{64}-2^{32}+1. Poseidon 置換的狀態(tài)寬度為8 個域元素,其中 capacity 為 4 個域元素。

Poseidon S盒 使用 7 次冪, 即:
SB(x) = x^7,
Poseidon full round 為 R_F=8, partial rounds R_P = 22 望几。

POSEIDON SM 有12個內(nèi)部的狀態(tài),即: in0, in1,... , in7, hashType, cap1, cap2, cap3 進(jìn)行置換運(yùn)算 \text{POSEIDON}^{\pi}.

\text{POSEIDON}^{\pi} 運(yùn)行30輪啼肩, 輸出4個hash 值橄妆,即: hash0, hash1, hash2, hash3

Poseidon算法實(shí)現(xiàn)過程為: https://github.com/0xPolygonHermez/zkevm-commonjs/blob/main/src/poseidon_opt.js

常量多項(xiàng)式構(gòu)建

Poseidon 狀態(tài)機(jī)的常量主要有: LAST, LATCH, C, LASTBLOCK.

module.exports.buildConstants = async function (pols) {
    const N = pols.LAST.length;   // 總行數(shù)

    const maxHashes = Math.floor(N / (nRoundsF + nRoundsP + 1));  // 支持計算的最大Hash的個數(shù)

    for (let i=0; i<N; i++) {
        const iH = Math.floor(i/(nRoundsF + nRoundsP + 1));  // 所計算hash的編號
        const r = i%(nRoundsF + nRoundsP + 1);                // 單個Hash計算中的步數(shù)編號
        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運(yùn)算的最后一步祈坠;
  • LATCH: 表示每個Hash運(yùn)算的第一行害碾;
  • LASTBLOCK: 表示每個Hash運(yùn)算的最后一步;
  • C 表示常量赦拘;
  • PARTIAL : 表示Partial Round.

Main_executor

在主狀態(tài)機(jī)執(zhí)行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

存儲狀態(tài)機(jī)在執(zhí)行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

當(dāng)執(zhí)行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 中執(zhí)行過程為:

        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 字節(jié)數(shù)組中:

 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 進(jìn)行Hash運(yùn)算,生成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運(yùn)算
        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

在執(zhí)行PaddingPG executor 的時候民效,會將輸入的數(shù)據(jù)填充為 BYTESPERBLOCK(7 * 8 = 56) 的整數(shù)倍,

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 數(shù)據(jù)作一次Poseidon 運(yùn)算涛救,也會生成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運(yùn)算的首行检吆。

然后對Poseidon初始狀態(tài)賦值:

       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輪運(yùn)算:

        for (r=0; r<nRoundsF + nRoundsP; r++) {
            state = state.map((a, i) => F.add(a, C[r * t + i]));  // 常量運(yùn)算

            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];   //每一步的中間結(jié)查
            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 結(jié)果
            pols.hash1[p] = input[i][13];
            pols.hash2[p] = input[i][14];
            pols.hash3[p] = input[i][15];
            p+=1;
        }

當(dāng)所的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;  // 保證中間每一輪結(jié)果的正確性
    (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 計算結(jié)果的正確性 
    (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;


主狀態(tài)機(jī)約束

主狀態(tài)機(jī)通過Plonkup 約束·PoseidonG 計算的準(zhǔn)確性蹭沛,由此完成整個Poseidon 狀態(tài)機(jī)約束系統(tǒng)的實(shí)現(xiàn)臂寝。

    (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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市摊灭,隨后出現(xiàn)的幾起案子交煞,更是在濱河造成了極大的恐慌,老刑警劉巖斟或,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件素征,死亡現(xiàn)場離奇詭異,居然都是意外死亡萝挤,警方通過查閱死者的電腦和手機(jī)御毅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來怜珍,“玉大人端蛆,你說我怎么就攤上這事∷址海” “怎么了今豆?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵嫌拣,是天一觀的道長。 經(jīng)常有香客問我呆躲,道長异逐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任插掂,我火速辦了婚禮灰瞻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘辅甥。我一直安慰自己酝润,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布璃弄。 她就那樣靜靜地躺著要销,像睡著了一般。 火紅的嫁衣襯著肌膚如雪夏块。 梳的紋絲不亂的頭發(fā)上疏咐,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天,我揣著相機(jī)與錄音拨扶,去河邊找鬼凳鬓。 笑死,一個胖子當(dāng)著我的面吹牛患民,可吹牛的內(nèi)容都是我干的缩举。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼匹颤,長吁一口氣:“原來是場噩夢啊……” “哼仅孩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起印蓖,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤辽慕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后赦肃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體溅蛉,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年他宛,在試婚紗的時候發(fā)現(xiàn)自己被綠了船侧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡厅各,死狀恐怖镜撩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情队塘,我是刑警寧澤袁梗,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布宜鸯,位于F島的核電站,受9級特大地震影響遮怜,放射性物質(zhì)發(fā)生泄漏淋袖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一奈泪、第九天 我趴在偏房一處隱蔽的房頂上張望适贸。 院中可真熱鬧灸芳,春花似錦涝桅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至谒获,卻和暖如春蛤肌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背批狱。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工裸准, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赔硫。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓炒俱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親爪膊。 傳聞我的和親對象是個殘疾皇子权悟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容