Polygon zkEVM zkASM中的函数集合

Posted mutourend

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Polygon zkEVM zkASM中的函数集合相关的知识,希望对你有一定的参考价值。

1. 引言

前序博客有:

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函数:

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

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

函数名函数实现说明
beforeLastfunction 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)
getGlobalHashfunction eval_getGlobalHash(ctx, tag)
  if (tag.params.length != 0) throw new Error(“Invalid number of parameters function…”)
  return scalar2fea(ctx.Fr, ctx.globalHash);
将ctx.globalHash值转换为8个32bit field elements表示。
getOldStateRoot将ctx.input.oldStateRoot值转换为8个32bit field elements表示。
getNewStateRoot将ctx.input.newStateRoot值转换为8个32bit field elements表示。
getSequencerAddr将ctx.input.sequencerAddr值转换为8个32bit field elements表示。
getOldLocalExitRoot将ctx.input.oldLocalExitRoot值转换为8个32bit field elements表示。
getNewLocalExitRoot将ctx.input.newLocalExitRoot值转换为8个32bit field elements表示。
getNumBatch返回结果为[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返回结果为[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将ctx.input.batchHashData值转换为8个32bit field elements表示。
getGlobalExitRoot将ctx.input.globalExitRoot值转换为8个32bit field elements表示。
getTxsfunction 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+offset2, 2+offset2 + 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.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 a1
inverseFnEc输入为a,若a为0,抛异常;否则返回 a − 1 a^-1 a1
sqrtFpEc输入为a,返回 a \\sqrta 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中的相关函数
getBytecodeevalCommand获得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。
GetTopOfBranchReturns 0 if we reached the top of the branch, i.e. if the level matches the siblings size。
GetNextKeyBitGet the next key bit。该调用会自动减少the current level。
isAlmostEndPolynomialif (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系列博客

以上是关于Polygon zkEVM zkASM中的函数集合的主要内容,如果未能解决你的问题,请参考以下文章

Polygon zkEVM zkASM语法

Polygon zkEVM zkASM编译器——zkasmcom

Polygon zkEVM交易解析

Polygon zkEVM zkROM代码解析

Polygon zkEVM zkROM代码解析

Polygon zkEVM中的Merkle tree