您当前的位置: 首页 > 

mutourend

暂无认证

  • 1浏览

    0关注

    661博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Polygon zkEVM zkASM语法

mutourend 发布时间:2022-09-13 18:42:22 ,浏览量:1

1. 引言

前序博客有:

  • 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有:

计数器名说明备注CNT_ARITH{ $$ = ‘cntArith’ }为调用Arithmetic状态机计数器。针对的操作符有:ARITH、ARITH_ECADD_DIFFERENT、ARITH_ECADD_SAME。CNT_BINARY{ $$ = ‘cntBinary’ }为调用Binary状态机计数器。针对的操作符有:ADD、SUB、LT、SLT、EQ、AND、OR、XOR。CNT_KECCAK_F{ $$ = ‘cntKeccakF’ }为调用Keccak哈希状态机计数器。针对的操作符有:HASHKDIGEST。计数单位为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

scope标志说明备注GLOBALCTX 2. zkASM statement基本类型定义
  • 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类型说明备注step{ $$ = $1; }label{ $$ = $1; }varDef{ $$ = $1; }constDef{ $$ = $1; }include{ $$ = $1; }command{ $$ = $1; }LF{ $$ = null; }

基于statement构建的statementList为:

statementList类型说明备注statmentList statment{ if ($2) $1.push($2); $$ = $1; }statment{ if ($1) { $$ = [$1]; } else { $$=[]; } }

基于statementList构建的allStatments为:

allStatments类型说明备注statmentList EOF{ // console.log($1); $$ = $1; return $$; } 2.1 zkASM statement step类型

zkASM语言支持的statement step类型有:

step标志说明备注assignment ‘:’ opList LF{ $$ = {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类型有:

label标志说明备注IDENTIFIER ‘:’{ $$ = {type: "label", identifier: $1}; setLine($$, @1)} 2.3 zkASM statement varDef类型

zkASM语言支持的statement varDef类型有:

varDef标志说明备注VAR scope IDENTIFIER{ $$ = {type: “var”, scope: $2, name: $3, count: 1 } }VAR scope IDENTIFIER ‘[’ NUMBER ‘]’{ $$ = {type: “var”, scope: $2, name: $3, count: $5 } } 2.4 zkASM statement constDef类型

zkASM语言支持的statement constDef类型有:

constDef标志说明备注‘CONST’ CONSTID ‘=’ nexpr %prec ‘=’{ $$ = {type: "constdef", name: $2, value: $4} setLine($$, @1); }‘CONSTL’ CONSTID ‘=’ nexpr %prec ‘=’{ $$ = {type: "constldef", name: $2, value: $4} setLine($$, @1); }

其中的nexpr类型有:

nexpr标志说明备注NUMBER{ $$ = {type: ‘CONSTL’ , value: $1} }NUMBERL{ $$ = {type: ‘CONSTL’ , value: $1} }CONSTID{ $$ = {type: ‘CONSTID’ , identifier: $1} }CONSTID ‘??’ nexpr{ $$ = {type: $2, values: [$3] , identifier: $1} }nexpr ‘+’ nexpr{ $$ = {type: $2, values: [$1, $3]} }nexpr ‘-’ nexpr{ $$ = {type: $2, values: [$1, $3]} }nexpr ‘*’ nexpr{ $$ = {type: $2, values: [$1, $3]} }nexpr ‘**’ nexpr{ $$ = {type: $2, values: [$1, $3]} }nexpr ‘%’ nexpr{ $$ = {type: $2, values: [$1, $3]} }nexpr ‘/’ nexpr{ $$ = {type: $2, values: [$1, $3]} }‘-’ nexpr{ $$ = {type: $1, values: [$2]} }nexpr ‘’ nexpr{ $$ = {type: $2, values: [$1, $3]} }nexpr ‘|’ nexpr{ $$ = {type: $2, values: [$1, $3]} }nexpr ‘&’ nexpr{ $$ = {type: $2, values: [$1, $3]} }nexpr ‘^’ nexpr{ $$ = {type: $2, values: [$1, $3]} }nexpr ‘’ nexpr{ $$ = {type: $2, values: [$1, $3]} }nexpr ‘=’ nexpr{ $$ = {type: $2, values: [$1, $3]} }nexpr ‘==’ nexpr{ $$ = {type: $2, values: [$1, $3]} }nexpr ‘!=’ nexpr{ $$ = {type: $2, values: [$1, $3]} }nexpr ‘&&’ nexpr{ $$ = {type: $2, values: [$1, $3]}}nexpr ‘||’ nexpr{ $$ = {type: $2, values: [$1, $3]} }‘!’ nexpr{ $$ = {type: $1, values: [$2]} }nexpr ‘?’ nexpr ‘:’ nexpr{ $$ = {type: $2, values: [$1, $3, $5]} }‘(’ nexpr ‘)’{ $$ = $2} 2.5 zkASM statement include类型

zkASM语言支持的statement include类型有:

include标志说明备注INCLUDE STRING{ $$ = {type: “include”, file: $2} } 2.6 zkASM statement command类型

zkASM语言支持的statement command类型有:

command标志说明备注COMMAND{ $$ = {type: “command”, cmd: $1} } 2.6.1 zkASM command中的leftExpression

zkASM语言command中支持的leftExpression有:

leftExpression标志说明备注VAR IDENTIFIER{ $$ = {op: “declareVar”, varName: $2} }IDENTIFIER{ $$ = {op: “getVar”, varName: $1} } 2.6.2 zkASM command中的e0

zkASM语言command中支持的e0有:

e0标志说明备注leftExpression{ $$ = $1 }NUMBER{ $$ = {op: “number”, num: $1 } }reg{ $$ = {op: “getReg”, regName: $1} }counter{ $$ = {op: “getReg”, regName: $1} }‘(’ expression ‘)’{ $$ = $2; }IDENTIFIER ‘.’ IDENTIFIER{ $$ = {op: “getData”, module: $1, offset: $3} } 2.6.3 zkASM command中的e1

zkASM语言command中支持的e1有:

e1标志说明备注functionCall{ $$ = $1; }e0{ $$ = $1 } 2.6.4 zkASM command中的e2

zkASM语言command中支持的e2有:

e2标志说明备注‘+’ e2 %prec UPLUS{ $$ = $2; }‘-’ e2 %prec UMINUS{ $$ = { op: “neg”, values: [$2] }; }‘~’ e2 %prec NOT{ $$ = { op: “bitnot”, values: [$2] }; }‘!’ e2 %prec NOT{ $$ = { op: “not”, values: [$2] }; }e1 %prec EMPTY{ $$ = $1; } 2.6.5 zkASM command中的e3

zkASM语言command中支持的e3有:

e3标志说明备注e3 ‘*’ e2{ $$ = { op: “mul”, values: [$1, $3] };}e3 ‘/’ e2{ $$ = { op: “div”, values: [$1, $3] };}e3 ‘%’ e2{ $$ = { op: “mod”, values: [$1, $3] }; }e3 ‘&’ e2{ $$ = { op: “bitand”, values: [$1, $3] }; }e3 ‘|’ e2{ $$ = { op: “bitor”, values: [$1, $3] }; }e3 ‘^’ e2{ $$ = { op: “bitxor”, values: [$1, $3] }; }e3 SHL e2{ $$ = { op: “shl”, values: [$1, $3] }; }e3 SHR e2{ $$ = { op: “shr”, values: [$1, $3] }; }e3 L_OR e2{ $$ = { op: “or”, values: [$1, $3] }; }e3 L_AND e2{ $$ = { op: “and”, values: [$1, $3] }; }e3 EXP e2{ $$ = { op: “exp”, values: [$1, $3] }; }e3 EQ e2{ $$ = { op: “eq”, values: [$1, $3] }; }e3 NE e2{ $$ = { op: “ne”, values: [$1, $3] }; }e3 LT e2{ $$ = { op: “lt”, values: [$1, $3] }; }e3 LE e2{ $$ = { op: “le”, values: [$1, $3] }; }e3 GT e2{ $$ = { op: “gt”, values: [$1, $3] }; }e3 GE e2{ $$ = { op: “ge”, values: [$1, $3] }; }e3 ‘?’ e2 ‘:’ e2{ $$ = { op: “if”, values: [$1, $3, $5] }; }e2 %prec EMPTY{ $$ = $1; } 2.6.6 zkASM command中的e4

zkASM语言command中支持的e4有:

e4标志说明备注e4 ‘+’ e3{ $$ = { op: “add”, values: [$1, $3] }; }e4 ‘-’ e3{ $$ = { op: “sub”, values: [$1, $3] }; }e3 %prec EMPTY{ $$ = $1; } 2.6.7 zkASM command中的e5

zkASM语言command中支持的e5有:

e5标志说明备注leftExpression ‘=’ e5{ $$ = { op: “setVar”, values: [$1, $3] }; }e4 %prec EMPTY{ $$ = $1; } 2.6.8 zkASM command中的expression

zkASM语言command中支持的expression有:

expression标志说明备注e5 %prec EMPTY{ $$ = $1; }

基于expression构建的tag为:

tag标志说明备注expression EOF{ // console.log($1); $$ = $1; return $$; }

基于expression构建的expressionList为:

expressionList标志说明备注expressionList ‘,’ expression{ $1.push($3); }expression %prec ‘,’{ $$ = [$1]; }

基于expressionList构建的functionCall为:

functionCall标志说明备注IDENTIFIER ‘(’ expressionList ‘)’{ $$ = {op: “functionCall”, funcName: $1, params: $3} }IDENTIFIER ‘(’ ‘)’{ $$ = {op: “functionCall”, funcName: $1, params: []} } 3. zkASM寄存器

zkASM语言支持的寄存器reg有:

寄存器名说明备注AASSERT操作符仅作用于A寄存器如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表示为:

寄存器列表标志说明备注regsList ‘,’ reg{ $1.push($3) }reg{ $$ = [$1]} 3.1 zkASM 寄存器赋值

zkASM语言支持的寄存器赋值操作assignment有:

assignment标志说明备注inRegsSum ‘=>’ regsList{ $$ = {in: $1, out: $3} }inRegsSum{ $$ = {in: $1, out: []} }

其中inRegsSum中支持的运算类型有:

inRegsSum运算标志说明备注inRegsSum ‘+’ inRegP{ $$ = {type: ‘add’, values: [$1, $3]} }inRegsSum ‘-’ inRegP{ $$ = {type: ‘sub’, values: [$1, $3]} }‘-’ inRegP{ $$ = {type: ‘neg’, values: [$2]} }inRegP{ $$ = $1 }

其中inRegP中支持的运算类型有:

inRegP运算标志说明备注inRegP ‘*’ inReg{ $$ = {type: ‘mul’, values: [$1, $3]} }inReg{ $$ = $1 }

其中inReg中支持的运算类型有:

inReg运算标志说明备注TAG{ $$ = {type: ‘TAG’ , tag: $1}}reg{ $$ = {type: ‘REG’ , reg: $1} }counter{ $$ = {type: ‘COUNTER’, counter: $1} }NUMBER ‘**’ NUMBER{ $$ = {type: “exp”, values: [$1, $3]} }NUMBER{ $$ = {type: ‘CONST’ , const: $1} }NUMBERL{ $$ = {type: ‘CONSTL’ , const: $1} }CONSTID{ $$ = {type: ‘CONSTID’ , identifier: $1} }REFERENCE{ $$ = {type: ‘reference’, identifier: $1} } 4. zkASM操作符

Rom状态机内包含了如下所有操作符的相应常量多项式。

zkASM语言支持的操作符op有:

操作符名对应列说明备注MLOAD ‘(’ addr ‘)’{ $$ = $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的类型有:

hashId取值类型对应列说明备注NUMBER{ $$ = {ind: 0, indRR: 0, offset:$1}}E{ $$ = {ind: 1, indRR: 0, offset:0}}

sm_main_exec.jsexecute函数中的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表示为:

操作符列表标志说明备注opList ‘,’ op{ $1.push($3); $$ = $1 }op{ $$ = [$1] } 4.1 Poseidon哈希运算

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
    
4.2 JMP/CALL/JMPN/JMPC/RETURN有条件跳转

具体参看:

  • 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             
关注
打赏
1664532908
查看更多评论
0.1262s