Polygon zkEVM zkASM 与 以太坊虚拟机opcode 对应集合

1. 引言

结合:

Polygon zkEVM的虚拟机支持的opcode为:【基本与以太坊虚拟机opcode对应】

opcode name cnt_arith cnt_binary cnt_mem_align cnt_keccak_f cnt_padding_pg cnt_poseidon_g is_dynamic
0x00 STOP 0 0 0 0 0 0 false
0x01 ADD 0 1 0 0 0 0 false
0x02 MUL 1 0 0 0 0 0 false
0x03 SUB 0 1 0 0 0 0 false
0x04 DIV 1 2 0 0 0 0 false
0x05 SDIV 1 8 0 0 0 0 false
0x06 MOD 1 2 0 0 0 0 false
0x07 SMOD 1 8 0 0 0 0 false
0x08 ADDMOD 1 3 0 0 0 0 false
0x09 MULMOD 2 2 0 0 0 0 false
0x0a EXP 512 1025 0 0 0 0 true
0x0b SIGNEXTEND 0 6 0 0 0 0 false
0x10 LT 0 1 0 0 0 0 false
0x11 GT 0 1 0 0 0 0 false
0x12 SLT 0 1 0 0 0 0 false
0x13 SGT 0 1 0 0 0 0 false
0x14 EQ 0 1 0 0 0 0 false
0x15 ISZERO 0 1 0 0 0 0 false
0x16 AND 0 1 0 0 0 0 false
0x17 OR 0 1 0 0 0 0 false
0x18 XOR 0 1 0 0 0 0 false
0x19 NOT 0 1 0 0 0 0 false
0x1a BYTE 2 4 0 0 0 0 false
0x1b SHL 1 2 0 0 0 0 false
0x1c SHR 1 3 0 0 0 0 false
0x1d SAR 2 10 0 0 0 0 false
0x20 SHA3 192 193 2 2 0 10 true
0x30 ADDRESS 0 0 0 0 0 0 false
0x31 BALANCE 0 0 0 0 0 9 false
0x32 ORIGIN 0 0 0 0 0 0 false
0x33 CALLER 0 0 0 0 0 0 false
0x34 CALLVALUE 0 0 0 0 0 0 false
0x35 CALLDATALOAD 64 66 0 0 0 0 true
0x36 CALLDATASIZE 0 0 0 0 0 0 false
0x37 CALLDATACOPY - - - 0 0 0 true
0x38 CODESIZE 0 0 0 0 0 252 true
0x39 CODECOPY 0 - - 0 0 255 true
0x3a GASPRICE 0 0 0 0 0 0 false
0x3b EXTCODESIZE 0 0 0 0 0 255 true
0x3c EXTCODECOPY 0 - - 0 11 510 true
0x3d RETURNDATASIZE 0 1 0 0 0 0 false
0x3e RETURNDATACOPY - - 2 0 0 0 true
0x3f EXTCODEHASH 0 0 0 0 0 255 true
0x40 BLOCKHASH 0 0 0 1 0 9 false
0x41 COINBASE 0 0 0 0 0 0 false
0x42 TIMESTAMP 0 0 0 0 0 0 false
0x43 NUMBER 0 0 0 0 0 0 false
0x44 DIFFICULTY 0 0 0 0 0 0 false
0x45 GASLIMIT 0 0 0 0 0 0 false
0x46 CHAINID 0 0 0 0 0 0 false
0x47 SELFBALANCE 0 0 0 0 0 255 true
0x50 POP 0 0 0 0 0 0 false
0x51 MLOAD 32 32 1 0 0 255 true
0x52 MSTORE 32 32 1 0 0 255 true
0x53 MSTORE8 32 1 1 0 0 255 false
0x54 SLOAD 0 0 0 0 0 255 true
0x55 SSTORE 0 - 0 0 0 255 true
0x56 JUMP 0 - 0 0 0 0 true
0x57 JUMPI 0 - 0 0 0 0 true
0x59 MSIZE 1 3 0 0 0 0 false
0x5a GAS 0 0 0 0 0 0 false
0x5b JUMPDEST 0 0 0 0 0 0 false
0x60 PUSH1 0 3 0 0 0 0 true
0x61 PUSH2 0 4 0 0 0 0 true
0x62 PUSH3 0 5 0 0 0 0 false
0x63 PUSH4 0 2 0 0 0 0 false
0x64 PUSH5 0 4 0 0 0 0 false
0x65 PUSH6 0 5 0 0 0 0 false
0x66 PUSH7 0 6 0 0 0 0 false
0x67 PUSH8 0 3 0 0 0 0 false
0x68 PUSH9 0 5 0 0 0 0 false
0x69 PUSH10 0 6 0 0 0 0 false
0x6a PUSH11 0 7 0 0 0 0 false
0x6b PUSH12 0 4 0 0 0 0 false
0x6c PUSH13 0 6 0 0 0 0 false
0x6d PUSH14 0 7 0 0 0 0 false
0x6e PUSH15 0 8 0 0 0 0 false
0x6f PUSH16 0 5 0 0 0 0 false
0x70 PUSH17 0 7 0 0 0 0 false
0x71 PUSH18 0 8 0 0 0 0 false
0x72 PUSH19 0 9 0 0 0 0 false
0x73 PUSH20 0 6 0 0 0 0 false
0x74 PUSH21 0 8 0 0 0 0 false
0x75 PUSH22 0 9 0 0 0 0 false
0x76 PUSH23 0 10 0 0 0 0 false
0x77 PUSH24 0 7 0 0 0 0 false
0x78 PUSH25 0 9 0 0 0 0 false
0x79 PUSH26 0 10 0 0 0 0 false
0x7a PUSH27 0 11 0 0 0 0 false
0x7b PUSH28 0 8 0 0 0 0 false
0x7c PUSH29 0 10 0 0 0 0 false
0x7d PUSH30 0 11 0 0 0 0 false
0x7e PUSH31 0 12 0 0 0 0 false
0x7f PUSH32 0 9 0 0 0 0 false
0x80 DUP1 0 0 0 0 0 0 false
0x81 DUP2 0 0 0 0 0 0 false
0x82 DUP3 0 0 0 0 0 0 false
0x83 DUP4 0 0 0 0 0 0 false
0x84 DUP5 0 0 0 0 0 0 false
0x85 DUP6 0 0 0 0 0 0 false
0x86 DUP7 0 0 0 0 0 0 false
0x87 DUP8 0 0 0 0 0 0 false
0x88 DUP9 0 0 0 0 0 0 false
0x90 SWAP1 0 0 0 0 0 0 false
0x91 SWAP2 0 0 0 0 0 0 false
0x92 SWAP3 0 0 0 0 0 0 false
0x93 SWAP4 0 0 0 0 0 0 false
0x94 SWAP5 0 0 0 0 0 0 false
0x95 SWAP6 0 0 0 0 0 0 false
0x96 SWAP7 0 0 0 0 0 0 false
0xa0 LOG0 0 - 0 0 0 0 true
0xa1 LOG1 0 - 0 0 0 0 true
0xa2 LOG2 0 - 0 0 0 0 true
0xa3 LOG3 0 - 0 0 0 0 true
0xa4 LOG4 0 - 0 0 0 0 true
0xf0 CREATE - - 0 - 0 - true
0xf1 CALL - - 0 0 - - true
0xf2 CALLCODE - - 0 0 - - true
0xf3 RETURN 0 0 0 0 0 0 false
0xf4 DELEGATECALL - - 0 0 - - true
0xf5 CREATE2 - - 0 - 0 - true
0xfa STATICCALL - - 0 0 - - true
0xfd REVERT 0 0 0 0 0 0 false
0xfe INVALID 0 1 0 0 0 0 false

各opcode详细的zkASM实现参见zkevm-rom项目中的opcodes.zkasm文件。

2. 0x01 ADD opcode

在这里插入图片描述
其中:

  • δ \delta δ为从stack中pop出来的value数,因ADD是对stack的top 2 values求和(除非明确说明,否则是对 2 256 2^{256} 2256取模)。
  • α \alpha α为向stack push进去的value数。ADD操作会将二值求和结果再push进stack中。

在这里插入图片描述
根据上图可知,0x01 ADD opcode所需最小gas为3。

在Polygon zkEVM中,以太坊虚拟机的0x01 ADD opcode对应的zkASM表示为:【分别调用了Memory二级状态机、Binary二级状态机。】

opADD:
	; 检查当前stack中确实有至少2个元素,否则跳转到stackUnderflow。
    SP - 2          :JMPN(stackUnderflow)
    ; 将stack pointer值减一
    SP - 1 => SP
    ; 将stack pointer值加载到A寄存器中;再将stack pointer值减一
    $ => A          :MLOAD(SP--)
    ; 将stack pointer值加载到C寄存器中
    $ => C          :MLOAD(SP)

    ; Add operation with Arith
    ; 将A寄存器的值存储在Memory状态机中的`arithA`变量中
    A               :MSTORE(arithA)
    ; 将C寄存器的值存储在Memory状态机中的`arithB`变量中
    C               :MSTORE(arithB)
    ; 调用`addARITH`子程序,负责执行加法运算
                    :CALL(addARITH)
    ; 从Memory状态机中的`arithRes1`变量中读取加法运算结果 存入在 E寄存器中
    $ => E          :MLOAD(arithRes1)
    ; 将E寄存器的值存储在stack pointer位置,将stack pointer值加一
    E               :MSTORE(SP++)
    ; stack空间为1024,若当前stack pointer值大于1024,则跳转到stackOverflow
    1024 - SP       :JMPN(stackOverflow)
    ; ADD opcode所需最低gas为3,若执行为ADD操作后GAS为负数,则跳转到outOfGas
    GAS-3 => GAS    :JMPN(outOfGas)
    ; 最后但同样重要的是,以下表示继续处理下一指令。
                    :JMP(readCode)

其中addARITH子程序负责执行加法运算,具体实现见:

  • zkEVM Rom项目中的utils.zkasm
    ; 其中tmpZkPC、storeTmp、arithA、arithB、arithRes1、loadTmp均为全局变量。
    addARITH:
    	; 将调用addARITH子程序之前的RR值存入tmpZkPC临时全局变量中。
        RR              :MSTORE(tmpZkPC)
        zkPC+1 => RR    :JMP(storeTmp) ; 等效为 CALL(storeTmp),将A/B/C/D/E寄存器的值存储在临时全局变量tmpVarA/B/C/D/E中。
    
        $ => A          :MLOAD(arithA)
        $ => B          :MLOAD(arithB)
        $ => E          :ADD ; 对应Binary状态机,为byte-wise加法运算。
    
        E               :MSTORE(arithRes1)
    
        zkPC+1 => RR    :JMP(loadTmp) ; 等效为 CALL(loadTmp),将临时全局变量tmpVarA/B/C/D/E中的值加载到A/B/C/D/E寄存器中。
        ; 重置RR值 为 调用addARITH子程序之前的RR值(从tmpZkPC临时全局变量中取出)
        $ => RR         :MLOAD(tmpZkPC)
                        :JMP(RR) ; 等效为 RETURN
    
    其中storeTmp子程序为将A/B/C/D/E寄存器的值存储在临时全局变量tmpVarA/B/C/D/E中,而loadTmp为将临时全局变量tmpVarA/B/C/D/E中的值加载到A/B/C/D/E寄存器中:
    storeTmp:
        A                   :MSTORE(tmpVarA)
        B                   :MSTORE(tmpVarB)
        C                   :MSTORE(tmpVarC)
        D                   :MSTORE(tmpVarD)
        E                   :MSTORE(tmpVarE)
                            :JMP(RR) ; 等效为 RETURN
    loadTmp:
        $ => A                  :MLOAD(tmpVarA)
        $ => B                  :MLOAD(tmpVarB)
        $ => C                  :MLOAD(tmpVarC)
        $ => D                  :MLOAD(tmpVarD)
        $ => E                  :MLOAD(tmpVarE)
                                :JMP(RR) ; 等效为 RETURN
    

不过,实际实现时,Polygon zkEVM中设定了一些常量上限值:

; COUNTERS
CONST %MAX_CNT_STEPS = 2**21 ; 最大STEP数

CONST %MAX_CNT_ARITH = %MAX_CNT_STEPS / 32 ; 最多ARITH计算数
CONST %MAX_CNT_BINARY = %MAX_CNT_STEPS / 32 ; 最多BINARY计算数
CONST %MAX_CNT_MEM_ALIGN = %MAX_CNT_STEPS / 32 ; 最多MemAlign计算数
CONST %MAX_CNT_KECCAK_F = (%MAX_CNT_STEPS / 158418) * 9 ; 最多Keccakf计算数
CONST %MAX_CNT_PADDING_PG = (%MAX_CNT_STEPS / 56) ; 最多padding pg计算数,针对Poseidon哈希
CONST %MAX_CNT_POSEIDON_G = (%MAX_CNT_STEPS / 30) ; 最多PoseidonG计算数,针对Poseidon哈希
CONST %MIN_CNT_KECCAK_BATCH = 2 ; 最少Keccak_batch数
; ETHEREUM CONSTANTS
CONSTL %MAX_NONCE = 0xffffffffffffffffn ; 以太坊nonce最大值为2^{64}-1。

因此,实际在zkevm-rom的opcodes.zkasm中对0x01 ADD opcode的实际实现为:【借助了Binary状态机默认是对A和B寄存器进行运算的,进行了优化,使代码更简洁;同时考虑实际应用场景,对相关计数器进行了约束。】

opADD:

    %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCounters) ; 对相关计算计数器进行了约束。
    %MAX_CNT_STEPS - STEP - 120 :JMPN(outOfCounters) ; 约束了计算复杂度。

    SP - 2          :JMPN(stackUnderflow)
    SP - 1 => SP
    $ => A          :MLOAD(SP--)
    $ => B          :MLOAD(SP)

    ; Add operation with Arith
    $ => E          :ADD

    E               :MSTORE(SP++)
    1024 - SP       :JMPN(stackOverflow)
    GAS-3 => GAS    :JMPN(outOfGas)
                    :JMP(readCode)

参考资料

[1] zkASM示例
[2] 以太坊黄皮书 https://ethereum.github.io/yellowpaper/paper.pdf
[3] 理解以太坊黄皮书
[3] EVM.Codes

附录:Polygon Hermez 2.0 zkEVM系列博客

猜你喜欢

转载自blog.csdn.net/mutourend/article/details/126938909