前序博客有:
- Polygon zkEVM中的常量多项式
- Polygon zkEVM zkASM编译器——zkasmcom
zkASM语法重点参看:
- https://github.com/0xPolygonHermez/zkasmcom/blob/main/src/zkasm_parser.jison(zkASM Compiler项目)
- https://github.com/0xPolygonHermez/zkasmcom/blob/main/src/command_parser.jison(zkASM Compiler项目)
- https://github.com/0xPolygonHermez/zkevm-storage-rom/blob/main/src/zkasm_parser.jison(zkEVM-Storage-Rom项目)
- https://github.com/0xPolygonHermez/zkevm-storage-rom/blob/main/src/command_parser.jison(zkEVM-Storage-Rom项目)
zkASM程序的基本结构为:
start(或其它任意label名,序号为0。为主业务流程):
assignment : opcode
; 以分号来表示注释。
; 以上主业务流程处理完之后,必须将相关寄存器清零,以防止重入问题。
; 该模块的作用是给相关寄存器清零,zkevm-proverjs中的sm_main_exec.js中会`checkFinalState`检查。
end(或其它任意label名,但必须在后面的补零操作label之前):
0 => A,B,C,D,E,CTX, SP, PC, GAS, MAXMEM, SR
; 补零操作必须紧跟上面的清零操作。
padZeros(因execution trace或者说多项式的degree size是固定的,因此需要做补零操作,补零到倒数第二行):
notLastTwo : padZerosOp
: JMP(start) ; 上面之所以补零到倒数第二行,是因为倒数第一行预留给本指令,以实现跳转到主业务流程功能。
; 以上操作将整个execution trace表已填满,后续的都是无效指令。
opInvalid(无效指令,没有意义):
以zkevm-proverjs中的arith.zkasm为例:
start:
STEP => A
0 :ASSERT
0 => A
CNT_ARITH :ASSERT
CNT_BINARY :ASSERT
CNT_KECCAK_F: ASSERT
CNT_MEM_ALIGN :ASSERT
CNT_POSEIDON_G :ASSERT
CNT_PADDING_PG :ASSERT
0 => A,B,C,D :ARITH
CNT_ARITH => A
1 :ASSERT
CNT_ARITH => A
1 :ASSERT
0x2000000000000000000000000000000000000000000000000000000000000001n => A
0x100 => B
0x73 => C
0x20 => D
0x173 :ARITH
2 => A
CNT_ARITH :ASSERT
0 => A
CNT_KECCAK_F: ASSERT
CNT_MEM_ALIGN :ASSERT
CNT_POSEIDON_G :ASSERT
CNT_PADDING_PG :ASSERT
end:
0 => A,B,C,D,E,CTX, SP, PC, GAS, MAXMEM, SR
finalWait:
${beforeLast()} : JMPN(finalWait)
: JMP(start)
opINVALID:
其经zkASM compiler编译后的结果为:【注意,labels中的数值对应上面program数组中的index,其中的JMP/JMPC/JMPN等与offset等配合进行跳转。】
{
"program": [
{
"inSTEP": "1",
"setA": 1,
"line": 3,
"fileName": "arith.zkasm",
"lineStr": " STEP => A"
},
{
"CONST": "0",
"assert": 1,
"line": 4,
"fileName": "arith.zkasm",
"lineStr": " 0 :ASSERT"
},
{
"CONST": "0",
"setA": 1,
"line": 6,
"fileName": "arith.zkasm",
"lineStr": " 0 => A"
},
{
"inCntArith": "1",
"assert": 1,
"line": 7,
"fileName": "arith.zkasm",
"lineStr": " CNT_ARITH :ASSERT"
},
{
"inCntBinary": "1",
"assert": 1,
"line": 8,
"fileName": "arith.zkasm",
"lineStr": " CNT_BINARY :ASSERT"
},
{
"inCntKeccakF": "1",
"assert": 1,
"line": 9,
"fileName": "arith.zkasm",
"lineStr": " CNT_KECCAK_F: ASSERT"
},
{
"inCntMemAlign": "1",
"assert": 1,
"line": 10,
"fileName": "arith.zkasm",
"lineStr": " CNT_MEM_ALIGN :ASSERT"
},
{
"inCntPoseidonG": "1",
"assert": 1,
"line": 11,
"fileName": "arith.zkasm",
"lineStr": " CNT_POSEIDON_G :ASSERT"
},
{
"inCntPaddingPG": "1",
"assert": 1,
"line": 12,
"fileName": "arith.zkasm",
"lineStr": " CNT_PADDING_PG :ASSERT"
},
{
"CONST": "0",
"setA": 1,
"setB": 1,
"setC": 1,
"setD": 1,
"arith": 1,
"arithEq0": 1,
"line": 14,
"fileName": "arith.zkasm",
"lineStr": " 0 => A,B,C,D :ARITH"
},
{
"inCntArith": "1",
"setA": 1,
"line": 16,
"fileName": "arith.zkasm",
"lineStr": " CNT_ARITH => A"
},
{
"CONST": "1",
"assert": 1,
"line": 17,
"fileName": "arith.zkasm",
"lineStr": " 1 :ASSERT"
},
{
"inCntArith": "1",
"setA": 1,
"line": 19,
"fileName": "arith.zkasm",
"lineStr": " CNT_ARITH => A"
},
{
"CONST": "1",
"assert": 1,
"line": 20,
"fileName": "arith.zkasm",
"lineStr": " 1 :ASSERT"
},
{
"CONSTL": "14474011154664524427946373126085988481658748083205070504932198000989141204993",
"setA": 1,
"line": 22,
"fileName": "arith.zkasm",
"lineStr": " 0x2000000000000000000000000000000000000000000000000000000000000001n => A"
},
{
"CONST": "256",
"setB": 1,
"line": 23,
"fileName": "arith.zkasm",
"lineStr": " 0x100 => B"
},
{
"CONST": "115",
"setC": 1,
"line": 24,
"fileName": "arith.zkasm",
"lineStr": " 0x73 => C"
},
{
"CONST": "32",
"setD": 1,
"line": 25,
"fileName": "arith.zkasm",
"lineStr": " 0x20 => D"
},
{
"CONST": "371",
"arith": 1,
"arithEq0": 1,
"line": 26,
"fileName": "arith.zkasm",
"lineStr": " 0x173 :ARITH"
},
{
"CONST": "2",
"setA": 1,
"line": 29,
"fileName": "arith.zkasm",
"lineStr": " 2 => A"
},
{
"inCntArith": "1",
"assert": 1,
"line": 30,
"fileName": "arith.zkasm",
"lineStr": " CNT_ARITH :ASSERT"
},
{
"CONST": "0",
"setA": 1,
"line": 32,
"fileName": "arith.zkasm",
"lineStr": " 0 => A"
},
{
"inCntKeccakF": "1",
"assert": 1,
"line": 33,
"fileName": "arith.zkasm",
"lineStr": " CNT_KECCAK_F: ASSERT"
},
{
"inCntMemAlign": "1",
"assert": 1,
"line": 34,
"fileName": "arith.zkasm",
"lineStr": " CNT_MEM_ALIGN :ASSERT"
},
{
"inCntPoseidonG": "1",
"assert": 1,
"line": 35,
"fileName": "arith.zkasm",
"lineStr": " CNT_POSEIDON_G :ASSERT"
},
{
"inCntPaddingPG": "1",
"assert": 1,
"line": 36,
"fileName": "arith.zkasm",
"lineStr": " CNT_PADDING_PG :ASSERT"
},
{
"CONST": "0",
"setA": 1,
"setB": 1,
"setC": 1,
"setD": 1,
"setE": 1,
"setCTX": 1,
"setSP": 1,
"setPC": 1,
"setGAS": 1,
"setMAXMEM": 1,
"setSR": 1,
"line": 39,
"fileName": "arith.zkasm",
"lineStr": " 0 => A,B,C,D,E,CTX, SP, PC, GAS, MAXMEM, SR"
},
{
"freeInTag": {
"op": "functionCall",
"funcName": "beforeLast",
"params": []
},
"inFREE": "1",
"JMPC": 0,
"JMPN": 1,
"offset": 27,
"line": 42,
"offsetLabel": "finalWait",
"fileName": "arith.zkasm",
"lineStr": " ${beforeLast()} : JMPN(finalWait)"
},
{
"JMP": 1,
"JMPC": 0,
"JMPN": 0,
"offset": 0,
"line": 44,
"offsetLabel": "start",
"fileName": "arith.zkasm",
"lineStr": " : JMP(start)"
}
],
"labels": {
"start": 0,
"end": 26,
"finalWait": 27,
"opINVALID": 29
}
}
1.1 zkASM计数器
zkASM语言支持的计数器counter
有:
incCounter
。CNT_MEM_ALIGN{ $$ = ‘cntMemAlign’ }为调用Memory Align状态机计数器。针对的操作符有:MEM_ALIGN_RD、MEM_ALIGN_WR、MEM_ALIGN_WR8。CNT_PADDING_PG{ $$ = ‘cntPaddingPG’ }为调用Poseidon Padding_pg状态机计数器。针对的操作符有:HASHPDIGEST。计数单位为incCounter
。CNT_POSEIDON_G{ $$ = ‘cntPoseidonG’ }为调用Poseidon Poseidong状态机计数器。针对的操作符有:HASHDIGEST、SLOAD、SSTORE。计数单位为incCounter
。
1.2 zkASM scope
zkASM语言支持2种scope
:
- IDENTIFIER格式为:
[a-zA-Z_][a-zA-Z$_0-9]*
,表示由字母和数字组成。 - setLine函数定义为:
function setLine(dst, first) { dst.line = first.first_line; }
- NUMBERL:为BigInt,对应CONSTL。
- NUMBER:为NUMBER,对应CONST。
zkASM语言支持的statement
类型有:
基于statement构建的statementList
为:
if ($1) {
$$ = [$1];
} else {
$$=[];
}
}
基于statementList构建的allStatments
为:
// console.log($1);
$$ = $1;
return $$;
}
2.1 zkASM statement step类型
zkASM语言支持的statement step
类型有:
$$ = {type: "step", assignment: $1, ops: $3};
setLine($$, @1)
}assignment LF{ $$ = {type: "step", assignment: $1, ops: []};
setLine($$, @1)
}‘:’ opList LF{ $$ = {type: "step", assignment: null, ops: $2}
setLine($$, @1)
}
2.2 zkASM statement label类型
zkASM语言支持的statement label
类型有:
$$ = {type: "label", identifier: $1};
setLine($$, @1)
}
2.3 zkASM statement varDef类型
zkASM语言支持的statement varDef
类型有:
zkASM语言支持的statement constDef
类型有:
$$ = {type: "constdef", name: $2, value: $4}
setLine($$, @1);
}‘CONSTL’ CONSTID ‘=’ nexpr %prec ‘=’{ $$ = {type: "constldef", name: $2, value: $4}
setLine($$, @1);
}
其中的nexpr
类型有:
zkASM语言支持的statement include
类型有:
zkASM语言支持的statement command
类型有:
zkASM语言command中支持的leftExpression
有:
zkASM语言command中支持的e0
有:
zkASM语言command中支持的e1
有:
zkASM语言command中支持的e2
有:
zkASM语言command中支持的e3
有:
zkASM语言command中支持的e4
有:
zkASM语言command中支持的e5
有:
zkASM语言command中支持的expression
有:
基于expression
构建的tag
为:
// console.log($1);
$$ = $1;
return $$;
}
基于expression
构建的expressionList
为:
基于expressionList
构建的functionCall
为:
zkASM语言支持的寄存器reg
有:
B : ASSERT
,表示断言A寄存器中的值与B寄存器中的值相等BCDESRStorage Merkle tree State Root寄存器SLOAD和SSTORE会对该寄存器代表的sparse merkle tree进行读写。CTXSPStack pointerPCProgram counter为实现有条件跳转,引入PC(Program Counter),记录了程序执行的当前指令的位置。GASRR与zkPC寄存器配合使用,控制子程序跳转和返回。如zkPC+1 => RR :JMP(subroutine) ; 等效为CALL(subroutime)
;:RETURN ; 等效为 :JMP(RR)
zkPCZero-knowledge program counterSTEP只读寄存器。number of polynomial evaluationMAXMEMHASHPOSROTL_C只读寄存器,仅作用于C寄存器,将其4个字节左移举例为:0x101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2Fn => CROTL_C => A0x1415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F10111213n: ASSERT
zkASM语言的寄存器列表regsList
表示为:
zkASM语言支持的寄存器赋值操作assignment
有:
其中inRegsSum
中支持的运算类型有:
其中inRegP
中支持的运算类型有:
其中inReg
中支持的运算类型有:
Rom状态机内包含了如下所有操作符的相应常量多项式。
zkASM语言支持的操作符op
有:
$$ = $3;
$$.mOp = 1;
$$.mWR = 0;
}使用Memory状态机。为32-byte word内存读操作。MSTORE ‘(’ addr ‘)’{$$ = $3;
$$.mOp = 1;
$$.mWR = 1;
}使用Memory状态机。为32-byte word内存写操作。HASHK ‘(’ hashId ‘)’{$$ = $3;
$$.hashK = 1;
}若hashId为Number,则addr=Number;若为E,则addr=E(0)。将A寄存器中ctx.D[0]个字节附加到 ctx.hashK[addr].data 中ctx.HASHPOS位置之后(若 ctx.hashK[addr].data相应位置有值,则不覆盖,仅在无值位置附加)。若inFree为1,则取ctx.hashK[addr].data中ctx.HASHPOS往后的ctx.D[0]个字节。HASHKLEN ‘(’ hashId ‘)’{$$ = $3;
$$.hashKLen = 1;
}若hashId为Number,则addr=Number;若为E,则addr=E(0)。HASHKLEN为对ctx.hashK[addr].data进行keccak256哈希运算,结果存在ctx.hashK[addr].digest中。HASHKDIGEST ‘(’ hashId ‘)’{ $$ = $3;
$$.hashKDigest = 1;
}若hashId为Number,则addr=Number;若为E,则addr=E(0)。返回ctx.hashK[addr].digest哈希值。HASHP ‘(’ hashId ‘)’{$$ = $3;
$$.hashP = 1;
}HASHPLEN ‘(’ hashId ‘)’{$$ = $3;
$$.hashPLen = 1;
}HASHPDIGEST ‘(’ hashId ‘)’{$$ = $3;
$$.hashPDigest = 1;
}JMP ‘(’ IDENTIFIER ‘)’{$$ = {JMP: 1, JMPC: 0, JMPN: 0, offset: $3}}JMP ‘(’ RR ‘)’{$$ = {JMP: 1, JMPC: 0, JMPN: 0, ind: 0, indRR: 1, offset: 0}}JMP ‘(’ E ‘)’{$$ = {JMP: 1, JMPC: 0, JMPN: 0, ind: 1, indRR: 0, offset: 0}}JMP ‘(’ REFERENCE ‘+’ RR ‘)’{$$ = {JMP: 1, JMPC: 0, JMPN: 0, ind: 0, indRR: 1, offset: $3}}JMP ‘(’ REFERENCE ‘+’ E ‘)’{$$ = {JMP: 1, JMPC: 0, JMPN: 0, ind: 1, indRR: 0, offset: $3}}JMPC ‘(’ IDENTIFIER ‘)’{$$ = {JMPC: 1, JMPN: 0, offset: $3} }JMPN ‘(’ IDENTIFIER ‘)’{$$ = {JMPC: 0, JMPN: 1, offset: $3}}CALL ‘(’ IDENTIFIER ‘)’{$$ = {JMP: 1, JMPC: 0, JMPN: 0, offset: $3, assignment: { in: {type: ‘add’, values: [{type: ‘REG’, reg: ‘zkPC’}, {type: ‘CONST’, const: 1}] }, out:[‘RR’]}}}即 CALL(subroutine)
等效为zkPC+1 => RR :JMP(subroutine)
。CALL ‘(’ REFERENCE ‘+’ RR ‘)’{ $$ = {JMP: 1, JMPC: 0, JMPN: 0, offset: $3, ind: 0, indRR: 1, assignment: { in: {type: ‘add’, values: [{type: ‘REG’, reg: ‘zkPC’}, {type: ‘CONST’, const: 1}] }, out:[‘RR’]}}}CALL ‘(’ REFERENCE ‘+’ E ‘)’{$$ = {JMP: 1, JMPC: 0, JMPN: 0, offset: $3, ind: 1, indRR: 0, assignment: { in: {type: ‘add’, values: [{type: ‘REG’, reg: ‘zkPC’}, {type: ‘CONST’, const: 1}] }, out:[‘RR’]}}}JMPC ‘(’ RR ‘)’{$$ = {JMP: 0, JMPC: 1, JMPN: 0, ind: 0, indRR: 1, offset: 0}}JMPC ‘(’ E ‘)’{ $$ = {JMP: 0, JMPC: 1, JMPN: 0, ind: 1, indRR: 0, offset: 0}}JMPC ‘(’ REFERENCE ‘+’ RR ‘)’{$$ = {JMP: 0, JMPC: 1, JMPN: 0, ind: 0, indRR: 1, offset: $3} }JMPC ‘(’ REFERENCE ‘+’ E ‘)’{ $$ = {JMP: 0, JMPC: 1, JMPN: 0, ind: 1, indRR: 0, offset: $3} }JMPN ‘(’ RR ‘)’{ $$ = {JMP: 0, JMPC: 0, JMPN: 1, ind: 0, indRR: 1, offset: 0}}JMPN ‘(’ E ‘)’{ $$ = {JMP: 0, JMPC: 0, JMPN: 1, ind: 1, indRR: 0, offset: 0}}JMPN ‘(’ REFERENCE ‘+’ RR ‘)’{ $$ = {JMP: 0, JMPC: 0, JMPN: 1, ind: 0, indRR: 1, offset: $3} }JMPN ‘(’ REFERENCE ‘+’ E ‘)’{ $$ = {JMP: 0, JMPC: 0, JMPN: 1, ind: 1, indRR: 0, offset: $3} }RETURN{ $$ = {JMP: 1, JMPC: 0, JMPN: 0, ind: 0, indRR: 1, offset: 0}}ASSERT{ $$ = {assert: 1} }ECRECOVER{ $$ = {ecRecover: 1} }SLOAD{ $$ = {sRD: 1} }Storage读操作。读取SMT中,以(A/B)C寄存器值为key的值。SSTORE{ $$ = {sWR: 1}}Storage写操作。将D寄存器的值存储到SMT((A/B)C寄存器值相关的)位置中。若inFree为1,同时还返回写操作之后的smt new root。ARITH{ $$ = { arith: 1, arithEq0: 1}}使用Arithmetic状态机。计算EQ0:
x
1
⋅
y
1
+
x
2
−
y
2
⋅
2
256
−
y
3
=
0
x_1\cdot y_1+x_2-y_2\cdot 2^{256}-y_3=0
x1⋅y1+x2−y2⋅2256−y3=0。实际为
A
⋅
B
+
C
=
D
⋅
2
256
+
E
A\cdot B+C=D\cdot 2^{256}+E
A⋅B+C=D⋅2256+E。ARITH_ECADD_DIFFERENT{ $$ = { arith: 1, arithEq1: 1, arithEq3: 1}}使用Arithmetic状态机。计算椭圆曲线上不同的2个点之和。ARITH_ECADD_SAME{ $$ = { arith: 1, arithEq2: 1, arithEq3: 1}}使用Arithmetic状态机。计算椭圆曲线上相同的2个点之和。SHL{ $$ = { shl: 1} }SHR{ $$ = { shr: 1} }ADD{ $$ = { bin: 1, binOpcode: 0} }使用Binary状态机。byte-wise加法运算。SUB{ $$ = { bin: 1, binOpcode: 1} }使用Binary状态机。byte-wise减法运算。LT{ $$ = { bin: 1, binOpcode: 2} }使用Binary状态机。byte-wise小于运算。SLT{ $$ = { bin: 1, binOpcode: 3} }使用Binary状态机。byte-wise有符号小于运算。EQ{ $$ = { bin: 1, binOpcode: 4} }使用Binary状态机。byte-wise等于运算。AND{ $$ = { bin: 1, binOpcode: 5} }使用Binary状态机。bit-wise位与运算。OR{ $$ = { bin: 1, binOpcode: 6} }使用Binary状态机。bit-wise位或运算。XOR{ $$ = { bin: 1, binOpcode: 7} }使用Binary状态机。bit-wise位异或运算。MEM_ALIGN_RD{ $$ = { memAlign: 1, memAlignWR: 0, memAlignWR8: 0}}使用Memory Align状态机。读取指定offset开始的32 byte内存值。MEM_ALIGN_WR{ $$ = { memAlign: 1, memAlignWR: 1, memAlignWR8: 0}}使用Memory Align状态机。写入指定offset开始的32 byte内存值。MEM_ALIGN_WR8{ $$ = { memAlign: 1, memAlignWR: 0, memAlignWR8: 1} }使用Memory Align状态机。写入指定offset开始的1 byte内存值。INST_MAP_ROM{ $$ = {instMapRom: 1}}
其中HASHK/HASHKLEN/HASHKDIGEST/HASHP/HASHPLEN/HASHPDIGEST中的参数hashId
的类型有:
sm_main_exec.js
中execute
函数中的incCounter
具体取值为:
- 1)对于HASHPDIGEST操作符为对56取模:
incCounter = Math.ceil((ctx.hashP[addr].data.length + 1) / 56);
- 2)对于HASHKDIGEST操作符为对136取模:
incCounter = Math.ceil((ctx.hashK[addr].data.length + 1) / 136)
- 3)对于SLOAD和SSTORE操作符为:
incCounter = res.proofHashCounter + 2;
,其中proofHashCounter
为 证明该操作所需的哈希次数:const res = await smt.get(sr8to4(ctx.Fr, ctx.SR), key); /** * Get value merkle-tree * @param {Array[Field]} root - merkle-tree root * @param {Array[Field]} key - path to retoreve the value * @returns {Object} Information about the value to retrieve * {Array[Field]} root: merkle-tree root, * {Array[Field]} key: key to look for, * {Scalar} value: value retrieved, * {Array[Array[Field]]} siblings: array of siblings, * {Bool} isOld0: is new insert or delete, * {Array[Field]} insKey: key found, * {Scalar} insValue: value found, * {Number} proofHashCounter: counter of hashs must be done to proof this operation */ async get(root, key) { const self = this; const { F } = this; let r = root; const keys = self.splitKey(key); let level = 0; const accKey = []; let foundKey; let siblings = []; let insKey; let insValue = Scalar.e(0); let value = Scalar.e(0); let isOld0 = true; let foundVal; while ((!nodeIsZero(r, F)) && (typeof (foundKey) === 'undefined')) { siblings[level] = await self.db.getSmtNode(r); if (isOneSiblings(siblings[level], F)) { const foundValA = (await self.db.getSmtNode(siblings[level].slice(4, 8))).slice(0, 8); const foundRKey = siblings[level].slice(0, 4); foundVal = fea2scalar(F, foundValA); foundKey = this.joinKey(accKey, foundRKey); } else { r = siblings[level].slice(keys[level] * 4, keys[level] * 4 + 4); accKey.push(keys[level]); level += 1; } } level -= 1; accKey.pop(); if (typeof (foundKey) !== 'undefined') { if (nodeIsEq(key, foundKey, F)) { value = foundVal; } else { insKey = foundKey; insValue = foundVal; isOld0 = false; } } siblings = siblings.slice(0, level + 1); return { root, key, value, siblings, isOld0, insKey, insValue, proofHashCounter: nodeIsZero(root, F) ? 0 : (siblings.length + ((F.isZero(value) && isOld0 !== false) ? 0 : 2)), }; }
zkASM操作符列表opList
表示为:
Polygon zkEVM Poseidon哈希运算相关操作符和寄存器有:
- 1)寄存器HASHPOS:对应Rom状态机内的
setHASHPOS
常量多项式。 - 2)操作符HASHP(hashId):以HASH(E)为例,对应Rom状态机内的
hashP、ind、indRR、offset
常量多项式。 - 3)操作符HASHPLEN(hashId):以HASHPLEN(E)为例,对应Rom状态机内的
hashPLen、ind、indRR、offset
常量多项式。 - 4)操作符HASHPDIGEST(hashId):以HASHPDIGEST(E)为例,对应Rom状态机内的
hashPDigest、ind、indRR、offset
常量多项式。
这些多项式之间的逻辑关系见zkevm-proverjs/src/sm/sm_main/sm_main_exec.js
中的execute
函数:
- 1)HASHPOS寄存器对应的
setHASHPOS
常量多项式计算逻辑为:
以// 1. 在每一步中,将incHashPos初始化为0 let incHashPos = 0; // 2. 在当前步中有hashP或hashK时,将D寄存器D[0]值给incHashPos const size = fe2n(Fr, ctx.D[0], ctx); incHashPos = size; const pos = fe2n(Fr, ctx.HASHPOS, ctx); console.log('ZYD i:' + i + ', hashP size:' + size + ', pos:' + pos); if (l.setHASHPOS == 1) { console.log('ZYD i:' + i + ', hashP size:' + size + ', pos:' + pos); pols.setHASHPOS[i]=1n; pols.HASHPOS[nexti] = BigInt(fe2n(Fr, op0, ctx) + incHashPos); } else { pols.setHASHPOS[i]=0n; pols.HASHPOS[nexti] = pols.HASHPOS[i] + BigInt( incHashPos); }
test/counters/padding_pg.js
为例,相应打印日志为:**** ZYD i:10, op0:0, incHashPos:0 ZYD i:12, hashP size:32, pos:0 ZYD i:14, hashP size:23, pos:32 **** ZYD i:23, op0:0, incHashPos:0 ZYD i:25, hashP size:32, pos:0 ZYD i:27, hashP size:24, pos:32 **** ZYD i:34, op0:0, incHashPos:0 ZYD i:36, hashP size:32, pos:0 ZYD i:38, hashP size:25, pos:32 **** ZYD i:45, op0:0, incHashPos:0 ZYD i:47, hashP size:32, pos:0 ZYD i:48, hashP size:32, pos:32 ZYD i:49, hashP size:32, pos:64 ZYD i:51, hashP size:15, pos:96 **** ZYD i:58, op0:0, incHashPos:0 ZYD i:60, hashP size:32, pos:0 ZYD i:61, hashP size:32, pos:32 ZYD i:62, hashP size:32, pos:64 ZYD i:64, hashP size:16, pos:96 **** ZYD i:71, op0:0, incHashPos:0 ZYD i:73, hashP size:32, pos:0 ZYD i:74, hashP size:32, pos:32 ZYD i:75, hashP size:32, pos:64 ZYD i:77, hashP size:17, pos:96 **** ZYD i:84, op0:0, incHashPos:0 ZYD i:86, hashP size:32, pos:0 ZYD i:87, hashP size:32, pos:32 ZYD i:88, hashP size:32, pos:64 ZYD i:90, hashP size:18, pos:96 **** ZYD i:101, op0:0, incHashPos:0
具体参看:
- zkASM Compiler项目中的c_code_generator.js文件
if (rom.program[zkPC].mOp || rom.program[zkPC].mWR || rom.program[zkPC].hashK || rom.program[zkPC].hashKLen || rom.program[zkPC].hashKDigest || rom.program[zkPC].hashP || rom.program[zkPC].hashPLen || rom.program[zkPC].hashPDigest || rom.program[zkPC].JMP || rom.program[zkPC].JMPN || rom.program[zkPC].JMPC) { let bAddrRel = false; let bOffset = false; code += " // If address is involved, load offset into addr\n"; if (rom.program[zkPC].ind && rom.program[zkPC].indRR) { console.log("Error: Both ind and indRR are set to 1"); process.exit(); } if (rom.program[zkPC].ind) { code += " fr.toS32(addrRel, pols.E0[" + (bFastMode?"0":"i") + "]);\n"; bAddrRel = true; } if (rom.program[zkPC].indRR) { code += " fr.toS32(addrRel, pols.RR[" + (bFastMode?"0":"i") + "]);\n"; bAddrRel = true; } if (rom.program[zkPC].offset && (rom.program[zkPC].offset != 0)) { bOffset = true; } if (bAddrRel && bOffset) { if (rom.program[zkPC].offset > 0) { code += " // If offset is possitive, and the sum is too big, fail\n" code += " if ((uint64_t(addrRel)+uint64_t(" + rom.program[zkPC].offset + "))>=0x10000)\n" code += " {\n" code += " cerr
关注打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?