基本介绍
Poseidon 函数用来优化零知识证明中证明者和验证者的复杂度。Poseidon运算定义在有限域 上,其中. Poseidon 置换的状态宽度为8 个域元素,其中 capacity 为 4 个域元素。
Poseidon S盒 使用 7 次幂, 即:
Poseidon full round 为 , partial rounds 。
POSEIDON SM 有12个内部的状态,即: in0, in1,... , in7, hashType, cap1, cap2, cap3
进行置换运算 .
运行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
在主状态机执行SLOAD
和 SSTORE
指令的时候,以如下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
网友评论