Skip to content

Commit

Permalink
Merge pull request #373 from 0xPolygonHermez/feature/specific-optz
Browse files Browse the repository at this point in the history
Specific coverage optimizations
  • Loading branch information
krlosMata authored Apr 8, 2024
2 parents dcbd682 + 8148d88 commit f6471e2
Show file tree
Hide file tree
Showing 13 changed files with 96 additions and 139 deletions.
9 changes: 4 additions & 5 deletions main/l2-tx-hash.zkasm
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
;; [ 8 bytes ] nonce
;; [ 32 bytes ] gasPrice
;; [ 8 bytes ] gasLimit
;; [ 1 bytes ] deployment ('0': no deloyment, '1': deployment)
;; [ 1 bytes ] deployment ('0': no deployment, '1': deployment)
;; [ 20 bytes ] to (0 bytes if it is a deployment)
;; [ 32 bytes ] value
;; [ 3 bytes ] dataLength
Expand All @@ -19,7 +19,7 @@
;; [ 8 bytes ] nonce
;; [ 32 bytes ] gasPrice
;; [ 8 bytes ] gasLimit
;; [ 1 bytes ] deployment ('0': no deloyment, '1': deployment)
;; [ 1 bytes ] deployment ('0': no deployment, '1': deployment)
;; [ 20 bytes ] to (0 bytes if it is a deployment)
;; [ 32 bytes ] value
;; [ 3 bytes ] dataLength
Expand Down Expand Up @@ -106,8 +106,7 @@ addL2HashTx_dataLength:
$ => E :MLOAD(l2TxHashPointer)
$ => HASHPOS :MLOAD(l2HASHP)
3 => D
$ => A :MLOAD(txCalldataLen)
A :HASHP(E)
${mem.txCalldataLen} :HASHP(E), MLOAD(txCalldataLen)
HASHPOS :MSTORE(l2HASHP)

; load temporary register values
Expand All @@ -117,7 +116,7 @@ addL2HashTx_dataLength:
$ => HASHPOS :MLOAD(tmpVar_HASHPOS_L2HashTx), RETURN

;; Write 1 byte to l2TxHash: txType
; note: HASHPOS is not reovered and the outcome register is the l2TxHash length
; note: HASHPOS is not recovered and the outcome register is the l2TxHash length
addL2HashTx_txType:
; store temporary register values
A :MSTORE(tmpVar_A_L2HashTx)
Expand Down
3 changes: 1 addition & 2 deletions main/load-change-l2-block-utils.zkasm
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
;@in C: current data parsed pointer
;@out A: D bytes from batch data at offset C
getChangeL2TxBytes:
$ => A :MLOAD(batchL2DataLength)
$ => B :MLOAD(batchL2DataParsed)
A - B - C - D :JMPN(invalidDecodeChangeL2Block)
$ - B - C - D :F_MLOAD(batchL2DataLength), JMPN(invalidDecodeChangeL2Block)
$ => E :MLOAD(batchHashDataPointer)
$ => HASHPOS :MLOAD(batchHashPos)
$ => A :HASHP(E)
Expand Down
25 changes: 10 additions & 15 deletions main/load-tx-rlp-utils.zkasm
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,24 @@
;@in C: current data parsed pointer
;@out A: D bytes from batchL2Data at offset C
getBatchL2DataBytes:
$ => A :MLOAD(batchL2DataLength)
$ => B :MLOAD(batchL2DataParsed)
A - B - C - D :JMPN(invalidTxRLP)
$ - B - C - D :F_MLOAD(batchL2DataLength), JMPN(invalidTxRLP)
$ => E :MLOAD(batchHashDataPointer)
$ => HASHPOS :MLOAD(batchHashPos)
$ => A :HASHP(E)
HASHPOS :MSTORE(batchHashPos)
C => HASHPOS
$ => E :MLOAD(txHashPointer)
:RETURN
$ => E :MLOAD(txHashPointer), RETURN

;; Add bytes to generate ethereum signed message
;; - legacy transaction: signedMessage = H_keccak(rlp(nonce, gasprice, gaslimit, to, value, data, chainId, 0, 0))
;; - pre EIP-155: signedMessage = H_keccak(rlp(nonce, gasprice, gaslimit, to, value, data))
; REVIEW: is it necessary?? (first two steps)
addHashTx:
$ => A :MLOAD(txRLPLength)
A - HASHPOS - D :JMPN(invalidTxRLP)
$ - HASHPOS - D :F_MLOAD(txRLPLength), JMPN(invalidTxRLP)
addHashTxBegin:
$ => A :MLOAD(batchL2DataLength)
$ => B :MLOAD(batchL2DataParsed)
A - B - C - D :JMPN(invalidTxRLP)
$ - B - C - D :F_MLOAD(batchL2DataLength), JMPN(invalidTxRLP)
$ => E :MLOAD(batchHashDataPointer)
$ => HASHPOS :MLOAD(batchHashPos)
$ => A :HASHP(E)
Expand All @@ -41,12 +37,11 @@ addHashTxBegin:
; @in D: number of bytes to add
; @in C: current tx data parsed pointer
addHashTxByteByByte:
$ => A :MLOAD(txRLPLength)
A - HASHPOS - D :JMPN(invalidTxRLP)
$ => A :MLOAD(batchL2DataLength)
$ - HASHPOS - D :F_MLOAD(txRLPLength), JMPN(invalidTxRLP)
$ => B :MLOAD(batchL2DataParsed)
; Save current registers
A - B - C - D :JMPN(invalidTxRLP), SAVE(B,C,D,E,RR,RCX)
; CHECK: Is correct to save here in same line as JMPN?
$ - B - C - D :F_MLOAD(batchL2DataLength), JMPN(invalidTxRLP), SAVE(B,C,D,E,RR,RCX)
$ => HASHPOS :MLOAD(batchHashPos)
D => E
readHash:
Expand Down Expand Up @@ -203,14 +198,14 @@ skipCheckShortData:
:RETURN

;; Check non-negative integer RLP representation has no leading zeros and it is encoded in its shortest form
VAR GLOBAL tmpVarAcheckNonLeadingZeros
VAR GLOBAL tmpVarACheckNonLeadingZeros
VAR GLOBAL tmpVarZkPCcheckNonLeadingZeros
checkNonLeadingZeros:
RR :MSTORE(tmpVarZkPCcheckNonLeadingZeros)
A :MSTORE(tmpVarAcheckNonLeadingZeros)
A :MSTORE(tmpVarACheckNonLeadingZeros)
; set value to B and get its
A => B :CALL(getLenBytes) ; in: [B: number] out: [A: byte length of B]
; check (bytes length - encoded length) are not equal
D - A :JMPNZ(invalidTxRLP)
$ => RR :MLOAD(tmpVarZkPCcheckNonLeadingZeros)
$ => A :MLOAD(tmpVarAcheckNonLeadingZeros), RETURN
$ => A :MLOAD(tmpVarACheckNonLeadingZeros), RETURN
52 changes: 25 additions & 27 deletions main/main.zkasm
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ INCLUDE "constants.zkasm"
INCLUDE "vars.zkasm"

; Blocks zkROM
; A - Load initial registers into memory: oldStateRoot (B), oldBatchAccInputHash (C), & chainID (GAS)
; B - Compute keccaks needed to finish the batch
; C - Loop parsing RLP transactions
; D - Load blockNum variable & Loop processing transactions
; E - Batch computations: get newLocalExitRoot, assert transactions size, compute batchHashData & compute newBatchAccInputHash
; F - Finalize execution
; A - Load initial registers into memory: oldStateRoot (SR), oldBatchAccInputHash (C), forkID (CTX), previousL1InfoTreeRoot (D), previousL1InfoTreeIndex (RCX), chainID (GAS)
; B - Compute forcedHashData
; C - Compute newBatchAccInputHash, load timestamp and blockNum
; D - Loop parsing RLP transactions
; E - Loop processing transactions
; F - FinalizeBatch
; G - Finalize execution

start: ; main zkROM entry point
;;;;;;;;;;;;;;;;;;
Expand Down Expand Up @@ -40,23 +41,22 @@ start: ; main zkROM entry point
; If forcedHashData ist no zero, is a forced batch
; Set forced batch flag
1 :MSTORE(isForced)
; Compute forcedHashData
;;;;;;;;;;;;;;;;;;
;; B - Compute forcedHashData
;;;;;;;;;;;;;;;;;;
$ => E :MLOAD(nextHashKId)
E + 1 :MSTORE(nextHashKId)
32 => D
${getForcedGER()} => A :MSTORE(forcedGER)
A :HASHK(E)
${getForcedBlockHashL1()} => A :MSTORE(forcedBlockHashL1InfoTree)
A :HASHK(E)
${getForcedGER()} => A :MSTORE(forcedGER), HASHK(E)
${getForcedBlockHashL1()} => A :MSTORE(forcedBlockHashL1InfoTree), HASHK(E)
8 => D
${getForcedTimestamp()} => A :MSTORE(forcedTimestamp)
A :HASHK(E)
${getForcedTimestamp()} => A :MSTORE(forcedTimestamp), HASHK(E)
HASHPOS :HASHKLEN(E)
; Assert forcedHashData computed matches with forcedHashData obtained from free input
$ => A :HASHKDIGEST(E)
$ :MLOAD(forcedHashData), ASSERT
;;;;;;;;;;;;;;;;;
;; B - Compute newBatchAccInputHash, load newLocalExitRoot and timestamp
;; C - Compute newBatchAccInputHash, load newLocalExitRoot and timestamp
;;;;;;;;;;;;;;;;;;
computeNewBatchAccInputHash:
; newBatchAccInputHash = LinearPoseidon(oldBatchAccInputHash, batchHashData, sequencerAddress, forcedHashData))
Expand All @@ -66,25 +66,20 @@ computeNewBatchAccInputHash:
0 => HASHPOS

32 => D
$ => A :MLOAD(oldBatchAccInputHash)
A :HASHP(E)
${mem.oldBatchAccInputHash} :HASHP(E), MLOAD(oldBatchAccInputHash)

$ => A :MLOAD(batchHashData)
A :HASHP(E)
${mem.batchHashData} :HASHP(E), MLOAD(batchHashData)

20 => D
$ => A :MLOAD(sequencerAddr)
A :HASHP(E)
${mem.sequencerAddr} :HASHP(E), MLOAD(sequencerAddr)

32 => D
$ => A :MLOAD(forcedHashData)
A :HASHP(E)
${mem.forcedHashData} :HASHP(E), MLOAD(forcedHashData)

; finish accInputHash
HASHPOS :HASHPLEN(E)

$ => C :HASHPDIGEST(E)
C :MSTORE(newBatchAccInputHash)
$ => C :HASHPDIGEST(E), MSTORE(newBatchAccInputHash)

; Compute batchHashData (loaded at smt from executor)
$ => E :MLOAD(nextHashPId)
Expand All @@ -111,7 +106,7 @@ setBlockNum:
$ => A :SLOAD,MSTORE(blockNum)

;;;;;;;;;;;;;;;;;;
;; C - Loop parsing RLP transactions
;; D - Loop parsing RLP transactions
;; - Load transaction RLP data and ensure it has correct RLP encoding
;; - If an error is found in any transaction, the batch will not process any transaction
;;;;;;;;;;;;;;;;;;
Expand All @@ -128,7 +123,7 @@ txLoopRLP:
C - A :JMPN(loadTx_rlp)

;;;;;;;;;;;;;;;;;;
;; D - Loop processing transactions
;; E - Loop processing transactions
;; - Load transaction data and interpret it
;;;;;;;;;;;;;;;;;;

Expand Down Expand Up @@ -169,7 +164,7 @@ processTxsEnd:
finalizeBatch:

;;;;;;;;;;;;;;;;;;
;; E - Check all save/restore have been consumed
;; F - Check all save/restore have been consumed
;; - Retrieve newLocalExitRoot
;; - Finalize execution: set output values at corresponding registers
;;;;;;;;;;;;;;;;;;
Expand Down Expand Up @@ -197,6 +192,9 @@ clearPendingRestores_end:
$ => A :SLOAD
A :MSTORE(newLocalExitRoot)

;;;;;;;;;;;;;;;;;;
;; G - Finalize execution
;;;;;;;;;;;;;;;;;;
SR :MSTORE(auxNewSR) ; Store final SR to recover at output setting phase
; Set registers to its initials values
; Save inputs to RESTORE at last - 1 step
Expand Down
12 changes: 4 additions & 8 deletions main/opcodes/calldata-returndata-code.zkasm
Original file line number Diff line number Diff line change
Expand Up @@ -296,29 +296,25 @@ opCODECOPYloop:
$ => A :MLOAD(memOffset), CALL(offsetUtil); in: [A: offset] out: [E: offset/32, C: offset%32]
E :MSTORE(memInteger)
; read M0 previous value
$ => A :MLOAD(MEM:E)
A :MSTORE(previousValue), CALL(opCODECOPYLoadBytes); in:[codecopyBytecodeLength, codecopyHashId] out: [B: readByte]
$ => A :MLOAD(previousValue)
$ => A :MLOAD(MEM:E), CALL(opCODECOPYLoadBytes); in:[codecopyBytecodeLength, codecopyHashId] out: [B: readByte], E is modified
C + 1 * %MEM_ALIGN_LEN => C
${memAlignWR_W0(A,B,C)} => D ; no trust calculate W0
B => E ; B and E must be same value
B :MEM_ALIGN_WR ; only use LSB of B, rest of bytes could be non zero
$ => E :MLOAD(memInteger)
D :MSTORE(MEM:E) ; write W0
; update vars loop
$ => B :MLOAD(remainingBytes)
B - 1 => B ; decrease 1 byte from length
$ - 1 => B :F_MLOAD(remainingBytes); decrease 1 byte from length
B :MSTORE(remainingBytes)
$ => A :MLOAD(memOffset)
A + 1 => A ; increment offset to write the next byte
$ + 1 => A :F_MLOAD(memOffset); increment offset to write the next byte
A :MSTORE(memOffset), JMP(opCODECOPYloop)


; @info Load 0 if read bytecode position is above bytecode length
opCODECOPYLoadBytes:
; codecopyBytecodeLength is less than 32 bits, length obtained from storage, max bytecode of a contract is 24kbytes
$ => B :MLOAD(codecopyBytecodeLength), JMPZ(readZero)
; if HASPOS < B, read value, else, read zero
; if HASHPOS < B, read value, else, read zero
HASHPOS - B :JMPN(readValueBytecode)
readZero:
0 => B :RETURN
Expand Down
6 changes: 1 addition & 5 deletions main/opcodes/flow-control.zkasm
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,11 @@ opPC:

/**
* @link [https://www.evm.codes/#5B?fork=berlin]
* @zk-counters
* - 10 steps
* @process-opcode
* - stack input: none
* - stack output: none
*/
opJUMPDEST:
; checks zk-counters
%MAX_CNT_STEPS - STEP - 10 :JMPN(outOfCountersStep)

; CHECK: counters check removed, is it safe? Check max bytecode/calldata length
; check out-of-gas
GAS - %JUMP_DEST_GAS => GAS :JMPN(outOfGas, readCode)
23 changes: 10 additions & 13 deletions main/opcodes/stack-operations.zkasm
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,9 @@ opAuxPUSHB:
; checks zk-counters
%MAX_CNT_STEPS - STEP - 400 :JMPN(outOfCountersStep)
; check is a create/create2
$ => A :MLOAD(isCreate), JMPNZ(opAuxPUSHBcreate)
$ => B :MLOAD(txCalldataLen)
PC + D - B :JMPN(opAuxPUSHB2)
B - PC => D :JMPZ(opAuxPUSHBend)
$ :MLOAD(isCreate), JMPNZ(opAuxPUSHBCreate)
PC + D - $ :F_MLOAD(txCalldataLen), JMPN(opAuxPUSHB2)
$ - PC => D :F_MLOAD(txCalldataLen), JMPZ(opAuxPUSHBend)

opAuxPUSHB2:
; set bytes length to read to C
Expand All @@ -159,16 +158,14 @@ opAuxPUSHB2:
; get memory pointer for hashing
$ => E :MLOAD(batchHashDataPointer)
; get position where data starts in the tx
$ => HASHPOS :MLOAD(dataStarts)
HASHPOS + PC => HASHPOS
$ + PC => HASHPOS :F_MLOAD(dataStarts)
PC + D => PC
; checks zk-counters
%MAX_CNT_STEPS - STEP - 10*D :JMPN(outOfCountersStep)

opAuxPUSHBloop:
$ => B :HASHP1(E)
; accumulate hash value
A + B => A
A + $ => A :F_HASHP1(E)
; decrease length for loop
C - 1 => C :JMPN(opAuxPUSHBend)
1 => D :CALL(SHLarith); in: [A: value, D: #bytes to left shift] out: [A: shifted result]
Expand All @@ -182,7 +179,7 @@ opAuxPUSHBend:
; check stack overflow
%MAX_STACK_SIZE - SP :JMPN(stackOverflow, readCode)

opAuxPUSHBcreate:
opAuxPUSHBCreate:
; get bytes length
$ => B :MLOAD(txCalldataLen)
; PUSH in a create, we need to get bytes from memory (not calldata)
Expand All @@ -193,19 +190,19 @@ opAuxPUSHBcreate:
; increase current program counter (PC) to offset for getting pushed bytes to read
E + PC => E
D => C
C - B + PC :JMPN(opAuxPUSHBcreate2)
C - B + PC :JMPN(opAuxPUSHBCreate2)
0 => A
B - PC => C :JMPZ(opfinalPUSHBcreate)
B - PC => C :JMPZ(opFinalPUSHBcreate)

opAuxPUSHBcreate2:
opAuxPUSHBCreate2:
; set length to read to C for MLOADX call
:CALL(MLOADX); in: [E: offset, C: length] out: [A: value, E: new offset]
; increase to PC the length of the read bytes
PC + D => PC
; put in the lowest significant bytes, align value to right
32 - D => D :CALL(SHRarith); in: [A: value, D: #bytes to right shift] out: [A: shifted result]

opfinalPUSHBcreate:
opFinalPUSHBcreate:
; return to current context
$ => CTX :MLOAD(currentCTX), JMP(opAuxPUSHBend)

Expand Down
18 changes: 6 additions & 12 deletions main/opcodes/storage-memory.zkasm
Original file line number Diff line number Diff line change
Expand Up @@ -122,21 +122,15 @@ opMSIZE:
; check out-of-gas
GAS - %GAS_QUICK_STEP => GAS :JMPN(outOfGas)

; load current memory length
$ => E :MLOAD(memLength)
; MSIZE should be multiple of a word (32 bytes)
; Div operation with Arith
E :MSTORE(arithA)
32 :MSTORE(arithB), CALL(divARITH); in: [arithA, arithB] out: [arithRes1: arithA/arithB, arithRes2: arithA%arithB]
$ => C :MLOAD(arithRes1)
; check arithRes2 is 0, no need to round in this case
$ :MLOAD(arithRes2), JMPZ(MSIZEend)

; load current memory length, less than 32 bits
$ => A :MLOAD(memLength), CALL(offsetUtil); in: [A: offset] out: [E: offset/32, C: offset%32]
; MSIZE should be multiple of a word (32 bytes), if mod is zero, return size, otherwise round up to next word
C :JMPZ(MSIZEend)
; Round size to 32bytes multiple
C * 32 + 32 => E
E * 32 + 32 => A

MSIZEend:
E :MSTORE(SP++); [size(E) => SP]
A :MSTORE(SP++); [size(E) => SP]
; check stack overflow
%MAX_STACK_SIZE - SP :JMPN(stackOverflow, readCode)
/**
Expand Down
Loading

0 comments on commit f6471e2

Please sign in to comment.