1. 引言

前序博客有:

  • Polygon zkEVM zkASM语法

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(无效指令,没有意义):

zkASM通过${ExecutorMethod(params)} => A :JMP(param),即$和大括号来表示函数调用。

Polygon zkEVM在各状态机中实现了一系列的zkASM函数,本文重点关注如下代码库中的相关zkASM函数:

  • 1)https://github.com/0xPolygonHermez/zkevm-proverjs
  • 2)https://github.com/0xPolygonHermez/zkevm-rom
  • 3)https://github.com/0xPolygonHermez/zkevm-storage-rom

2. zkevm-proverjs项目sm_main_exec.js文件中的函数

zkevm-proverjs项目sm_main_exec.js文件中支持的函数调用有:

函数名 函数实现 说明
beforeLast function eval_beforeLast(ctx) {
  if (ctx.step >= ctx.N-2) {
    return [0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n];
  } else {
   return [ctx.Fr.negone, 0n, 0n, 0n, 0n, 0n, 0n, 0n]; //不是倒数第二行,直接返回负值。
  }
}
在主业务流程和最后清零操作之后,进行补零到execution trace表的倒数第二行。通常的调用方式类似为:【当beforeLast()返回负值时,会持续调用JMPN。】
finalWait:
  ${beforeLast()} : JMPN(finalWait)
                                    : JMP(start)
getGlobalHash 本质上ctx.globalHahs=Keccak256(oldStateRoot|
oldLocalExitRoot|newStateRoot
|newLocalExitRoot|batchHashData
|numBatch|timestamp),
其中batchHashData=Keccak256(batchL2Data|globalExitRoot|sequencerAddr),
这些参数均来自inputs-executor/*.json文件,均以16进制256bit表示,不足的前方补零。
将ctx.globalHash值转换为8个32bit field elements表示。
getOldStateRoot 为inputs-executor/*.json文件中的oldStateRoot。 将ctx.input.oldStateRoot值转换为8个32bit field elements表示。
getNewStateRoot 为inputs-executor/*.json文件中的newStateRoot。 将ctx.input.newStateRoot值转换为8个32bit field elements表示。
getSequencerAddr 为inputs-executor/*.json文件中的sequencerAddr。 将ctx.input.sequencerAddr值转换为8个32bit field elements表示。
getOldLocalExitRoot 为inputs-executor/*.json文件中的oldLocalExitRoot。 将ctx.input.oldLocalExitRoot值转换为8个32bit field elements表示。
getNewLocalExitRoot 为inputs-executor/*.json文件中的newLocalExitRoot。 将ctx.input.newLocalExitRoot值转换为8个32bit field elements表示。
getNumBatch 为inputs-executor/*.json文件中的numBatch。 返回结果为[ctx.Fr.e(ctx.input.numBatch), ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero];
getTimestamp 为inputs-executor/*.json文件中的timestamp。 返回结果为[ctx.Fr.e(ctx.input.timestamp), ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero];
getBatchHashData batchHashData=Keccak256(batchL2Data|globalExitRoot|sequencerAddr),
这些参数均来自inputs-executor/*.json文件,均以16进制256bit表示,不足的前方补零。
将ctx.input.batchHashData值转换为8个32bit field elements表示。
getGlobalExitRoot 为inputs-executor/*.json文件中的globalExitRoot。 将ctx.input.globalExitRoot值转换为8个32bit field elements表示。
getTxs function eval_getTxs(ctx, tag) {
  if (tag.params.length != 2) throw new Error(“Invalid number of parameters function …”);
  const txs = ctx.input.batchL2Data;
  const offset = Number(evalCommand(ctx,tag.params[0]));
  const len = Number(evalCommand(ctx,tag.params[1]));
  let d = “0x” + txs.slice(2+offset*2, 2+offset*2 + len*2);
  if (d.length == 2) d = d+‘0’;
  return scalar2fea(ctx.Fr, Scalar.e(d));
}
从ctx.input.batchL2Data中截取特定长度值,转换为8个32bit field elements表示。
getTxsLen 为:(ctx.input.batchL2Data.length-2) / 2 返回的结果为[ctx.Fr.e((ctx.input.batchL2Data.length-2) / 2), ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero]
eventLog 返回为全零值:[ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero, ctx.Fr.zero];
cond 有条件返回,若evalCommand结果为true,则返回-1;否则返回0。
inverseFpEc 输入为a,若a为0,抛异常;否则返回 a − 1 a^{-1} a−1
inverseFnEc 输入为a,若a为0,抛异常;否则返回 a − 1 a^{-1} a−1
sqrtFpEc 输入为a,返回 a \sqrt{a} a ​
dumpRegs 打印A/B/C/D/E寄存器中的值,并返回0。
dump 打印输入信息,并返回0。
dumphex 以16进制打印输入信息,并返回0。
xAddPointEc 取不同点求和后的x坐标。
yAddPointEc 取不同点求和后的y坐标。
xDblPointEc 取相同点求和后的x坐标。
yDblPointEc 取相同点求和后的y坐标。
test** 对应test_tools.js中的相关函数
getBytecode evalCommand获得hashContract=》从ctx.input.contractsBytecode中获得bytecode,从bytecode中截取特定长度值,转换为8个32bit field elements表示。
touchedAddress 若地址对应为某预编译合约,则考虑warm access,直接返回0。若该地址在ctx.input.touchedAddress数组之中,则返回0;否则将addr放入ctx.input.touchedAddress中并返回1。
touchedStorageSlots 输入为addr和key,若addr已在ctx.input.touchedStorageSlots中,则返回0;否则将{addr,key}存入ctx.input.touchedStorageSlots中,并返回1。
**bitwise** 输入为a,b,根据具体的函数名进行add/or/xor/not运算。
**comp** 输入为a,b,根据具体的函数名进行lt/gt/eq运算。
loadScalar 读取相应参数中的值并处理
log 输入为frLog和label,打印frLog等信息。返回0。
resetTouchedAddress 将ctx.input.touchedAddress置空,返回0。
resetStorageSlots 将ctx.input.touchedStorageSlots置空,并返回0。
exp 输入为a,b,将 a b a^b ab结果转换为8个32bit field elements表示。
storeLog 输入为indexLog、isTopic、data,若ctx.outLogs[indexLog]未定义,若isTopic为true,则将data以十六进制形式存入ctx.outLogs[indexLog].topics中;否则将data以十六进制形式存入ctx.outLogs[indexLog].data中。返回0。
**precompiled**
break 打印断点信息,返回0。
memAlignWR_W0 输入为m0,value,offset,进行处理后将结果以8个32bit field elements表示。
memAlignWR_W1 输入为m1,value,offset,进行处理后将结果以8个32bit field elements表示。
memAlignWR8_W0 输入为m0,value,offset,取bits=(31-offset)*8,进行处理后将结果以8个32bit field elements表示。
saveContractBytecode 输入为addr,将ctx.hashP[addr].data 存入 ctx.input.contractsBytecode[ctx.hashP[addr].digest] 中,并返回0。

3. zkevm-proverjs项目sm_storage.js文件中的函数

zkevm-proverjs项目sm_storage.js文件中的函数调用有:【对应为Storage状态机的action。Storage状态机的输入和输出状态实际上是SMT(Sparse Merkle Tree),所以相应的action也是SMT set】

函数名 函数实现 说明
isSetUpdate (!actionListEmpty && action[a].bIsSet && action[a].setResult.mode == "update")为true,则设置op[0]=1。update existing value
isSetInsertFound (!actionListEmpty && action[a].bIsSet && action[a].setResult.mode == "insertFound")为true,则设置op[0]=1。insert with found key; found a leaf node with a common set of key bits
isSetInsertNotFound (!actionListEmpty && action[a].bIsSet && action[a].setResult.mode == "insertNotFound")为true,则设置op[0]=1。insert with no found key
isSetReplacingZero (!actionListEmpty && action[a].bIsSet && action[a].setResult.mode == "insertNotFound")为true,则设置op[0]=1。替换为0
isSetDeleteLast (!actionListEmpty && action[a].bIsSet && action[a].setResult.mode == "deleteLast")为true,则设置op[0]=1。delete the last node, so root becomes 0
isSetDeleteFound (!actionListEmpty && action[a].bIsSet && action[a].setResult.mode == "deleteFound")为true,则设置op[0]=1。delete with found key
isSetDeleteNotFound (!actionListEmpty && action[a].bIsSet && action[a].setResult.mode == "deleteNotFound")为true,则设置op[0]=1。delete with no found key
isSetZeroToZero (!actionListEmpty && action[a].bIsSet && action[a].setResult.mode == "zeroToZero")为true,则设置op[0]=1。value was zero and remains zero
GetIsOld0 !actionListEmpty && (action[a].bIsSet ? action[a].setResult.isOld0 : action[a].getResult.isOld0)为true,则设置op[0]=1。can be a final leaf (isOld0=true)。
isGet (!actionListEmpty && !action[a].bIsSet)为true,则设置op[0]=1。若key not found,则返回0;否则,返回非零值。
GetRkey 设置op[0/1/2/3]=ctx.rkey[0/1/2/3]。Get the remaining key, i.e. the key after removing the bits used in the tree node navigation。
GetSiblingRkey 设置op[0/1/2/3]=ctx.rkey[0/1/2/3]。Get the sibling remaining key, i.e. the part that is not common to the value key。
GetSiblingHash 若action[a].bIsSet为true对应setResult,否则为getResult,相应设置op[0/1/2/3]=action[a].set/getResult.siblings[ctx.currentLevel][(1n-ctx.bits[ctx.currentLevel])*4n+0/1/2/3n]。Get the sibling hash, obtained from the siblings array of the current level, taking into account that the sibling bit is the opposite (1-x) of the value bit。
GetValueLow 取action的getResult.value或setResult.newValue值,将该值的lower 4 elements赋值为op[0/1/2/3]。Value is an u256 split in 8 u32 chuncks, each one stored in the lower 32 bits of an u63 field element。u63 means that it is not an u64, since some of the possible values are lost due to the prime effect。
GetValueHigh 取action的getResult.value或setResult.newValue值,将该值的higher 4 elements赋值为op[0/1/2/3]。
GetSiblingValueLow 取action的getResult.insValue或setResult.insValue值,将该值的lower 4 elements赋值为op[0/1/2/3]。
GetSiblingValueHigh 取action的getResult.insValue或setResult.insValue值,将该值的higher 4 elements赋值为op[0/1/2/3]。
GetOldValueLow 取action的setResult.oldValue值,将该值的lower 4 elements赋值为op[0/1/2/3]。
GetOldValueHigh 取action的setResult.oldValue值,将该值的higher 4 elements赋值为op[0/1/2/3]。
GetLevelBit 输入为单个bit,若( ctx.level & (1<<bit) ) != 0为true,则设置op[0]=1。
GetTopTree 仅当到达the top of the tree(即ctx.currentLevel=0),返回0。
GetTopOfBranch Returns 0 if we reached the top of the branch, i.e. if the level matches the siblings size。
GetNextKeyBit Get the next key bit。该调用会自动减少the current level。
isAlmostEndPolynomial if (i == (polSize-2))
{
  op[0] = fr.one;
}
与前面的beforeLast函数功能类似。在主业务流程和最后清零操作之后,进行补零到execution trace表的倒数第二行。通常的调用方式类似为:【仅当为倒数第二行时,isAlmostEndPolynomial才返回1,否则返回均为0值。若返回0值,则持续调用NotEndPol。】
NotEndPol:
  ${isAlmostEndPolynomial()} :JMPZ(NotEndPol)
                                                            :JMP(Run) ;为execution trace的最后一行。

附录:Polygon Hermez 2.0 zkEVM系列博客

  • ZK-Rollups工作原理
  • Polygon zkEVM——Hermez 2.0简介
  • Polygon zkEVM网络节点
  • Polygon zkEVM 基本概念
  • Polygon zkEVM Prover
  • Polygon zkEVM工具——PIL和CIRCOM
  • Polygon zkEVM节点代码解析
  • Polygon zkEVM的pil-stark Fibonacci状态机初体验
  • Polygon zkEVM的pil-stark Fibonacci状态机代码解析
  • Polygon zkEVM PIL编译器——pilcom 代码解析
  • Polygon zkEVM Arithmetic状态机
  • Polygon zkEVM中的常量多项式
  • Polygon zkEVM Binary状态机
  • Polygon zkEVM Memory状态机
  • Polygon zkEVM Memory Align状态机
  • Polygon zkEVM zkASM编译器——zkasmcom
  • Polygon zkEVM哈希状态机——Keccak-256和Poseidon
  • Polygon zkEVM zkASM语法
  • Polygon zkEVM可验证计算简单状态机示例
  • Polygon zkEVM zkASM 与 以太坊虚拟机opcode 对应集合

Polygon zkEVM zkASM中的函数集合相关推荐

  1. Polygon zkEVM中Goldilocks域元素circom约束

    1. 引言 前序博客有: Goldilocks域 Goldilocks域 p=264−232+1p= 2^{64} - 2^{32} + 1p=264−232+1. Polygon zkEVM中Gol ...

  2. Polygon zkEVM中的Merkle tree

    1. 引言 前序博客有: Merkle tree及其在区块链等领域的应用 以https://github.com/0xPolygonHermez/pil-stark为例,Polygon zkEVM中实 ...

  3. Polygon zkEVM zkROM代码解析(2)

    1. 引言 Polygon zkEVM zkROM代码库为: https://github.com/0xPolygonHermez/zkevm-rom zkROM的基本流程为: 1)A:加载输入变量: ...

  4. Polygon zkEVM交易解析

    1. 引言 前序博客有: Ethereum EVM简介 揭秘EVM Opcodes 剖析Solidity合约创建EVM bytecode Polygon zkEVM zkASM 与 以太坊虚拟机opc ...

  5. Polygon zkEVM zkProver基本设计原则 以及 Storage状态机

    1. zkProver基本设计原则 Polygon zkEVM采用状态机模型来模拟EVM(Ethereum Virtual Machine),从而提供与以太坊相同的用户体验,并支持部署运行相同的以太坊 ...

  6. Polygon zkEVM——Hermez 2.0简介

    1. 引言 前序博客有: ZK-Rollups工作原理 近期,Polygon团队开源了其Hermez 2.0 zkEVM代码,公开测试网即将上线: https://github.com/0xpolyg ...

  7. python中哪个函数能生成集合_神奇的python系列11:函数之生成器,列表推导式

    1.生成器 生成器的本质是迭代器. 在python中有三种方式来获取生成器 1.通过生成器函数 2.通过各种推到式来实现生成器 3.通过数据的转换也可以获取生成器 #函数 deffunc():prin ...

  8. python中集合所用的reduce_Python中reduce函数和lambda表达式的学习

    reduce函数将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1.2 个元素进行操作,得到的结果再与第三个数据用 ...

  9. matlab中的mkdir函数_matlab所有函数集合

    matlab所有函数集合 更新时间:2017-2-10 14:33:00  浏览量:568  手机版 一.常用命令 1.常用命令-->管理命令和函数 addpath 添加目录到MATLAB 搜索 ...

最新文章

  1. 深度学习的四个学习阶段!
  2. Spark源码阅读01-SparkConf
  3. PHP mysqli 扩展库(面向对象/数据库操作封装/事务控制/预编译)
  4. nginx全局内存缓存
  5. 长安渝北工厂机器人_探秘长安UNI-T生产基地 智造工厂机器人24小时不休
  6. [笔记]java-package
  7. java map 数组_java技术Spring集合属性
  8. 如何自己写xuetr(一) 每次改变的驱动名和服务名
  9. hibernate和struts实现分页
  10. 【洛谷 P4291】 [HAOI2008]排名系统(Splay,Trie)
  11. DateTime.Now函数详解 所有用法
  12. 厉害了!百度智能云NIRO Pro智能机器人半年内连获三项产品设计大奖
  13. 关于Negative values in data passed to MultinomialNB (input X)报错问题
  14. python基础(中)
  15. mysql 清除表中的数据 (TRUNCATE )
  16. 计算机网络要点归纳-(谢希仁版本)
  17. 03-iptables-实验
  18. 记一道USB流量分析题
  19. 兄弟连教育python培训
  20. MySQL消除笛卡尔积的方法,mysql-了解SQL中的笛卡尔积

热门文章

  1. 【图像翻译GAN】我家那只蠢猫更像狗子还是更像虎哥?让AI模型来看看
  2. 【论文阅读】AI20 A Dirichlet process biterm-based mixture model for short text stream clustering
  3. Windows 10使用 Packer 和 VMware Player 自动构建CentOS 8虚拟机镜像
  4. 1.7.2服务器修改器,关于S7修改器V1.72的问题
  5. Win11怎么给麦克风降噪?
  6. HashMap的问答总结
  7. 阿里云函数 实现企业微信消息 回调地址验证
  8. win10安装hypermesh无法启动_解决win10系统无法安装打印机
  9. 人脸表情判别,口罩识别
  10. java中list集合删除其中的某一个元素