From 0abafa997ca1cd7fbf92f8de7ccbcfaf818e06bb Mon Sep 17 00:00:00 2001 From: Ignasi Date: Thu, 7 Mar 2024 15:55:30 +0100 Subject: [PATCH 01/16] Use poseidon for batchHashData --- counters/tests/addBatchHashByteByByte.zkasm | 31 ---- main/ecrecover/ecrecover.zkasm | 3 +- main/load-change-l2-block-utils.zkasm | 9 +- main/load-change-l2-block.zkasm | 4 +- main/load-tx-rlp-utils.zkasm | 32 ++--- main/load-tx-rlp.zkasm | 82 +++-------- main/main.zkasm | 150 ++++++++------------ main/opcodes/block.zkasm | 3 +- main/opcodes/crypto.zkasm | 3 +- main/opcodes/flow-control.zkasm | 2 +- main/opcodes/stack-operations.zkasm | 2 +- main/process-change-l2-block.zkasm | 9 +- main/process-tx.zkasm | 12 +- main/utils.zkasm | 44 +----- main/vars.zkasm | 4 +- package.json | 6 +- test/ecrecover.zkasm | 1 - 17 files changed, 119 insertions(+), 278 deletions(-) delete mode 100644 counters/tests/addBatchHashByteByByte.zkasm diff --git a/counters/tests/addBatchHashByteByByte.zkasm b/counters/tests/addBatchHashByteByByte.zkasm deleted file mode 100644 index 850b5c34..00000000 --- a/counters/tests/addBatchHashByteByByte.zkasm +++ /dev/null @@ -1,31 +0,0 @@ -INCLUDE "../initIncludes.zkasm" - -start: - 1000000 => GAS - -operation: - ;@info: adds data to batchHashdata byte by byte - ;@in: A: bytes to add - ;@in D: bytes length - 12 => A - 31 => D - :CALL(addBatchHashByteByByte) - - %ADDBATCHHASH_STEP*D - STEP:JMPN(failedCounters) - %ADDBATCHHASH_CNT_BINARY - CNT_BINARY :JMPNZ(failedCounters) - %ADDBATCHHASH_CNT_ARITH - CNT_ARITH :JMPNZ(failedCounters) - %ADDBATCHHASH_CNT_KECCAK_F - CNT_KECCAK_F :JMPNZ(failedCounters) - %ADDBATCHHASH_CNT_MEM_ALIGN - CNT_MEM_ALIGN :JMPNZ(failedCounters) - %ADDBATCHHASH_CNT_PADDING_PG - CNT_PADDING_PG :JMPNZ(failedCounters) - %ADDBATCHHASH_CNT_POSEIDON_G - CNT_POSEIDON_G :JMPNZ(failedCounters) - -0 => A,B,C,D,E,CTX, SP, PC, GAS, SR, HASHPOS, RR ; Set all registers to 0 -finalizeExecution: - :JMP(finalWait) -readCode: - :RETURN -failedCounters: -2 => A -1 :ASSERT - -INCLUDE "../endIncludes.zkasm" diff --git a/main/ecrecover/ecrecover.zkasm b/main/ecrecover/ecrecover.zkasm index ebe99b09..e87070ec 100644 --- a/main/ecrecover/ecrecover.zkasm +++ b/main/ecrecover/ecrecover.zkasm @@ -58,8 +58,7 @@ ecrecover_store_args: %MAX_CNT_ARITH - CNT_ARITH - 1100 :JMPN(outOfCountersArith) %MAX_CNT_STEPS - STEP - 6400 :JMPN(outOfCountersStep) - $ => A :MLOAD(cntKeccakPreProcess) - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - A - 1 :JMPN(outOfCountersKeccak) + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 1 :JMPN(outOfCountersKeccak) ; save RR to call return at end of routine RR :MSTORE(ecrecover_RR) diff --git a/main/load-change-l2-block-utils.zkasm b/main/load-change-l2-block-utils.zkasm index 6041c2b0..fba01923 100644 --- a/main/load-change-l2-block-utils.zkasm +++ b/main/load-change-l2-block-utils.zkasm @@ -6,6 +6,9 @@ getChangeL2TxBytes: $ => A :MLOAD(batchL2DataLength) $ => B :MLOAD(batchL2DataParsed) A - B - C - D :JMPN(invalidDecodeChangeL2Block) - ${getTxs(p,D)} => A - $${p = p + D} - :RETURN \ No newline at end of file + $ => E :MLOAD(batchHashDataPointer) + $ => HASHPOS :MLOAD(batchHashPos) + $ => A :HASHP(E) + HASHPOS :MSTORE(batchHashPos) + C => HASHPOS + $ => E :MLOAD(lastHashKIdUsed), RETURN \ No newline at end of file diff --git a/main/load-change-l2-block.zkasm b/main/load-change-l2-block.zkasm index e26e7415..27137d86 100644 --- a/main/load-change-l2-block.zkasm +++ b/main/load-change-l2-block.zkasm @@ -11,11 +11,11 @@ decodeChangeL2BlockTx: ; Decode deltaTimestamp / 4 bytes %DELTA_TIMESTAMP_NUM_BYTES => D :CALL(getChangeL2TxBytes) - C + D => C :CALL(addBatchHashData) + C + D => C A :MSTORE(deltaTimestamp) ; Decode indexL1InfoTree / 4 bytes %INDEX_L1INFOTREE_NUM_BYTES => D :CALL(getChangeL2TxBytes) - C + D => C :CALL(addBatchHashData) + C + D => C A :MSTORE(indexL1InfoTree) 1 :MSTORE(isChangeL2BlockTx), JMP(finishLoadChangeL2BlockTx) diff --git a/main/load-tx-rlp-utils.zkasm b/main/load-tx-rlp-utils.zkasm index e81d810a..25beb9eb 100644 --- a/main/load-tx-rlp-utils.zkasm +++ b/main/load-tx-rlp-utils.zkasm @@ -1,23 +1,17 @@ -;@info: Add 'data' bytes to batchHashData. batchHashData = H_keccak( transactions ) -;@in: D: length of the hash -addBatchHashData: - $ => HASHPOS :MLOAD(batchHashPos) - $ => E :MLOAD(batchHashDataId) - A :HASHK(E) - HASHPOS :MSTORE(batchHashPos) - C => HASHPOS - $ => E :MLOAD(lastHashKIdUsed), RETURN - -;; get D bytes from transaction bytes +;; get D bytes from batchL2Data ;@in D: number of bytes to get ;@in C: current data parsed pointer -;@out A: D bytes from batch data at offset C -getTxBytes: +;@out A: D bytes from batchL2Data at offset C +getBatchL2DataBytes: $ => A :MLOAD(batchL2DataLength) $ => B :MLOAD(batchL2DataParsed) A - B - C - D :JMPN(invalidTxRLP) - ${getTxs(p,D)} => A - $${p = p + D} + $ => E :MLOAD(batchHashDataPointer) + $ => HASHPOS :MLOAD(batchHashPos) + $ => A :HASHP(E) + HASHPOS :MSTORE(batchHashPos) + C => HASHPOS + $ => E :MLOAD(lastHashKIdUsed) :RETURN ;; Add bytes to generate ethereum signed message @@ -30,8 +24,12 @@ addHashTxBegin: $ => A :MLOAD(batchL2DataLength) $ => B :MLOAD(batchL2DataParsed) A - B - C - D :JMPN(invalidTxRLP) - ${getTxs(p,D)} => A - $${p = p + D} + $ => E :MLOAD(batchHashDataPointer) + $ => HASHPOS :MLOAD(batchHashPos) + $ => A :HASHP(E) + HASHPOS :MSTORE(batchHashPos) + $ => E :MLOAD(lastHashKIdUsed) + C => HASHPOS A :HASHK(E) C + D => C :RETURN diff --git a/main/load-tx-rlp.zkasm b/main/load-tx-rlp.zkasm index 18e4e2e8..2356a317 100644 --- a/main/load-tx-rlp.zkasm +++ b/main/load-tx-rlp.zkasm @@ -24,17 +24,18 @@ INCLUDE "l2-tx-hash.zkasm" loadTx_rlp: ; check one keccak is available to begin processing the RLP - $ => D :MLOAD(cntKeccakPreProcess) - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 1 - D :JMPN(outOfCountersKeccak) + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 1 :JMPN(outOfCountersKeccak) ; Pointer to next RLP bytes to read 0 => C ; Check it is a change L2 block transaction %TX_TYPE_NUM_BYTES => D ; batchL2DataLength is not zero (at least 1 byte), checked at main - ${getTxs(p,D)} => A - $${p = p + D} - C + D => C :CALL(addBatchHashData) + $ => E :MLOAD(batchHashDataPointer) + $ => HASHPOS :MLOAD(batchHashPos) + $ => A :HASHP(E) + HASHPOS :MSTORE(batchHashPos) + C + D => C A - %CHANGE_L2_BLOCK_TX_TYPE :JMPZ(decodeChangeL2BlockTx) checkFirstTxType: ; First transaction must be a change L2 block transaction if it is NOT a forced batch @@ -67,7 +68,6 @@ loadTx_rlp_continue: longList: A - 0xf7 => D :CALL(addHashTxBegin) - :CALL(addBatchHashData) :CALL(checkLongRLP) :CALL(checkNonLeadingZeros) :JMP(endList) @@ -82,15 +82,13 @@ endList: B + 1 :MSTORE(arithA) 136 :MSTORE(arithB), CALL(divARITH); in: [arithA, arithB] out: [arithRes1: arithA/arithB, arithRes2: arithA%arithB] $ => B :MLOAD(arithRes1) - $ => D :MLOAD(cntKeccakPreProcess) - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - B - D - 1 :JMPN(outOfCountersKeccak) + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - B - 1 :JMPN(outOfCountersKeccak) :CALL (initL2HashTx) ;; Read RLP 'nonce' ; 64 bits max nonceREAD: 1 => D :CALL(addHashTx) - :CALL(addBatchHashData) A - 0x80 :JMPN(endNonce) A - 0x81 :JMPN(nonce0) A - 0x89 :JMPN(shortNonce, invalidTxRLP) @@ -101,7 +99,6 @@ nonce0: shortNonce: A - 0x80 => D D :MSTORE(lengthNonce),CALL(addHashTx) - :CALL(addBatchHashData) :CALL(checkShortRLP) :CALL(checkNonLeadingZeros) @@ -113,7 +110,6 @@ endNonce: ; 256 bits max gasPriceREAD: 1 => D :CALL(addHashTx) - :CALL(addBatchHashData) A - 0x80 :JMPN(endGasPrice) A - 0x81 :JMPN(gasPrice0) A - 0xa1 :JMPN(shortGasPrice, invalidTxRLP) @@ -123,7 +119,6 @@ gasPrice0: shortGasPrice: A - 0x80 => D :CALL(addHashTx) - :CALL(addBatchHashData) :CALL(checkShortRLP) :CALL(checkNonLeadingZeros) @@ -136,7 +131,6 @@ endGasPrice: ; 64 bits max gasLimitREAD: 1 => D :CALL(addHashTx) - :CALL(addBatchHashData) A - 0x80 :JMPN(endGasLimit) A - 0x81 :JMPN(gasLimit0) A - 0x89 :JMPN(shortGasLimit, invalidTxRLP) @@ -146,7 +140,6 @@ gasLimit0: shortGasLimit: A - 0x80 => D :CALL(addHashTx) - :CALL(addBatchHashData) :CALL(checkShortRLP) :CALL(checkNonLeadingZeros) @@ -158,7 +151,6 @@ endGasLimit: ; 160 bits or empty toREAD: 1 => D :CALL(addHashTx) - :CALL(addBatchHashData) A - 0x80 :JMPN(invalidTxRLP) A - 0x81 :JMPN(noTo) A - 0x94 :JMPN(invalidTxRLP) @@ -172,7 +164,6 @@ shortTo: A - 0x80 => D :CALL(addHashTx) :CALL(addL2HashTx_isNotDeploy) :CALL(addL2HashTx) - :CALL(addBatchHashData) A :MSTORE(txDestAddr) A :MSTORE(storageAddr) @@ -182,7 +173,6 @@ endTo: ; 256 bits max valueREAD: 1 => D :CALL(addHashTx) - :CALL(addBatchHashData) A - 0x80 :JMPN(endValue) A - 0x81 :JMPN(value0) A - 0xa1 :JMPN(shortValue, invalidTxRLP) @@ -192,7 +182,6 @@ value0: shortValue: A - 0x80 => D :CALL(addHashTx) - :CALL(addBatchHashData) :CALL(checkShortRLP) :CALL(checkNonLeadingZeros) @@ -210,7 +199,6 @@ dataREAD: $ => D :MLOAD(batchHashPos) D :MSTORE(dataStarts) 1 => D :CALL(addHashTx) - :CALL(addBatchHashData) A - 0x80 :JMPN(veryShortData) A - 0x81 :JMPN(zeroBytesData) A - 0xb8 :JMPN(shortData) @@ -242,7 +230,6 @@ shortData: longData: A - 0xb7 => D :CALL(addHashTx) - :CALL(addBatchHashData) :CALL(checkLongRLP) :CALL(checkNonLeadingZeros) $ => D :MLOAD(batchHashPos) @@ -261,7 +248,7 @@ readData: A :MSTORE(MEM:E) ; Restore current CTX B => CTX - E + 1 :MSTORE(globalCalldataMemoryOffset), CALL(addBatchHashByteByByte) ; in: [A: bytes to add, D: bytes length] out: [E: lastHashKIdUsed, A: shifted bytes to add] + E + 1 :MSTORE(globalCalldataMemoryOffset) $ => B :MLOAD(txDataRead), JMP(readData) readDataFinal: @@ -278,7 +265,6 @@ readDataFinal: ; Restore current CTX B => CTX E + 1 :MSTORE(globalCalldataMemoryOffset) - 32 - D => D :CALL(addBatchHashByteByByte); in: [A: bytes to add, D: bytes length] out: [E: lastHashKIdUsed, A: shifted bytes to add] :CALL(checkShortDataRLP) :JMP(endData) @@ -295,7 +281,6 @@ endData: ; 64 bits max chainREAD: 1 => D :CALL(addHashTx) - :CALL(addBatchHashData) A - 0x80 :JMPN(endChainId) A - 0x81 :JMPN(chainId0) A - 0x89 :JMPN(shortChainId, invalidTxRLP) @@ -306,7 +291,6 @@ chainId0: shortChainId: A - 0x80 => D :CALL(addHashTx) - :CALL(addBatchHashData) :CALL(checkShortRLP) :CALL(checkNonLeadingZeros) @@ -316,7 +300,6 @@ endChainId: ;; Read RLP last two values (0, 0) 2 => D :CALL(addHashTx) - :CALL(addBatchHashData) ; We compare the last two bytes of the RLP with 0x8080, no need to use a binary A - 0x8080 :JMPZ(sizeVerification, invalidTxRLP) @@ -337,27 +320,27 @@ sizeVerificationSuccess: ;; read ecdsa 'r' rREADTx: - 32 => D :CALL(getTxBytes) + 32 => D :CALL(getBatchL2DataBytes) A :MSTORE(txR) - C + D => C :CALL(addBatchHashData) + C + D => C ;; read ecdsa 's' sREADTx: - 32 => D :CALL(getTxBytes) + 32 => D :CALL(getBatchL2DataBytes) A :MSTORE(txS) - C + D => C :CALL(addBatchHashData) + C + D => C ;; read ecdsa 'v' vREADTx: - 1 => D :CALL(getTxBytes) + 1 => D :CALL(getBatchL2DataBytes) A :MSTORE(txV) - C + D => C :CALL(addBatchHashData) + C + D => C ;; read effective percentage effectivePercentageTx: - 1 => D :CALL(getTxBytes) + 1 => D :CALL(getBatchL2DataBytes) A :MSTORE(effectivePercentageRLP) - C + D => C :CALL(addBatchHashData) + C + D => C ;;;;;;;;; ;; D - Finish RLP parsing @@ -395,37 +378,10 @@ checkAndSaveFrom: ;; E - Handler error RLP fields ;;;;;;;;; invalidTxRLP: - $${eventLog(onError, invalidRLP)} :JMP(appendTxsInit) + $${eventLog(onError, invalidRLP)} :JMP(finalizeBatch) invalidDecodeChangeL2Block: - $${eventLog(onError, invalidDecodeChangeL2Block)} :JMP(appendTxsInit) + $${eventLog(onError, invalidDecodeChangeL2Block)} :JMP(finalizeBatch) invalidNotFirstTxChangeL2Block: - $${eventLog(onError, invalidNotFirstTxChangeL2Block)} :JMP(appendTxsInit) - -appendTxsInit: -;; Append all missing 'batchL2Data' to 'batchDataHash' bytes - $ => B :MLOAD(batchL2DataLength) - $ => C :MLOAD(batchHashPos) - $${p = C} - $ => HASHPOS :MLOAD(batchHashPos) - $ => E :MLOAD(batchHashDataId) - -appendTxs: - B - C - 32 :JMPN(finalAppendTxs) - 32 => D - ${getTxs(p,D)} => A - $${p = p + D} - A :HASHK(E) - C + D => C :JMP(appendTxs) - -finalAppendTxs: - B - C => D - D - 1 :JMPN(endAppendTxs) - ${getTxs(p,D)} => A - $${p = p + D} - A :HASHK(E) - C + D => C - -endAppendTxs: - HASHPOS :MSTORE(batchHashPos),JMP(finalizeBatch) + $${eventLog(onError, invalidNotFirstTxChangeL2Block)} :JMP(finalizeBatch) diff --git a/main/main.zkasm b/main/main.zkasm index 84818323..55f3cb0b 100644 --- a/main/main.zkasm +++ b/main/main.zkasm @@ -34,7 +34,7 @@ start: ; main zkROM entry point ${getTimestampLimit()} :MSTORE(timestampLimit) ${getTxsLen()} :MSTORE(batchL2DataLength) ; less than 120000 bytes. Enforced by the smart contract ${getForcedBlockHashL1()} => A :MSTORE(forcedBlockHashL1) - + ${getBatchHashData()} :MSTORE(batchHashData) ;set initial state root $ => SR :MLOAD(oldStateRoot) SR :MSTORE(batchSR) @@ -42,41 +42,78 @@ start: ; main zkROM entry point SP + 1 :MSTORE(newNumBatch) ; compute isForced flag 0 => B - $ :EQ, JMPC(computeKeccaks) + $ :EQ, JMPC(computeNewAccInputHash) 1 :MSTORE(isForced) ;;;;;;;;;;;;;;;;;; -;; B - Compute keccaks needed to finish the batch +;; B - Compute newAccInputHash, load newLocalExitRoot and timestamp ;;;;;;;;;;;;;;;;;; -computeKeccaks: +computeNewAccInputHash: $${eventLog(onStartBatch, C)} + 0 => HASHPOS + + 32 => D + $ => A :MLOAD(oldAccInputHash) + A :HASHK(0) + + $ => A :MLOAD(batchHashData) + A :HASHK(0) + + $ => A :MLOAD(l1InfoRoot) + A :HASHK(0) + + 8 => D + $ => A :MLOAD(timestampLimit) + A :HASHK(0) + + 20 => D + $ => A :MLOAD(sequencerAddr) + A :HASHK(0) + + 32 => D + $ => A :MLOAD(forcedBlockHashL1) + A :HASHK(0) - ; Compute necessary keccak counters to finish batch - $ => A :MLOAD(batchL2DataLength) - ; Divide the total data length + 1 by 136 to obtain the keccak counter increment. - ; 136 is the value used by the prover to increment keccak counters - A + 1 :MSTORE(arithA) - 136 :MSTORE(arithB), CALL(divARITH); in: [arithA, arithB] out: [arithRes1: arithA/arithB, arithRes2: arithA%arithB] - $ => B :MLOAD(arithRes1) - ; Compute minimum necessary keccaks to finish the batch - B + 1 + %MIN_CNT_KECCAK_BATCH => B :MSTORE(cntKeccakPreProcess) - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - B :JMPN(outOfCountersKeccak) + ; finish accInputHash + HASHPOS :HASHKLEN(0) + $ => C :HASHKDIGEST(0) + C :MSTORE(newAccInputHash) + ; Compute batchHashData (loaded at smt from executor) + $ => E :MLOAD(nextHashPId) + E :MSTORE(batchHashDataPointer) + E + 1 :MSTORE(nextHashPId) + ; Initialize batchHashPos to zero (CHECK: is this necessary?) + 0 :MSTORE(batchHashPos) + $ => A :MLOAD(batchHashData) + ; No need to compute poseidon consumption, max batchL2Data length is 120000 bytes and this is the beginning of the execution, will always have enough poseidons + A :HASHPDIGEST(E) + ; Check batchL2DataLength (CHECK: is it necessary to check this? Is a correct behavior? Is possible to get the length from hashplen?) + $ => HASHPOS :MLOAD(batchL2DataLength) + HASHPOS :HASHPLEN(E) + + ;; Get local exit root + ; Read 'localExitRoot' variable from GLOBAL_EXIT_ROOT_MANAGER_L2 and store + ; it to the 'newLocalExitRoot' input, will be used to compute newAccInputHash + %ADDRESS_GLOBAL_EXIT_ROOT_MANAGER_L2 => A + %SMT_KEY_SC_STORAGE => B + %LOCAL_EXIT_ROOT_STORAGE_POS => C + $ => A :SLOAD + A :MSTORE(newLocalExitRoot) + + ; Load current timestamp + %TIMESTAMP_STORAGE_POS => C + %ADDRESS_SYSTEM => A + %SMT_KEY_SC_STORAGE => B + $ => A :SLOAD, MSTORE(timestamp) ;;;;;;;;;;;;;;;;;; ;; C - 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 ;;;;;;;;;;;;;;;;;; - - 1 => E :MSTORE(lastHashKIdUsed) - 0 :MSTORE(batchHashPos) - E :MSTORE(batchHashDataId) $ => A :MLOAD(lastCtxUsed) A + %CALLDATA_RESERVED_CTX => A :MSTORE(ctxTxToUse) ; Points at first context to be used when processing transactions. We reserve ctx = 1 for calldata A :MSTORE(lastCtxUsed) - $${var p = 0} - ; set flag isLoadingRLP to 1 - 1 :MSTORE(isLoadingRLP) txLoopRLP: $ => A :MLOAD(lastCtxUsed) @@ -84,11 +121,7 @@ txLoopRLP: ; If batchL2DataLength is zero, we finalize batch $ => A :MLOAD(batchL2DataLength), JMPZ(finalizeBatch) $ => C :MLOAD(batchL2DataParsed) - C - A :JMPN(loadTx_rlp, endCheckRLP) - -endCheckRLP: - ; set flag isLoadingRLP to 0 - 0 :MSTORE(isLoadingRLP) + C - A :JMPN(loadTx_rlp, setBlockNum) ;;;;;;;;;;;;;;;;;; ;; D - Load blockNum variable @@ -139,71 +172,8 @@ processTxsEnd: finalizeBatch: ;;;;;;;;;;;;;;;;;; -;; E - Batch asserts & computations: -;; - get newLocalExitRoot -;; - assert transactions size -;; - compute batchHashData -;; - compute newAccInputHash +;; E - Finalize execution: set output values at corresponding registers ;;;;;;;;;;;;;;;;;; - -;; Batch must be always end correctly -;; Meaning that enough zk-counters should be available to finalize it -;; - 'keccaks' are reserved at the very beginning of the batch in order to be able to perform the final 'accInputHash' hash -;; - the rest of counters will not overflow since it is added a %SAFE_RANGE bandwith - -;; Get local exit root - ; Read 'localExitRoot' variable from GLOBAL_EXIT_ROOT_MANAGER_L2 and store - ; it to the 'newLocalExitRoot' input - %ADDRESS_GLOBAL_EXIT_ROOT_MANAGER_L2 => A - %SMT_KEY_SC_STORAGE => B - %LOCAL_EXIT_ROOT_STORAGE_POS => C - $ => A :SLOAD - A :MSTORE(newLocalExitRoot) - -;; Transactions size verification - ; Ensure bytes added to compute the 'batchHashData' matches the number of bytes loaded from input - $ => A :MLOAD(batchHashPos) - $ :MLOAD(batchL2DataLength), ASSERT - -;; Compute 'batchHashData' - A => HASHPOS - $ => E :MLOAD(batchHashDataId) - - HASHPOS :HASHKLEN(E) - $ => A :HASHKDIGEST(E) - - A :MSTORE(batchHashData) - -;; Compute 'newAccInputHash' - 0 => HASHPOS - - 32 => D - $ => A :MLOAD(oldAccInputHash) - A :HASHK(0) - - $ => A :MLOAD(batchHashData) - A :HASHK(0) - - $ => A :MLOAD(l1InfoRoot) - A :HASHK(0) - - 8 => D - $ => A :MLOAD(timestampLimit) - A :HASHK(0) - - 20 => D - $ => A :MLOAD(sequencerAddr) - A :HASHK(0) - - 32 => D - $ => A :MLOAD(forcedBlockHashL1) - A :HASHK(0) - - ; finish accInputHash - HASHPOS :HASHKLEN(0) - - $ => C :HASHKDIGEST(0) - C :MSTORE(newAccInputHash) $${eventLog(onFinishBatch)} ;;;;;;;;;;;;;;;;;; diff --git a/main/opcodes/block.zkasm b/main/opcodes/block.zkasm index a72452f3..9b77545e 100644 --- a/main/opcodes/block.zkasm +++ b/main/opcodes/block.zkasm @@ -11,8 +11,7 @@ opBLOCKHASH: ; checks zk-counters %MAX_CNT_POSEIDON_G - CNT_POSEIDON_G - %MAX_CNT_POSEIDON_SLOAD_SSTORE :JMPN(outOfCountersPoseidon) - $ => A :MLOAD(cntKeccakPreProcess) - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - A - 1 :JMPN(outOfCountersKeccak) + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 1 :JMPN(outOfCountersKeccak) %MAX_CNT_STEPS - STEP - 100 :JMPN(outOfCountersStep) ; check stack underflow diff --git a/main/opcodes/crypto.zkasm b/main/opcodes/crypto.zkasm index 8c73c019..55a68ed6 100644 --- a/main/opcodes/crypto.zkasm +++ b/main/opcodes/crypto.zkasm @@ -43,9 +43,8 @@ opSHA3: C + 1 :MSTORE(arithA) 136 :MSTORE(arithB), CALL(divARITH); in: [arithA, arithB] out: [arithRes1: arithA/arithB, arithRes2: arithA%arithB] $ => B :MLOAD(arithRes1) - $ => A :MLOAD(cntKeccakPreProcess) ; checks keccak counters - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - A - 1 - B :JMPN(outOfCountersKeccak) + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 1 - B :JMPN(outOfCountersKeccak) ; new hash id $ => B :MLOAD(lastHashKIdUsed) diff --git a/main/opcodes/flow-control.zkasm b/main/opcodes/flow-control.zkasm index 9a090add..2d6cbdcf 100644 --- a/main/opcodes/flow-control.zkasm +++ b/main/opcodes/flow-control.zkasm @@ -69,7 +69,7 @@ checkJumpDestDeployment: A => PC HASHPOS + PC => HASHPOS ; get memory pointer for hashing - $ => E :MLOAD(batchHashDataId) + $ => E :MLOAD(batchHashDataPointer) ; set number of bytes to hashK $ => A :HASHK1(E) ; check if is a jumpDest (0x5B) diff --git a/main/opcodes/stack-operations.zkasm b/main/opcodes/stack-operations.zkasm index c7b419c4..f9fa2fb9 100644 --- a/main/opcodes/stack-operations.zkasm +++ b/main/opcodes/stack-operations.zkasm @@ -168,7 +168,7 @@ opAuxPUSHBloop: HASHPOS + PC => HASHPOS PC + 1 => PC ; get memory pointer for hashing - $ => E :MLOAD(batchHashDataId) + $ => E :MLOAD(batchHashDataPointer) $ => B :HASHK1(E) ; accumulate hash value A + B => A diff --git a/main/process-change-l2-block.zkasm b/main/process-change-l2-block.zkasm index 75581d64..a49d913c 100644 --- a/main/process-change-l2-block.zkasm +++ b/main/process-change-l2-block.zkasm @@ -2,8 +2,7 @@ processChangeL2Block: ; checks zk-counters %MAX_CNT_POSEIDON_G - CNT_POSEIDON_G - %MAX_CNT_POSEIDON_SLOAD_SSTORE*6 :JMPN(outOfCountersPoseidon) - $ => A :MLOAD(cntKeccakPreProcess) - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - A - 2 :JMPN(outOfCountersKeccak) + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 2 :JMPN(outOfCountersKeccak) %MAX_CNT_STEPS - STEP - 500 :JMPN(outOfCountersStep) %MAX_CNT_BINARY - CNT_BINARY - 8 :JMPN(outOfCountersBinary) @@ -48,11 +47,7 @@ continueProcessChangeL2Block: $ => SR :SSTORE ; Load current timestamp - %TIMESTAMP_STORAGE_POS => C - %ADDRESS_SYSTEM => A - %SMT_KEY_SC_STORAGE => B - $ => A :SLOAD ; currentTimestamp => A - + $ => A :MLOAD(timestamp) ; currentTimestamp => A $ => B :MLOAD(timestampLimit) ; timestampLimit => B ; If it is NOT a forced tx ==> verify Timestamp & L1InfoRoot diff --git a/main/process-tx.zkasm b/main/process-tx.zkasm index 72766493..cdb7cca5 100644 --- a/main/process-tx.zkasm +++ b/main/process-tx.zkasm @@ -139,8 +139,8 @@ loopBytes: %MAX_CNT_STEPS - STEP - 10 :JMPN(outOfCountersStep) A - C - 1 :JMPN(endCalldataIntrinsicGas) E => B - $ => E :MLOAD(batchHashDataId) - $ => D :HASHK1(E) + $ => E :MLOAD(batchHashDataPointer) + $ => D :HASHP1(E) B => E C + 1 => C D - 1 :JMPN(add4Gas, add16Gas) @@ -230,8 +230,7 @@ getContractAddress: ; Check if create is with CREATE2 opcode $ => A :MLOAD(isCreate2), JMPNZ(create2) ; Check keccak counters - $ => A :MLOAD(cntKeccakPreProcess) - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - A - 1:JMPN(outOfCountersKeccak) + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 1:JMPN(outOfCountersKeccak) $ => A :MLOAD(txNonce) 0x80 => B $ :LT,JMPC(nonce1byte) @@ -271,9 +270,8 @@ create2: C + 1 :MSTORE(arithA) 136 :MSTORE(arithB), CALL(divARITH); in: [arithA, arithB] out: [arithRes1: arithA/arithB, arithRes2: arithA%arithB] $ => B :MLOAD(arithRes1) - $ => A :MLOAD(cntKeccakPreProcess) ; -2 because we will use one more keccak for generating contract address - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - A - 2 - B :JMPN(outOfCountersKeccak) + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 2 - B :JMPN(outOfCountersKeccak) $ => CTX :MLOAD(originCTX) $ => B :MLOAD(argsOffsetCall) @@ -369,7 +367,7 @@ readDeployBytecode: B - PC - 1 :JMPN(defaultOpCode) $ => HASHPOS :MLOAD(dataStarts) HASHPOS + PC => HASHPOS - $ => E :MLOAD(batchHashDataId) + $ => E :MLOAD(batchHashDataPointer) $ => RR :HASHK1(E) $${eventLog(onOpcode(RR))} PC + 1 => PC :JMP(@mapping_opcodes + RR) diff --git a/main/utils.zkasm b/main/utils.zkasm index 4b1dab16..32e841b2 100644 --- a/main/utils.zkasm +++ b/main/utils.zkasm @@ -885,9 +885,6 @@ handleError: handleBatchError: ; restore init state root and finish batch $ => SR :MLOAD(batchSR) - ; if batch error is triggered while parsing the RLP, it jumps to 'appendTxsInit' - ; to fill the missing bytes to complete 'batchDataHash' - $ :MLOAD(isLoadingRLP),JMPNZ(appendTxsInit) $${eventLog(onFinishTx)} :JMP(finalizeBatch) errorAtFirstContext: @@ -1279,43 +1276,6 @@ readPushBytes_1: $ => D :MLOAD(pushBytes), RETURN -VAR GLOBAL tmpVarDaddB -VAR GLOBAL tmpVarBaddB -VAR GLOBAL tmpZkPCaddB -VAR GLOBAL auxBytes - -;@info: adds data to batchHashdata byte by byte -;@in: A: bytes to add -;@in D: bytes length -addBatchHashByteByByte: - %MAX_CNT_STEPS - STEP - 10 :JMPN(outOfCountersStep) - RR :MSTORE(tmpZkPCaddB) - A :MSTORE(auxBytes) - D :MSTORE(tmpVarDaddB) - B :MSTORE(tmpVarBaddB) - 1 => D - -utilsAddBatchHashBytebyByteLoop: - %MAX_CNT_STEPS - STEP - 50 :JMPN(outOfCountersStep) - %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) - 32 - D => D - $ => A :MLOAD(auxBytes), CALL(SHRarith); in: [A: value, D: #bytes to right shift] out: [A: shifted result] - ; get last byte in A - 0xFFn => B - $ => A :AND - D => B - ; add last byte to batchHashData - 1 => D :CALL(addBatchHashData); in:[D: length of the hash] - ; check loop - B => D - ; D + 1 => D, we set 33 instead of 32 to earn 1 step - 33 - D => D - $ => B :MLOAD(tmpVarDaddB) - D - B - 1 :JMPN(utilsAddBatchHashBytebyByteLoop) - $ => B :MLOAD(tmpVarBaddB) - $ => RR :MLOAD(tmpZkPCaddB) - :RETURN - VAR GLOBAL startsWithEF VAR GLOBAL tmpVarAEF VAR GLOBAL tmpVarBEF @@ -1661,10 +1621,8 @@ VAR GLOBAL tmpZkPCVerifyMerkleProof ;@in C: timestamp verifyMerkleProof: ; check zk-counters - $ => E :MLOAD(cntKeccakPreProcess) - ; 1 keccak for the leaf and 32 for the L1InfoTree - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - E - 33 :JMPN(outOfCountersKeccak) + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 33 :JMPN(outOfCountersKeccak) ; 7 steps at most per bit + 21 statics %MAX_CNT_STEPS - STEP - 7 * 32 - 21 :JMPN(outOfCountersStep) diff --git a/main/vars.zkasm b/main/vars.zkasm index 63ec168f..d6bf6d17 100644 --- a/main/vars.zkasm +++ b/main/vars.zkasm @@ -26,7 +26,7 @@ VAR GLOBAL lastHashKIdUsed ; Last hash address used VAR GLOBAL nextHashPId ; Next poseidon hash address available VAR GLOBAL batchL2DataLength ; Transactions bytes read from the input -VAR GLOBAL batchHashDataId ; hash address used when adding bytes to batchHashData +VAR GLOBAL batchHashDataPointer ; hash address used when adding bytes to batchHashData VAR GLOBAL batchHashPos ; hash batchHashData position VAR GLOBAL currentCTX ; keeps track of the context used VAR GLOBAL originAuxCTX ; keeps track of the previous context when a new one is created @@ -38,7 +38,6 @@ VAR GLOBAL valueCall ; value parameter when creating a new context VAR GLOBAL argsLengthCall ; size of the calldata creating a new context VAR GLOBAL txSrcOriginAddr ; origin address of a tx VAR GLOBAL txGasPrice ; transaction parameter: 'gasPrice' global var -VAR GLOBAL cntKeccakPreProcess ; Number of keccak counters needed to finish the batch VAR GLOBAL originSR ; State root before processing each transaction VAR GLOBAL batchSR ; State root before processing any transaction @@ -52,7 +51,6 @@ VAR GLOBAL numTopics ; number of topics depending on LOG opcode call VAR GLOBAL auxSR ; auxiliary variable. Temporary state root VAR GLOBAL txRLPLength ; transaction RLP list length VAR GLOBAL txDataRead ; aux variable to check transaction 'data' left that needs to be read -VAR GLOBAL isLoadingRLP ; flag to determine if the function is called from RLP loop VAR GLOBAL globalCalldataMemoryOffset ; Aux variable to store current calldata memory offset at calldata CTX's memory VAR GLOBAL txIndex ; index of the current tx in the block diff --git a/package.json b/package.json index 18618387..2c1f15d6 100644 --- a/package.json +++ b/package.json @@ -43,9 +43,9 @@ "yargs": "^17.5.1" }, "devDependencies": { - "@0xpolygonhermez/zkevm-commonjs": "github:0xPolygonHermez/zkevm-commonjs#v5.0.0-fork.8", - "@0xpolygonhermez/zkevm-proverjs": "github:0xPolygonHermez/zkevm-proverjs#493569b08869a496e5de379c83263e4a10d5e585", - "@0xpolygonhermez/zkevm-testvectors": "github:0xPolygonHermez/zkevm-testvectors#v5.0.0-fork.8", + "@0xpolygonhermez/zkevm-commonjs": "github:0xPolygonHermez/zkevm-commonjs#develop-feijoa", + "@0xpolygonhermez/zkevm-proverjs": "github:0xPolygonHermez/zkevm-proverjs#feature/batch-hash-data", + "@0xpolygonhermez/zkevm-testvectors": "github:0xPolygonHermez/zkevm-testvectors#feature/batch-hash-data", "chai": "^4.3.6", "chalk": "^3.0.0", "eslint": "^8.25.0", diff --git a/test/ecrecover.zkasm b/test/ecrecover.zkasm index bff8bf55..4d27fcd4 100644 --- a/test/ecrecover.zkasm +++ b/test/ecrecover.zkasm @@ -3,7 +3,6 @@ ;;;;;;;;;;;; INCLUDE "../main/constants.zkasm" VAR GLOBAL lastHashKIdUsed -VAR GLOBAL cntKeccakPreProcess VAR GLOBAL originalCTX start: From d2fba54b727cd5ef173b3263e283599eed683aee Mon Sep 17 00:00:00 2001 From: Ignasi Date: Mon, 4 Mar 2024 10:00:44 +0100 Subject: [PATCH 02/16] Remove rlp parsing --- .github/workflows/main.yaml | 2 +- main/load-tx-rlp-utils.zkasm | 37 +++++++++++++++++++++++++++++ main/load-tx-rlp.zkasm | 9 +++---- main/opcodes/flow-control.zkasm | 3 ++- main/opcodes/stack-operations.zkasm | 24 +++++++++---------- main/process-tx.zkasm | 31 ++++++++++++------------ 6 files changed, 72 insertions(+), 34 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 725ed920..8465d3af 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -32,7 +32,7 @@ jobs: npm run test:zkasm - name: Generate tests run: | - node tools/parallel-testing/gen-parallel-tests.js + node tools/parallel-testing/gen-parallel-tests.js --skipVCounters - name: Run tests run: | export NUM_CPUS=31 diff --git a/main/load-tx-rlp-utils.zkasm b/main/load-tx-rlp-utils.zkasm index 25beb9eb..0f593d7f 100644 --- a/main/load-tx-rlp-utils.zkasm +++ b/main/load-tx-rlp-utils.zkasm @@ -33,6 +33,43 @@ addHashTxBegin: A :HASHK(E) C + D => C :RETURN +;; Add bytes to generate ethereum signed message byte by byte +; It's done byte by byte to get 1 byte access to hashp during execution +;; - 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)) +addHashTxFromFreeInput: + $ => A :MLOAD(txRLPLength) + A - HASHPOS - D :JMPN(invalidTxRLP) + $ => A :MLOAD(batchL2DataLength) + $ => B :MLOAD(batchL2DataParsed) + A - B - C - D :JMPN(invalidTxRLP) + B + C => A + ; Read data from free input + ${getTxs(A,D)} => A, B + $ => E :MLOAD(lastHashKIdUsed) + C => HASHPOS + ; Insert data into txhash (hashk) + A :HASHK(E) + C + D => C + ; Save current registers + A :SAVE(B,C,D,E,RR,RCX) + $ => E :MLOAD(batchHashDataPointer) + $ => HASHPOS :MLOAD(batchHashPos) + 1 => C ; Current pointer + D => RCX ; total bytes + ; Validate free input +validateFreeInputLoop: + RCX - C :JMPN(validateFreeInputLoopEnd) + ; Get free input byte by byte + RCX - C => D :CALL(SHRarith) ; in: [A: value, D: #bytes to right shift] out: [A: shifted result] + $ :HASHP1(E), ASSERT + ; The remainder of divArith used at SHRarith is the following bytes I want to check + $ => A :MLOAD(arithRes2) + C + 1 => C :JMP(validateFreeInputLoop) +validateFreeInputLoopEnd: + HASHPOS :MSTORE(batchHashPos) + $ => A :RESTORE + C => HASHPOS :RETURN ;; Check short value is over 127. Error RLP: single byte < 0x80 are not prefixed checkShortRLP: diff --git a/main/load-tx-rlp.zkasm b/main/load-tx-rlp.zkasm index 2356a317..0b94eead 100644 --- a/main/load-tx-rlp.zkasm +++ b/main/load-tx-rlp.zkasm @@ -229,7 +229,7 @@ shortData: :JMP(readData) longData: - A - 0xb7 => D :CALL(addHashTx) + A - 0xb7 => D :CALL(addHashTxFromFreeInput) :CALL(checkLongRLP) :CALL(checkNonLeadingZeros) $ => D :MLOAD(batchHashPos) @@ -239,7 +239,7 @@ longData: readData: 32 => D B - D :JMPN(readDataFinal) - B - D :MSTORE(txDataRead), CALL(addHashTx) + B - D :MSTORE(txDataRead), CALL(addHashTxFromFreeInput) $ => E :MLOAD(globalCalldataMemoryOffset), CALL(addL2HashTx) ; Store current CTX CTX => B @@ -253,8 +253,9 @@ readData: readDataFinal: B - 1 :JMPN(endData) - B => D :CALL(addHashTx) + B => D :CALL(addHashTxFromFreeInput) :CALL(addL2HashTx) + :CALL(checkShortDataRLP) 32 - D => D :CALL(SHLarith); in: [A: value, D: #bytes to left shift] out: [A: shifted result] $ => E :MLOAD(globalCalldataMemoryOffset) ; Store current CTX @@ -265,7 +266,6 @@ readDataFinal: ; Restore current CTX B => CTX E + 1 :MSTORE(globalCalldataMemoryOffset) - :CALL(checkShortDataRLP) :JMP(endData) zeroBytesData: @@ -305,6 +305,7 @@ endChainId: setPreEIP155Flag: 1 :MSTORE(isPreEIP155) + $ => E :MLOAD(lastHashKIdUsed) ;; size verification ; checks RLP length read at the RLP header with bytes read during RLP parsing sizeVerification: diff --git a/main/opcodes/flow-control.zkasm b/main/opcodes/flow-control.zkasm index 2d6cbdcf..763a0475 100644 --- a/main/opcodes/flow-control.zkasm +++ b/main/opcodes/flow-control.zkasm @@ -71,10 +71,11 @@ checkJumpDestDeployment: ; get memory pointer for hashing $ => E :MLOAD(batchHashDataPointer) ; set number of bytes to hashK - $ => A :HASHK1(E) + $ => A :HASHP1(E) ; check if is a jumpDest (0x5B) A - 0x5B :JMPZ(readCode, invalidJump) + checkJumpDestDeploymentCreate: ; get bytes from previous context memory $ => CTX :MLOAD(originCTX) diff --git a/main/opcodes/stack-operations.zkasm b/main/opcodes/stack-operations.zkasm index f9fa2fb9..0c135b12 100644 --- a/main/opcodes/stack-operations.zkasm +++ b/main/opcodes/stack-operations.zkasm @@ -151,25 +151,23 @@ opAuxPUSHB: $ => A :MLOAD(isCreate), JMPNZ(opAuxPUSHBcreate) $ => B :MLOAD(txCalldataLen) PC + D - B :JMPN(opAuxPUSHB2) - B - PC => D + B - PC => D :JMPZ(opAuxPUSHBend) opAuxPUSHB2: ; set bytes length to read to C 0 => A D - 1 => C :JMPN(opAuxPUSHBend) - - -opAuxPUSHBloop: - ; checks zk-counters - %MAX_CNT_STEPS - STEP - 100 :JMPN(outOfCountersStep) + ; get memory pointer for hashing + $ => E :MLOAD(batchHashDataPointer) ; get position where data starts in the tx $ => HASHPOS :MLOAD(dataStarts) - ; add PC to data starts to point the bytes to read for the push HASHPOS + PC => HASHPOS - PC + 1 => PC - ; get memory pointer for hashing - $ => E :MLOAD(batchHashDataPointer) - $ => B :HASHK1(E) + PC + D => PC + ; checks zk-counters + %MAX_CNT_STEPS - STEP - 10*D :JMPN(outOfCountersStep) + +opAuxPUSHBloop: + $ => B :HASHP1(E) ; accumulate hash value A + B => A ; decrease length for loop @@ -179,11 +177,11 @@ opAuxPUSHBloop: opAuxPUSHBend: ; check out-of-gas - GAS - %GAS_FASTEST_STEP => GAS :JMPN(outOfGas) + GAS - %GAS_FASTEST_STEP => GAS :JMPN(outOfGas) ; store stack output (value) A :MSTORE(SP++); [pushed_value(E) => SP] ; check stack overflow - %MAX_STACK_SIZE - SP :JMPN(stackOverflow, readCode) + %MAX_STACK_SIZE - SP :JMPN(stackOverflow, readCode) opAuxPUSHBcreate: ; get bytes length diff --git a/main/process-tx.zkasm b/main/process-tx.zkasm index cdb7cca5..ebbb2603 100644 --- a/main/process-tx.zkasm +++ b/main/process-tx.zkasm @@ -119,12 +119,13 @@ endCheckChainId: %TX_GAS_LIMIT => A $ :LT,JMPC(invalidIntrinsicBatchGasLimit) - ; Intrinsic gas --> gas Limit >= 21000 + calldata cost + deployment cost - %BASE_TX_GAS => E ; Store init intrinsic gas at E + ; Intrinsic gas --> gas Limit >= 21000 + calldata cost + deployment cost + ; Intrinsic gas --> gas Limit >= 21000 + calldata cost + deployment cost + %BASE_TX_GAS => B ; Store init intrinsic gas at E $ => A :MLOAD(isCreateContract), JMPNZ(addDeploymentGasCost, getCalldataGasCost) addDeploymentGasCost: - %BASE_TX_DEPLOY_GAS => E ; 53000 gas if transaction is a create + %BASE_TX_DEPLOY_GAS => B ; 53000 gas if transaction is a create getCalldataGasCost: $ => A :MLOAD(txCalldataLen) @@ -133,31 +134,30 @@ getCalldataGasCost: addGas: $ => HASHPOS :MLOAD(dataStarts) - 0 => C :JMP(loopBytes) + $ => E :MLOAD(batchHashDataPointer) + 0 => C + %MAX_CNT_STEPS - STEP - 10*A :JMPN(outOfCountersStep) loopBytes: - %MAX_CNT_STEPS - STEP - 10 :JMPN(outOfCountersStep) A - C - 1 :JMPN(endCalldataIntrinsicGas) - E => B - $ => E :MLOAD(batchHashDataPointer) $ => D :HASHP1(E) - B => E C + 1 => C D - 1 :JMPN(add4Gas, add16Gas) add4Gas: - E + 4 => E :JMP(loopBytes) + B + 4 => B :JMP(loopBytes) add16Gas: - E + 16 => E :JMP(loopBytes) + B + 16 => B :JMP(loopBytes) endCalldataIntrinsicGas: + ; Restore current context + $ => CTX :MLOAD(currentCTX) ; Compare gas limit >= intrinsic gas $ => A :MLOAD(txGasLimit) - E => B $ :LT, JMPC(invalidIntrinsicTxGasLimit) ; Store calculated gas for later usage - E :MSTORE(gasCalldata) + B :MSTORE(gasCalldata) ; Check upfront cost: balance >= gas price * gas limit + value ; gas price * gas limit @@ -368,10 +368,11 @@ readDeployBytecode: $ => HASHPOS :MLOAD(dataStarts) HASHPOS + PC => HASHPOS $ => E :MLOAD(batchHashDataPointer) - $ => RR :HASHK1(E) + $ => RR :HASHP1(E) $${eventLog(onOpcode(RR))} PC + 1 => PC :JMP(@mapping_opcodes + RR) + ;; read calldata bytes of a CREATE/CREATE2 call and process them readDeployBytecodeCreate: $ => E :MLOAD(txCalldataLen) @@ -380,9 +381,9 @@ readDeployBytecodeCreate: E - PC - 1 :JMPN(readDeployBytecodeCreateDefault) $ => E :MLOAD(argsOffsetCall) E + PC => E - 1 => C :CALL(MLOADX) + 1 => C :CALL(MLOADX) ; in: [E: offset, C: length] out: [A: value, E: new offset] $ => CTX :MLOAD(currentCTX) - 31 => D :CALL(SHRarith) + 31 => D :CALL(SHRarith) ; in: [A: value, D: #bytes to right shift] out: [A: shifted result] A => RR $${eventLog(onOpcode(RR))} PC + 1 => PC :JMP(@mapping_opcodes + RR) From 4ff9967f3ec984912bd4a51e4987686b2e215b5e Mon Sep 17 00:00:00 2001 From: Ignasi Date: Thu, 7 Mar 2024 16:00:20 +0100 Subject: [PATCH 03/16] Refactor hashkUsed --- main/ecrecover/ecrecover.zkasm | 4 ++-- main/load-change-l2-block-utils.zkasm | 2 +- main/load-tx-rlp-utils.zkasm | 12 +++++++----- main/load-tx-rlp.zkasm | 9 +++++---- main/main.zkasm | 18 ++++++++++-------- main/opcodes/block.zkasm | 4 ++-- main/opcodes/crypto.zkasm | 11 ++++++----- main/process-change-l2-block.zkasm | 8 ++++---- main/process-tx.zkasm | 17 ++++++++--------- main/utils.zkasm | 10 +++++----- main/vars.zkasm | 6 ++++-- package.json | 6 +++--- test/ecrecover.zkasm | 9 +++++---- 13 files changed, 62 insertions(+), 54 deletions(-) diff --git a/main/ecrecover/ecrecover.zkasm b/main/ecrecover/ecrecover.zkasm index e87070ec..7877eadb 100644 --- a/main/ecrecover/ecrecover.zkasm +++ b/main/ecrecover/ecrecover.zkasm @@ -217,8 +217,8 @@ k1_calculated: ; [steps: 6280, bin: 522, arith: 527] ; generate keccak of public key to obtain ethereum address - $ => E :MLOAD(lastHashKIdUsed) - E + 1 => E :MSTORE(lastHashKIdUsed) + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) 0 => HASHPOS 32 => D diff --git a/main/load-change-l2-block-utils.zkasm b/main/load-change-l2-block-utils.zkasm index fba01923..b85a92d9 100644 --- a/main/load-change-l2-block-utils.zkasm +++ b/main/load-change-l2-block-utils.zkasm @@ -11,4 +11,4 @@ getChangeL2TxBytes: $ => A :HASHP(E) HASHPOS :MSTORE(batchHashPos) C => HASHPOS - $ => E :MLOAD(lastHashKIdUsed), RETURN \ No newline at end of file + $ => E :MLOAD(txHashPointer), RETURN \ No newline at end of file diff --git a/main/load-tx-rlp-utils.zkasm b/main/load-tx-rlp-utils.zkasm index 0f593d7f..75d2956b 100644 --- a/main/load-tx-rlp-utils.zkasm +++ b/main/load-tx-rlp-utils.zkasm @@ -11,7 +11,7 @@ getBatchL2DataBytes: $ => A :HASHP(E) HASHPOS :MSTORE(batchHashPos) C => HASHPOS - $ => E :MLOAD(lastHashKIdUsed) + $ => E :MLOAD(txHashPointer) :RETURN ;; Add bytes to generate ethereum signed message @@ -28,7 +28,7 @@ addHashTxBegin: $ => HASHPOS :MLOAD(batchHashPos) $ => A :HASHP(E) HASHPOS :MSTORE(batchHashPos) - $ => E :MLOAD(lastHashKIdUsed) + $ => E :MLOAD(txHashPointer) C => HASHPOS A :HASHK(E) C + D => C :RETURN @@ -46,7 +46,7 @@ addHashTxFromFreeInput: B + C => A ; Read data from free input ${getTxs(A,D)} => A, B - $ => E :MLOAD(lastHashKIdUsed) + $ => E :MLOAD(txHashPointer) C => HASHPOS ; Insert data into txhash (hashk) A :HASHK(E) @@ -57,11 +57,13 @@ addHashTxFromFreeInput: $ => HASHPOS :MLOAD(batchHashPos) 1 => C ; Current pointer D => RCX ; total bytes + ; Set default remainder to 0, in case SHRarith is not using arithDiv because is shifting zero bytes + 0 :MSTORE(arithRes2) ; Validate free input validateFreeInputLoop: - RCX - C :JMPN(validateFreeInputLoopEnd) + RCX - C :JMPN(validateFreeInputLoopEnd) ; Get free input byte by byte - RCX - C => D :CALL(SHRarith) ; in: [A: value, D: #bytes to right shift] out: [A: shifted result] + RCX - C => D :CALL(SHRarith) ; in: [A: value, D: #bytes to right shift] out: [A: shifted result] $ :HASHP1(E), ASSERT ; The remainder of divArith used at SHRarith is the following bytes I want to check $ => A :MLOAD(arithRes2) diff --git a/main/load-tx-rlp.zkasm b/main/load-tx-rlp.zkasm index 0b94eead..08006511 100644 --- a/main/load-tx-rlp.zkasm +++ b/main/load-tx-rlp.zkasm @@ -48,8 +48,9 @@ loadTx_rlp_continue: $ => E :MLOAD(nextHashPId) E :MSTORE(l2TxHashPointer) E + 1 :MSTORE(nextHashPId) - $ => E :MLOAD(lastHashKIdUsed) - E + 1 => E :MSTORE(lastHashKIdUsed) + $ => E :MLOAD(nextHashKId) + E :MSTORE(txHashPointer) + E + 1 :MSTORE(nextHashKId) ;;;;;;;;;;;;;;;;;; ;; B - Read and check RLP fields. Fill 'batchHashData' and Ethereum signed transaction bytes ;;;;;;;;;;;;;;;;;; @@ -218,7 +219,7 @@ veryShortData: $ => E :MLOAD(globalCalldataMemoryOffset) A :MSTORE(MEM:E) E + 1 :MSTORE(globalCalldataMemoryOffset) - $ => E :MLOAD(lastHashKIdUsed) + $ => E :MLOAD(txHashPointer) ; Restore current CTX B => CTX :JMP(endData) @@ -305,7 +306,7 @@ endChainId: setPreEIP155Flag: 1 :MSTORE(isPreEIP155) - $ => E :MLOAD(lastHashKIdUsed) + $ => E :MLOAD(txHashPointer) ;; size verification ; checks RLP length read at the RLP header with bytes read during RLP parsing sizeVerification: diff --git a/main/main.zkasm b/main/main.zkasm index 55f3cb0b..3e7c3731 100644 --- a/main/main.zkasm +++ b/main/main.zkasm @@ -49,35 +49,37 @@ start: ; main zkROM entry point ;; B - Compute newAccInputHash, load newLocalExitRoot and timestamp ;;;;;;;;;;;;;;;;;; computeNewAccInputHash: + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) $${eventLog(onStartBatch, C)} 0 => HASHPOS 32 => D $ => A :MLOAD(oldAccInputHash) - A :HASHK(0) + A :HASHK(E) $ => A :MLOAD(batchHashData) - A :HASHK(0) + A :HASHK(E) $ => A :MLOAD(l1InfoRoot) - A :HASHK(0) + A :HASHK(E) 8 => D $ => A :MLOAD(timestampLimit) - A :HASHK(0) + A :HASHK(E) 20 => D $ => A :MLOAD(sequencerAddr) - A :HASHK(0) + A :HASHK(E) 32 => D $ => A :MLOAD(forcedBlockHashL1) - A :HASHK(0) + A :HASHK(E) ; finish accInputHash - HASHPOS :HASHKLEN(0) + HASHPOS :HASHKLEN(E) - $ => C :HASHKDIGEST(0) + $ => C :HASHKDIGEST(E) C :MSTORE(newAccInputHash) ; Compute batchHashData (loaded at smt from executor) $ => E :MLOAD(nextHashPId) diff --git a/main/opcodes/block.zkasm b/main/opcodes/block.zkasm index 9b77545e..a4180957 100644 --- a/main/opcodes/block.zkasm +++ b/main/opcodes/block.zkasm @@ -28,8 +28,8 @@ opBLOCKHASH: 32 => D ; A new hash with position 0 is started 0 => HASHPOS - $ => E :MLOAD(lastHashKIdUsed) - E+1 => E :MSTORE(lastHashKIdUsed) + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) B :HASHK(E) %STATE_ROOT_STORAGE_POS :HASHK(E) HASHPOS :HASHKLEN(E) diff --git a/main/opcodes/crypto.zkasm b/main/opcodes/crypto.zkasm index 55a68ed6..1f3d83f0 100644 --- a/main/opcodes/crypto.zkasm +++ b/main/opcodes/crypto.zkasm @@ -47,8 +47,9 @@ opSHA3: %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 1 - B :JMPN(outOfCountersKeccak) ; new hash id - $ => B :MLOAD(lastHashKIdUsed) - B + 1 => B :MSTORE(lastHashKIdUsed) + $ => B :MLOAD(nextHashKId) + B :MSTORE(sha3Pointer) + B + 1 :MSTORE(nextHashKId) ; set bytes to hash at D 32 => D ; A new hash with position 0 is started @@ -65,7 +66,7 @@ opSHA3Loop: ; save new offset at B E => B ; get current hash pointer - $ => E :MLOAD(lastHashKIdUsed) + $ => E :MLOAD(sha3Pointer) ; append A to hash pointer E A :HASHK(E) ; restore new offset at E @@ -78,7 +79,7 @@ opSHA3Final: ; set #bytes to right shift 32 - C => D :CALL(SHRarith); in: [A: value, D: #bytes to right shift] out: [A: shifted result] ; get current hash pointer - $ => E :MLOAD(lastHashKIdUsed) + $ => E :MLOAD(sha3Pointer) ; set remaining bytes length to hash at D C => D ; append A to hash pointer E @@ -86,7 +87,7 @@ opSHA3Final: opSHA3End: ; get current hash pointer - $ => E :MLOAD(lastHashKIdUsed) + $ => E :MLOAD(sha3Pointer) ; append A to hash pointer E HASHPOS :HASHKLEN(E) ; compute hash diff --git a/main/process-change-l2-block.zkasm b/main/process-change-l2-block.zkasm index a49d913c..e9a1a0f8 100644 --- a/main/process-change-l2-block.zkasm +++ b/main/process-change-l2-block.zkasm @@ -21,8 +21,8 @@ continueProcessChangeL2Block: ; Update state root mapping 32 => D 0 => HASHPOS ; A new hash with position 0 is started - $ => E :MLOAD(lastHashKIdUsed) - E + 1 => E :MSTORE(lastHashKIdUsed) + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) %ADDRESS_SYSTEM => A %SMT_KEY_SC_STORAGE => B @@ -114,8 +114,8 @@ setGERL1InfoTree: ; Do not set if zero $ :EQ, JMPC(skipSetGERL1InfoTree) 0 => HASHPOS - $ => E :MLOAD(lastHashKIdUsed) - E + 1 => E :MSTORE(lastHashKIdUsed) + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) 32 => D A :HASHK(E) diff --git a/main/process-tx.zkasm b/main/process-tx.zkasm index ebbb2603..9d3d5b49 100644 --- a/main/process-tx.zkasm +++ b/main/process-tx.zkasm @@ -128,9 +128,7 @@ addDeploymentGasCost: %BASE_TX_DEPLOY_GAS => B ; 53000 gas if transaction is a create getCalldataGasCost: - $ => A :MLOAD(txCalldataLen) - 0 => B - $ :EQ,JMPC(endCalldataIntrinsicGas) + $ => A :MLOAD(txCalldataLen), JMPZ(endCalldataIntrinsicGas) ; less than 32 bits. Enforced by memory expansion gas cost & smart contract batchL2DataHash addGas: $ => HASHPOS :MLOAD(dataStarts) @@ -225,8 +223,9 @@ getContractAddress: ; A new hash with position 0 is started 0 => HASHPOS ; We get a new hashId - $ => E :MLOAD(lastHashKIdUsed) - E+1 => E :MSTORE(lastHashKIdUsed) + $ => E :MLOAD(nextHashKId) + E :MSTORE(createAddressPointer) + E + 1 :MSTORE(nextHashKId) ; Check if create is with CREATE2 opcode $ => A :MLOAD(isCreate2), JMPNZ(create2) ; Check keccak counters @@ -285,7 +284,7 @@ loopCreate2: B => E :CALL(MLOAD32) E => B 32 => D - $ => E :MLOAD(lastHashKIdUsed) + $ => E :MLOAD(createAddressPointer) A :HASHK(E) C - 32 => C :JMP(loopCreate2) @@ -293,7 +292,7 @@ endloopCreate2: B => E :CALL(MLOADX) 32 - C => D :CALL(SHRarith) C => D - $ => E :MLOAD(lastHashKIdUsed) + $ => E :MLOAD(createAddressPointer) A :HASHK(E) create2end: @@ -303,8 +302,8 @@ create2end: ; new hash with position 0 is started 0 => HASHPOS - $ => E :MLOAD(lastHashKIdUsed) - E+1 => E :MSTORE(lastHashKIdUsed) + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) 0xff :HASHK1(E) 20 => D $ => A :MLOAD(txSrcAddr) diff --git a/main/utils.zkasm b/main/utils.zkasm index 32e841b2..a58bddef 100644 --- a/main/utils.zkasm +++ b/main/utils.zkasm @@ -1633,8 +1633,8 @@ verifyMerkleProof: ;;;;;;;;;;;;;;;;;;;;; ; new keccak address - $ => E :MLOAD(lastHashKIdUsed) - E + 1 => E :MSTORE(lastHashKIdUsed) + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) ; add gerL1InfoTree (32 bytes) 0 => HASHPOS @@ -1658,8 +1658,8 @@ verifyMerkleProof: $ => B :MLOAD(indexL1InfoTree) ; prepare new hash - $ => E :MLOAD(lastHashKIdUsed) - E + 1 => E :MSTORE(lastHashKIdUsed) + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) 32 => D ; - Start loop 32 levels: @@ -2213,7 +2213,7 @@ hashBranchEnd31: ; verify linear combination of 'indexL1InfoTree' B :ASSERT - E + 31 => E :MSTORE(lastHashKIdUsed) + E + 32 => E :MSTORE(nextHashKId) verifyMerkleProofEnd: diff --git a/main/vars.zkasm b/main/vars.zkasm index d6bf6d17..721ec8b6 100644 --- a/main/vars.zkasm +++ b/main/vars.zkasm @@ -22,9 +22,11 @@ VAR GLOBAL batchL2DataParsed ; Number of bytes read when decoding RLP transactio VAR GLOBAL pendingTxs ; Number of transactions decoded in RLP block VAR GLOBAL lastCtxUsed ; Last context that has been used VAR GLOBAL ctxTxToUse ; First context to be used when processing transactions -VAR GLOBAL lastHashKIdUsed ; Last hash address used +VAR GLOBAL nextHashKId ; Last hash address used VAR GLOBAL nextHashPId ; Next poseidon hash address available - +VAR GLOBAL createAddressPointer ; E pointer for create contract address computation +VAR GLOBAL sha3Pointer ; E pointer for sha3 computation +VAR GLOBAL txHashPointer ; E pointer for tx hash computation VAR GLOBAL batchL2DataLength ; Transactions bytes read from the input VAR GLOBAL batchHashDataPointer ; hash address used when adding bytes to batchHashData VAR GLOBAL batchHashPos ; hash batchHashData position diff --git a/package.json b/package.json index 2c1f15d6..c962f0cc 100644 --- a/package.json +++ b/package.json @@ -39,13 +39,13 @@ "url": "https://github.com/0xPolygonHermez/zkevm-rom.git" }, "dependencies": { - "@0xpolygonhermez/zkasmcom": "https://github.com/0xPolygonHermez/zkasmcom.git#v5.0.0-fork.8", + "@0xpolygonhermez/zkasmcom": "https://github.com/0xPolygonHermez/zkasmcom.git#develop-feijoa", "yargs": "^17.5.1" }, "devDependencies": { "@0xpolygonhermez/zkevm-commonjs": "github:0xPolygonHermez/zkevm-commonjs#develop-feijoa", - "@0xpolygonhermez/zkevm-proverjs": "github:0xPolygonHermez/zkevm-proverjs#feature/batch-hash-data", - "@0xpolygonhermez/zkevm-testvectors": "github:0xPolygonHermez/zkevm-testvectors#feature/batch-hash-data", + "@0xpolygonhermez/zkevm-proverjs": "github:0xPolygonHermez/zkevm-proverjs#feature/feijoa-batch", + "@0xpolygonhermez/zkevm-testvectors": "github:0xPolygonHermez/zkevm-testvectors#feature/feijoa-batch", "chai": "^4.3.6", "chalk": "^3.0.0", "eslint": "^8.25.0", diff --git a/test/ecrecover.zkasm b/test/ecrecover.zkasm index 4d27fcd4..d7c69124 100644 --- a/test/ecrecover.zkasm +++ b/test/ecrecover.zkasm @@ -2,7 +2,7 @@ ;; ecrecover_tx ;;;;;;;;;;;; INCLUDE "../main/constants.zkasm" -VAR GLOBAL lastHashKIdUsed +VAR GLOBAL nextHashKId VAR GLOBAL originalCTX start: @@ -10,9 +10,10 @@ start: 0 :ASSERT CTX :MSTORE(originalCTX) - -1 :MSTORE(lastHashKIdUsed) - ; :JMP(repeat_ecrecover_test) - :JMP(edge_cases) + :JMP(repeat_ecrecover_test) + ; :JMP(edge_cases) + ; :JMP(worst_case) + ; :JMP(point_arith_tests) INCLUDE "../main/ecrecover/ecrecover.zkasm" From 6670d335e362ce067024aa4999f7379b510c33a3 Mon Sep 17 00:00:00 2001 From: Ignasi Date: Fri, 8 Mar 2024 09:56:46 +0100 Subject: [PATCH 04/16] Set inputs/outputs --- main/end.zkasm | 6 +- main/main.zkasm | 96 +++++++++++++++++------------- main/process-change-l2-block.zkasm | 7 +-- main/utils.zkasm | 2 - main/vars.zkasm | 14 +++-- 5 files changed, 69 insertions(+), 56 deletions(-) diff --git a/main/end.zkasm b/main/end.zkasm index 78d7e172..448fb7fb 100644 --- a/main/end.zkasm +++ b/main/end.zkasm @@ -1,4 +1,6 @@ finalWait: ${beforeLast()} :JMPN(finalWait) - ; Set all registers to 0 except inputs: B (oldStateRoot), C (oldAccInputHash), SP (oldNumBatch), GAS (chainID) & CTX (forkID) - 0 => A, D, E, PC, SR, HASHPOS, RR, RCX :JMP(start) \ No newline at end of file + ; Set registers to its initials values + $ => SR :RESTORE + ; Set all registers to 0 except inputs: SR (oldStateRoot), C (oldBatchAccInputHash), D (previousL1InfoTreeRoot), RCX (previousL1InfoTreeIndex), GAS (chainID) & CTX (forkID) + 0 => A, B, E, PC, SP, HASHPOS, RR, zkPC :JMP(start) \ No newline at end of file diff --git a/main/main.zkasm b/main/main.zkasm index 3e7c3731..6e8d9a26 100644 --- a/main/main.zkasm +++ b/main/main.zkasm @@ -2,11 +2,11 @@ INCLUDE "constants.zkasm" INCLUDE "vars.zkasm" ; Blocks zkROM -; A - Load initial registers into memory: oldStateRoot (B), oldAccInputHash (C), oldNumBatch (SP) & chainID (GAS) +; 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 newAccInputHash +; E - Batch computations: get newLocalExitRoot, assert transactions size, compute batchHashData & compute newBatchAccInputHash ; F - Finalize execution start: ; main zkROM entry point @@ -16,71 +16,85 @@ start: ; main zkROM entry point STEP => A 0 :ASSERT ; Ensure it is the beginning of the execution - CTX :MSTORE(forkID) + CTX :MSTORE(forkID) ; Fork id from CTX CTX - %FORK_ID :JMPNZ(failAssert) - B => A :MSTORE(oldStateRoot) + SR => A :MSTORE(oldStateRoot) ; oldStateRoot from SR ; safety check that the input root is indeed inside the range limit of 4 goldilocks fields elements %FOUR_GOLDILOCKS => B 1 :LT4 - C :MSTORE(oldAccInputHash) - SP :MSTORE(oldNumBatch) - GAS :MSTORE(chainID) ; assumed to be less than 32 bits + C :MSTORE(oldBatchAccInputHash) ; oldBatchAccInputHash from C + D :MSTORE(oldL1InfoTreeRoot) ; oldL1InfoTreeRoot from D + D :MSTORE(l1InfoRoot) + RCX :MSTORE(oldL1InfoTreeIndex) ; oldL1InfoTreeIndex from E + RCX :MSTORE(l1InfoTreeIndex) + GAS :MSTORE(chainID) ; chainID from GAS, assumed to be less than 32 bits + SR :SAVE(B,C,D,E,RR,RCX) - ${getL1InfoRoot()} :MSTORE(l1InfoRoot) ${getSequencerAddr()} :MSTORE(sequencerAddr) - ${getTimestampLimit()} :MSTORE(timestampLimit) ${getTxsLen()} :MSTORE(batchL2DataLength) ; less than 120000 bytes. Enforced by the smart contract - ${getForcedBlockHashL1()} => A :MSTORE(forcedBlockHashL1) ${getBatchHashData()} :MSTORE(batchHashData) - ;set initial state root - $ => SR :MLOAD(oldStateRoot) - SR :MSTORE(batchSR) - ; Increase batch number - SP + 1 :MSTORE(newNumBatch) - ; compute isForced flag - 0 => B - $ :EQ, JMPC(computeNewAccInputHash) - 1 :MSTORE(isForced) + $0{getType()} => A :MSTORE(type) + ; If is not forced, forcedHashData is zero, CHECK: remove? + 0 :MSTORE(forcedHashData) + A - 2 :JMPNZ(computeNewBatchAccInputHash) + 1 :MSTORE(isForced) + ; compute isForced flag + ${getGER()} :MSTORE(gerL1InfoTree) + ${getBlockHashL1()} :MSTORE(blockHashL1InfoTree) + ${getMinTimestamp()} :MSTORE(timestampL1InfoTree) + ; Compute forcedHashData + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) + 32 => D + $ => A :MLOAD(gerL1InfoTree) + A :HASHK(E) + $ => A :MLOAD(blockHashL1InfoTree) + A :HASHK(E) + 8 => D + $ => A :MLOAD(timestampL1InfoTree) + A :HASHK(E) + HASHPOS :HASHKLEN(E) + ; CHECK: need to assert with a forcedHashData obtained from free input? + $ => C :HASHKDIGEST(E) + C :MSTORE(forcedHashData) +;;;;;;;;;;;;;;;;; +;; B - Compute newBatchAccInputHash, load newLocalExitRoot and timestamp ;;;;;;;;;;;;;;;;;; -;; B - Compute newAccInputHash, load newLocalExitRoot and timestamp -;;;;;;;;;;;;;;;;;; -computeNewAccInputHash: +computeNewBatchAccInputHash: $ => E :MLOAD(nextHashKId) E + 1 :MSTORE(nextHashKId) $${eventLog(onStartBatch, C)} 0 => HASHPOS 32 => D - $ => A :MLOAD(oldAccInputHash) + $ => A :MLOAD(oldBatchAccInputHash) A :HASHK(E) $ => A :MLOAD(batchHashData) A :HASHK(E) - $ => A :MLOAD(l1InfoRoot) - A :HASHK(E) - - 8 => D - $ => A :MLOAD(timestampLimit) - A :HASHK(E) - 20 => D $ => A :MLOAD(sequencerAddr) A :HASHK(E) 32 => D - $ => A :MLOAD(forcedBlockHashL1) + $ => A :MLOAD(forcedHashData) + A :HASHK(E) + + 1 => D + $ => A :MLOAD(type) A :HASHK(E) ; finish accInputHash HASHPOS :HASHKLEN(E) $ => C :HASHKDIGEST(E) - C :MSTORE(newAccInputHash) + C :MSTORE(newBatchAccInputHash) + ; Compute batchHashData (loaded at smt from executor) $ => E :MLOAD(nextHashPId) E :MSTORE(batchHashDataPointer) @@ -96,7 +110,7 @@ computeNewAccInputHash: ;; Get local exit root ; Read 'localExitRoot' variable from GLOBAL_EXIT_ROOT_MANAGER_L2 and store - ; it to the 'newLocalExitRoot' input, will be used to compute newAccInputHash + ; it to the 'newLocalExitRoot' input, will be used to compute newBatchAccInputHash %ADDRESS_GLOBAL_EXIT_ROOT_MANAGER_L2 => A %SMT_KEY_SC_STORAGE => B %LOCAL_EXIT_ROOT_STORAGE_POS => C @@ -181,22 +195,24 @@ finalizeBatch: ;;;;;;;;;;;;;;;;;; ;; F - Finalize execution ;;;;;;;;;;;;;;;;;; + ; safety check that the output root is indeed inside the range limit of 4 goldilocks fields elements - SR => A + SR => A ; newStateRoot at A %FOUR_GOLDILOCKS => B 1 :LT4 ; Set output registers - $ => D :MLOAD(newAccInputHash) - $ => E :MLOAD(newLocalExitRoot) - $ => PC :MLOAD(newNumBatch) + $ => RR :MLOAD(timestamp) ; Timestamp at RR + $ => RCX :MLOAD(l1InfoTreeIndex) ; l1InfoTreeIndex at RCX + $ => D :MLOAD(l1InfoRoot) ; l1InfoTreeIndex at D + $ => C :MLOAD(newBatchAccInputHash) ; newBatchAccInputHash at C + $ => E :MLOAD(newLocalExitRoot) ; NewLocalExitRoot at E + ; SR is already at SR reg ; Set registers to its initials values $ => CTX :MLOAD(forkID) - $ => B :MLOAD(oldStateRoot) - $ => C :MLOAD(oldAccInputHash) - $ => SP :MLOAD(oldNumBatch) $ => GAS :MLOAD(chainID) + finalizeExecution: :JMP(finalWait) diff --git a/main/process-change-l2-block.zkasm b/main/process-change-l2-block.zkasm index e9a1a0f8..f9d59eb4 100644 --- a/main/process-change-l2-block.zkasm +++ b/main/process-change-l2-block.zkasm @@ -48,7 +48,6 @@ continueProcessChangeL2Block: ; Load current timestamp $ => A :MLOAD(timestamp) ; currentTimestamp => A - $ => B :MLOAD(timestampLimit) ; timestampLimit => B ; If it is NOT a forced tx ==> verify Timestamp & L1InfoRoot $ :MLOAD(isForced), JMPZ(verifyTimestampAndL1InfoRoot) @@ -56,7 +55,7 @@ continueProcessChangeL2Block: ; forced batch ; - update timestamp only if currentTimestamp < limitTimestamp ; - set blockHash to default - $ => C :MLOAD(forcedBlockHashL1) + $ => C :MLOAD(forcedHashData) C :MSTORE(blockHashL1InfoTree) A :MSTORE(timestamp) $ :LT, JMPNC(initSetGERL1InfoTree) @@ -69,10 +68,6 @@ verifyTimestampAndL1InfoRoot: ; Addition of two values of 8 bytes [B: currentTimestamp(A) + deltaTimestamp(B)] $ => B :ADD, MSTORE(timestamp) - ; Verify (currentTimestamp + deltaTimestamp) <= limitTimestamp - $ => A :MLOAD(timestampLimit) - $ :LT, JMPC(invalidChangeL2BlockLimitTimestamp) - ; Set new timestamp %TIMESTAMP_STORAGE_POS => C %ADDRESS_SYSTEM => A diff --git a/main/utils.zkasm b/main/utils.zkasm index a58bddef..6f45de2d 100644 --- a/main/utils.zkasm +++ b/main/utils.zkasm @@ -841,8 +841,6 @@ outOfCountersPoseidon: $${eventLog(onError, OOCPO)} :JMP(handleBatchError) outOfCountersSha256: $${eventLog(onError, OOCSH)} :JMP(handleBatchError) -invalidChangeL2BlockLimitTimestamp: - $${eventLog(onError, invalid_change_l2_block_limit_timestamp)} :JMP(handleBatchError) invalidChangeL2BlockMinTimestamp: $${eventLog(onError, invalid_change_l2_block_min_timestamp)} :JMP(handleBatchError) outOfGas: diff --git a/main/vars.zkasm b/main/vars.zkasm index 721ec8b6..b6a145c3 100644 --- a/main/vars.zkasm +++ b/main/vars.zkasm @@ -1,20 +1,22 @@ ; Input variables VAR GLOBAL oldStateRoot ; Previous state-tree root -VAR GLOBAL oldAccInputHash ; Previous accumulated input hash +VAR GLOBAL oldBatchAccInputHash ; Previous accumulated input hash +VAR GLOBAL oldL1InfoTreeRoot ; Previous L1 info tree root +VAR GLOBAL oldL1InfoTreeIndex ; Previous L1 info tree index VAR GLOBAL l1InfoRoot ; Global exit-tree root -VAR GLOBAL oldNumBatch ; Previous batch processed VAR GLOBAL sequencerAddr ; Coinbase address which will receive the fees VAR GLOBAL batchHashData ; batchHashData = H_keccak( transactions ) -VAR GLOBAL timestampLimit ; timestampLimit of the batch VAR GLOBAL timestamp ; Current batch timestamp VAR GLOBAL chainID ; Current batch chain id VAR GLOBAL forkID ; Fork identifier -VAR GLOBAL forcedBlockHashL1 ; blockHash ¡n L1 when a forced transaction has been done VAR GLOBAL isForced ; Flag to determine if the batch is forced VAR GLOBAL cumulativeGasUsed ; cumulative gas used in the block - +VAR GLOBAL forcedHashData ; solidtykeccak256(abi.encode(GER, blockHashL1, minTimestamp)) +VAR GLOBAL type ; Type of the batch 0: data-availability comes from calldata, 1: data-availability comes from blob transaction, 2: forced blob (data-availability comes from calldata +VAR GLOBAL L1LeafHash ; Hash of the new L1 leaf of the exit tree ; Output variables -VAR GLOBAL newAccInputHash ; Final accumulated input hash. newAccInputHash = H_keccak( oldAccInputHash | batchHashData | l1InfoRoot | timestamp | sequencerAddr ) +VAR GLOBAL newBatchAccInputHash ; Final accumulated input hash. newBatchAccInputHash = H_keccak( oldAccBathHashData | batchHashData | forcedHashData | sequencerAddr ) +VAR GLOBAL l1InfoTreeIndex ; New L1 info tree index VAR GLOBAL newLocalExitRoot ; Updated local exit tree root VAR GLOBAL newNumBatch ; Current batch processed From a180f875adbe4f8be690159b7a50d0c5b24d6c4d Mon Sep 17 00:00:00 2001 From: Ignasi Date: Fri, 8 Mar 2024 16:55:43 +0100 Subject: [PATCH 05/16] Implement forced batch --- main/constants.zkasm | 2 +- main/main.zkasm | 16 +++++++++------- main/process-change-l2-block.zkasm | 19 ++++++++----------- main/utils.zkasm | 3 +-- main/vars.zkasm | 5 ++++- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/main/constants.zkasm b/main/constants.zkasm index d177f2df..d1b89c25 100644 --- a/main/constants.zkasm +++ b/main/constants.zkasm @@ -6,7 +6,7 @@ CONST %BATCH_DIFFICULTY = 0 CONST %TX_GAS_LIMIT = 30000000 CONSTL %BLOCK_GAS_LIMIT = 2**50 CONST %MAX_MEM_EXPANSION_BYTES = 0x3fffe0 -CONST %FORK_ID = 8 +CONST %FORK_ID = 9 CONST %L1INFO_TREE_LEVELS = 32 CONST %CALLDATA_RESERVED_CTX = 1 CONSTL %FOUR_GOLDILOCKS = 0xffffffff00000001ffffffff00000001ffffffff00000001ffffffff00000001n diff --git a/main/main.zkasm b/main/main.zkasm index 6e8d9a26..1640333c 100644 --- a/main/main.zkasm +++ b/main/main.zkasm @@ -31,7 +31,6 @@ start: ; main zkROM entry point RCX :MSTORE(oldL1InfoTreeIndex) ; oldL1InfoTreeIndex from E RCX :MSTORE(l1InfoTreeIndex) GAS :MSTORE(chainID) ; chainID from GAS, assumed to be less than 32 bits - SR :SAVE(B,C,D,E,RR,RCX) ${getSequencerAddr()} :MSTORE(sequencerAddr) ${getTxsLen()} :MSTORE(batchL2DataLength) ; less than 120000 bytes. Enforced by the smart contract @@ -43,19 +42,16 @@ start: ; main zkROM entry point A - 2 :JMPNZ(computeNewBatchAccInputHash) 1 :MSTORE(isForced) ; compute isForced flag - ${getGER()} :MSTORE(gerL1InfoTree) - ${getBlockHashL1()} :MSTORE(blockHashL1InfoTree) - ${getMinTimestamp()} :MSTORE(timestampL1InfoTree) ; Compute forcedHashData $ => E :MLOAD(nextHashKId) E + 1 :MSTORE(nextHashKId) 32 => D - $ => A :MLOAD(gerL1InfoTree) + ${getForcedGER()} => A :MSTORE(forcedGER) A :HASHK(E) - $ => A :MLOAD(blockHashL1InfoTree) + ${getForcedBlockHashL1()} => A :MSTORE(forcedBlockHashL1InfoTree) A :HASHK(E) 8 => D - $ => A :MLOAD(timestampL1InfoTree) + ${getForcedTimestamp()} => A :MSTORE(getForcedTimestamp) A :HASHK(E) HASHPOS :HASHKLEN(E) ; CHECK: need to assert with a forcedHashData obtained from free input? @@ -214,6 +210,12 @@ finalizeBatch: $ => GAS :MLOAD(chainID) finalizeExecution: + ; Save inputs to RESTORE at last - 1 step + $ => SR :MLOAD(oldStateRoot) ; oldStateRoot from SR + $ => C :MLOAD(oldBatchAccInputHash) ; oldBatchAccInputHash from C + $ => D :MLOAD(oldL1InfoTreeRoot) ; oldL1InfoTreeRoot from D + $ => RCX :MLOAD(oldL1InfoTreeIndex) ; oldL1InfoTreeIndex from E + SR :SAVE(B,C,D,E,RR,RCX) :JMP(finalWait) INCLUDE "end.zkasm" diff --git a/main/process-change-l2-block.zkasm b/main/process-change-l2-block.zkasm index f9d59eb4..fc5cbf63 100644 --- a/main/process-change-l2-block.zkasm +++ b/main/process-change-l2-block.zkasm @@ -55,13 +55,10 @@ continueProcessChangeL2Block: ; forced batch ; - update timestamp only if currentTimestamp < limitTimestamp ; - set blockHash to default - $ => C :MLOAD(forcedHashData) + $ => C :MLOAD(forcedBlockHashL1InfoTree) C :MSTORE(blockHashL1InfoTree) - A :MSTORE(timestamp) - $ :LT, JMPNC(initSetGERL1InfoTree) - -newForcedTimestamp: - B :MSTORE(timestamp), JMP(setNewTimestamp) + $ => B :MLOAD(getForcedTimestamp) + $ :LT, JMPC(setMinTimestamp, initSetGERL1InfoTree) verifyTimestampAndL1InfoRoot: $ => B :MLOAD(deltaTimestamp) @@ -88,20 +85,20 @@ ${getL1InfoTimestamp(mem.indexL1InfoTree)} => C :MSTORE(timestampL1InfoTree) $ => B :MLOAD(timestampL1InfoTree) $ :LT, JMPC(invalidChangeL2BlockMinTimestamp, initSetGERL1InfoTree) -setNewTimestamp: - ; Set new timestamp +setMinTimestamp: + ; Set getForcedTimestamp (now new Timestamp) from forced batch data %TIMESTAMP_STORAGE_POS => C %ADDRESS_SYSTEM => A + B => D :MSTORE(timestamp) %SMT_KEY_SC_STORAGE => B - $ => D :MLOAD(timestamp) $ => SR :SSTORE initSetGERL1InfoTree: ; Set new GER $ => A :MLOAD(gerL1InfoTree) - ; If it is a forced tx ==> gerL1InfoTree = l1InfoRoot + ; If it is a forced tx ==> gerL1InfoTree = forcedGER $ :MLOAD(isForced), JMPZ(setGERL1InfoTree) - $ => A :MLOAD(l1InfoRoot) + $ => A :MLOAD(forcedGER) A :MSTORE(gerL1InfoTree) setGERL1InfoTree: diff --git a/main/utils.zkasm b/main/utils.zkasm index 6f45de2d..092c38ed 100644 --- a/main/utils.zkasm +++ b/main/utils.zkasm @@ -1609,8 +1609,7 @@ expADend: ;@info function to force a failed assert failAssert: - 1 => A - 2 :ASSERT + A - 1 :ASSERT VAR GLOBAL tmpZkPCVerifyMerkleProof ;@info verifies L1Info data with sibilings diff --git a/main/vars.zkasm b/main/vars.zkasm index b6a145c3..2a8009a0 100644 --- a/main/vars.zkasm +++ b/main/vars.zkasm @@ -7,11 +7,14 @@ VAR GLOBAL l1InfoRoot ; Global exit-tree root VAR GLOBAL sequencerAddr ; Coinbase address which will receive the fees VAR GLOBAL batchHashData ; batchHashData = H_keccak( transactions ) VAR GLOBAL timestamp ; Current batch timestamp +VAR GLOBAL getForcedTimestamp ; Timestamp proposed by a forced batch +VAR GLOBAL forcedGER ; GER proposed by a forced batch +VAR GLOBAL forcedBlockHashL1InfoTree ; BlockHashL1 of the forced batch VAR GLOBAL chainID ; Current batch chain id VAR GLOBAL forkID ; Fork identifier VAR GLOBAL isForced ; Flag to determine if the batch is forced VAR GLOBAL cumulativeGasUsed ; cumulative gas used in the block -VAR GLOBAL forcedHashData ; solidtykeccak256(abi.encode(GER, blockHashL1, minTimestamp)) +VAR GLOBAL forcedHashData ; solidtykeccak256(abi.encode(GER, blockHashL1, getForcedTimestamp)) VAR GLOBAL type ; Type of the batch 0: data-availability comes from calldata, 1: data-availability comes from blob transaction, 2: forced blob (data-availability comes from calldata VAR GLOBAL L1LeafHash ; Hash of the new L1 leaf of the exit tree ; Output variables From 96f06e7f17d74afbdafd1fcd7755f56384fcfb01 Mon Sep 17 00:00:00 2001 From: Ignasi Date: Sun, 10 Mar 2024 22:10:14 +0100 Subject: [PATCH 06/16] Implementation of new recursive tree --- .github/workflows/main.yaml | 4 +- counters/tests/opBLOCKHASH.zkasm | 3 +- counters/tests/opSHA3.zkasm | 3 +- main/load-tx-rlp.zkasm | 1 + main/main.zkasm | 41 ++++--- main/precompiled/selector.zkasm | 2 +- main/process-change-l2-block.zkasm | 78 ++++++++++-- main/process-tx.zkasm | 5 +- main/utils.zkasm | 187 ++++++++++++----------------- main/vars.zkasm | 15 ++- package.json | 2 +- test/performance/read-push.zkasm | 8 +- test/read-push.zkasm | 8 +- 13 files changed, 193 insertions(+), 164 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 8465d3af..b29465e8 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -6,7 +6,7 @@ name: Test executor inputs on: workflow_dispatch: pull_request: - branches: [main, develop, develop-no-opt, develop-feijoa] + branches: [main, develop, develop-feijoa] jobs: build: @@ -26,7 +26,7 @@ jobs: npm run test:build:gasLimit:v3 - name: run counters tests run: | - npm run test:counters + # npm run test:counters - name: run zkasm tests run: | npm run test:zkasm diff --git a/counters/tests/opBLOCKHASH.zkasm b/counters/tests/opBLOCKHASH.zkasm index 0679c951..5057e54e 100644 --- a/counters/tests/opBLOCKHASH.zkasm +++ b/counters/tests/opBLOCKHASH.zkasm @@ -4,7 +4,8 @@ start: 1000000 => GAS operation: - 2 :HASHK1(0) + 0 => E + 2 :HASHK1(E) 10 :MSTORE(blockNum) 1 :MSTORE(SP++) :JMP(opBLOCKHASH) diff --git a/counters/tests/opSHA3.zkasm b/counters/tests/opSHA3.zkasm index 9f34f286..15eb9ed3 100644 --- a/counters/tests/opSHA3.zkasm +++ b/counters/tests/opSHA3.zkasm @@ -4,7 +4,8 @@ start: 1000000 => GAS operation: - 2 :HASHK1(0) + 0 => E + 2 :HASHK1(E) 2000 :MSTORE(SP++) 100 :MSTORE(SP++) :JMP(opSHA3) diff --git a/main/load-tx-rlp.zkasm b/main/load-tx-rlp.zkasm index 08006511..2f909b17 100644 --- a/main/load-tx-rlp.zkasm +++ b/main/load-tx-rlp.zkasm @@ -80,6 +80,7 @@ endList: ; Check enough keccak zk counters to digest tx hash ; We don't check poseidon counters spent for l2 tx hash computing because the number of poseidon counters available is x100 the number of keccak available ; so while rlp parsing, keccaks will always be the bottleneck + ; CHECK: we can assume we will always have enough keccaks at this point of batch processing, so maybe there is no need to check B + 1 :MSTORE(arithA) 136 :MSTORE(arithB), CALL(divARITH); in: [arithA, arithB] out: [arithRes1: arithA/arithB, arithRes2: arithA%arithB] $ => B :MLOAD(arithRes1) diff --git a/main/main.zkasm b/main/main.zkasm index 1640333c..874732c1 100644 --- a/main/main.zkasm +++ b/main/main.zkasm @@ -20,16 +20,16 @@ start: ; main zkROM entry point CTX - %FORK_ID :JMPNZ(failAssert) SR => A :MSTORE(oldStateRoot) ; oldStateRoot from SR - + SR :MSTORE(batchSR) ; safety check that the input root is indeed inside the range limit of 4 goldilocks fields elements %FOUR_GOLDILOCKS => B 1 :LT4 C :MSTORE(oldBatchAccInputHash) ; oldBatchAccInputHash from C - D :MSTORE(oldL1InfoTreeRoot) ; oldL1InfoTreeRoot from D - D :MSTORE(l1InfoRoot) - RCX :MSTORE(oldL1InfoTreeIndex) ; oldL1InfoTreeIndex from E - RCX :MSTORE(l1InfoTreeIndex) + D :MSTORE(previousL1InfoTreeRoot) ; previousL1InfoTreeRoot from D + D :MSTORE(currentL1InfoTreeRoot) + RCX :MSTORE(previousL1InfoTreeIndex) ; previousL1InfoTreeIndex from E + RCX :MSTORE(currentL1InfoTreeIndex) GAS :MSTORE(chainID) ; chainID from GAS, assumed to be less than 32 bits ${getSequencerAddr()} :MSTORE(sequencerAddr) @@ -51,7 +51,7 @@ start: ; main zkROM entry point ${getForcedBlockHashL1()} => A :MSTORE(forcedBlockHashL1InfoTree) A :HASHK(E) 8 => D - ${getForcedTimestamp()} => A :MSTORE(getForcedTimestamp) + ${getForcedTimestamp()} => A :MSTORE(forcedTimestamp) A :HASHK(E) HASHPOS :HASHKLEN(E) ; CHECK: need to assert with a forcedHashData obtained from free input? @@ -61,34 +61,35 @@ start: ; main zkROM entry point ;; B - Compute newBatchAccInputHash, load newLocalExitRoot and timestamp ;;;;;;;;;;;;;;;;;; computeNewBatchAccInputHash: - $ => E :MLOAD(nextHashKId) - E + 1 :MSTORE(nextHashKId) + ; newBatchAccInputHash = LinearPoseidon(oldBatchAccInputHash, batchHashData, sequencerAddress, forcedHashData, type)) + $ => E :MLOAD(nextHashPId) + E + 1 :MSTORE(nextHashPId) $${eventLog(onStartBatch, C)} 0 => HASHPOS 32 => D $ => A :MLOAD(oldBatchAccInputHash) - A :HASHK(E) + A :HASHP(E) $ => A :MLOAD(batchHashData) - A :HASHK(E) + A :HASHP(E) 20 => D $ => A :MLOAD(sequencerAddr) - A :HASHK(E) + A :HASHP(E) 32 => D $ => A :MLOAD(forcedHashData) - A :HASHK(E) + A :HASHP(E) 1 => D $ => A :MLOAD(type) - A :HASHK(E) + A :HASHP(E) ; finish accInputHash - HASHPOS :HASHKLEN(E) + HASHPOS :HASHPLEN(E) - $ => C :HASHKDIGEST(E) + $ => C :HASHPDIGEST(E) C :MSTORE(newBatchAccInputHash) ; Compute batchHashData (loaded at smt from executor) @@ -145,7 +146,7 @@ setBlockNum: %LAST_BLOCK_STORAGE_POS => C %ADDRESS_SYSTEM => A %SMT_KEY_SC_STORAGE => B - $ :SLOAD,MSTORE(blockNum) + $ => A :SLOAD,MSTORE(blockNum) ; If forced batch ==> process a forced changeL2BlockTx $ :MLOAD(isForced), JMPZ(txLoop, handleForcedBatch) @@ -199,8 +200,8 @@ finalizeBatch: ; Set output registers $ => RR :MLOAD(timestamp) ; Timestamp at RR - $ => RCX :MLOAD(l1InfoTreeIndex) ; l1InfoTreeIndex at RCX - $ => D :MLOAD(l1InfoRoot) ; l1InfoTreeIndex at D + $ => RCX :MLOAD(currentL1InfoTreeIndex) ; currentL1InfoTreeIndex at RCX + $ => D :MLOAD(currentL1InfoTreeRoot) ; currentL1InfoTreeRoot at D $ => C :MLOAD(newBatchAccInputHash) ; newBatchAccInputHash at C $ => E :MLOAD(newLocalExitRoot) ; NewLocalExitRoot at E ; SR is already at SR reg @@ -213,8 +214,8 @@ finalizeBatch: ; Save inputs to RESTORE at last - 1 step $ => SR :MLOAD(oldStateRoot) ; oldStateRoot from SR $ => C :MLOAD(oldBatchAccInputHash) ; oldBatchAccInputHash from C - $ => D :MLOAD(oldL1InfoTreeRoot) ; oldL1InfoTreeRoot from D - $ => RCX :MLOAD(oldL1InfoTreeIndex) ; oldL1InfoTreeIndex from E + $ => D :MLOAD(previousL1InfoTreeRoot) ; previousL1InfoTreeRoot from D + $ => RCX :MLOAD(previousL1InfoTreeIndex) ; previousL1InfoTreeIndex from E SR :SAVE(B,C,D,E,RR,RCX) :JMP(finalWait) diff --git a/main/precompiled/selector.zkasm b/main/precompiled/selector.zkasm index 0bd3047b..c81a55e0 100644 --- a/main/precompiled/selector.zkasm +++ b/main/precompiled/selector.zkasm @@ -70,7 +70,7 @@ selectorPrecompiled: A - 3 :JMPN(funcSHA256) A - 4 :JMPN(revertPrecompiled) ;:JMPN(RIPEMD160) A - 5 :JMPN(IDENTITY) - A - 6 :JMPN(revertPrecompiled) ;:JMPN(funcModexp) + A - 6 :JMPN(funcModexp) A - 7 :JMPN(funcEcAdd) A - 8 :JMPN(funcEcMul) A - 9 :JMPN(funcEcPairing) diff --git a/main/process-change-l2-block.zkasm b/main/process-change-l2-block.zkasm index fc5cbf63..74ae4714 100644 --- a/main/process-change-l2-block.zkasm +++ b/main/process-change-l2-block.zkasm @@ -2,9 +2,9 @@ processChangeL2Block: ; checks zk-counters %MAX_CNT_POSEIDON_G - CNT_POSEIDON_G - %MAX_CNT_POSEIDON_SLOAD_SSTORE*6 :JMPN(outOfCountersPoseidon) - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 2 :JMPN(outOfCountersKeccak) + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 2 :JMPN(outOfCountersKeccak) %MAX_CNT_STEPS - STEP - 500 :JMPN(outOfCountersStep) - %MAX_CNT_BINARY - CNT_BINARY - 8 :JMPN(outOfCountersBinary) + %MAX_CNT_BINARY - CNT_BINARY - 7 :JMPN(outOfCountersBinary) ; If it is not the first transaction, we must consolidate previous block $ => A :MLOAD(currentTx) @@ -57,7 +57,7 @@ continueProcessChangeL2Block: ; - set blockHash to default $ => C :MLOAD(forcedBlockHashL1InfoTree) C :MSTORE(blockHashL1InfoTree) - $ => B :MLOAD(getForcedTimestamp) + $ => B :MLOAD(forcedTimestamp) $ :LT, JMPC(setMinTimestamp, initSetGERL1InfoTree) verifyTimestampAndL1InfoRoot: @@ -73,20 +73,72 @@ verifyTimestampAndL1InfoRoot: $ => SR :SSTORE ; check indexL1InfoTree != 0 to verify data L1InfoTree - $ :MLOAD(indexL1InfoTree), JMPZ(skipSetGERL1InfoTree) + $ => A :MLOAD(indexL1InfoTree), JMPZ(skipSetGERL1InfoTree) + ; Verify indexL1InfoTree > currentL1InfoTreeIndex + $ => B :MLOAD(currentL1InfoTreeIndex) + A - B - 1 :JMPN(invalidL1InfoTreeIndex) + ${getL1InfoGER(mem.indexL1InfoTree)} :MSTORE(gerL1InfoTree) + ${getL1InfoBlockHash(mem.indexL1InfoTree)} :MSTORE(blockHashL1InfoTree) + ${getL1InfoMinTimestamp(mem.indexL1InfoTree)} => B :MSTORE(timestampL1InfoTree) + ; Verify (currentTimestamp + deltaTimestamp) >= l1InfoRoot.timestamp + $ => A :MLOAD(timestamp) + $ :LT, JMPC(invalidChangeL2BlockMinTimestamp) + ; Compute infoTreeData + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) + 0 => HASHPOS + 32 => D + $ => A :MLOAD(gerL1InfoTree) + A :HASHK(E) + $ => A :MLOAD(blockHashL1InfoTree) + A :HASHK(E) + 8 => D + $ => A :MLOAD(timestampL1InfoTree) + A :HASHK(E) + HASHPOS :HASHKLEN(E) + ; Info tree data at C + $ => C :HASHKDIGEST(E), MSTORE(computedL1InfoTreeData) + $ => B :MLOAD(currentL1InfoTreeIndex), JMPNZ(previousL1InfoTreeIndexIsNotZero) + ; Previous L1 Info TreeIndex is zero + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) + 0 => HASHPOS + 32 => D + ${getL1HistoricRoot(mem.indexL1InfoTree)} :HASHK(E) ; historic root + $ => A :MLOAD(blockHashL1InfoTree) + C :HASHK(E) ; Info tree Data + HASHPOS :HASHKLEN(E) + ; compute "new" currentL1InfoRoot + $ => A :HASHKDIGEST(E) + ; update currentL1InfoTreeRoot + A :MSTORE(currentL1InfoTreeRoot) + $ => A :MLOAD(indexL1InfoTree) + ; Update currentL1InfoTreeIndex + A :MSTORE(currentL1InfoTreeIndex), JMP(initSetGERL1InfoTree) + +previousL1InfoTreeIndexIsNotZero: + :CALL(computeMerkleProof) ; out: [C: computed merkle root] + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 2 :JMPN(outOfCountersKeccak) + ; Compute newL1InfoTreeRoot + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) + 0 => HASHPOS + 32 => D + C :HASHK(E) ; computed merkle root + $ => C :MLOAD(computedL1InfoTreeData) + C :HASHK(E) + HASHPOS :HASHKLEN(E) + $ => A :HASHKDIGEST(E) + ; update currentL1InfoTreeRoot + A :MSTORE(currentL1InfoTreeRoot) + $ => A :MLOAD(indexL1InfoTree) + ; Update currentL1InfoTreeIndex + A :MSTORE(currentL1InfoTreeIndex), JMP(initSetGERL1InfoTree) -${getL1InfoGER(mem.indexL1InfoTree)} => A :MSTORE(gerL1InfoTree) -${getL1InfoBlockHash(mem.indexL1InfoTree)} => B :MSTORE(blockHashL1InfoTree) -${getL1InfoTimestamp(mem.indexL1InfoTree)} => C :MSTORE(timestampL1InfoTree) - :CALL(verifyMerkleProof) - ; Verify (currentTimestamp + deltaTimestamp) >= l1InfoRoot.timestamp - $ => A :MLOAD(timestamp) - $ => B :MLOAD(timestampL1InfoTree) - $ :LT, JMPC(invalidChangeL2BlockMinTimestamp, initSetGERL1InfoTree) setMinTimestamp: - ; Set getForcedTimestamp (now new Timestamp) from forced batch data + ; Set forcedTimestamp (now new Timestamp) from forced batch data %TIMESTAMP_STORAGE_POS => C %ADDRESS_SYSTEM => A B => D :MSTORE(timestamp) diff --git a/main/process-tx.zkasm b/main/process-tx.zkasm index 9d3d5b49..851aaf4e 100644 --- a/main/process-tx.zkasm +++ b/main/process-tx.zkasm @@ -149,8 +149,6 @@ add16Gas: B + 16 => B :JMP(loopBytes) endCalldataIntrinsicGas: - ; Restore current context - $ => CTX :MLOAD(currentCTX) ; Compare gas limit >= intrinsic gas $ => A :MLOAD(txGasLimit) $ :LT, JMPC(invalidIntrinsicTxGasLimit) @@ -230,6 +228,7 @@ getContractAddress: $ => A :MLOAD(isCreate2), JMPNZ(create2) ; Check keccak counters %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 1:JMPN(outOfCountersKeccak) + %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) $ => A :MLOAD(txNonce) 0x80 => B $ :LT,JMPC(nonce1byte) @@ -289,7 +288,7 @@ loopCreate2: C - 32 => C :JMP(loopCreate2) endloopCreate2: - B => E :CALL(MLOADX) + B => E :CALL(MLOADX) ; in: [E: offset, C: length] out: [A: value, E: new offset] 32 - C => D :CALL(SHRarith) C => D $ => E :MLOAD(createAddressPointer) diff --git a/main/utils.zkasm b/main/utils.zkasm index 092c38ed..71e79973 100644 --- a/main/utils.zkasm +++ b/main/utils.zkasm @@ -843,6 +843,8 @@ outOfCountersSha256: $${eventLog(onError, OOCSH)} :JMP(handleBatchError) invalidChangeL2BlockMinTimestamp: $${eventLog(onError, invalid_change_l2_block_min_timestamp)} :JMP(handleBatchError) +invalidL1InfoTreeIndex: + $${eventLog(onError, invalid_L1_info_tree_index)} :JMP(handleBatchError) outOfGas: $${eventLog(onError, OOG)} :JMP(handleError) invalidJump: @@ -1611,49 +1613,22 @@ expADend: failAssert: A - 1 :ASSERT -VAR GLOBAL tmpZkPCVerifyMerkleProof -;@info verifies L1Info data with sibilings -;@in A: ger -;@in B: blockhashL1 -;@in C: timestamp -verifyMerkleProof: +VAR GLOBAL tmpZkPCComputeMerkleProof +;@info Computes merkle root with from currentL1InfoTreeRoot, currentL1InfoTreeIndex and sibilings +;@out C: merkle tree root +computeMerkleProof: ; check zk-counters ; 1 keccak for the leaf and 32 for the L1InfoTree %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 33 :JMPN(outOfCountersKeccak) ; 7 steps at most per bit + 21 statics %MAX_CNT_STEPS - STEP - 7 * 32 - 21 :JMPN(outOfCountersStep) - RR :MSTORE(tmpZkPCVerifyMerkleProof) - - ;;;;;;;;;;;;;;;;;;;;; - ;; compute leaf value - ;;;;;;;;;;;;;;;;;;;;; - - ; new keccak address - $ => E :MLOAD(nextHashKId) - E + 1 :MSTORE(nextHashKId) - - ; add gerL1InfoTree (32 bytes) - 0 => HASHPOS - 32 => D - A :HASHK(E) - - ; add blockHashL1 (32 bytes) - B :HASHK(E) - - ; add timestamp (8 bytes) - 8 => D - C :HASHK(E) - - ; compute l1InfoTree Leaf value - HASHPOS :HASHKLEN(E) - $ => C :HASHKDIGEST(E) ; initial value - + RR :MSTORE(tmpZkPCComputeMerkleProof) ; initialization registers for smt verify 0 => D, A - $ => B :MLOAD(indexL1InfoTree) - + $ => B :MLOAD(currentL1InfoTreeIndex) + $ => C :MLOAD(currentL1InfoTreeRoot) ; prepare new hash $ => E :MLOAD(nextHashKId) E + 1 :MSTORE(nextHashKId) @@ -1668,13 +1643,13 @@ verifyMerkleProof: ${B & 0x00000001} :JMPZ(hashLeft0) hashRight0: - ${getSmtProof(mem.indexL1InfoTree, 0)} :HASHK(E+0) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 0)} :HASHK(E+0) C :HASHK(E+0) A + 0x00000001 => A :JMP(hashBranchEnd0) hashLeft0: C :HASHK(E+0) - ${getSmtProof(mem.indexL1InfoTree, 0)} :HASHK(E+0) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 0)} :HASHK(E+0) hashBranchEnd0: HASHPOS :HASHKLEN(E+0) @@ -1685,13 +1660,13 @@ hashBranchEnd0: ${B & 0x00000002} :JMPZ(hashLeft1) hashRight1: - ${getSmtProof(mem.indexL1InfoTree, 1)} :HASHK(E+1) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 1)} :HASHK(E+1) C :HASHK(E+1) A + 0x00000002 => A :JMP(hashBranchEnd1) hashLeft1: C :HASHK(E+1) - ${getSmtProof(mem.indexL1InfoTree, 1)} :HASHK(E+1) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 1)} :HASHK(E+1) hashBranchEnd1: HASHPOS :HASHKLEN(E+1) @@ -1702,13 +1677,13 @@ hashBranchEnd1: ${B & 0x00000004} :JMPZ(hashLeft2) hashRight2: - ${getSmtProof(mem.indexL1InfoTree, 2)} :HASHK(E+2) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 2)} :HASHK(E+2) C :HASHK(E+2) A + 0x00000004 => A :JMP(hashBranchEnd2) hashLeft2: C :HASHK(E+2) - ${getSmtProof(mem.indexL1InfoTree, 2)} :HASHK(E+2) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 2)} :HASHK(E+2) hashBranchEnd2: HASHPOS :HASHKLEN(E+2) @@ -1719,13 +1694,13 @@ hashBranchEnd2: ${B & 0x00000008} :JMPZ(hashLeft3) hashRight3: - ${getSmtProof(mem.indexL1InfoTree, 3)} :HASHK(E+3) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 3)} :HASHK(E+3) C :HASHK(E+3) A + 0x00000008 => A :JMP(hashBranchEnd3) hashLeft3: C :HASHK(E+3) - ${getSmtProof(mem.indexL1InfoTree, 3)} :HASHK(E+3) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 3)} :HASHK(E+3) hashBranchEnd3: HASHPOS :HASHKLEN(E+3) @@ -1736,13 +1711,13 @@ hashBranchEnd3: ${B & 0x00000010} :JMPZ(hashLeft4) hashRight4: - ${getSmtProof(mem.indexL1InfoTree, 4)} :HASHK(E+4) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 4)} :HASHK(E+4) C :HASHK(E+4) A + 0x00000010 => A :JMP(hashBranchEnd4) hashLeft4: C :HASHK(E+4) - ${getSmtProof(mem.indexL1InfoTree, 4)} :HASHK(E+4) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 4)} :HASHK(E+4) hashBranchEnd4: HASHPOS :HASHKLEN(E+4) @@ -1753,13 +1728,13 @@ hashBranchEnd4: ${B & 0x00000020} :JMPZ(hashLeft5) hashRight5: - ${getSmtProof(mem.indexL1InfoTree, 5)} :HASHK(E+5) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 5)} :HASHK(E+5) C :HASHK(E+5) A + 0x00000020 => A :JMP(hashBranchEnd5) hashLeft5: C :HASHK(E+5) - ${getSmtProof(mem.indexL1InfoTree, 5)} :HASHK(E+5) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 5)} :HASHK(E+5) hashBranchEnd5: HASHPOS :HASHKLEN(E+5) @@ -1770,13 +1745,13 @@ hashBranchEnd5: ${B & 0x00000040} :JMPZ(hashLeft6) hashRight6: - ${getSmtProof(mem.indexL1InfoTree, 6)} :HASHK(E+6) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 6)} :HASHK(E+6) C :HASHK(E+6) A + 0x00000040 => A :JMP(hashBranchEnd6) hashLeft6: C :HASHK(E+6) - ${getSmtProof(mem.indexL1InfoTree, 6)} :HASHK(E+6) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 6)} :HASHK(E+6) hashBranchEnd6: HASHPOS :HASHKLEN(E+6) @@ -1787,13 +1762,13 @@ hashBranchEnd6: ${B & 0x00000080} :JMPZ(hashLeft7) hashRight7: - ${getSmtProof(mem.indexL1InfoTree, 7)} :HASHK(E+7) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 7)} :HASHK(E+7) C :HASHK(E+7) A + 0x00000080 => A :JMP(hashBranchEnd7) hashLeft7: C :HASHK(E+7) - ${getSmtProof(mem.indexL1InfoTree, 7)} :HASHK(E+7) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 7)} :HASHK(E+7) hashBranchEnd7: HASHPOS :HASHKLEN(E+7) @@ -1804,13 +1779,13 @@ hashBranchEnd7: ${B & 0x00000100} :JMPZ(hashLeft8) hashRight8: - ${getSmtProof(mem.indexL1InfoTree, 8)} :HASHK(E+8) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 8)} :HASHK(E+8) C :HASHK(E+8) A + 0x00000100 => A :JMP(hashBranchEnd8) hashLeft8: C :HASHK(E+8) - ${getSmtProof(mem.indexL1InfoTree, 8)} :HASHK(E+8) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 8)} :HASHK(E+8) hashBranchEnd8: HASHPOS :HASHKLEN(E+8) @@ -1821,13 +1796,13 @@ hashBranchEnd8: ${B & 0x00000200} :JMPZ(hashLeft9) hashRight9: - ${getSmtProof(mem.indexL1InfoTree, 9)} :HASHK(E+9) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 9)} :HASHK(E+9) C :HASHK(E+9) A + 0x00000200 => A :JMP(hashBranchEnd9) hashLeft9: C :HASHK(E+9) - ${getSmtProof(mem.indexL1InfoTree, 9)} :HASHK(E+9) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 9)} :HASHK(E+9) hashBranchEnd9: HASHPOS :HASHKLEN(E+9) @@ -1838,13 +1813,13 @@ hashBranchEnd9: ${B & 0x00000400} :JMPZ(hashLeft10) hashRight10: - ${getSmtProof(mem.indexL1InfoTree, 10)} :HASHK(E+10) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 10)} :HASHK(E+10) C :HASHK(E+10) A + 0x00000400 => A :JMP(hashBranchEnd10) hashLeft10: C :HASHK(E+10) - ${getSmtProof(mem.indexL1InfoTree, 10)} :HASHK(E+10) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 10)} :HASHK(E+10) hashBranchEnd10: HASHPOS :HASHKLEN(E+10) @@ -1855,13 +1830,13 @@ hashBranchEnd10: ${B & 0x00000800} :JMPZ(hashLeft11) hashRight11: - ${getSmtProof(mem.indexL1InfoTree, 11)} :HASHK(E+11) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 11)} :HASHK(E+11) C :HASHK(E+11) A + 0x00000800 => A :JMP(hashBranchEnd11) hashLeft11: C :HASHK(E+11) - ${getSmtProof(mem.indexL1InfoTree, 11)} :HASHK(E+11) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 11)} :HASHK(E+11) hashBranchEnd11: HASHPOS :HASHKLEN(E+11) @@ -1873,13 +1848,13 @@ hashBranchEnd11: ${B & 0x00001000} :JMPZ(hashLeft12) hashRight12: - ${getSmtProof(mem.indexL1InfoTree, 12)} :HASHK(E+12) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 12)} :HASHK(E+12) C :HASHK(E+12) A + 0x00001000 => A :JMP(hashBranchEnd12) hashLeft12: C :HASHK(E+12) - ${getSmtProof(mem.indexL1InfoTree, 12)} :HASHK(E+12) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 12)} :HASHK(E+12) hashBranchEnd12: HASHPOS :HASHKLEN(E+12) @@ -1890,13 +1865,13 @@ hashBranchEnd12: ${B & 0x00002000} :JMPZ(hashLeft13) hashRight13: - ${getSmtProof(mem.indexL1InfoTree, 13)} :HASHK(E+13) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 13)} :HASHK(E+13) C :HASHK(E+13) A + 0x00002000 => A :JMP(hashBranchEnd13) hashLeft13: C :HASHK(E+13) - ${getSmtProof(mem.indexL1InfoTree, 13)} :HASHK(E+13) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 13)} :HASHK(E+13) hashBranchEnd13: HASHPOS :HASHKLEN(E+13) @@ -1907,13 +1882,13 @@ hashBranchEnd13: ${B & 0x00004000} :JMPZ(hashLeft14) hashRight14: - ${getSmtProof(mem.indexL1InfoTree, 14)} :HASHK(E+14) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 14)} :HASHK(E+14) C :HASHK(E+14) A + 0x00004000 => A :JMP(hashBranchEnd14) hashLeft14: C :HASHK(E+14) - ${getSmtProof(mem.indexL1InfoTree, 14)} :HASHK(E+14) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 14)} :HASHK(E+14) hashBranchEnd14: HASHPOS :HASHKLEN(E+14) @@ -1924,13 +1899,13 @@ hashBranchEnd14: ${B & 0x00008000} :JMPZ(hashLeft15) hashRight15: - ${getSmtProof(mem.indexL1InfoTree, 15)} :HASHK(E+15) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 15)} :HASHK(E+15) C :HASHK(E+15) A + 0x00008000 => A :JMP(hashBranchEnd15) hashLeft15: C :HASHK(E+15) - ${getSmtProof(mem.indexL1InfoTree, 15)} :HASHK(E+15) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 15)} :HASHK(E+15) hashBranchEnd15: HASHPOS :HASHKLEN(E+15) @@ -1941,13 +1916,13 @@ hashBranchEnd15: ${B & 0x00010000} :JMPZ(hashLeft16) hashRight16: - ${getSmtProof(mem.indexL1InfoTree, 16)} :HASHK(E+16) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 16)} :HASHK(E+16) C :HASHK(E+16) A + 0x00010000 => A :JMP(hashBranchEnd16) hashLeft16: C :HASHK(E+16) - ${getSmtProof(mem.indexL1InfoTree, 16)} :HASHK(E+16) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 16)} :HASHK(E+16) hashBranchEnd16: HASHPOS :HASHKLEN(E+16) @@ -1958,13 +1933,13 @@ hashBranchEnd16: ${B & 0x00020000} :JMPZ(hashLeft17) hashRight17: - ${getSmtProof(mem.indexL1InfoTree, 17)} :HASHK(E+17) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 17)} :HASHK(E+17) C :HASHK(E+17) A + 0x00020000 => A :JMP(hashBranchEnd17) hashLeft17: C :HASHK(E+17) - ${getSmtProof(mem.indexL1InfoTree, 17)} :HASHK(E+17) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 17)} :HASHK(E+17) hashBranchEnd17: HASHPOS :HASHKLEN(E+17) @@ -1975,13 +1950,13 @@ hashBranchEnd17: ${B & 0x00040000} :JMPZ(hashLeft18) hashRight18: - ${getSmtProof(mem.indexL1InfoTree, 18)} :HASHK(E+18) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 18)} :HASHK(E+18) C :HASHK(E+18) A + 0x00040000 => A :JMP(hashBranchEnd18) hashLeft18: C :HASHK(E+18) - ${getSmtProof(mem.indexL1InfoTree, 18)} :HASHK(E+18) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 18)} :HASHK(E+18) hashBranchEnd18: HASHPOS :HASHKLEN(E+18) @@ -1992,13 +1967,13 @@ hashBranchEnd18: ${B & 0x00080000} :JMPZ(hashLeft19) hashRight19: - ${getSmtProof(mem.indexL1InfoTree, 19)} :HASHK(E+19) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 19)} :HASHK(E+19) C :HASHK(E+19) A + 0x00080000 => A :JMP(hashBranchEnd19) hashLeft19: C :HASHK(E+19) - ${getSmtProof(mem.indexL1InfoTree, 19)} :HASHK(E+19) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 19)} :HASHK(E+19) hashBranchEnd19: HASHPOS :HASHKLEN(E+19) @@ -2009,13 +1984,13 @@ hashBranchEnd19: ${B & 0x00100000} :JMPZ(hashLeft20) hashRight20: - ${getSmtProof(mem.indexL1InfoTree, 20)} :HASHK(E+20) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 20)} :HASHK(E+20) C :HASHK(E+20) A + 0x00100000 => A :JMP(hashBranchEnd20) hashLeft20: C :HASHK(E+20) - ${getSmtProof(mem.indexL1InfoTree, 20)} :HASHK(E+20) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 20)} :HASHK(E+20) hashBranchEnd20: HASHPOS :HASHKLEN(E+20) @@ -2026,13 +2001,13 @@ hashBranchEnd20: ${B & 0x00200000} :JMPZ(hashLeft21) hashRight21: - ${getSmtProof(mem.indexL1InfoTree, 21)} :HASHK(E+21) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 21)} :HASHK(E+21) C :HASHK(E+21) A + 0x00200000 => A :JMP(hashBranchEnd21) hashLeft21: C :HASHK(E+21) - ${getSmtProof(mem.indexL1InfoTree, 21)} :HASHK(E+21) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 21)} :HASHK(E+21) hashBranchEnd21: HASHPOS :HASHKLEN(E+21) @@ -2043,13 +2018,13 @@ hashBranchEnd21: ${B & 0x00400000} :JMPZ(hashLeft22) hashRight22: - ${getSmtProof(mem.indexL1InfoTree, 22)} :HASHK(E+22) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 22)} :HASHK(E+22) C :HASHK(E+22) A + 0x00400000 => A :JMP(hashBranchEnd22) hashLeft22: C :HASHK(E+22) - ${getSmtProof(mem.indexL1InfoTree, 22)} :HASHK(E+22) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 22)} :HASHK(E+22) hashBranchEnd22: HASHPOS :HASHKLEN(E+22) @@ -2060,13 +2035,13 @@ hashBranchEnd22: ${B & 0x00800000} :JMPZ(hashLeft23) hashRight23: - ${getSmtProof(mem.indexL1InfoTree, 23)} :HASHK(E+23) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 23)} :HASHK(E+23) C :HASHK(E+23) A + 0x00800000 => A :JMP(hashBranchEnd23) hashLeft23: C :HASHK(E+23) - ${getSmtProof(mem.indexL1InfoTree, 23)} :HASHK(E+23) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 23)} :HASHK(E+23) hashBranchEnd23: HASHPOS :HASHKLEN(E+23) @@ -2077,13 +2052,13 @@ hashBranchEnd23: ${B & 0x01000000} :JMPZ(hashLeft24) hashRight24: - ${getSmtProof(mem.indexL1InfoTree, 24)} :HASHK(E+24) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 24)} :HASHK(E+24) C :HASHK(E+24) A + 0x01000000 => A :JMP(hashBranchEnd24) hashLeft24: C :HASHK(E+24) - ${getSmtProof(mem.indexL1InfoTree, 24)} :HASHK(E+24) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 24)} :HASHK(E+24) hashBranchEnd24: HASHPOS :HASHKLEN(E+24) @@ -2094,13 +2069,13 @@ hashBranchEnd24: ${B & 0x02000000} :JMPZ(hashLeft25) hashRight25: - ${getSmtProof(mem.indexL1InfoTree, 25)} :HASHK(E+25) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 25)} :HASHK(E+25) C :HASHK(E+25) A + 0x02000000 => A :JMP(hashBranchEnd25) hashLeft25: C :HASHK(E+25) - ${getSmtProof(mem.indexL1InfoTree, 25)} :HASHK(E+25) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 25)} :HASHK(E+25) hashBranchEnd25: HASHPOS :HASHKLEN(E+25) @@ -2111,13 +2086,13 @@ hashBranchEnd25: ${B & 0x04000000} :JMPZ(hashLeft26) hashRight26: - ${getSmtProof(mem.indexL1InfoTree, 26)} :HASHK(E+26) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 26)} :HASHK(E+26) C :HASHK(E+26) A + 0x04000000 => A :JMP(hashBranchEnd26) hashLeft26: C :HASHK(E+26) - ${getSmtProof(mem.indexL1InfoTree, 26)} :HASHK(E+26) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 26)} :HASHK(E+26) hashBranchEnd26: HASHPOS :HASHKLEN(E+26) @@ -2128,13 +2103,13 @@ hashBranchEnd26: ${B & 0x08000000} :JMPZ(hashLeft27) hashRight27: - ${getSmtProof(mem.indexL1InfoTree, 27)} :HASHK(E+27) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 27)} :HASHK(E+27) C :HASHK(E+27) A + 0x08000000 => A :JMP(hashBranchEnd27) hashLeft27: C :HASHK(E+27) - ${getSmtProof(mem.indexL1InfoTree, 27)} :HASHK(E+27) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 27)} :HASHK(E+27) hashBranchEnd27: HASHPOS :HASHKLEN(E+27) @@ -2145,13 +2120,13 @@ hashBranchEnd27: ${B & 0x10000000} :JMPZ(hashLeft28) hashRight28: - ${getSmtProof(mem.indexL1InfoTree, 28)} :HASHK(E+28) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 28)} :HASHK(E+28) C :HASHK(E+28) A + 0x10000000 => A :JMP(hashBranchEnd28) hashLeft28: C :HASHK(E+28) - ${getSmtProof(mem.indexL1InfoTree, 28)} :HASHK(E+28) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 28)} :HASHK(E+28) hashBranchEnd28: HASHPOS :HASHKLEN(E+28) @@ -2162,13 +2137,13 @@ hashBranchEnd28: ${B & 0x20000000} :JMPZ(hashLeft29) hashRight29: - ${getSmtProof(mem.indexL1InfoTree, 29)} :HASHK(E+29) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 29)} :HASHK(E+29) C :HASHK(E+29) A + 0x20000000 => A :JMP(hashBranchEnd29) hashLeft29: C :HASHK(E+29) - ${getSmtProof(mem.indexL1InfoTree, 29)} :HASHK(E+29) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 29)} :HASHK(E+29) hashBranchEnd29: HASHPOS :HASHKLEN(E+29) @@ -2179,13 +2154,13 @@ hashBranchEnd29: ${B & 0x40000000} :JMPZ(hashLeft30) hashRight30: - ${getSmtProof(mem.indexL1InfoTree, 30)} :HASHK(E+30) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 30)} :HASHK(E+30) C :HASHK(E+30) A + 0x40000000 => A :JMP(hashBranchEnd30) hashLeft30: C :HASHK(E+30) - ${getSmtProof(mem.indexL1InfoTree, 30)} :HASHK(E+30) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 30)} :HASHK(E+30) hashBranchEnd30: HASHPOS :HASHKLEN(E+30) @@ -2196,30 +2171,26 @@ hashBranchEnd30: ${B & 0x80000000} :JMPZ(hashLeft31) hashRight31: - ${getSmtProof(mem.indexL1InfoTree, 31)} :HASHK(E+31) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 31)} :HASHK(E+31) C :HASHK(E+31) A + 0x80000000 => A :JMP(hashBranchEnd31) hashLeft31: C :HASHK(E+31) - ${getSmtProof(mem.indexL1InfoTree, 31)} :HASHK(E+31) + ${getSmtProofPreviousIndex(mem.indexL1InfoTree, 31)} :HASHK(E+31) hashBranchEnd31: HASHPOS :HASHKLEN(E+31) + ; Merkle root at C $ => C :HASHKDIGEST(E+31) ; verify linear combination of 'indexL1InfoTree' - B :ASSERT - E + 32 => E :MSTORE(nextHashKId) - - -verifyMerkleProofEnd: - $ => A :MLOAD(l1InfoRoot) - C :ASSERT + B :ASSERT + E + 32 => E :MSTORE(nextHashKId) -verifyMerkleProofReturn: - $ => RR :MLOAD(tmpZkPCVerifyMerkleProof) - :RETURN +computeMerkleProofReturn: + $ => RR :MLOAD(tmpZkPCComputeMerkleProof) + :RETURN VAR GLOBAL tmpZkPCreadXFromOffset VAR GLOBAL readXFromCalldataOffset diff --git a/main/vars.zkasm b/main/vars.zkasm index 2a8009a0..a41d5974 100644 --- a/main/vars.zkasm +++ b/main/vars.zkasm @@ -1,27 +1,25 @@ ; Input variables VAR GLOBAL oldStateRoot ; Previous state-tree root VAR GLOBAL oldBatchAccInputHash ; Previous accumulated input hash -VAR GLOBAL oldL1InfoTreeRoot ; Previous L1 info tree root -VAR GLOBAL oldL1InfoTreeIndex ; Previous L1 info tree index -VAR GLOBAL l1InfoRoot ; Global exit-tree root +VAR GLOBAL previousL1InfoTreeRoot ; Previous L1 info tree root +VAR GLOBAL previousL1InfoTreeIndex ; Previous L1 info tree index +VAR GLOBAL currentL1InfoTreeRoot ; Current L1 info tree root +VAR GLOBAL currentL1InfoTreeIndex ; Current L1 info tree index VAR GLOBAL sequencerAddr ; Coinbase address which will receive the fees VAR GLOBAL batchHashData ; batchHashData = H_keccak( transactions ) VAR GLOBAL timestamp ; Current batch timestamp -VAR GLOBAL getForcedTimestamp ; Timestamp proposed by a forced batch +VAR GLOBAL forcedTimestamp ; Timestamp proposed by a forced batch VAR GLOBAL forcedGER ; GER proposed by a forced batch VAR GLOBAL forcedBlockHashL1InfoTree ; BlockHashL1 of the forced batch VAR GLOBAL chainID ; Current batch chain id VAR GLOBAL forkID ; Fork identifier VAR GLOBAL isForced ; Flag to determine if the batch is forced VAR GLOBAL cumulativeGasUsed ; cumulative gas used in the block -VAR GLOBAL forcedHashData ; solidtykeccak256(abi.encode(GER, blockHashL1, getForcedTimestamp)) +VAR GLOBAL forcedHashData ; solidtykeccak256(abi.encode(GER, blockHashL1, forcedTimestamp)) VAR GLOBAL type ; Type of the batch 0: data-availability comes from calldata, 1: data-availability comes from blob transaction, 2: forced blob (data-availability comes from calldata -VAR GLOBAL L1LeafHash ; Hash of the new L1 leaf of the exit tree ; Output variables VAR GLOBAL newBatchAccInputHash ; Final accumulated input hash. newBatchAccInputHash = H_keccak( oldAccBathHashData | batchHashData | forcedHashData | sequencerAddr ) -VAR GLOBAL l1InfoTreeIndex ; New L1 info tree index VAR GLOBAL newLocalExitRoot ; Updated local exit tree root -VAR GLOBAL newNumBatch ; Current batch processed VAR GLOBAL batchL2DataParsed ; Number of bytes read when decoding RLP transactions. Computed during RLP loop VAR GLOBAL pendingTxs ; Number of transactions decoded in RLP block @@ -115,6 +113,7 @@ VAR CTX initLogIndex ; log index once a new context begins VAR CTX deltaTimestamp ; delta timestamp of the current change L2 block tx VAR CTX indexL1InfoTree ; indexL1InfoTree of the current change L2 block tx VAR CTX gerL1InfoTree ; new GER of the current change L2 block tx +VAR CTX computedL1InfoTreeData ; solidtykeccak256(GER, blockHashL1, timestamp) VAR CTX blockHashL1InfoTree ; new BlockhashL1 of the current change L2 block tx VAR CTX timestampL1InfoTree ; new timestamp of the current change L2 block tx VAR CTX isChangeL2BlockTx ; flag to determine if the current tx is a change L2 block tx diff --git a/package.json b/package.json index c962f0cc..a4a1beed 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ }, "devDependencies": { "@0xpolygonhermez/zkevm-commonjs": "github:0xPolygonHermez/zkevm-commonjs#develop-feijoa", - "@0xpolygonhermez/zkevm-proverjs": "github:0xPolygonHermez/zkevm-proverjs#feature/feijoa-batch", + "@0xpolygonhermez/zkevm-proverjs": "github:0xPolygonHermez/zkevm-proverjs#feature/batch-feijoa", "@0xpolygonhermez/zkevm-testvectors": "github:0xPolygonHermez/zkevm-testvectors#feature/feijoa-batch", "chai": "^4.3.6", "chalk": "^3.0.0", diff --git a/test/performance/read-push.zkasm b/test/performance/read-push.zkasm index 81d57f44..439b7232 100644 --- a/test/performance/read-push.zkasm +++ b/test/performance/read-push.zkasm @@ -18,9 +18,10 @@ start: 0x2122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F40n => A :CALL(initLoop) 0x4142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60n => A :CALL(initLoop) + 0 => E ; close hash - HASHPOS :HASHPLEN(0) - $ :HASHPDIGEST(0) + HASHPOS :HASHPLEN(E) + $ :HASHPDIGEST(E) 0 :MSTORE(contractHashId) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -61,7 +62,8 @@ initLoop: 0 => B ; to allow $$ loopAdd32Byte: - ${(A >> (rounds * 8)) & 0xFF} :HASHP1(0) + 0 => E + ${(A >> (rounds * 8)) & 0xFF} :HASHP1(E) $${rounds = rounds - 1} ${rounds} :JMPZ(endLoop, loopAdd32Byte) diff --git a/test/read-push.zkasm b/test/read-push.zkasm index 32358b8f..2aadd966 100644 --- a/test/read-push.zkasm +++ b/test/read-push.zkasm @@ -18,9 +18,10 @@ start: 0x2122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F40n => A :CALL(initLoop) 0x4142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60n => A :CALL(initLoop) + 0 => E ; close hash - HASHPOS :HASHPLEN(0) - $ :HASHPDIGEST(0) + HASHPOS :HASHPLEN(E) + $ :HASHPDIGEST(E) 0 :MSTORE(contractHashId) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -295,7 +296,8 @@ initLoop: loopAdd32Byte: $${rounds = rounds - 1} - ${(A >> (rounds * 8)) & 0xFF} => E :HASHP1(0) + 0 => E + ${(A >> (rounds * 8)) & 0xFF} => E :HASHP1(E) ${rounds} :JMPZ(endLoop, loopAdd32Byte) endLoop: From 8b27fd19d019b6b5b2c809c1427669dc86dc37df Mon Sep 17 00:00:00 2001 From: Ignasi Date: Wed, 20 Mar 2024 10:25:14 +0100 Subject: [PATCH 07/16] First review fixes --- main/end.zkasm | 4 +- main/load-tx-rlp-utils.zkasm | 1 + main/load-tx-rlp.zkasm | 19 +++---- main/main.zkasm | 66 ++++++++++++------------ main/process-change-l2-block-utils.zkasm | 51 ++++++++++++++++++ main/process-change-l2-block.zkasm | 60 +++++---------------- main/process-tx.zkasm | 11 ++-- main/vars.zkasm | 2 +- 8 files changed, 111 insertions(+), 103 deletions(-) create mode 100644 main/process-change-l2-block-utils.zkasm diff --git a/main/end.zkasm b/main/end.zkasm index 448fb7fb..af6b875a 100644 --- a/main/end.zkasm +++ b/main/end.zkasm @@ -1,6 +1,4 @@ finalWait: ${beforeLast()} :JMPN(finalWait) ; Set registers to its initials values - $ => SR :RESTORE - ; Set all registers to 0 except inputs: SR (oldStateRoot), C (oldBatchAccInputHash), D (previousL1InfoTreeRoot), RCX (previousL1InfoTreeIndex), GAS (chainID) & CTX (forkID) - 0 => A, B, E, PC, SP, HASHPOS, RR, zkPC :JMP(start) \ No newline at end of file + $ => SR :RESTORE, JMP(start) \ No newline at end of file diff --git a/main/load-tx-rlp-utils.zkasm b/main/load-tx-rlp-utils.zkasm index 75d2956b..037ad892 100644 --- a/main/load-tx-rlp-utils.zkasm +++ b/main/load-tx-rlp-utils.zkasm @@ -17,6 +17,7 @@ getBatchL2DataBytes: ;; 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) diff --git a/main/load-tx-rlp.zkasm b/main/load-tx-rlp.zkasm index 2f909b17..81186c88 100644 --- a/main/load-tx-rlp.zkasm +++ b/main/load-tx-rlp.zkasm @@ -76,16 +76,10 @@ shortList: A - 0xc0 => A endList: - A + C => B :MSTORE(txRLPLength) - ; Check enough keccak zk counters to digest tx hash - ; We don't check poseidon counters spent for l2 tx hash computing because the number of poseidon counters available is x100 the number of keccak available - ; so while rlp parsing, keccaks will always be the bottleneck - ; CHECK: we can assume we will always have enough keccaks at this point of batch processing, so maybe there is no need to check - B + 1 :MSTORE(arithA) - 136 :MSTORE(arithB), CALL(divARITH); in: [arithA, arithB] out: [arithRes1: arithA/arithB, arithRes2: arithA%arithB] - $ => B :MLOAD(arithRes1) - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - B - 1 :JMPN(outOfCountersKeccak) - :CALL (initL2HashTx) + ; We can assume we will always have enough keccaks at this point of batch processing, so there is no need to check outOfCountersKeccak. + ; Max amount of bytes is 120k and this is the first hashkdigest of the batch so max consumed keccaks is 120k / 136 = 883 keccaks << keccaks available (2257) + ; In case malicious prover lies in the rlp length, the batch will be discarded after reaching this max length (120 kb) + A + C => B :MSTORE(txRLPLength), CALL (initL2HashTx) ;; Read RLP 'nonce' ; 64 bits max @@ -231,7 +225,7 @@ shortData: :JMP(readData) longData: - A - 0xb7 => D :CALL(addHashTxFromFreeInput) + A - 0xb7 => D :CALL(addHashTx) :CALL(checkLongRLP) :CALL(checkNonLeadingZeros) $ => D :MLOAD(batchHashPos) @@ -257,6 +251,7 @@ readDataFinal: B - 1 :JMPN(endData) B => D :CALL(addHashTxFromFreeInput) :CALL(addL2HashTx) + ; WARNING: check checkShortDataRLP correctness :CALL(checkShortDataRLP) 32 - D => D :CALL(SHLarith); in: [A: value, D: #bytes to left shift] out: [A: shifted result] $ => E :MLOAD(globalCalldataMemoryOffset) @@ -307,7 +302,6 @@ endChainId: setPreEIP155Flag: 1 :MSTORE(isPreEIP155) - $ => E :MLOAD(txHashPointer) ;; size verification ; checks RLP length read at the RLP header with bytes read during RLP parsing sizeVerification: @@ -315,6 +309,7 @@ sizeVerification: $ => B :MLOAD(txRLPLength) C - B :JMPZ(sizeVerificationSuccess, invalidTxRLP) sizeVerificationSuccess: + $ => E :MLOAD(txHashPointer) HASHPOS :HASHKLEN(E) ;;;;;;;;;;;;;;;;;; diff --git a/main/main.zkasm b/main/main.zkasm index 874732c1..9607f8a6 100644 --- a/main/main.zkasm +++ b/main/main.zkasm @@ -33,7 +33,7 @@ start: ; main zkROM entry point GAS :MSTORE(chainID) ; chainID from GAS, assumed to be less than 32 bits ${getSequencerAddr()} :MSTORE(sequencerAddr) - ${getTxsLen()} :MSTORE(batchL2DataLength) ; less than 120000 bytes. Enforced by the smart contract + $0{getTxsLen()} :MSTORE(batchL2DataLength) ; less than 120000 bytes. Enforced by the smart contract ${getBatchHashData()} :MSTORE(batchHashData) $0{getType()} => A :MSTORE(type) @@ -105,20 +105,18 @@ computeNewBatchAccInputHash: $ => HASHPOS :MLOAD(batchL2DataLength) HASHPOS :HASHPLEN(E) - ;; Get local exit root - ; Read 'localExitRoot' variable from GLOBAL_EXIT_ROOT_MANAGER_L2 and store - ; it to the 'newLocalExitRoot' input, will be used to compute newBatchAccInputHash - %ADDRESS_GLOBAL_EXIT_ROOT_MANAGER_L2 => A - %SMT_KEY_SC_STORAGE => B - %LOCAL_EXIT_ROOT_STORAGE_POS => C - $ => A :SLOAD - A :MSTORE(newLocalExitRoot) - ; Load current timestamp %TIMESTAMP_STORAGE_POS => C %ADDRESS_SYSTEM => A %SMT_KEY_SC_STORAGE => B $ => A :SLOAD, MSTORE(timestamp) + +setBlockNum: + %LAST_BLOCK_STORAGE_POS => C + %ADDRESS_SYSTEM => A + %SMT_KEY_SC_STORAGE => B + $ => A :SLOAD,MSTORE(blockNum) + ;;;;;;;;;;;;;;;;;; ;; C - Loop parsing RLP transactions ;; - Load transaction RLP data and ensure it has correct RLP encoding @@ -134,22 +132,15 @@ txLoopRLP: ; If batchL2DataLength is zero, we finalize batch $ => A :MLOAD(batchL2DataLength), JMPZ(finalizeBatch) $ => C :MLOAD(batchL2DataParsed) - C - A :JMPN(loadTx_rlp, setBlockNum) + C - A :JMPN(loadTx_rlp) ;;;;;;;;;;;;;;;;;; -;; D - Load blockNum variable -;; - Loop processing transactions +;; D - Loop processing transactions ;; - Load transaction data and interpret it ;;;;;;;;;;;;;;;;;; -setBlockNum: - %LAST_BLOCK_STORAGE_POS => C - %ADDRESS_SYSTEM => A - %SMT_KEY_SC_STORAGE => B - $ => A :SLOAD,MSTORE(blockNum) ; If forced batch ==> process a forced changeL2BlockTx $ :MLOAD(isForced), JMPZ(txLoop, handleForcedBatch) - handleForcedBatch: 1 :MSTORE(currentTx), JMP(processChangeL2Block) @@ -188,12 +179,32 @@ finalizeBatch: ;; E - Finalize execution: set output values at corresponding registers ;;;;;;;;;;;;;;;;;; $${eventLog(onFinishBatch)} + ; Retrieve newLocalExitRoot + ; Read 'localExitRoot' variable from GLOBAL_EXIT_ROOT_MANAGER_L2 and store + ; it to the 'newLocalExitRoot' var + %MAX_CNT_POSEIDON_G - CNT_POSEIDON_G - %MAX_CNT_POSEIDON_SLOAD_SSTORE :JMPN(outOfCountersPoseidon) + %ADDRESS_GLOBAL_EXIT_ROOT_MANAGER_L2 => A + %SMT_KEY_SC_STORAGE => B + %LOCAL_EXIT_ROOT_STORAGE_POS => C + $ => A :SLOAD + A :MSTORE(newLocalExitRoot) -;;;;;;;;;;;;;;;;;; -;; F - 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 + $ => SR :MLOAD(oldStateRoot) ; oldStateRoot from SR + $ => C :MLOAD(oldBatchAccInputHash) ; oldBatchAccInputHash from C + $ => D :MLOAD(previousL1InfoTreeRoot) ; previousL1InfoTreeRoot from D + $ => RCX :MLOAD(previousL1InfoTreeIndex) ; previousL1InfoTreeIndex from E + ; Set all registers to 0 except inputs: SR (oldStateRoot), C (oldBatchAccInputHash), D (previousL1InfoTreeRoot), RCX (previousL1InfoTreeIndex), GAS (chainID) & CTX (forkID) + 0 => A, B, E, PC, SP, HASHPOS, RR, zkPC + SR :SAVE(B,C,D,E,RR,RCX) + $ => CTX :MLOAD(forkID) + $ => GAS :MLOAD(chainID) + ; Set output registers ; safety check that the output root is indeed inside the range limit of 4 goldilocks fields elements + $ => SR :MLOAD(auxNewSR) ; newStateRoot at SR SR => A ; newStateRoot at A %FOUR_GOLDILOCKS => B 1 :LT4 @@ -205,18 +216,7 @@ finalizeBatch: $ => C :MLOAD(newBatchAccInputHash) ; newBatchAccInputHash at C $ => E :MLOAD(newLocalExitRoot) ; NewLocalExitRoot at E ; SR is already at SR reg - - ; Set registers to its initials values - $ => CTX :MLOAD(forkID) - $ => GAS :MLOAD(chainID) - finalizeExecution: - ; Save inputs to RESTORE at last - 1 step - $ => SR :MLOAD(oldStateRoot) ; oldStateRoot from SR - $ => C :MLOAD(oldBatchAccInputHash) ; oldBatchAccInputHash from C - $ => D :MLOAD(previousL1InfoTreeRoot) ; previousL1InfoTreeRoot from D - $ => RCX :MLOAD(previousL1InfoTreeIndex) ; previousL1InfoTreeIndex from E - SR :SAVE(B,C,D,E,RR,RCX) :JMP(finalWait) INCLUDE "end.zkasm" diff --git a/main/process-change-l2-block-utils.zkasm b/main/process-change-l2-block-utils.zkasm new file mode 100644 index 00000000..8c876906 --- /dev/null +++ b/main/process-change-l2-block-utils.zkasm @@ -0,0 +1,51 @@ +; Computes L1InfoTree leaf value computedL1InfoTreeData = keccak(gerL1InfoTree, blockHashL1InfoTree, timestampL1InfoTree) +computeL1InfoTreeValue: + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 1 :JMPN(outOfCountersKeccak) + + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) + 0 => HASHPOS + 32 => D + $ => A :MLOAD(gerL1InfoTree) + A :HASHK(E) + $ => A :MLOAD(blockHashL1InfoTree) + A :HASHK(E) + 8 => D + $ => A :MLOAD(timestampL1InfoTree) + A :HASHK(E) + HASHPOS :HASHKLEN(E) + ; Info tree data at C + $ => C :HASHKDIGEST(E), MSTORE(computedL1InfoTreeData), RETURN + +; compute "new" currentL1InfoRoot from historicRoot, currentL1InfoTreeRoot = keccak(HistoricRoot, blockHashL1InfoTree) +computeNewCurrentL1InfoRootFromHistoric: + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 1 :JMPN(outOfCountersKeccak) + + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) + 0 => HASHPOS + 32 => D + ${getL1HistoricRoot(mem.indexL1InfoTree)} :HASHK(E) ; historic root + $ => A :MLOAD(blockHashL1InfoTree) + C :HASHK(E) ; Info tree Data + HASHPOS :HASHKLEN(E) + ; compute "new" currentL1InfoRoot + $ => A :HASHKDIGEST(E) + ; update currentL1InfoTreeRoot + A :MSTORE(currentL1InfoTreeRoot), RETURN + +; compute "new" currentL1InfoRoot from computed merkle root, currentL1InfoTreeRoot = keccak(computedMerkleRoot, computedL1InfoTreeData) +; @in C: computed merkle root +computeNewCurrentL1InfoRoot: + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 1 :JMPN(outOfCountersKeccak) + $ => E :MLOAD(nextHashKId) + E + 1 :MSTORE(nextHashKId) + 0 => HASHPOS + 32 => D + C :HASHK(E) ; computed merkle root + $ => C :MLOAD(computedL1InfoTreeData) + C :HASHK(E) + HASHPOS :HASHKLEN(E) + $ => A :HASHKDIGEST(E) + ; update currentL1InfoTreeRoot + A :MSTORE(currentL1InfoTreeRoot), RETURN diff --git a/main/process-change-l2-block.zkasm b/main/process-change-l2-block.zkasm index 74ae4714..caa5033d 100644 --- a/main/process-change-l2-block.zkasm +++ b/main/process-change-l2-block.zkasm @@ -2,7 +2,7 @@ processChangeL2Block: ; checks zk-counters %MAX_CNT_POSEIDON_G - CNT_POSEIDON_G - %MAX_CNT_POSEIDON_SLOAD_SSTORE*6 :JMPN(outOfCountersPoseidon) - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 2 :JMPN(outOfCountersKeccak) + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 1 :JMPN(outOfCountersKeccak) %MAX_CNT_STEPS - STEP - 500 :JMPN(outOfCountersStep) %MAX_CNT_BINARY - CNT_BINARY - 7 :JMPN(outOfCountersBinary) @@ -58,7 +58,7 @@ continueProcessChangeL2Block: $ => C :MLOAD(forcedBlockHashL1InfoTree) C :MSTORE(blockHashL1InfoTree) $ => B :MLOAD(forcedTimestamp) - $ :LT, JMPC(setMinTimestamp, initSetGERL1InfoTree) + $ :LT, JMPC(setNewTimestamp, initSetGERL1InfoTree) verifyTimestampAndL1InfoRoot: $ => B :MLOAD(deltaTimestamp) @@ -79,65 +79,28 @@ verifyTimestampAndL1InfoRoot: A - B - 1 :JMPN(invalidL1InfoTreeIndex) ${getL1InfoGER(mem.indexL1InfoTree)} :MSTORE(gerL1InfoTree) ${getL1InfoBlockHash(mem.indexL1InfoTree)} :MSTORE(blockHashL1InfoTree) - ${getL1InfoMinTimestamp(mem.indexL1InfoTree)} => B :MSTORE(timestampL1InfoTree) + ${getL1InfoMinTimestamp(mem.indexL1InfoTree)} => B :MSTORE(timestampL1InfoTree) ; Verify (currentTimestamp + deltaTimestamp) >= l1InfoRoot.timestamp $ => A :MLOAD(timestamp) $ :LT, JMPC(invalidChangeL2BlockMinTimestamp) ; Compute infoTreeData - $ => E :MLOAD(nextHashKId) - E + 1 :MSTORE(nextHashKId) - 0 => HASHPOS - 32 => D - $ => A :MLOAD(gerL1InfoTree) - A :HASHK(E) - $ => A :MLOAD(blockHashL1InfoTree) - A :HASHK(E) - 8 => D - $ => A :MLOAD(timestampL1InfoTree) - A :HASHK(E) - HASHPOS :HASHKLEN(E) - ; Info tree data at C - $ => C :HASHKDIGEST(E), MSTORE(computedL1InfoTreeData) + :CALL(computeL1InfoTreeValue) $ => B :MLOAD(currentL1InfoTreeIndex), JMPNZ(previousL1InfoTreeIndexIsNotZero) - ; Previous L1 Info TreeIndex is zero - $ => E :MLOAD(nextHashKId) - E + 1 :MSTORE(nextHashKId) - 0 => HASHPOS - 32 => D - ${getL1HistoricRoot(mem.indexL1InfoTree)} :HASHK(E) ; historic root - $ => A :MLOAD(blockHashL1InfoTree) - C :HASHK(E) ; Info tree Data - HASHPOS :HASHKLEN(E) - ; compute "new" currentL1InfoRoot - $ => A :HASHKDIGEST(E) - ; update currentL1InfoTreeRoot - A :MSTORE(currentL1InfoTreeRoot) + ; if previous L1 Info TreeIndex is zero, currentL1InfoTreeRoot = keccak(HistoricRoot, blockHashL1InfoTree) + :CALL(computeNewCurrentL1InfoRootFromHistoric) $ => A :MLOAD(indexL1InfoTree) ; Update currentL1InfoTreeIndex A :MSTORE(currentL1InfoTreeIndex), JMP(initSetGERL1InfoTree) previousL1InfoTreeIndexIsNotZero: :CALL(computeMerkleProof) ; out: [C: computed merkle root] - %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 2 :JMPN(outOfCountersKeccak) ; Compute newL1InfoTreeRoot - $ => E :MLOAD(nextHashKId) - E + 1 :MSTORE(nextHashKId) - 0 => HASHPOS - 32 => D - C :HASHK(E) ; computed merkle root - $ => C :MLOAD(computedL1InfoTreeData) - C :HASHK(E) - HASHPOS :HASHKLEN(E) - $ => A :HASHKDIGEST(E) - ; update currentL1InfoTreeRoot - A :MSTORE(currentL1InfoTreeRoot) - $ => A :MLOAD(indexL1InfoTree) + :CALL(computeNewCurrentL1InfoRoot) ; Update currentL1InfoTreeIndex + $ => A :MLOAD(indexL1InfoTree) A :MSTORE(currentL1InfoTreeIndex), JMP(initSetGERL1InfoTree) - - -setMinTimestamp: +setNewTimestamp: ; Set forcedTimestamp (now new Timestamp) from forced batch data %TIMESTAMP_STORAGE_POS => C %ADDRESS_SYSTEM => A @@ -154,6 +117,7 @@ initSetGERL1InfoTree: A :MSTORE(gerL1InfoTree) setGERL1InfoTree: + %MAX_CNT_KECCAK_F - CNT_KECCAK_F - 1 :JMPN(outOfCountersKeccak) 0 => B ; Do not set if zero $ :EQ, JMPC(skipSetGERL1InfoTree) @@ -183,4 +147,6 @@ setGERL1InfoTree: skipSetGERL1InfoTree: :CALL(setupNewBlockInfoTree) - :JMP(txLoop) \ No newline at end of file + :JMP(txLoop) + +INCLUDE "process-change-l2-block-utils.zkasm" \ No newline at end of file diff --git a/main/process-tx.zkasm b/main/process-tx.zkasm index 851aaf4e..6a82c73b 100644 --- a/main/process-tx.zkasm +++ b/main/process-tx.zkasm @@ -359,12 +359,10 @@ deploy: ;; read calldata bytes of a deploy transaction and process them readDeployBytecode: ; check transaction is a deploy transaction - $ => B :MLOAD(isCreate), JMPNZ(readDeployBytecodeCreate) + $ :MLOAD(isCreate), JMPNZ(readDeployBytecodeCreate) ; check enough bytes to read in calldata - $ => B :MLOAD(txCalldataLen) - B - PC - 1 :JMPN(defaultOpCode) - $ => HASHPOS :MLOAD(dataStarts) - HASHPOS + PC => HASHPOS + $ - PC - 1 :F_MLOAD(txCalldataLen), JMPN(defaultOpCode) + $ + PC => HASHPOS :F_MLOAD(dataStarts) $ => E :MLOAD(batchHashDataPointer) $ => RR :HASHP1(E) $${eventLog(onOpcode(RR))} @@ -377,8 +375,7 @@ readDeployBytecodeCreate: $ => CTX :MLOAD(originCTX) ; check enough bytes to read in memory E - PC - 1 :JMPN(readDeployBytecodeCreateDefault) - $ => E :MLOAD(argsOffsetCall) - E + PC => E + $ + PC => E :F_MLOAD(argsOffsetCall) 1 => C :CALL(MLOADX) ; in: [E: offset, C: length] out: [A: value, E: new offset] $ => CTX :MLOAD(currentCTX) 31 => D :CALL(SHRarith) ; in: [A: value, D: #bytes to right shift] out: [A: shifted result] diff --git a/main/vars.zkasm b/main/vars.zkasm index a41d5974..37c3213e 100644 --- a/main/vars.zkasm +++ b/main/vars.zkasm @@ -49,7 +49,7 @@ VAR GLOBAL batchSR ; State root before processing any transaction VAR GLOBAL blockNum ; Current block number VAR GLOBAL previousBlockHash ; Previous block hash VAR GLOBAL currentTx ; Current tx index in batch - +VAR GLOBAL auxNewSR ; auxiliary variable, used to store final SR at outputs phase VAR GLOBAL blockInfoSR ; block info tree root VAR GLOBAL touchedSR ; touched tree root VAR GLOBAL numTopics ; number of topics depending on LOG opcode call From b10a9ddfa298c9a3f89368f0deba2f90fe856a6c Mon Sep 17 00:00:00 2001 From: Ignasi Date: Wed, 20 Mar 2024 13:41:34 +0100 Subject: [PATCH 08/16] Remove getTxs free input --- main/load-tx-rlp-utils.zkasm | 285 +++++++++++++++++++++++++++++++---- main/load-tx-rlp.zkasm | 4 +- main/main.zkasm | 17 ++- main/process-tx.zkasm | 4 +- main/vars.zkasm | 1 + 5 files changed, 277 insertions(+), 34 deletions(-) diff --git a/main/load-tx-rlp-utils.zkasm b/main/load-tx-rlp-utils.zkasm index 037ad892..5c4d202d 100644 --- a/main/load-tx-rlp-utils.zkasm +++ b/main/load-tx-rlp-utils.zkasm @@ -38,41 +38,268 @@ addHashTxBegin: ; It's done byte by byte to get 1 byte access to hashp during execution ;; - 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)) -addHashTxFromFreeInput: +; @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) $ => B :MLOAD(batchL2DataParsed) - A - B - C - D :JMPN(invalidTxRLP) - B + C => A - ; Read data from free input - ${getTxs(A,D)} => A, B - $ => E :MLOAD(txHashPointer) - C => HASHPOS - ; Insert data into txhash (hashk) - A :HASHK(E) - C + D => C ; Save current registers - A :SAVE(B,C,D,E,RR,RCX) - $ => E :MLOAD(batchHashDataPointer) + A - B - C - D :JMPN(invalidTxRLP), SAVE(B,C,D,E,RR,RCX) $ => HASHPOS :MLOAD(batchHashPos) - 1 => C ; Current pointer - D => RCX ; total bytes - ; Set default remainder to 0, in case SHRarith is not using arithDiv because is shifting zero bytes - 0 :MSTORE(arithRes2) - ; Validate free input -validateFreeInputLoop: - RCX - C :JMPN(validateFreeInputLoopEnd) - ; Get free input byte by byte - RCX - C => D :CALL(SHRarith) ; in: [A: value, D: #bytes to right shift] out: [A: shifted result] - $ :HASHP1(E), ASSERT - ; The remainder of divArith used at SHRarith is the following bytes I want to check - $ => A :MLOAD(arithRes2) - C + 1 => C :JMP(validateFreeInputLoop) -validateFreeInputLoopEnd: - HASHPOS :MSTORE(batchHashPos) - $ => A :RESTORE - C => HASHPOS :RETURN + D => E +readHash: + :JMP(@readHash+E) + :JMP(_readHash1) ;1 + :JMP(_readHash2) ;2 + :JMP(_readHash3) ;3 + :JMP(_readHash4) ;4 + :JMP(_readHashX) ;5 + :JMP(_readHashX) ;6 + :JMP(_readHashX) ;7 + :JMP(_readHashX) ;8 + :JMP(_readHashX) ;9 + :JMP(_readHashX) ;10 + :JMP(_readHashX) ;11 + :JMP(_readHashX) ;12 + :JMP(_readHashX) ;13 + :JMP(_readHashX) ;14 + :JMP(_readHashX) ;15 + :JMP(_readHashX) ;16 + :JMP(_readHashX) ;17 + :JMP(_readHashX) ;18 + :JMP(_readHashX) ;19 + :JMP(_readHashX) ;20 + :JMP(_readHashX) ;21 + :JMP(_readHashX) ;22 + :JMP(_readHashX) ;23 + :JMP(_readHashX) ;24 + :JMP(_readHashX) ;25 + :JMP(_readHashX) ;26 + :JMP(_readHashX) ;27 + :JMP(_readHashX) ;28 + :JMP(_readHashX) ;29 + :JMP(_readHashX) ;30 + :JMP(_readHashX) ;31 + :JMP(_readHash32) ;32 + +finishReadHash: +HASHPOS :MSTORE(batchHashPos), RESTORE +$ => E :MLOAD(txHashPointer) +C => HASHPOS +; Insert data into txhash (hashk) +A :HASHK(E) +C + D => C :RETURN + +_readHash1: + $ => E :MLOAD(batchHashDataPointer) + $ => A :HASHP1(E), JMP(finishReadHash) + +_readHash2: + $ => E :MLOAD(batchHashDataPointer) + $ => C :HASHP1(E) + $ => E :HASHP1(E) + C * 256 + E => A :JMP(finishReadHash) + +_readHash3: + $ => E :MLOAD(batchHashDataPointer) + $ => A :HASHP1(E) + $ => C :HASHP1(E) + $ => E :HASHP1(E) + A * 2**16 + C * 2**8 + E => A :JMP(finishReadHash) + +_readHash4: + $ => E :MLOAD(batchHashDataPointer) + $ => A :HASHP1(E) + $ => B :HASHP1(E) + $ => C :HASHP1(E) + $ => E :HASHP1(E) + A * 2**24 + B * 2**16 + C * 2**8 + E => A :JMP(finishReadHash) + +_readHash32: + $ => E :MLOAD(batchHashDataPointer) + $ => B :HASHP1(E) + $ => RCX :HASHP1(E) + $ => D :HASHP1(E) + $ => A :HASHP1(E) + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + + ; 28 bytes + + $ => B :HASHP1(E) + $ => RCX :HASHP1(E) + $ => D :HASHP1(E) + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + + ; 24 bytes + + $ => B :HASHP1(E) + $ => RCX :HASHP1(E) + $ => D :HASHP1(E) + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + + ; 20 bytes + + $ => B :HASHP1(E) + $ => RCX :HASHP1(E) + $ => D :HASHP1(E) + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + + ; 16 bytes + + $ => B :HASHP1(E) + $ => RCX :HASHP1(E) + $ => D :HASHP1(E) + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + + ; 12 bytes + + $ => B :HASHP1(E) + $ => RCX :HASHP1(E) + $ => D :HASHP1(E) + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + + ; 8 bytes + + $ => B :HASHP1(E) + $ => RCX :HASHP1(E) + $ => D :HASHP1(E) + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + + ; 4 bytes + + $ => B :HASHP1(E) + $ => RCX :HASHP1(E) + $ => D :HASHP1(E) + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => A :JMP(finishReadHash) + + +_readHashX: + $ => B :MLOAD(batchHashDataPointer) + +readHashBytes: + B => E :JMP(@readHashBytes + E) + + 0 => RCX, B, D, A, C :JMP(readHashBytes_1) + 0 => RCX, B, D, A, C :JMP(readHashBytes_2) + 0 => RCX, B, D, A, C :JMP(readHashBytes_3) + 0 => RCX, B, D, A, C :JMP(readHashBytes_4) + 0 => RCX, B, D, A, C :JMP(readHashBytes_5) + 0 => RCX, B, D, A, C :JMP(readHashBytes_6) + 0 => RCX, B, D, A, C :JMP(readHashBytes_7) + 0 => RCX, B, D, A, C :JMP(readHashBytes_8) + 0 => RCX, B, D, A, C :JMP(readHashBytes_9) + 0 => RCX, B, D, A, C :JMP(readHashBytes_10) + 0 => RCX, B, D, A, C :JMP(readHashBytes_11) + 0 => RCX, B, D, A, C :JMP(readHashBytes_12) + 0 => RCX, B, D, A, C :JMP(readHashBytes_13) + 0 => RCX, B, D, A, C :JMP(readHashBytes_14) + 0 => RCX, B, D, A, C :JMP(readHashBytes_15) + 0 => RCX, B, D, A, C :JMP(readHashBytes_16) + 0 => RCX, B, D, A, C :JMP(readHashBytes_17) + 0 => RCX, B, D, A, C :JMP(readHashBytes_18) + 0 => RCX, B, D, A, C :JMP(readHashBytes_19) + 0 => RCX, B, D, A, C :JMP(readHashBytes_20) + 0 => RCX, B, D, A, C :JMP(readHashBytes_21) + 0 => RCX, B, D, A, C :JMP(readHashBytes_22) + 0 => RCX, B, D, A, C :JMP(readHashBytes_23) + 0 => RCX, B, D, A, C :JMP(readHashBytes_24) + 0 => RCX, B, D, A, C :JMP(readHashBytes_25) + 0 => RCX, B, D, A, C :JMP(readHashBytes_26) + 0 => RCX, B, D, A, C :JMP(readHashBytes_27) + 0 => RCX, B, D, A, C :JMP(readHashBytes_28) + 0 => RCX, B, D, A, C :JMP(readHashBytes_29) + 0 => RCX, B, D, A, C :JMP(readHashBytes_30) + 0 => RCX, B, D, A, C :JMP(readHashBytes_31) + 0 => RCX, B, D, A, C :JMP(readHashBytes_32) + +readHashBytes_32: + $ => B :HASHP1(E) +readHashBytes_31: + $ => RCX :HASHP1(E) +readHashBytes_30: + $ => D :HASHP1(E) +readHashBytes_29: + $ => A :HASHP1(E) + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + +readHashBytes_28: + $ => B :HASHP1(E) +readHashBytes_27: + $ => RCX :HASHP1(E) +readHashBytes_26: + $ => D :HASHP1(E) +readHashBytes_25: + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + +readHashBytes_24: + $ => B :HASHP1(E) +readHashBytes_23: + $ => RCX :HASHP1(E) +readHashBytes_22: + $ => D :HASHP1(E) +readHashBytes_21: + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + +readHashBytes_20: + $ => B :HASHP1(E) +readHashBytes_19: + $ => RCX :HASHP1(E) +readHashBytes_18: + $ => D :HASHP1(E) +readHashBytes_17: + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + +readHashBytes_16: + $ => B :HASHP1(E) +readHashBytes_15: + $ => RCX :HASHP1(E) +readHashBytes_14: + $ => D :HASHP1(E) +readHashBytes_13: + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + +readHashBytes_12: + $ => B :HASHP1(E) +readHashBytes_11: + $ => RCX :HASHP1(E) +readHashBytes_10: + $ => D :HASHP1(E) +readHashBytes_9: + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + +readHashBytes_8: + $ => B :HASHP1(E) +readHashBytes_7: + $ => RCX :HASHP1(E) +readHashBytes_6: + $ => D :HASHP1(E) +readHashBytes_5: + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => C + +readHashBytes_4: + $ => B :HASHP1(E) +readHashBytes_3: + $ => RCX :HASHP1(E) +readHashBytes_2: + $ => D :HASHP1(E) +readHashBytes_1: + $ => A :HASHP1(E) + ROTL_C + 2**24 * B + 2**16 * RCX + 2**8 * D + A => A :JMP(finishReadHash) ;; Check short value is over 127. Error RLP: single byte < 0x80 are not prefixed checkShortRLP: diff --git a/main/load-tx-rlp.zkasm b/main/load-tx-rlp.zkasm index 81186c88..08305f6a 100644 --- a/main/load-tx-rlp.zkasm +++ b/main/load-tx-rlp.zkasm @@ -235,7 +235,7 @@ longData: readData: 32 => D B - D :JMPN(readDataFinal) - B - D :MSTORE(txDataRead), CALL(addHashTxFromFreeInput) + B - D :MSTORE(txDataRead), CALL(addHashTxByteByByte) $ => E :MLOAD(globalCalldataMemoryOffset), CALL(addL2HashTx) ; Store current CTX CTX => B @@ -249,7 +249,7 @@ readData: readDataFinal: B - 1 :JMPN(endData) - B => D :CALL(addHashTxFromFreeInput) + B => D :CALL(addHashTxByteByByte) :CALL(addL2HashTx) ; WARNING: check checkShortDataRLP correctness :CALL(checkShortDataRLP) diff --git a/main/main.zkasm b/main/main.zkasm index 9607f8a6..2944f982 100644 --- a/main/main.zkasm +++ b/main/main.zkasm @@ -176,9 +176,24 @@ processTxsEnd: finalizeBatch: ;;;;;;;;;;;;;;;;;; -;; E - Finalize execution: set output values at corresponding registers +;; E - Check all save/restore have been consumed +;; - Retrieve newLocalExitRoot +;; - Finalize execution: set output values at corresponding registers ;;;;;;;;;;;;;;;;;; $${eventLog(onFinishBatch)} + ;Each save must be restored precisely once. At the end of the program, all saves without restoration must be cleaned because if not, proof generation fails. + :SAVE(B,C,D,E,RR,RCX) + RID :MSTORE(lastRID) + ; CHECK: maybe only the loop needed? Why doing one more save/restore? +clearPendingRestores_loop: + ${getPendingRID(mem.lastRID)} => RID :JMPN(clearPendingRestores_end) + :RESTORE, JMP(clearPendingRestores_loop) + +clearPendingRestores_end: + $ => RID :MLOAD(lastRID) + :RESTORE + 0 => RID + ; Retrieve newLocalExitRoot ; Read 'localExitRoot' variable from GLOBAL_EXIT_ROOT_MANAGER_L2 and store ; it to the 'newLocalExitRoot' var diff --git a/main/process-tx.zkasm b/main/process-tx.zkasm index 6a82c73b..25930ac0 100644 --- a/main/process-tx.zkasm +++ b/main/process-tx.zkasm @@ -279,7 +279,7 @@ loopCreate2: %MAX_CNT_STEPS - STEP - 100 :JMPN(outOfCountersStep) C :JMPZ(create2end) - C - 32 :JMPN(endloopCreate2) + C - 32 :JMPN(endLoopCreate2) B => E :CALL(MLOAD32) E => B 32 => D @@ -287,7 +287,7 @@ loopCreate2: A :HASHK(E) C - 32 => C :JMP(loopCreate2) -endloopCreate2: +endLoopCreate2: B => E :CALL(MLOADX) ; in: [E: offset, C: length] out: [A: value, E: new offset] 32 - C => D :CALL(SHRarith) C => D diff --git a/main/vars.zkasm b/main/vars.zkasm index 37c3213e..bd852fa9 100644 --- a/main/vars.zkasm +++ b/main/vars.zkasm @@ -43,6 +43,7 @@ VAR GLOBAL valueCall ; value parameter when creating a new context VAR GLOBAL argsLengthCall ; size of the calldata creating a new context VAR GLOBAL txSrcOriginAddr ; origin address of a tx VAR GLOBAL txGasPrice ; transaction parameter: 'gasPrice' global var +VAR GLOBAL lastRID ; Global VAR to check all save and restore have been consumed at the end of the execution VAR GLOBAL originSR ; State root before processing each transaction VAR GLOBAL batchSR ; State root before processing any transaction From f8019f0051bd2da2d65daf09d1de6ec1198846d9 Mon Sep 17 00:00:00 2001 From: Ignasi Date: Thu, 21 Mar 2024 13:10:30 +0100 Subject: [PATCH 09/16] Remove type and use forced hash data --- main/main.zkasm | 25 ++++++++++--------------- main/vars.zkasm | 3 +-- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/main/main.zkasm b/main/main.zkasm index 2944f982..60292223 100644 --- a/main/main.zkasm +++ b/main/main.zkasm @@ -33,15 +33,14 @@ start: ; main zkROM entry point GAS :MSTORE(chainID) ; chainID from GAS, assumed to be less than 32 bits ${getSequencerAddr()} :MSTORE(sequencerAddr) - $0{getTxsLen()} :MSTORE(batchL2DataLength) ; less than 120000 bytes. Enforced by the smart contract + $0{getTxsLen()} :MSTORE(batchL2DataLength) ; less than 120000 bytes. Enforced by the smart contract ${getBatchHashData()} :MSTORE(batchHashData) - $0{getType()} => A :MSTORE(type) - - ; If is not forced, forcedHashData is zero, CHECK: remove? - 0 :MSTORE(forcedHashData) - A - 2 :JMPNZ(computeNewBatchAccInputHash) + ${getForcedHashData()} => A :MSTORE(forcedHashData) + 0 => B + $ :EQ, JMPC(computeNewBatchAccInputHash) + ; If forcedHashData ist no zero, is a forced batch + ; Set forced batch flag 1 :MSTORE(isForced) - ; compute isForced flag ; Compute forcedHashData $ => E :MLOAD(nextHashKId) E + 1 :MSTORE(nextHashKId) @@ -54,14 +53,14 @@ start: ; main zkROM entry point ${getForcedTimestamp()} => A :MSTORE(forcedTimestamp) A :HASHK(E) HASHPOS :HASHKLEN(E) - ; CHECK: need to assert with a forcedHashData obtained from free input? - $ => C :HASHKDIGEST(E) - C :MSTORE(forcedHashData) + ; Assert forcedHashData computed matches with forcedHashData obtained from free input + $ => A :HASHKDIGEST(E) + $ :MLOAD(forcedHashData), ASSERT ;;;;;;;;;;;;;;;;; ;; B - Compute newBatchAccInputHash, load newLocalExitRoot and timestamp ;;;;;;;;;;;;;;;;;; computeNewBatchAccInputHash: - ; newBatchAccInputHash = LinearPoseidon(oldBatchAccInputHash, batchHashData, sequencerAddress, forcedHashData, type)) + ; newBatchAccInputHash = LinearPoseidon(oldBatchAccInputHash, batchHashData, sequencerAddress, forcedHashData)) $ => E :MLOAD(nextHashPId) E + 1 :MSTORE(nextHashPId) $${eventLog(onStartBatch, C)} @@ -82,10 +81,6 @@ computeNewBatchAccInputHash: $ => A :MLOAD(forcedHashData) A :HASHP(E) - 1 => D - $ => A :MLOAD(type) - A :HASHP(E) - ; finish accInputHash HASHPOS :HASHPLEN(E) diff --git a/main/vars.zkasm b/main/vars.zkasm index bd852fa9..6dc2bb7b 100644 --- a/main/vars.zkasm +++ b/main/vars.zkasm @@ -16,9 +16,8 @@ VAR GLOBAL forkID ; Fork identifier VAR GLOBAL isForced ; Flag to determine if the batch is forced VAR GLOBAL cumulativeGasUsed ; cumulative gas used in the block VAR GLOBAL forcedHashData ; solidtykeccak256(abi.encode(GER, blockHashL1, forcedTimestamp)) -VAR GLOBAL type ; Type of the batch 0: data-availability comes from calldata, 1: data-availability comes from blob transaction, 2: forced blob (data-availability comes from calldata ; Output variables -VAR GLOBAL newBatchAccInputHash ; Final accumulated input hash. newBatchAccInputHash = H_keccak( oldAccBathHashData | batchHashData | forcedHashData | sequencerAddr ) +VAR GLOBAL newBatchAccInputHash ; Final accumulated input hash. newBatchAccInputHash = LinearPoseidon(oldBatchAccInputHash, batchHashData, sequencerAddress, forcedHashData)) VAR GLOBAL newLocalExitRoot ; Updated local exit tree root VAR GLOBAL batchL2DataParsed ; Number of bytes read when decoding RLP transactions. Computed during RLP loop From 885b4c71c330aa58441fa0bd2dcc4d573cb346ea Mon Sep 17 00:00:00 2001 From: Ignasi Date: Thu, 21 Mar 2024 13:33:44 +0100 Subject: [PATCH 10/16] Optimizations --- main/process-tx.zkasm | 4 +--- main/utils.zkasm | 48 ++++++++++++++----------------------------- 2 files changed, 16 insertions(+), 36 deletions(-) diff --git a/main/process-tx.zkasm b/main/process-tx.zkasm index 25930ac0..407318a3 100644 --- a/main/process-tx.zkasm +++ b/main/process-tx.zkasm @@ -435,10 +435,8 @@ callContract: readByteCode: $ => E :MLOAD(contractHashId) ; hash index - $ => A :MLOAD(txDestAddr) ; check next byte exist on the bytecode - $ => B :MLOAD(bytecodeLength) - B - PC - 1 :JMPN(defaultOpCode) ; no bytecode treated as 0x00 + $ - PC - 1 :F_MLOAD(bytecodeLength),JMPN(defaultOpCode) ; no bytecode treated as 0x00 PC => HASHPOS $ => RR :HASHP1(E) $${eventLog(onOpcode(RR))} diff --git a/main/utils.zkasm b/main/utils.zkasm index 71e79973..36a7b7c7 100644 --- a/main/utils.zkasm +++ b/main/utils.zkasm @@ -534,7 +534,6 @@ VAR GLOBAL tmpVarBArith VAR GLOBAL tmpVarCArith VAR GLOBAL tmpVarDArith VAR GLOBAL tmpVarEArith -VAR GLOBAL tmpZkPCArith VAR GLOBAL arithA VAR GLOBAL arithB VAR GLOBAL arithRes1 @@ -547,7 +546,7 @@ VAR GLOBAL addArithOverflow ; @out: arithRes1: arithA + arithB addARITH: - RR :MSTORE(tmpZkPCArith), CALL(storeTmp) + A :SAVE(B,C,D,E,RR,RCX) $ => A :MLOAD(arithA) $ => B :MLOAD(arithB) $ => E :ADD, MSTORE(arithRes1), JMPC(setAddArithOverflow) @@ -557,19 +556,20 @@ setAddArithOverflow: 1 :MSTORE(addArithOverflow) finishAddArith: - $ => RR :MLOAD(tmpZkPCArith), JMP(loadTmp) + $ => A :RESTORE, RETURN ; @info binary subtraction ; @in: arithA: minuend value ; @in: arithB: subtrahend value ; @out: arithRes1: arithA - arithB subARITH: - - RR :MSTORE(tmpZkPCArith),CALL(storeTmp) + %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 10 :JMPN(outOfCountersStep) + A :SAVE(B,C,D,E,RR,RCX) $ => A :MLOAD(arithA) $ => B :MLOAD(arithB) $ => A :SUB,MSTORE(arithRes1) - $ => RR :MLOAD(tmpZkPCArith),JMP(loadTmp) + $ => A :RESTORE, RETURN VAR GLOBAL mulArithOverflowValue VAR GLOBAL mulArithOverflowFlag @@ -585,7 +585,7 @@ mulARITH: %MAX_CNT_ARITH - CNT_ARITH - 1 :JMPN(outOfCountersArith) %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) - RR :MSTORE(tmpZkPCArith), CALL(storeTmp) + A :SAVE(B,C,D,E,RR,RCX) $ => A :MLOAD(arithA) $ => B :MLOAD(arithB) 0 => C @@ -604,7 +604,7 @@ setMulArithOverflow: 1 :MSTORE(mulArithOverflowFlag) finishMulArith: - $ => RR :MLOAD(tmpZkPCArith),JMP(loadTmp) + $ => A :RESTORE, RETURN ; @info arithmetic division ; @in: arithA: dividend value @@ -616,8 +616,7 @@ divARITH: %MAX_CNT_STEPS - STEP - 50 :JMPN(outOfCountersStep) %MAX_CNT_BINARY - CNT_BINARY - 3 :JMPN(outOfCountersBinary) %MAX_CNT_ARITH - CNT_ARITH - 1 :JMPN(outOfCountersArith) - - RR :MSTORE(tmpZkPCArith), CALL(storeTmp) + A :SAVE(B,C,D,E,RR,RCX) $ => E :MLOAD(arithA) $ => A :MLOAD(arithB) ; Check denominator(A) is not zero @@ -643,35 +642,18 @@ divARITH: A => B ; divisor C => A ; remainder $ => A :LT - 1 :ASSERT,CALL(loadTmp) - $ => RR :MLOAD(tmpZkPCArith) - :RETURN + 1 :ASSERT + $ => A :RESTORE, RETURN zeroDiv: 0 :MSTORE(arithRes1) - 0 :MSTORE(arithRes2), CALL(loadTmp) - $ => RR :MLOAD(tmpZkPCArith) - :RETURN + 0 :MSTORE(arithRes2) + $ => A :RESTORE, RETURN divisorSmallerDiv: 0 :MSTORE(arithRes1) - E :MSTORE(arithRes2), CALL(loadTmp) - $ => RR :MLOAD(tmpZkPCArith) - :RETURN - -loadTmp: - $ => A :MLOAD(tmpVarAArith) - $ => B :MLOAD(tmpVarBArith) - $ => C :MLOAD(tmpVarCArith) - $ => D :MLOAD(tmpVarDArith) - $ => E :MLOAD(tmpVarEArith), RETURN - -storeTmp: - A :MSTORE(tmpVarAArith) - B :MSTORE(tmpVarBArith) - C :MSTORE(tmpVarCArith) - D :MSTORE(tmpVarDArith) - E :MSTORE(tmpVarEArith), RETURN + E :MSTORE(arithRes2) + $ => A :RESTORE, RETURN VAR GLOBAL tmpSHXZkPC VAR GLOBAL tmpSHXZkPC2 From ae24659e8dc321164c1fe6b6cc8bfaaff052f52b Mon Sep 17 00:00:00 2001 From: zkronos73 Date: Tue, 12 Mar 2024 08:43:12 +0100 Subject: [PATCH 11/16] optimization of shl/shr with last features --- main/tables/shl_bits_table.zkasm | 259 +++++++++++++++++++++++++++++++ main/tables/shr_bits_table.zkasm | 259 +++++++++++++++++++++++++++++++ main/utils.zkasm | 235 ++++++++++++---------------- 3 files changed, 613 insertions(+), 140 deletions(-) create mode 100644 main/tables/shl_bits_table.zkasm create mode 100644 main/tables/shr_bits_table.zkasm diff --git a/main/tables/shl_bits_table.zkasm b/main/tables/shl_bits_table.zkasm new file mode 100644 index 00000000..7b589677 --- /dev/null +++ b/main/tables/shl_bits_table.zkasm @@ -0,0 +1,259 @@ +; for (let i=0; i<256;++i) console.log(((i % 8 === 0 && i) ? `\t${i/8} => C`.padEnd(74) + `:JMP(SHLarithBit_memalign) ;2**${i}`:(`\t0x${(2n**BigInt(i)).toString(16)}n => B`).padEnd(74) + `:JMP(SHLarithBit_arith) ;2**${i}`)) + +SHLarithBit_table: + 0x1n => B :JMP(SHLarithBit_arith) ;2**0 + 0x2n => B :JMP(SHLarithBit_arith) ;2**1 + 0x4n => B :JMP(SHLarithBit_arith) ;2**2 + 0x8n => B :JMP(SHLarithBit_arith) ;2**3 + 0x10n => B :JMP(SHLarithBit_arith) ;2**4 + 0x20n => B :JMP(SHLarithBit_arith) ;2**5 + 0x40n => B :JMP(SHLarithBit_arith) ;2**6 + 0x80n => B :JMP(SHLarithBit_arith) ;2**7 + 1 => C :JMP(SHLarithBit_memalign) ;2**8 + 0x200n => B :JMP(SHLarithBit_arith) ;2**9 + 0x400n => B :JMP(SHLarithBit_arith) ;2**10 + 0x800n => B :JMP(SHLarithBit_arith) ;2**11 + 0x1000n => B :JMP(SHLarithBit_arith) ;2**12 + 0x2000n => B :JMP(SHLarithBit_arith) ;2**13 + 0x4000n => B :JMP(SHLarithBit_arith) ;2**14 + 0x8000n => B :JMP(SHLarithBit_arith) ;2**15 + 2 => C :JMP(SHLarithBit_memalign) ;2**16 + 0x20000n => B :JMP(SHLarithBit_arith) ;2**17 + 0x40000n => B :JMP(SHLarithBit_arith) ;2**18 + 0x80000n => B :JMP(SHLarithBit_arith) ;2**19 + 0x100000n => B :JMP(SHLarithBit_arith) ;2**20 + 0x200000n => B :JMP(SHLarithBit_arith) ;2**21 + 0x400000n => B :JMP(SHLarithBit_arith) ;2**22 + 0x800000n => B :JMP(SHLarithBit_arith) ;2**23 + 3 => C :JMP(SHLarithBit_memalign) ;2**24 + 0x2000000n => B :JMP(SHLarithBit_arith) ;2**25 + 0x4000000n => B :JMP(SHLarithBit_arith) ;2**26 + 0x8000000n => B :JMP(SHLarithBit_arith) ;2**27 + 0x10000000n => B :JMP(SHLarithBit_arith) ;2**28 + 0x20000000n => B :JMP(SHLarithBit_arith) ;2**29 + 0x40000000n => B :JMP(SHLarithBit_arith) ;2**30 + 0x80000000n => B :JMP(SHLarithBit_arith) ;2**31 + 4 => C :JMP(SHLarithBit_memalign) ;2**32 + 0x200000000n => B :JMP(SHLarithBit_arith) ;2**33 + 0x400000000n => B :JMP(SHLarithBit_arith) ;2**34 + 0x800000000n => B :JMP(SHLarithBit_arith) ;2**35 + 0x1000000000n => B :JMP(SHLarithBit_arith) ;2**36 + 0x2000000000n => B :JMP(SHLarithBit_arith) ;2**37 + 0x4000000000n => B :JMP(SHLarithBit_arith) ;2**38 + 0x8000000000n => B :JMP(SHLarithBit_arith) ;2**39 + 5 => C :JMP(SHLarithBit_memalign) ;2**40 + 0x20000000000n => B :JMP(SHLarithBit_arith) ;2**41 + 0x40000000000n => B :JMP(SHLarithBit_arith) ;2**42 + 0x80000000000n => B :JMP(SHLarithBit_arith) ;2**43 + 0x100000000000n => B :JMP(SHLarithBit_arith) ;2**44 + 0x200000000000n => B :JMP(SHLarithBit_arith) ;2**45 + 0x400000000000n => B :JMP(SHLarithBit_arith) ;2**46 + 0x800000000000n => B :JMP(SHLarithBit_arith) ;2**47 + 6 => C :JMP(SHLarithBit_memalign) ;2**48 + 0x2000000000000n => B :JMP(SHLarithBit_arith) ;2**49 + 0x4000000000000n => B :JMP(SHLarithBit_arith) ;2**50 + 0x8000000000000n => B :JMP(SHLarithBit_arith) ;2**51 + 0x10000000000000n => B :JMP(SHLarithBit_arith) ;2**52 + 0x20000000000000n => B :JMP(SHLarithBit_arith) ;2**53 + 0x40000000000000n => B :JMP(SHLarithBit_arith) ;2**54 + 0x80000000000000n => B :JMP(SHLarithBit_arith) ;2**55 + 7 => C :JMP(SHLarithBit_memalign) ;2**56 + 0x200000000000000n => B :JMP(SHLarithBit_arith) ;2**57 + 0x400000000000000n => B :JMP(SHLarithBit_arith) ;2**58 + 0x800000000000000n => B :JMP(SHLarithBit_arith) ;2**59 + 0x1000000000000000n => B :JMP(SHLarithBit_arith) ;2**60 + 0x2000000000000000n => B :JMP(SHLarithBit_arith) ;2**61 + 0x4000000000000000n => B :JMP(SHLarithBit_arith) ;2**62 + 0x8000000000000000n => B :JMP(SHLarithBit_arith) ;2**63 + 8 => C :JMP(SHLarithBit_memalign) ;2**64 + 0x20000000000000000n => B :JMP(SHLarithBit_arith) ;2**65 + 0x40000000000000000n => B :JMP(SHLarithBit_arith) ;2**66 + 0x80000000000000000n => B :JMP(SHLarithBit_arith) ;2**67 + 0x100000000000000000n => B :JMP(SHLarithBit_arith) ;2**68 + 0x200000000000000000n => B :JMP(SHLarithBit_arith) ;2**69 + 0x400000000000000000n => B :JMP(SHLarithBit_arith) ;2**70 + 0x800000000000000000n => B :JMP(SHLarithBit_arith) ;2**71 + 9 => C :JMP(SHLarithBit_memalign) ;2**72 + 0x2000000000000000000n => B :JMP(SHLarithBit_arith) ;2**73 + 0x4000000000000000000n => B :JMP(SHLarithBit_arith) ;2**74 + 0x8000000000000000000n => B :JMP(SHLarithBit_arith) ;2**75 + 0x10000000000000000000n => B :JMP(SHLarithBit_arith) ;2**76 + 0x20000000000000000000n => B :JMP(SHLarithBit_arith) ;2**77 + 0x40000000000000000000n => B :JMP(SHLarithBit_arith) ;2**78 + 0x80000000000000000000n => B :JMP(SHLarithBit_arith) ;2**79 + 10 => C :JMP(SHLarithBit_memalign) ;2**80 + 0x200000000000000000000n => B :JMP(SHLarithBit_arith) ;2**81 + 0x400000000000000000000n => B :JMP(SHLarithBit_arith) ;2**82 + 0x800000000000000000000n => B :JMP(SHLarithBit_arith) ;2**83 + 0x1000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**84 + 0x2000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**85 + 0x4000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**86 + 0x8000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**87 + 11 => C :JMP(SHLarithBit_memalign) ;2**88 + 0x20000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**89 + 0x40000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**90 + 0x80000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**91 + 0x100000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**92 + 0x200000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**93 + 0x400000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**94 + 0x800000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**95 + 12 => C :JMP(SHLarithBit_memalign) ;2**96 + 0x2000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**97 + 0x4000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**98 + 0x8000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**99 + 0x10000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**100 + 0x20000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**101 + 0x40000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**102 + 0x80000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**103 + 13 => C :JMP(SHLarithBit_memalign) ;2**104 + 0x200000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**105 + 0x400000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**106 + 0x800000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**107 + 0x1000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**108 + 0x2000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**109 + 0x4000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**110 + 0x8000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**111 + 14 => C :JMP(SHLarithBit_memalign) ;2**112 + 0x20000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**113 + 0x40000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**114 + 0x80000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**115 + 0x100000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**116 + 0x200000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**117 + 0x400000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**118 + 0x800000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**119 + 15 => C :JMP(SHLarithBit_memalign) ;2**120 + 0x2000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**121 + 0x4000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**122 + 0x8000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**123 + 0x10000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**124 + 0x20000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**125 + 0x40000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**126 + 0x80000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**127 + 16 => C :JMP(SHLarithBit_memalign) ;2**128 + 0x200000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**129 + 0x400000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**130 + 0x800000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**131 + 0x1000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**132 + 0x2000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**133 + 0x4000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**134 + 0x8000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**135 + 17 => C :JMP(SHLarithBit_memalign) ;2**136 + 0x20000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**137 + 0x40000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**138 + 0x80000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**139 + 0x100000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**140 + 0x200000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**141 + 0x400000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**142 + 0x800000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**143 + 18 => C :JMP(SHLarithBit_memalign) ;2**144 + 0x2000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**145 + 0x4000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**146 + 0x8000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**147 + 0x10000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**148 + 0x20000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**149 + 0x40000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**150 + 0x80000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**151 + 19 => C :JMP(SHLarithBit_memalign) ;2**152 + 0x200000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**153 + 0x400000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**154 + 0x800000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**155 + 0x1000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**156 + 0x2000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**157 + 0x4000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**158 + 0x8000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**159 + 20 => C :JMP(SHLarithBit_memalign) ;2**160 + 0x20000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**161 + 0x40000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**162 + 0x80000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**163 + 0x100000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**164 + 0x200000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**165 + 0x400000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**166 + 0x800000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**167 + 21 => C :JMP(SHLarithBit_memalign) ;2**168 + 0x2000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**169 + 0x4000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**170 + 0x8000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**171 + 0x10000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**172 + 0x20000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**173 + 0x40000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**174 + 0x80000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**175 + 22 => C :JMP(SHLarithBit_memalign) ;2**176 + 0x200000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**177 + 0x400000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**178 + 0x800000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**179 + 0x1000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**180 + 0x2000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**181 + 0x4000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**182 + 0x8000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**183 + 23 => C :JMP(SHLarithBit_memalign) ;2**184 + 0x20000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**185 + 0x40000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**186 + 0x80000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**187 + 0x100000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**188 + 0x200000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**189 + 0x400000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**190 + 0x800000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**191 + 24 => C :JMP(SHLarithBit_memalign) ;2**192 + 0x2000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**193 + 0x4000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**194 + 0x8000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**195 + 0x10000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**196 + 0x20000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**197 + 0x40000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**198 + 0x80000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**199 + 25 => C :JMP(SHLarithBit_memalign) ;2**200 + 0x200000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**201 + 0x400000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**202 + 0x800000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**203 + 0x1000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**204 + 0x2000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**205 + 0x4000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**206 + 0x8000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**207 + 26 => C :JMP(SHLarithBit_memalign) ;2**208 + 0x20000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**209 + 0x40000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**210 + 0x80000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**211 + 0x100000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**212 + 0x200000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**213 + 0x400000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**214 + 0x800000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**215 + 27 => C :JMP(SHLarithBit_memalign) ;2**216 + 0x2000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**217 + 0x4000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**218 + 0x8000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**219 + 0x10000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**220 + 0x20000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**221 + 0x40000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**222 + 0x80000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**223 + 28 => C :JMP(SHLarithBit_memalign) ;2**224 + 0x200000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**225 + 0x400000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**226 + 0x800000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**227 + 0x1000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**228 + 0x2000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**229 + 0x4000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**230 + 0x8000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**231 + 29 => C :JMP(SHLarithBit_memalign) ;2**232 + 0x20000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**233 + 0x40000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**234 + 0x80000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**235 + 0x100000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**236 + 0x200000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**237 + 0x400000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**238 + 0x800000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**239 + 30 => C :JMP(SHLarithBit_memalign) ;2**240 + 0x2000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**241 + 0x4000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**242 + 0x8000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**243 + 0x10000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**244 + 0x20000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**245 + 0x40000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**246 + 0x80000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**247 + 31 => C :JMP(SHLarithBit_memalign) ;2**248 + 0x200000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**249 + 0x400000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**250 + 0x800000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**251 + 0x1000000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**252 + 0x2000000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**253 + 0x4000000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**254 + 0x8000000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHLarithBit_arith) ;2**255 \ No newline at end of file diff --git a/main/tables/shr_bits_table.zkasm b/main/tables/shr_bits_table.zkasm new file mode 100644 index 00000000..8e35448e --- /dev/null +++ b/main/tables/shr_bits_table.zkasm @@ -0,0 +1,259 @@ +; for (let i=0; i<256;++i) console.log(((i % 8 === 0 && i) ? `\t${32-(i/8)} => C`.padEnd(74) + `:JMP(SHRarithBit_memalign) ; #${i} 2**${256-i}`:(`\t0x${(2n**BigInt(256-i)).toString(16)}n => B`).padEnd(74) + `:JMP(SHRarithBit_arith) ; #${i} 2**${256-i}`)) + +SHRarithBit_table: + :RESTORE,RETURN ; #0 2**256 + 0x8000000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #1 2**255 + 0x4000000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #2 2**254 + 0x2000000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #3 2**253 + 0x1000000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #4 2**252 + 0x800000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #5 2**251 + 0x400000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #6 2**250 + 0x200000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #7 2**249 + 31 => C :JMP(SHRarithBit_memalign) ; #8 2**248 + 0x80000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #9 2**247 + 0x40000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #10 2**246 + 0x20000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #11 2**245 + 0x10000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #12 2**244 + 0x8000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #13 2**243 + 0x4000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #14 2**242 + 0x2000000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #15 2**241 + 30 => C :JMP(SHRarithBit_memalign) ; #16 2**240 + 0x800000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #17 2**239 + 0x400000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #18 2**238 + 0x200000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #19 2**237 + 0x100000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #20 2**236 + 0x80000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #21 2**235 + 0x40000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #22 2**234 + 0x20000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #23 2**233 + 29 => C :JMP(SHRarithBit_memalign) ; #24 2**232 + 0x8000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #25 2**231 + 0x4000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #26 2**230 + 0x2000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #27 2**229 + 0x1000000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #28 2**228 + 0x800000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #29 2**227 + 0x400000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #30 2**226 + 0x200000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #31 2**225 + 28 => C :JMP(SHRarithBit_memalign) ; #32 2**224 + 0x80000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #33 2**223 + 0x40000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #34 2**222 + 0x20000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #35 2**221 + 0x10000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #36 2**220 + 0x8000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #37 2**219 + 0x4000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #38 2**218 + 0x2000000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #39 2**217 + 27 => C :JMP(SHRarithBit_memalign) ; #40 2**216 + 0x800000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #41 2**215 + 0x400000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #42 2**214 + 0x200000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #43 2**213 + 0x100000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #44 2**212 + 0x80000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #45 2**211 + 0x40000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #46 2**210 + 0x20000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #47 2**209 + 26 => C :JMP(SHRarithBit_memalign) ; #48 2**208 + 0x8000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #49 2**207 + 0x4000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #50 2**206 + 0x2000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #51 2**205 + 0x1000000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #52 2**204 + 0x800000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #53 2**203 + 0x400000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #54 2**202 + 0x200000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #55 2**201 + 25 => C :JMP(SHRarithBit_memalign) ; #56 2**200 + 0x80000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #57 2**199 + 0x40000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #58 2**198 + 0x20000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #59 2**197 + 0x10000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #60 2**196 + 0x8000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #61 2**195 + 0x4000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #62 2**194 + 0x2000000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #63 2**193 + 24 => C :JMP(SHRarithBit_memalign) ; #64 2**192 + 0x800000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #65 2**191 + 0x400000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #66 2**190 + 0x200000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #67 2**189 + 0x100000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #68 2**188 + 0x80000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #69 2**187 + 0x40000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #70 2**186 + 0x20000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #71 2**185 + 23 => C :JMP(SHRarithBit_memalign) ; #72 2**184 + 0x8000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #73 2**183 + 0x4000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #74 2**182 + 0x2000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #75 2**181 + 0x1000000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #76 2**180 + 0x800000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #77 2**179 + 0x400000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #78 2**178 + 0x200000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #79 2**177 + 22 => C :JMP(SHRarithBit_memalign) ; #80 2**176 + 0x80000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #81 2**175 + 0x40000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #82 2**174 + 0x20000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #83 2**173 + 0x10000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #84 2**172 + 0x8000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #85 2**171 + 0x4000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #86 2**170 + 0x2000000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #87 2**169 + 21 => C :JMP(SHRarithBit_memalign) ; #88 2**168 + 0x800000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #89 2**167 + 0x400000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #90 2**166 + 0x200000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #91 2**165 + 0x100000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #92 2**164 + 0x80000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #93 2**163 + 0x40000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #94 2**162 + 0x20000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #95 2**161 + 20 => C :JMP(SHRarithBit_memalign) ; #96 2**160 + 0x8000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #97 2**159 + 0x4000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #98 2**158 + 0x2000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #99 2**157 + 0x1000000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #100 2**156 + 0x800000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #101 2**155 + 0x400000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #102 2**154 + 0x200000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #103 2**153 + 19 => C :JMP(SHRarithBit_memalign) ; #104 2**152 + 0x80000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #105 2**151 + 0x40000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #106 2**150 + 0x20000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #107 2**149 + 0x10000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #108 2**148 + 0x8000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #109 2**147 + 0x4000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #110 2**146 + 0x2000000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #111 2**145 + 18 => C :JMP(SHRarithBit_memalign) ; #112 2**144 + 0x800000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #113 2**143 + 0x400000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #114 2**142 + 0x200000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #115 2**141 + 0x100000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #116 2**140 + 0x80000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #117 2**139 + 0x40000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #118 2**138 + 0x20000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #119 2**137 + 17 => C :JMP(SHRarithBit_memalign) ; #120 2**136 + 0x8000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #121 2**135 + 0x4000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #122 2**134 + 0x2000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #123 2**133 + 0x1000000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #124 2**132 + 0x800000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #125 2**131 + 0x400000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #126 2**130 + 0x200000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #127 2**129 + 16 => C :JMP(SHRarithBit_memalign) ; #128 2**128 + 0x80000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #129 2**127 + 0x40000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #130 2**126 + 0x20000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #131 2**125 + 0x10000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #132 2**124 + 0x8000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #133 2**123 + 0x4000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #134 2**122 + 0x2000000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #135 2**121 + 15 => C :JMP(SHRarithBit_memalign) ; #136 2**120 + 0x800000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #137 2**119 + 0x400000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #138 2**118 + 0x200000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #139 2**117 + 0x100000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #140 2**116 + 0x80000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #141 2**115 + 0x40000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #142 2**114 + 0x20000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #143 2**113 + 14 => C :JMP(SHRarithBit_memalign) ; #144 2**112 + 0x8000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #145 2**111 + 0x4000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #146 2**110 + 0x2000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #147 2**109 + 0x1000000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #148 2**108 + 0x800000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #149 2**107 + 0x400000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #150 2**106 + 0x200000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #151 2**105 + 13 => C :JMP(SHRarithBit_memalign) ; #152 2**104 + 0x80000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #153 2**103 + 0x40000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #154 2**102 + 0x20000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #155 2**101 + 0x10000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #156 2**100 + 0x8000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #157 2**99 + 0x4000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #158 2**98 + 0x2000000000000000000000000n => B :JMP(SHRarithBit_arith) ; #159 2**97 + 12 => C :JMP(SHRarithBit_memalign) ; #160 2**96 + 0x800000000000000000000000n => B :JMP(SHRarithBit_arith) ; #161 2**95 + 0x400000000000000000000000n => B :JMP(SHRarithBit_arith) ; #162 2**94 + 0x200000000000000000000000n => B :JMP(SHRarithBit_arith) ; #163 2**93 + 0x100000000000000000000000n => B :JMP(SHRarithBit_arith) ; #164 2**92 + 0x80000000000000000000000n => B :JMP(SHRarithBit_arith) ; #165 2**91 + 0x40000000000000000000000n => B :JMP(SHRarithBit_arith) ; #166 2**90 + 0x20000000000000000000000n => B :JMP(SHRarithBit_arith) ; #167 2**89 + 11 => C :JMP(SHRarithBit_memalign) ; #168 2**88 + 0x8000000000000000000000n => B :JMP(SHRarithBit_arith) ; #169 2**87 + 0x4000000000000000000000n => B :JMP(SHRarithBit_arith) ; #170 2**86 + 0x2000000000000000000000n => B :JMP(SHRarithBit_arith) ; #171 2**85 + 0x1000000000000000000000n => B :JMP(SHRarithBit_arith) ; #172 2**84 + 0x800000000000000000000n => B :JMP(SHRarithBit_arith) ; #173 2**83 + 0x400000000000000000000n => B :JMP(SHRarithBit_arith) ; #174 2**82 + 0x200000000000000000000n => B :JMP(SHRarithBit_arith) ; #175 2**81 + 10 => C :JMP(SHRarithBit_memalign) ; #176 2**80 + 0x80000000000000000000n => B :JMP(SHRarithBit_arith) ; #177 2**79 + 0x40000000000000000000n => B :JMP(SHRarithBit_arith) ; #178 2**78 + 0x20000000000000000000n => B :JMP(SHRarithBit_arith) ; #179 2**77 + 0x10000000000000000000n => B :JMP(SHRarithBit_arith) ; #180 2**76 + 0x8000000000000000000n => B :JMP(SHRarithBit_arith) ; #181 2**75 + 0x4000000000000000000n => B :JMP(SHRarithBit_arith) ; #182 2**74 + 0x2000000000000000000n => B :JMP(SHRarithBit_arith) ; #183 2**73 + 9 => C :JMP(SHRarithBit_memalign) ; #184 2**72 + 0x800000000000000000n => B :JMP(SHRarithBit_arith) ; #185 2**71 + 0x400000000000000000n => B :JMP(SHRarithBit_arith) ; #186 2**70 + 0x200000000000000000n => B :JMP(SHRarithBit_arith) ; #187 2**69 + 0x100000000000000000n => B :JMP(SHRarithBit_arith) ; #188 2**68 + 0x80000000000000000n => B :JMP(SHRarithBit_arith) ; #189 2**67 + 0x40000000000000000n => B :JMP(SHRarithBit_arith) ; #190 2**66 + 0x20000000000000000n => B :JMP(SHRarithBit_arith) ; #191 2**65 + 8 => C :JMP(SHRarithBit_memalign) ; #192 2**64 + 0x8000000000000000n => B :JMP(SHRarithBit_arith) ; #193 2**63 + 0x4000000000000000n => B :JMP(SHRarithBit_arith) ; #194 2**62 + 0x2000000000000000n => B :JMP(SHRarithBit_arith) ; #195 2**61 + 0x1000000000000000n => B :JMP(SHRarithBit_arith) ; #196 2**60 + 0x800000000000000n => B :JMP(SHRarithBit_arith) ; #197 2**59 + 0x400000000000000n => B :JMP(SHRarithBit_arith) ; #198 2**58 + 0x200000000000000n => B :JMP(SHRarithBit_arith) ; #199 2**57 + 7 => C :JMP(SHRarithBit_memalign) ; #200 2**56 + 0x80000000000000n => B :JMP(SHRarithBit_arith) ; #201 2**55 + 0x40000000000000n => B :JMP(SHRarithBit_arith) ; #202 2**54 + 0x20000000000000n => B :JMP(SHRarithBit_arith) ; #203 2**53 + 0x10000000000000n => B :JMP(SHRarithBit_arith) ; #204 2**52 + 0x8000000000000n => B :JMP(SHRarithBit_arith) ; #205 2**51 + 0x4000000000000n => B :JMP(SHRarithBit_arith) ; #206 2**50 + 0x2000000000000n => B :JMP(SHRarithBit_arith) ; #207 2**49 + 6 => C :JMP(SHRarithBit_memalign) ; #208 2**48 + 0x800000000000n => B :JMP(SHRarithBit_arith) ; #209 2**47 + 0x400000000000n => B :JMP(SHRarithBit_arith) ; #210 2**46 + 0x200000000000n => B :JMP(SHRarithBit_arith) ; #211 2**45 + 0x100000000000n => B :JMP(SHRarithBit_arith) ; #212 2**44 + 0x80000000000n => B :JMP(SHRarithBit_arith) ; #213 2**43 + 0x40000000000n => B :JMP(SHRarithBit_arith) ; #214 2**42 + 0x20000000000n => B :JMP(SHRarithBit_arith) ; #215 2**41 + 5 => C :JMP(SHRarithBit_memalign) ; #216 2**40 + 0x8000000000n => B :JMP(SHRarithBit_arith) ; #217 2**39 + 0x4000000000n => B :JMP(SHRarithBit_arith) ; #218 2**38 + 0x2000000000n => B :JMP(SHRarithBit_arith) ; #219 2**37 + 0x1000000000n => B :JMP(SHRarithBit_arith) ; #220 2**36 + 0x800000000n => B :JMP(SHRarithBit_arith) ; #221 2**35 + 0x400000000n => B :JMP(SHRarithBit_arith) ; #222 2**34 + 0x200000000n => B :JMP(SHRarithBit_arith) ; #223 2**33 + 4 => C :JMP(SHRarithBit_memalign) ; #224 2**32 + 0x80000000n => B :JMP(SHRarithBit_arith) ; #225 2**31 + 0x40000000n => B :JMP(SHRarithBit_arith) ; #226 2**30 + 0x20000000n => B :JMP(SHRarithBit_arith) ; #227 2**29 + 0x10000000n => B :JMP(SHRarithBit_arith) ; #228 2**28 + 0x8000000n => B :JMP(SHRarithBit_arith) ; #229 2**27 + 0x4000000n => B :JMP(SHRarithBit_arith) ; #230 2**26 + 0x2000000n => B :JMP(SHRarithBit_arith) ; #231 2**25 + 3 => C :JMP(SHRarithBit_memalign) ; #232 2**24 + 0x800000n => B :JMP(SHRarithBit_arith) ; #233 2**23 + 0x400000n => B :JMP(SHRarithBit_arith) ; #234 2**22 + 0x200000n => B :JMP(SHRarithBit_arith) ; #235 2**21 + 0x100000n => B :JMP(SHRarithBit_arith) ; #236 2**20 + 0x80000n => B :JMP(SHRarithBit_arith) ; #237 2**19 + 0x40000n => B :JMP(SHRarithBit_arith) ; #238 2**18 + 0x20000n => B :JMP(SHRarithBit_arith) ; #239 2**17 + 2 => C :JMP(SHRarithBit_memalign) ; #240 2**16 + 0x8000n => B :JMP(SHRarithBit_arith) ; #241 2**15 + 0x4000n => B :JMP(SHRarithBit_arith) ; #242 2**14 + 0x2000n => B :JMP(SHRarithBit_arith) ; #243 2**13 + 0x1000n => B :JMP(SHRarithBit_arith) ; #244 2**12 + 0x800n => B :JMP(SHRarithBit_arith) ; #245 2**11 + 0x400n => B :JMP(SHRarithBit_arith) ; #246 2**10 + 0x200n => B :JMP(SHRarithBit_arith) ; #247 2**9 + 1 => C :JMP(SHRarithBit_memalign) ; #248 2**8 + 0x80n => B :JMP(SHRarithBit_arith) ; #249 2**7 + 0x40n => B :JMP(SHRarithBit_arith) ; #250 2**6 + 0x20n => B :JMP(SHRarithBit_arith) ; #251 2**5 + 0x10n => B :JMP(SHRarithBit_arith) ; #252 2**4 + 0x8n => B :JMP(SHRarithBit_arith) ; #253 2**3 + 0x4n => B :JMP(SHRarithBit_arith) ; #254 2**2 + 0x2n => B :JMP(SHRarithBit_arith) ; #255 2**1 \ No newline at end of file diff --git a/main/utils.zkasm b/main/utils.zkasm index 36a7b7c7..8eb9d255 100644 --- a/main/utils.zkasm +++ b/main/utils.zkasm @@ -655,156 +655,111 @@ divisorSmallerDiv: E :MSTORE(arithRes2) $ => A :RESTORE, RETURN -VAR GLOBAL tmpSHXZkPC -VAR GLOBAL tmpSHXZkPC2 - -VAR GLOBAL tmpVarBSHX -VAR GLOBAL tmpVarCSHX -VAR GLOBAL tmpVarDSHX -VAR GLOBAL tmpVarESHX - -VAR GLOBAL result -;@info Shift right D bytes to A -;@in A - (A >> D) -;@in D - (A >> D) D bytes -;@out A - A >> D => A +; @info Shift right D bytes to A +; @in A +; @in D +; @out A - A >> (8*D) => A + SHRarith: - ; check zk-counters - %MAX_CNT_STEPS - STEP - 50 :JMPN(outOfCountersStep) - %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) - %MAX_CNT_ARITH - CNT_ARITH - 1 :JMPN(outOfCountersArith) + %MAX_CNT_STEPS - STEP - 8 :JMPN(outOfCountersStep) - RR :MSTORE(tmpSHXZkPC2) - B :MSTORE(tmpVarBSHX) - C :MSTORE(tmpVarCSHX) - D :MSTORE(tmpVarDSHX) - E :MSTORE(tmpVarESHX) - ; E init number - A => E - ; A bytes - D => A - ; B = 8 (1 byte = 8 bits) - 8 => B - 0 => C - 0 => D - ; A * B = op --> D = op (D bits) - ${A*B} => D :ARITH - ; A init number - E => A :JMP(SHRarithinit) - -;@in A - (A >> D) -;@in D - (A >> D) D bits -;@out A - A >> D => A -SHRarithBit: - ; check zk-counters - %MAX_CNT_STEPS - STEP - 30 :JMPN(outOfCountersStep) - %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) - RR :MSTORE(tmpSHXZkPC2) - B :MSTORE(tmpVarBSHX) - C :MSTORE(tmpVarCSHX) - D :MSTORE(tmpVarDSHX) - E :MSTORE(tmpVarESHX) + 31 - D :JMPN(SHRarith_32) + D :JMPZ(SHRarith_0) -SHRarithinit: - 0 => B - ; if A == 0 --> no shift - $ :EQ,JMPC(SHRarithfinal) - ; E init number - A => E - ; B bits - D => B - 255 => A - ; A < B, 255 < bits - $ :LT,JMPC(SHRarith0) - D => RR - E => A :MSTORE(arithA) - :CALL(@exp_num + RR); out:[B: 2**RR] - B :MSTORE(arithB),CALL(divARITH); in: [arithA, arithB] out: [arithRes1: arithA/arithB, arithRes2: arithA%arithB] - $ => A :MLOAD(arithRes1),JMP(SHRarithfinal) - -SHRarith0: + %MAX_CNT_MEM_ALIGN - CNT_MEM_ALIGN - 1 :JMPN(outOfCountersMemalign) + + 32 - D => C :SAVE(B,C,D,E,RCX,RR) + A => B 0 => A + $ => A :MEM_ALIGN_RD + :RESTORE, RETURN + +SHRarith_32: + 0 => A :RETURN +SHRarith_0: + :RETURN + +; @info Shift right D bytes to A +; @in A +; @in D +; @out A - A >> (8*D)) => A + -SHRarithfinal: - $ => B :MLOAD(tmpVarBSHX) - $ => C :MLOAD(tmpVarCSHX) - $ => D :MLOAD(tmpVarDSHX) - $ => RR :MLOAD(tmpSHXZkPC2) - $ => E :MLOAD(tmpVarESHX), RETURN - -;@info Shift left D bytes to A -;@in A - (A << D) -;@in D - (A << D) D bytes -;@out A - A << D => A SHLarith: - ; check zk-counters - %MAX_CNT_STEPS - STEP - 100 :JMPN(outOfCountersStep) - %MAX_CNT_BINARY - CNT_BINARY - 4 :JMPN(outOfCountersBinary) - %MAX_CNT_ARITH - CNT_ARITH - 2 :JMPN(outOfCountersArith) - RR :MSTORE(tmpSHXZkPC2) - B :MSTORE(tmpVarBSHX) - C :MSTORE(tmpVarCSHX) - D :MSTORE(tmpVarDSHX) - E :MSTORE(tmpVarESHX) - ; E init number - A => E - ; A bytes + %MAX_CNT_STEPS - STEP - 7 :JMPN(outOfCountersStep) + + 31 - D :JMPN(SHRarith_32) + D :JMPZ(SHRarith_0) + + %MAX_CNT_MEM_ALIGN - CNT_MEM_ALIGN - 1 :JMPN(outOfCountersMemalign) + + D => C :SAVE(B,C,D,E,RCX,RR) + 0 => B + $ => A :MEM_ALIGN_RD + :RESTORE, RETURN + +SHRarith_32: + 0 => A :RETURN +SHRarith_0: + :RETURN + +; @info Shift right D bits to A +; @in A +; @in D +; @out A - (A >> D) => A + +SHRarithBit: + %MAX_CNT_STEPS - STEP - 9 :JMPN(outOfCountersStep) + 255 - D :JMPN(SHRarithBit_A0) + + D => RR,RCX :SAVE(B,C,D,E,RCX,RR) + 0 => C,B :JMP(@SHRarithBit_table + RR) + +SHRarithBit_arith: + %MAX_CNT_ARITH - CNT_ARITH - 1 :JMPN(outOfCountersArith) + + ${(A >> RCX) & const.MAX_UINT_256} => D + ${(A << (256 - RCX)) & const.MAX_UINT_256} :ARITH D => A - 8 => B - 0 => C, D - ; D = A * 8, D bits - ${A*B} => D :ARITH - ; A init number - E => A - :JMP(SHLarithinit) -SHLarithBit: - ; check zk-counters - %MAX_CNT_STEPS - STEP - 100 :JMPN(outOfCountersStep) - %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) - %MAX_CNT_ARITH - CNT_ARITH - 1 :JMPN(outOfCountersArith) - RR :MSTORE(tmpSHXZkPC2) - B :MSTORE(tmpVarBSHX) - C :MSTORE(tmpVarCSHX) - D :MSTORE(tmpVarDSHX) - E :MSTORE(tmpVarESHX) - -SHLarithinit: - ; E init number - A => E + :RESTORE, RETURN +SHRarithBit_memalign: + %MAX_CNT_MEM_ALIGN - CNT_MEM_ALIGN - 1 :JMPN(outOfCountersMemalign) + A => B 0 => A - ; D --> B bits - D => B - ; if D == 0 --> no shift - $ :EQ,JMPC(SHLarithfinal) - 255 => A - ; A < B, 255 < bits - $ :LT,JMPC(SHLarith0) - - D => RR - ; A init number and calculate B = 2**D - E => A :CALL(@exp_num + RR); out:[B: 2**RR] - ; E = init number * 2**D (result) - ${A*B} => E - E :MSTORE(result) - ; D = 256 - D - 256 - D => D, RR - B => C :CALL(@exp_num + RR); out:[B: 2**RR] - ${A/B} => D - C => B - 0 => C - E :ARITH, JMP(SHLarithfinal) + $ => A :MEM_ALIGN_RD + :RESTORE, RETURN +SHRarithBit_A0: + 0 => A :RETURN -SHLarith0: - 0 => E - :JMP(SHLarithfinal) +INCLUDE "tables/shr_bits_table.zkasm" -SHLarithfinal: - E => A - $ => B :MLOAD(tmpVarBSHX) - $ => C :MLOAD(tmpVarCSHX) - $ => D :MLOAD(tmpVarDSHX) - $ => RR :MLOAD(tmpSHXZkPC2) - $ => E :MLOAD(tmpVarESHX), RETURN + +; @info Shift left D bits to A +; @in A +; @in D +; @out A - (A << D) => A + +SHLarithBit: + %MAX_CNT_STEPS - STEP - 9 :JMPN(outOfCountersStep) + 255 - D :JMPN(SHLarithBit_A0) + + D => RR,RCX :SAVE(B,C,D,E,RCX,RR) + 0 => C,B :JMP(@SHLarithBit_table + RR) + +SHLarithBit_arith: + %MAX_CNT_ARITH - CNT_ARITH - 1 :JMPN(outOfCountersArith) + + ${(A >> (256 - RCX)) & const.MAX_UINT_256} => D + ${(A << RCX) & const.MAX_UINT_256} => A :ARITH + :RESTORE, RETURN +SHLarithBit_memalign: + %MAX_CNT_MEM_ALIGN - CNT_MEM_ALIGN - 1 :JMPN(outOfCountersMemalign) + $ => A :MEM_ALIGN_RD + :RESTORE, RETURN +SHLarithBit_A0: + 0 => A :RETURN + +INCLUDE "tables/shl_bits_table.zkasm" ; out of counters full tracer event trigger outOfCountersStep: From 8405d79029dab0e97cc7b348c2eaf4f3926b7254 Mon Sep 17 00:00:00 2001 From: zkronos73 Date: Tue, 12 Mar 2024 13:45:53 +0100 Subject: [PATCH 12/16] fix typo labels --- main/utils.zkasm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/main/utils.zkasm b/main/utils.zkasm index 8eb9d255..c1a6f2a5 100644 --- a/main/utils.zkasm +++ b/main/utils.zkasm @@ -679,17 +679,17 @@ SHRarith_32: SHRarith_0: :RETURN -; @info Shift right D bytes to A +; @info Shift left D bytes to A ; @in A ; @in D -; @out A - A >> (8*D)) => A +; @out A - A << (8*D) => A SHLarith: %MAX_CNT_STEPS - STEP - 7 :JMPN(outOfCountersStep) - 31 - D :JMPN(SHRarith_32) - D :JMPZ(SHRarith_0) + 31 - D :JMPN(SHLarith_32) + D :JMPZ(SHLarith_0) %MAX_CNT_MEM_ALIGN - CNT_MEM_ALIGN - 1 :JMPN(outOfCountersMemalign) @@ -698,9 +698,9 @@ SHLarith: $ => A :MEM_ALIGN_RD :RESTORE, RETURN -SHRarith_32: +SHLarith_32: 0 => A :RETURN -SHRarith_0: +SHLarith_0: :RETURN ; @info Shift right D bits to A From 68928fb5436cd489e8a3727e08e67d00df00f754 Mon Sep 17 00:00:00 2001 From: zkronos73 Date: Tue, 12 Mar 2024 23:19:54 +0100 Subject: [PATCH 13/16] optimize a few steps on SHL/SHR --- main/utils.zkasm | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/main/utils.zkasm b/main/utils.zkasm index c1a6f2a5..1d63cd20 100644 --- a/main/utils.zkasm +++ b/main/utils.zkasm @@ -686,14 +686,13 @@ SHRarith_0: SHLarith: - %MAX_CNT_STEPS - STEP - 7 :JMPN(outOfCountersStep) + %MAX_CNT_STEPS - STEP - 6 :JMPN(outOfCountersStep) 31 - D :JMPN(SHLarith_32) - D :JMPZ(SHLarith_0) - %MAX_CNT_MEM_ALIGN - CNT_MEM_ALIGN - 1 :JMPN(outOfCountersMemalign) + D => C :SAVE(B,C,D,E,RCX,RR),JMPZ(SHLarith_0) - D => C :SAVE(B,C,D,E,RCX,RR) + %MAX_CNT_MEM_ALIGN - CNT_MEM_ALIGN - 1 :JMPN(outOfCountersMemalign) 0 => B $ => A :MEM_ALIGN_RD :RESTORE, RETURN @@ -701,7 +700,7 @@ SHLarith: SHLarith_32: 0 => A :RETURN SHLarith_0: - :RETURN + :RESTORE, RETURN ; @info Shift right D bits to A ; @in A @@ -712,21 +711,22 @@ SHRarithBit: %MAX_CNT_STEPS - STEP - 9 :JMPN(outOfCountersStep) 255 - D :JMPN(SHRarithBit_A0) - D => RR,RCX :SAVE(B,C,D,E,RCX,RR) + D => RR :SAVE(B,C,D,E,RCX,RR),JMPZ(SHRarithBit_D0) 0 => C,B :JMP(@SHRarithBit_table + RR) SHRarithBit_arith: %MAX_CNT_ARITH - CNT_ARITH - 1 :JMPN(outOfCountersArith) - ${(A >> RCX) & const.MAX_UINT_256} => D - ${(A << (256 - RCX)) & const.MAX_UINT_256} :ARITH - D => A - :RESTORE, RETURN + ${(A >> RR) & const.MAX_UINT_256} => D + ${(A << (256 - RR)) & const.MAX_UINT_256} :ARITH + D => A :RESTORE, RETURN + SHRarithBit_memalign: %MAX_CNT_MEM_ALIGN - CNT_MEM_ALIGN - 1 :JMPN(outOfCountersMemalign) A => B 0 => A $ => A :MEM_ALIGN_RD +SHRarithBit_D0: :RESTORE, RETURN SHRarithBit_A0: 0 => A :RETURN @@ -740,21 +740,23 @@ INCLUDE "tables/shr_bits_table.zkasm" ; @out A - (A << D) => A SHLarithBit: - %MAX_CNT_STEPS - STEP - 9 :JMPN(outOfCountersStep) + %MAX_CNT_STEPS - STEP - 8 :JMPN(outOfCountersStep) 255 - D :JMPN(SHLarithBit_A0) - D => RR,RCX :SAVE(B,C,D,E,RCX,RR) + D => RR :SAVE(B,C,D,E,RCX,RR),JMPZ(SHLarithBit_D0) 0 => C,B :JMP(@SHLarithBit_table + RR) SHLarithBit_arith: %MAX_CNT_ARITH - CNT_ARITH - 1 :JMPN(outOfCountersArith) - ${(A >> (256 - RCX)) & const.MAX_UINT_256} => D - ${(A << RCX) & const.MAX_UINT_256} => A :ARITH - :RESTORE, RETURN + ${(A >> (256 - RR)) & const.MAX_UINT_256} => D + ${(A << RR) & const.MAX_UINT_256} => A :ARITH + :RESTORE, RETURN SHLarithBit_memalign: %MAX_CNT_MEM_ALIGN - CNT_MEM_ALIGN - 1 :JMPN(outOfCountersMemalign) $ => A :MEM_ALIGN_RD + +SHLarithBit_D0: :RESTORE, RETURN SHLarithBit_A0: 0 => A :RETURN From 5b4c23594ebadab7f17c4815cd452545598ce9c0 Mon Sep 17 00:00:00 2001 From: Ignasi Date: Thu, 21 Mar 2024 15:47:37 +0100 Subject: [PATCH 14/16] Optimizations 2 --- main/opcodes/create-terminate-context.zkasm | 12 +- main/utils.zkasm | 236 ++++---------------- 2 files changed, 55 insertions(+), 193 deletions(-) diff --git a/main/opcodes/create-terminate-context.zkasm b/main/opcodes/create-terminate-context.zkasm index 92ad41d3..075d2493 100644 --- a/main/opcodes/create-terminate-context.zkasm +++ b/main/opcodes/create-terminate-context.zkasm @@ -223,8 +223,8 @@ opCALL2: GAS - %CALL_VALUE_TRANSFER_GAS => GAS :JMPN(outOfGas) ; if destAddress is an empty account, we should add 25k of gas to base cost - $ => E :MLOAD(addrCall), CALL(isEmptyAccount); in: [E: address] out: [E: 0 if is not empty, 1 if is empty] - GAS - %CALL_NEW_ACCOUNT_GAS*E => GAS :JMPN(outOfGas) + $ => A :MLOAD(addrCall), CALL(isEmptyAccount); in: [A: address] out: [A: 0 if is not empty, 1 if is empty] + GAS - %CALL_NEW_ACCOUNT_GAS*A => GAS :JMPN(outOfGas) opCALLend: ; setup vars for next CTX @@ -929,8 +929,8 @@ opSENDALL: $ => A :MLOAD(SP), CALL(maskAddress); in: [A: address] out: [A: masked address] A :MSTORE(sendAllAddress) - ; store address receiver in [C, E] - A => C, E + ; store address receiver in C + A => C ; check balance to move is greater than 0 0 => A @@ -945,8 +945,8 @@ opSENDALL: ; move balances opSENDALL2: ; check gas empty account - :CALL(isEmptyAccount); in: [E: address] out: [E: 0 if is not empty, 1 if is empty] - GAS - %CALL_NEW_ACCOUNT_GAS * E => GAS :JMPN(outOfGas) + C => A :CALL(isEmptyAccount); in: [A: address] out: [A: 0 if is not empty, 1 if is empty] + GAS - %CALL_NEW_ACCOUNT_GAS * A => GAS :JMPN(outOfGas) ; save balance storageAddr in arithA for later usage D :MSTORE(arithA) diff --git a/main/utils.zkasm b/main/utils.zkasm index 1d63cd20..830ca7f9 100644 --- a/main/utils.zkasm +++ b/main/utils.zkasm @@ -18,10 +18,6 @@ absIsNeg: $ => A :SUB 1 => B :RETURN -VAR GLOBAL tmpVarBgetLen -VAR GLOBAL tmpVarCgetLen -VAR GLOBAL tmpVarDgetLen -VAR GLOBAL tmpZkPCgetLen ; @info byte length of B ; @in B => number ; @out A => bytes length @@ -29,10 +25,7 @@ getLenBytes: ; checks zk-counters %MAX_CNT_STEPS - STEP - 20 :JMPN(outOfCountersStep) ; store current registries - RR :MSTORE(tmpZkPCgetLen) - B :MSTORE(tmpVarBgetLen) - C :MSTORE(tmpVarCgetLen) - D :MSTORE(tmpVarDgetLen) + :SAVE(B,C,D,E,RR,RCX) ; set C as counter to 0 0 => C B => A @@ -46,8 +39,7 @@ getLenBytesLoop: ; if A is zero, finish counter $ :EQ,JMPC(getLenEnd) ; right shift one byte - 1 => D - zkPC+1 => RR :JMP(SHRarith); in: [A: value, D: #bytes to right shift] out: [A: shifted result] + 1 => D :CALL(SHRarith); in: [A: value, D: #bytes to right shift] out: [A: shifted result] ; increase counter C + 1 => C :JMP(getLenBytesLoop) @@ -55,10 +47,7 @@ getLenEnd: ; counter to A C => A ; recover registries - $ => B :MLOAD(tmpVarBgetLen) - $ => C :MLOAD(tmpVarCgetLen) - $ => RR :MLOAD(tmpZkPCgetLen) - $ => D :MLOAD(tmpVarDgetLen), RETURN + :RESTORE, RETURN ; @info bits length of B ; @in B => number @@ -67,10 +56,7 @@ getLenBits: ; checks zk-counters %MAX_CNT_STEPS - STEP - 20 :JMPN(outOfCountersStep) ; store current registries - RR :MSTORE(tmpZkPCgetLen) - B :MSTORE(tmpVarBgetLen) - C :MSTORE(tmpVarCgetLen) - D :MSTORE(tmpVarDgetLen) + :SAVE(B,C,D,E,RR,RCX) ; set C as counter to 0 0 => C B => A @@ -94,20 +80,16 @@ getLenBitsEnd: ; counter to A C => A ; recover registries - $ => B :MLOAD(tmpVarBgetLen) - $ => C :MLOAD(tmpVarCgetLen) - $ => RR :MLOAD(tmpZkPCgetLen) - $ => D :MLOAD(tmpVarDgetLen), RETURN + :RESTORE, RETURN +VAR GLOBAL tmpVarEmstore +VAR GLOBAL bytesToStore +VAR GLOBAL isMSTOREX +VAR GLOBAL tmpZkPCmstore VAR GLOBAL tmpVarAmstore VAR GLOBAL tmpVarBmstore VAR GLOBAL tmpVarCmstore VAR GLOBAL tmpVarDmstore -VAR GLOBAL tmpVarEmstore -VAR GLOBAL tmpZkPCmstore - -VAR GLOBAL bytesToStore -VAR GLOBAL isMSTOREX ; @info save value to memory < 32 bytes with offset ; @in bytesToStore => bytes to store in memory ; @in E => offset @@ -338,14 +320,9 @@ endMLOAD: errorMLOADMSTORE: :JMP(outOfGas) -VAR GLOBAL tmpVarAemptyAcc -VAR GLOBAL tmpVarBemptyAcc -VAR GLOBAL tmpVarCemptyAcc -VAR GLOBAL tmpVarDemptyAcc - ; @info check account is empty ( balance == nonce == code == 0x ) -; @in E => address -; @out E => isEmpty => 1 = true, 0 = false +; @in A => address +; @out A => isEmpty => 1 = true, 0 = false isEmptyAccount: ; check zk-counters %MAX_CNT_STEPS - STEP - 50 :JMPN(outOfCountersStep) @@ -353,12 +330,8 @@ isEmptyAccount: %MAX_CNT_POSEIDON_G - CNT_POSEIDON_G - %MAX_CNT_POSEIDON_SLOAD_SSTORE*3 :JMPN(outOfCountersPoseidon) ; store current registries - A :MSTORE(tmpVarAemptyAcc) - B :MSTORE(tmpVarBemptyAcc) - C :MSTORE(tmpVarCemptyAcc) - D :MSTORE(tmpVarDemptyAcc) - - E => A + :SAVE(B,C,D,E,RR,RCX) + A => E ; read balance ; set key for smt balance query. %SMT_KEY_BALANCE => B @@ -386,22 +359,14 @@ isEmptyAccount: 0 => A ; if code is not zero, is not empty $ :LT,JMPC(isNotEmptyAccount) - 1 => E :JMP(ISEMPTYEnd) + 1 => A :JMP(IsEmptyEnd) isNotEmptyAccount: - 0 => E :JMP(ISEMPTYEnd) + 0 => A :JMP(IsEmptyEnd) -ISEMPTYEnd: +IsEmptyEnd: ; recover registries - $ => A :MLOAD(tmpVarAemptyAcc) - $ => B :MLOAD(tmpVarBemptyAcc) - $ => C :MLOAD(tmpVarCemptyAcc) - $ => D :MLOAD(tmpVarDemptyAcc), RETURN - -VAR GLOBAL tmpVarBcompGas -VAR GLOBAL tmpVarCcompGas -VAR GLOBAL tmpVarDcompGas -VAR GLOBAL tmpVarEcompGas + :RESTORE,RETURN ; @info Compute gas to send to call following EIP 150 ; @in gasCall: gas sent to call @@ -411,11 +376,7 @@ computeGasSendCall: %MAX_CNT_STEPS - STEP - 30 :JMPN(outOfCountersStep) %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) ; save tmp vars - B :MSTORE(tmpVarBcompGas) - C :MSTORE(tmpVarCcompGas) - D :MSTORE(tmpVarDcompGas) - E :MSTORE(tmpVarEcompGas) - + :SAVE(B,C,D,E,RR,RCX) ; compute all_but_one_64th gas GAS => A @@ -441,17 +402,8 @@ computeGasSendCall: computeGasSendCallEnd: ; restore stored values - $ => B :MLOAD(tmpVarBcompGas) - $ => C :MLOAD(tmpVarCcompGas) - $ => D :MLOAD(tmpVarDcompGas) - $ => E :MLOAD(tmpVarEcompGas), RETURN - -VAR GLOBAL tmpVarAsaveMem -VAR GLOBAL tmpVarBsaveMem -VAR GLOBAL tmpVarCsaveMem -VAR GLOBAL tmpVarDsaveMem -VAR GLOBAL tmpVarEsaveMem -VAR GLOBAL tmpZkPCsaveMem + :RESTORE, RETURN + ; @info compute memory expansion gas cost ; @in: lastMemOffset: offset to copy bytes ; @in: lastMemLength: size of the bytes to copy @@ -459,12 +411,7 @@ saveMem: ; check zk-counters %MAX_CNT_STEPS - STEP - 100 :JMPN(outOfCountersStep) %MAX_CNT_BINARY - CNT_BINARY - 5 :JMPN(outOfCountersBinary) - RR :MSTORE(tmpZkPCsaveMem) - A :MSTORE(tmpVarAsaveMem) - B :MSTORE(tmpVarBsaveMem) - C :MSTORE(tmpVarCsaveMem) - D :MSTORE(tmpVarDsaveMem) - E :MSTORE(tmpVarEsaveMem) + A :SAVE(B,C,D,E,RR,RCX) $ => A :MLOAD(lastMemLength) ; If no len, no memory expansion 0 => B @@ -522,18 +469,8 @@ saveMemGAS: saveMemEnd: ; restore stored values - $ => A :MLOAD(tmpVarAsaveMem) - $ => B :MLOAD(tmpVarBsaveMem) - $ => C :MLOAD(tmpVarCsaveMem) - $ => D :MLOAD(tmpVarDsaveMem) - $ => RR :MLOAD(tmpZkPCsaveMem) - $ => E :MLOAD(tmpVarEsaveMem), RETURN - -VAR GLOBAL tmpVarAArith -VAR GLOBAL tmpVarBArith -VAR GLOBAL tmpVarCArith -VAR GLOBAL tmpVarDArith -VAR GLOBAL tmpVarEArith + :RESTORE, RETURN + VAR GLOBAL arithA VAR GLOBAL arithB VAR GLOBAL arithRes1 @@ -834,34 +771,25 @@ errorAtFirstContext: ;remaining gas = 0 0 => GAS :JMP(sendGasSeq) -VAR GLOBAL tmpVarAoffsetUtil -VAR GLOBAL tmpVarBoffsetUtil ;Get offset/32 & offset%32 ;@in A offset (offset is assumed to be less than %MAX_MEM_EXPANSION_BYTES) ;@out E offset/32 ;@out C offset%32 offsetUtil: %MAX_CNT_STEPS - STEP - 20 :JMPN(outOfCountersStep) - %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) - A :MSTORE(tmpVarAoffsetUtil) - B :MSTORE(tmpVarBoffsetUtil) ; E = [e7, e6, ..., e0] ; JMPN instruction assures e0 is within the range [0, 2**32 - 1] ${A >> 5} => E :JMPN(failAssert) - ${A & 0x1F} => C + $0{A & 0x1F} => C ; C is 32 bits ; since C is assured to be less than 0x20 ; it is enforced that [e7, e6, ..., e1] are 0 since there is no value multiplied by 32 ; that equals the field ; Since e0 is assured to be less than 32 bits, e0 * 32 + c0 could not overflow the field E * 32 + C :ASSERT - C => A - 0x20 => B - $ :LT,JMPNC(failAssert) - - $ => A :MLOAD(tmpVarAoffsetUtil) - $ => B :MLOAD(tmpVarBoffsetUtil), RETURN + 0x1F - C :JMPN(failAssert); If C is greater than 31, it is an error + :RETURN ;@info: move balances between two accounts ;@in: txSrcAddr: source address @@ -1216,24 +1144,13 @@ readPushBytes_1: $ => D :MLOAD(pushBytes), RETURN VAR GLOBAL startsWithEF -VAR GLOBAL tmpVarAEF -VAR GLOBAL tmpVarBEF -VAR GLOBAL tmpVarCEF -VAR GLOBAL tmpVarDEF -VAR GLOBAL tmpVarEEF -VAR GLOBAL tmpZkPCEF ; @info check bytecode first byte != 0xEF as defined in EIP-3541 (https://eips.ethereum.org/EIPS/eip-3541) ; @internalParam {memOffset} memory offset to read bytes from ; @internalParam {startsWithEF} flag to indicate if first deployed byte on the bytecode is 0xEF checkBytecodeStartsEF: %MAX_CNT_STEPS - STEP - 50 :JMPN(outOfCountersStep) ; save temporary registers - A :MSTORE(tmpVarAEF) - B :MSTORE(tmpVarBEF) - C :MSTORE(tmpVarCEF) - D :MSTORE(tmpVarDEF) - E :MSTORE(tmpVarEEF) - RR :MSTORE(tmpZkPCEF) + A :SAVE(B,C,D,E,RCX,RR) ; set flag to 0 0 :MSTORE(startsWithEF) @@ -1254,20 +1171,11 @@ checkBytecodeStartsEF: checkBytecodeStartsEFend: ; set back tmp registers - $ => RR :MLOAD(tmpZkPCEF) - $ => A :MLOAD(tmpVarAEF) - $ => B :MLOAD(tmpVarBEF) - $ => C :MLOAD(tmpVarCEF) - $ => D :MLOAD(tmpVarDEF) - $ => E :MLOAD(tmpVarEEF), RETURN - -VAR GLOBAL tmpVarAhashP -VAR GLOBAL tmpVarBhashP -VAR GLOBAL tmpVarChashP -VAR GLOBAL tmpVarEhashP -VAR GLOBAL tmpZkPChashP + $ => A :RESTORE, RETURN + VAR GLOBAL memOffsetLinearPoseidon VAR GLOBAL memSizeLinearPoseidon +VAR GLOBAL linearPoseidonOutD ; @info Computes hash bytecode from memory bytes ; @internalParam {memOffset} memory offset to read bytes from ; @internalParam {memSize} memory size to read bytes from @@ -1275,11 +1183,7 @@ VAR GLOBAL memSizeLinearPoseidon hashPoseidonLinearFromMemory: %MAX_CNT_STEPS - STEP - 50 :JMPN(outOfCountersStep) %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) - A :MSTORE(tmpVarAhashP) - B :MSTORE(tmpVarBhashP) - C :MSTORE(tmpVarChashP) - E :MSTORE(tmpVarEhashP) - RR :MSTORE(tmpZkPChashP) + A :SAVE(B,C,D,E,RCX,RR) $ => E :MLOAD(memOffsetLinearPoseidon) $ => C :MLOAD(memSizeLinearPoseidon) 0 => D @@ -1290,7 +1194,7 @@ hashPoseidonLinearFromMemory: 56 :MSTORE(arithB), CALL(divARITH); in: [arithA, arithB] out: [arithRes1: arithA/arithB, arithRes2: arithA%arithB] $ => B :MLOAD(arithRes1) %MAX_CNT_POSEIDON_G - CNT_POSEIDON_G - 1 - B :JMPN(outOfCountersPoseidon) - %MAX_CNT_PADDING_PG - CNT_PADDING_PG - 1 - B :JMPN(outOfCountersPadding) + %MAX_CNT_PADDING_PG - CNT_PADDING_PG - 1 - B :JMPN(outOfCountersPadding) ; get a new hashPId $ => B :MLOAD(nextHashPId) @@ -1325,11 +1229,9 @@ hashPoseidonEnd: $ => D :HASHPDIGEST(E) hashPoseidonReturn: - $ => RR :MLOAD(tmpZkPChashP) - $ => A :MLOAD(tmpVarAhashP) - $ => B :MLOAD(tmpVarBhashP) - $ => C :MLOAD(tmpVarChashP) - $ => E :MLOAD(tmpVarEhashP), RETURN + D :MSTORE(linearPoseidonOutD) + $ => A :RESTORE + $ => D :MLOAD(linearPoseidonOutD), RETURN VAR GLOBAL tmpVarBmask ; @info Mask address to 20 bytes @@ -1343,11 +1245,9 @@ maskAddress: $ => A :AND $ => B :MLOAD(tmpVarBmask), RETURN -VAR GLOBAL tmpVarAmulmod -VAR GLOBAL tmpVarBmulmod -VAR GLOBAL tmpVarDmulmod -VAR GLOBAL tmpVarEmulmod -VAR GLOBAL tmpZkPCmulmod +VAR GLOBAL mulModOutC +VAR GLOBAL tmpVarMulMod1 + ; @info (A*B)%C => C ; @in A ; @in B @@ -1359,11 +1259,7 @@ utilMULMOD: %MAX_CNT_BINARY - CNT_BINARY - 4 :JMPN(outOfCountersBinary) %MAX_CNT_ARITH - CNT_ARITH - 2 :JMPN(outOfCountersArith) - RR :MSTORE(tmpZkPCmulmod) - A :MSTORE(tmpVarAmulmod) - B :MSTORE(tmpVarBmulmod) - D :MSTORE(tmpVarDmulmod) - E :MSTORE(tmpVarEmulmod) + A :SAVE(B,C,D,E,RCX,RR) ; The following approach will be followed in order to verify the mulmod operation ; A * B + 0 = D*2^256 + E @@ -1411,7 +1307,7 @@ utilMULMOD: ; D2 must be less than 2²⁵⁶ C => A ; Modulus 0 => C, D - ${B * A} => E :MSTORE(tmpVarDmulmod), ARITH ; D2 + ${B * A} => E :MSTORE(tmpVarMulMod1), ARITH ; D2 ; k.l * N + mulModResult = D1 * 2²⁵⁶ + E ; B * A + C = D*2^256 + E @@ -1434,7 +1330,7 @@ utilMULMOD: ; Assert D1 + D2 = D ; ADD ;ASSERT D => A ; D1 - $ => B :MLOAD(tmpVarDmulmod) ;D2 + $ => B :MLOAD(tmpVarMulMod1) ;D2 ; verify no carry, because D = D1 + D2 must be less than 2**256 ; to pass arithmetic equation A * B + C = D * 2**256 + op @@ -1461,16 +1357,9 @@ zeroOneMod: 0 => C utilMULMODend: - $ => A :MLOAD(tmpVarAmulmod) - $ => B :MLOAD(tmpVarBmulmod) - $ => D :MLOAD(tmpVarDmulmod) - $ => RR :MLOAD(tmpZkPCmulmod) - $ => E :MLOAD(tmpVarEmulmod), RETURN - -VAR GLOBAL tmpVarBexp -VAR GLOBAL tmpVarCexp -VAR GLOBAL tmpVarEexp -VAR GLOBAL tmpZkPCexp + C :MSTORE(mulModOutC) + $ => A :RESTORE + $ => C :MLOAD(mulModOutC), RETURN ;@info exp(A,D) --> A^D ;@in A, D => A^D @@ -1478,10 +1367,7 @@ VAR GLOBAL tmpZkPCexp expAD: %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) %MAX_CNT_STEPS - STEP - 20 :JMPN(outOfCountersStep) - RR :MSTORE(tmpZkPCexp) - B :MSTORE(tmpVarBexp) - C :MSTORE(tmpVarCexp) - E :MSTORE(tmpVarEexp) + :SAVE(B,C,D,E,RCX,RR) ;E base A => E ;B exp @@ -1495,16 +1381,9 @@ expAD: ;if base == 0 --> expA0D $ :EQ,JMPC(expA0D) 1 => C - D => B :CALL(getLenBits) ;A exp bits length - - ; check zk-counters on each loop (A loops) - ; - 3 ARITH: 1 in divARITH + 1 in 2*mulARITH - ; - 5 BINARIES: 5 in divARITH - ; - 100 steps (rounded up): 37 in divARITH + 11 in 2*mulARITH + 18 self - %MAX_CNT_BINARY - CNT_BINARY - 2*A :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 50*A :JMPN(outOfCountersStep) expADloop: + %MAX_CNT_STEPS - STEP - 50 :JMPN(outOfCountersStep) ;A exp D => A 0 => B @@ -1543,10 +1422,7 @@ expAD0: expADend: C => A - $ => B :MLOAD(tmpVarBexp) - $ => C :MLOAD(tmpVarCexp) - $ => RR :MLOAD(tmpZkPCexp) - $ => E :MLOAD(tmpVarEexp), RETURN + :RESTORE, RETURN ;@info function to force a failed assert failAssert: @@ -2131,26 +2007,16 @@ computeMerkleProofReturn: $ => RR :MLOAD(tmpZkPCComputeMerkleProof) :RETURN -VAR GLOBAL tmpZkPCreadXFromOffset VAR GLOBAL readXFromCalldataOffset VAR GLOBAL readXFromCalldataLength VAR GLOBAL readXFromCalldataResult -VAR GLOBAL tmpVarAReadXFromOffset -VAR GLOBAL tmpVarBReadXFromOffset -VAR GLOBAL tmpVarCReadXFromOffset -VAR GLOBAL tmpVarDReadXFromOffset -VAR GLOBAL tmpVarEReadXFromOffset ; @info Reads {readXFromCalldataOffset} bytes (max 32) from a given offset in calldata memory. If offset or offset + length exceeds txCalldataLen, zeros are added ; @internalParam {readXFromCalldataOffset} offset to read from calldata ; @internalParam {readXFromCalldataLength} length to read from calldata ; @returns {readXFromCalldataResult} bytes read from calldata readFromCalldataOffset: %MAX_CNT_STEPS - STEP - 100 :JMPN(outOfCountersStep) - RR :MSTORE(tmpZkPCreadXFromOffset) - A :MSTORE(tmpVarAReadXFromOffset) - B :MSTORE(tmpVarBReadXFromOffset) - C :MSTORE(tmpVarCReadXFromOffset) - E :MSTORE(tmpVarEReadXFromOffset) + A :SAVE(B,C,D,E,RCX,RR) $ => A :MLOAD(txCalldataLen), JMPZ(return0FromCalldata) $ => B :MLOAD(calldataOffset) $ => C :MLOAD(readXFromCalldataLength) @@ -2170,11 +2036,7 @@ return0FromCalldata: 0 :MSTORE(readXFromCalldataResult) readFromCalldataOffsetEnd: - $ => RR :MLOAD(tmpZkPCreadXFromOffset) - $ => A :MLOAD(tmpVarAReadXFromOffset) - $ => B :MLOAD(tmpVarBReadXFromOffset) - $ => C :MLOAD(tmpVarCReadXFromOffset) - $ => E :MLOAD(tmpVarEReadXFromOffset), RETURN + $ => A :RESTORE, RETURN ; @info store calldata pointer to read calldata saveCalldataPointer: From aae005d6eec1f539261a594c35d4352346fceb31 Mon Sep 17 00:00:00 2001 From: Ignasi Date: Fri, 22 Mar 2024 11:35:31 +0100 Subject: [PATCH 15/16] Shift fixes --- main/main.zkasm | 6 ++---- main/opcodes/comparison.zkasm | 20 ++++++++++++-------- main/process-change-l2-block.zkasm | 2 +- main/utils.zkasm | 13 +++++-------- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/main/main.zkasm b/main/main.zkasm index 60292223..56ce5e8e 100644 --- a/main/main.zkasm +++ b/main/main.zkasm @@ -33,7 +33,6 @@ start: ; main zkROM entry point GAS :MSTORE(chainID) ; chainID from GAS, assumed to be less than 32 bits ${getSequencerAddr()} :MSTORE(sequencerAddr) - $0{getTxsLen()} :MSTORE(batchL2DataLength) ; less than 120000 bytes. Enforced by the smart contract ${getBatchHashData()} :MSTORE(batchHashData) ${getForcedHashData()} => A :MSTORE(forcedHashData) 0 => B @@ -96,9 +95,8 @@ computeNewBatchAccInputHash: $ => A :MLOAD(batchHashData) ; No need to compute poseidon consumption, max batchL2Data length is 120000 bytes and this is the beginning of the execution, will always have enough poseidons A :HASHPDIGEST(E) - ; Check batchL2DataLength (CHECK: is it necessary to check this? Is a correct behavior? Is possible to get the length from hashplen?) - $ => HASHPOS :MLOAD(batchL2DataLength) - HASHPOS :HASHPLEN(E) + ; store batchL2DataLength, less than 120000 bytes. Enforced by the smart contract + $ :HASHPLEN(E), MSTORE(batchL2DataLength) ; Load current timestamp %TIMESTAMP_STORAGE_POS => C diff --git a/main/opcodes/comparison.zkasm b/main/opcodes/comparison.zkasm index 6a7ef2d9..a48985a8 100644 --- a/main/opcodes/comparison.zkasm +++ b/main/opcodes/comparison.zkasm @@ -344,11 +344,14 @@ opSHR: ; read two items from the stack SP - 1 => SP - $ => D :MLOAD(SP--) ; [shift => D] + $ => D, A :MLOAD(SP--) ; [shift => D, A] + 256 => B + $ :LT, JMPNC(opSHRZero) ; call SHRarithBit util $ => A :MLOAD(SP), CALL(SHRarithBit) ; [value => A]; [ A >> D => A] A :MSTORE(SP++), JMP(readCode) ; [ A => SP] - +opSHRZero: + 0 :MSTORE(SP++), JMP(readCode) ; [ 0 => SP] /** * @link [https://www.evm.codes/#1b?fork=berlin] * @zk-counters @@ -369,13 +372,14 @@ opSHL: ; read two items from the stack SP - 1 => SP - $ => D :MLOAD(SP--) - $ => A :MLOAD(SP) - - ; CALL shl util - :CALL(SHLarithBit) ; [ A << D => A] + $ => D, A :MLOAD(SP--) ; [shift => D, A] + 256 => B + $ :LT, JMPNC(opSHLZero) + ; CALL SHLarithBit util + $ => A :MLOAD(SP), CALL(SHLarithBit) ; [ A << D => A] A :MSTORE(SP++), JMP(readCode) ; [A => SP] - +opSHLZero: + 0 :MSTORE(SP++), JMP(readCode) ; [ 0 => SP] /** * @link [https://www.evm.codes/#1d?fork=berlin] * @zk-counters diff --git a/main/process-change-l2-block.zkasm b/main/process-change-l2-block.zkasm index caa5033d..8fee1a69 100644 --- a/main/process-change-l2-block.zkasm +++ b/main/process-change-l2-block.zkasm @@ -80,7 +80,7 @@ verifyTimestampAndL1InfoRoot: ${getL1InfoGER(mem.indexL1InfoTree)} :MSTORE(gerL1InfoTree) ${getL1InfoBlockHash(mem.indexL1InfoTree)} :MSTORE(blockHashL1InfoTree) ${getL1InfoMinTimestamp(mem.indexL1InfoTree)} => B :MSTORE(timestampL1InfoTree) - ; Verify (currentTimestamp + deltaTimestamp) >= l1InfoRoot.timestamp + ; Verify (currentTimestamp + deltaTimestamp) >= l1InfoRoot.minTimestamp $ => A :MLOAD(timestamp) $ :LT, JMPC(invalidChangeL2BlockMinTimestamp) ; Compute infoTreeData diff --git a/main/utils.zkasm b/main/utils.zkasm index 830ca7f9..827d3949 100644 --- a/main/utils.zkasm +++ b/main/utils.zkasm @@ -594,9 +594,8 @@ divisorSmallerDiv: ; @info Shift right D bytes to A ; @in A -; @in D +; @in D -> WARNING: expect D to be less than 32 bits ; @out A - A >> (8*D) => A - SHRarith: %MAX_CNT_STEPS - STEP - 8 :JMPN(outOfCountersStep) @@ -618,10 +617,8 @@ SHRarith_0: ; @info Shift left D bytes to A ; @in A -; @in D +; @in D -> WARNING: expect D to be less than 32 bits ; @out A - A << (8*D) => A - - SHLarith: %MAX_CNT_STEPS - STEP - 6 :JMPN(outOfCountersStep) @@ -641,7 +638,7 @@ SHLarith_0: ; @info Shift right D bits to A ; @in A -; @in D +; @in D -> WARNING: expect D to be less than 32 bits ; @out A - (A >> D) => A SHRarithBit: @@ -673,7 +670,7 @@ INCLUDE "tables/shr_bits_table.zkasm" ; @info Shift left D bits to A ; @in A -; @in D +; @in D -> WARNING: expect D to be less than 32 bits ; @out A - (A << D) => A SHLarithBit: @@ -696,7 +693,7 @@ SHLarithBit_memalign: SHLarithBit_D0: :RESTORE, RETURN SHLarithBit_A0: - 0 => A :RETURN + 0 => A :RETURN INCLUDE "tables/shl_bits_table.zkasm" From 232fde26c365621f31533b03df8ff3559a23456f Mon Sep 17 00:00:00 2001 From: Ignasi Date: Fri, 22 Mar 2024 16:01:49 +0100 Subject: [PATCH 16/16] Mstore X optimitzation --- main/utils.zkasm | 385 ++++++++++++++++++++++++++++++----------------- 1 file changed, 245 insertions(+), 140 deletions(-) diff --git a/main/utils.zkasm b/main/utils.zkasm index 827d3949..ecdd1589 100644 --- a/main/utils.zkasm +++ b/main/utils.zkasm @@ -82,160 +82,265 @@ getLenBitsEnd: ; recover registries :RESTORE, RETURN -VAR GLOBAL tmpVarEmstore +VAR GLOBAL tmpVarA_mstore +VAR GLOBAL tmpVarB_mstore +VAR GLOBAL tmpVarD_mstore +VAR GLOBAL tmpVarRR_mstore +VAR GLOBAL tmpVarLength_mstore +VAR GLOBAL tmpVarOffset_mstore +VAR GLOBAL tmpVar32BytesToStore_mstore + VAR GLOBAL bytesToStore -VAR GLOBAL isMSTOREX -VAR GLOBAL tmpZkPCmstore -VAR GLOBAL tmpVarAmstore -VAR GLOBAL tmpVarBmstore -VAR GLOBAL tmpVarCmstore -VAR GLOBAL tmpVarDmstore -; @info save value to memory < 32 bytes with offset -; @in bytesToStore => bytes to store in memory -; @in E => offset -; @in C => length -; @out E => new offset + MSTOREX: - %MAX_CNT_STEPS - STEP - 100 :JMPN(outOfCountersStep) - C :JMPZ(endMSTOREX) - 32 - C :JMPN(errorMLOADMSTORE) - 32 - C - 1 :JMPN(MSTORE32); in: [bytesToStore, E: offset] out: [E: new offset] - 1 :MSTORE(isMSTOREX) + ; check if C == 32 then go to MSTORE32 + C - 32 :JMPZ(MSTORE32) ; in: [bytesToStore, E: offset] out: [E: new offset] + + ; store C with length (bytes), if length == 0 then nothing to do, go to __MSTOREX_end + C :MSTORE(tmpVarLength_mstore),JMPZ(__MSTOREX_end) + + ; check step counters + %MAX_CNT_STEPS - STEP - 40 :JMPN(outOfCountersStep) + + ; if length > 32 then ERROR + 32 - C :JMPN(errorMLOADMSTORE) + + ; saving registers used + A :MSTORE(tmpVarA_mstore) + B :MSTORE(tmpVarB_mstore) + D :MSTORE(tmpVarD_mstore) + RR :MSTORE(tmpVarRR_mstore) + + ; A = offset in bytes of byte-address, no trust, if offset = 0 then go __MSTOREX_offset0 + ; on __MSTOREX_offset0 must be verified value of A. + $0{E % 32} => A :MSTORE(tmpVarOffset_mstore), JMPZ(__MSTOREX_offset0) + + ; check MemAlign counters + %MAX_CNT_MEM_ALIGN - CNT_MEM_ALIGN - 3 :JMPN(outOfCountersMemalign) + + A => C :JMPN(failAssert) ; check A,C is positive 32 bits (A7..A1 = 0 because use $0) + 31 - C :JMPN(failAssert) ; check C < 32, if not MAP + + $0{E / 32} => RR :JMPN(failAssert) ; address (ASSERT RR is 32-bit value) 4G x 32 bytes = 128GB + RR * 32 + C => A ; rebuild address to check that is same. + E :ASSERT + + ; + ; [STEP 1]: Obtain a copy of memory (as a backup) of a 32-byte word that will be partially overwritten. + ; + ; =========================== A (M0_addr) ========================######################### B (M0_addr+1) ######################## + ; : : + ; |<-------- offset ------->======================================########################## => B,oldvalue + ; |<--------------------------- 32 bytes ----------------------->| + ; + + $ => A :MLOAD(MEM:RR) ; M0 + $ => B :MLOAD(MEM:RR+1) ; M1 + ; C = offset, + ; B = 32 current bytes of memory + $ => B :MEM_ALIGN_RD ; read this 32 bytes with offset + + ; + ; [STEP 2]: clear not used bytes of bytesToStore and oldvalue at same time. + ; A short-example with 3 bytes instead of 32. + ; + ; bytesToStore = ABCDEF + ; B (memory backup) = 123456 + ; length = 2 + ; + ; In this operation is cleared two things: + ; - bytes of bytesToStore out of length: ABCDEF => AB0000 + ; - on bytes read from memory, clean where we put bytesToStore: 123456 => 003456 + ; + ; bytesToStore = AB0000 + ; B (memory backup) = 003456 + ; + ; Now we put bytesToStore and B side-by-side + ; + ; bytesToStore | B = ABCDEF123456 + ; ↓ write 0, with offset = 2 + ; bytesToStore' | B' = AB0000003456 + ; + ; This operation is like a MEM_ALIGN_WR where M0 = bytesToStore, M1 = B, V = 0, offset = bytes = 2, W0 = bytesToStore', W1 = B' + ; + ; + ; Graphical example: + ; + ; ******************* A (bytesToStore) ***************************======================================########################## + ; : : + ; |<----------- length ------------->0000000000000000000000000000000000000000000000000000000000000000 + ; |<--------------------------- 32 bytes ----------------------->| + ; ************************************0000000000000000000000000000 : => D + ; 000000000000000000000000000000000000==########################## => E + ; + + $ => A :MLOAD(bytesToStore) + ; B contains bytes of memory before write + $ => C :MLOAD(tmpVarLength_mstore) + ${memAlignWR_W0(A,0,C)} => D ; no trust calculate W0 + ${memAlignWR_W1(B,0,C)} => E ; no trust calculate W1 + 0 :MEM_ALIGN_WR + + ; D ************************************0000000000000000000000000000 + ; E 000000000000000000000000000000000000==########################## + ; D+E ************************************==########################## => tmpVar32BytesToStore_mstore + ; D and E are bit-disjoint, addition as logical-or + + D + E :MSTORE(tmpVar32BytesToStore_mstore) + + ; + ; [STEP 3]: store 32 bytes of this mix of bytes, first "length" bytes comes from bytesToStore, and others bytes comes current value + ; in memory, before write. + ; + ; =========================== A (M0_addr) ========================######################### B (M0_addr+1) ######################## + ; : : + ; |<-------- offset ------->************************************==########################## + ; |<--------------------------- 32 bytes ----------------------->| + ; + ; ==========================************************************==################################################################ + + $ => A :MLOAD(MEM:RR) ;M0 + $ => B :MLOAD(MEM:RR+1) ;M1 + $ => C :MLOAD(tmpVarOffset_mstore) + + ${memAlignWR_W0(A,mem.tmpVar32BytesToStore_mstore,C)} => D ; no trust calculate W0 + ${memAlignWR_W1(B,mem.tmpVar32BytesToStore_mstore,C)} => E ; no trust calculate W1 + $ :MEM_ALIGN_WR,MLOAD(tmpVar32BytesToStore_mstore) + + ; write values on memory + D :MSTORE(MEM:RR) + E :MSTORE(MEM:RR+1) + + ; recalculate result on E as address + length. At this point E = 256-bit address * 32 + offset (C) + ; pending add length + RR * 32 + C => E + + ; restore C with length and add it to E + $ => C :MLOAD(tmpVarLength_mstore) + E + C => E + + ; restore used registers and return + $ => RR :MLOAD(tmpVarRR_mstore) + $ => A :MLOAD(tmpVarA_mstore) + $ => B :MLOAD(tmpVarB_mstore) + $ => D :MLOAD(tmpVarD_mstore),RETURN + +__MSTOREX_end: + ; trivial case if length(C) == 0 + :RETURN + +__MSTOREX_offset0: + ; short path, offset == 0 (no trust) + + %MAX_CNT_MEM_ALIGN - CNT_MEM_ALIGN - 1 :JMPN(outOfCountersMemalign) + + ; in this branch assume offset == 0, if offset != 0 ==> RR * 32 != E + $0{E / 32} => RR :JMPN(failAssert) ; address (ASSERT E is 32-bit value) 4G x 32 bytes = 128GB + RR * 32 - E :JMPNZ(failAssert) ; 32 bits * 32 (5 bits) = 37 bits is secure for FF + + ; [STEP 1]: offset == 0, aligned read, memalign no needed. + $ => B :MLOAD(MEM:RR) ; M0 + + ; [STEP 2]: (see previous explanation) + $ => A :MLOAD(bytesToStore) + ; B = current 32 bytes of memory + ; C = length + ${memAlignWR_W0(A,0,C)} => D ; no trust calculate W0 + ${memAlignWR_W1(B,0,C)} => E ; no trust calculate W1 + 0 :MEM_ALIGN_WR + + ; [STEP 3]: trivial step, offset == 0 ==> aligned write, + ; memalign no needed, directly store the logical-or of D and E + D + E :MSTORE(MEM:RR) + + ; Calculate output E = 256-bit address * 32 + length (C), offset = 0 + RR * 32 + C => E + + ; restore used registers, C contains original value (length) + $ => RR :MLOAD(tmpVarRR_mstore) + $ => A :MLOAD(tmpVarA_mstore) + $ => B :MLOAD(tmpVarB_mstore) + $ => D :MLOAD(tmpVarD_mstore),RETURN ; @info save value to memory 32 bytes with offset ; @in bytesToStore => bytes to store in memory ; @in E => offset ; @out E => new offset + MSTORE32: - ; checks zk-counters - %MAX_CNT_STEPS - STEP - 50 :JMPN(outOfCountersStep) - %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) - %MAX_CNT_MEM_ALIGN - CNT_MEM_ALIGN - 1 :JMPN(outOfCountersMemalign) - ; store current registries - RR :MSTORE(tmpZkPCmstore) - A :MSTORE(tmpVarAmstore) - B :MSTORE(tmpVarBmstore) - C :MSTORE(tmpVarCmstore) - D :MSTORE(tmpVarDmstore) - ; check offset is lower than max memory - E => A - %MAX_MEM_EXPANSION_BYTES => B - $ :LT,JMPC(initMSTORE, errorMLOADMSTORE) - -initMSTORE: - zkPC+1 => RR :JMP(offsetUtil); in: [A: offset] out: [E: offset/32, C: offset%32] - ; is storing <32 bytes, jump to store last bytes or finish if 0 bytes left - $ => B :MLOAD(isMSTOREX), JMPZ(finalMSTORE) - ; if C has value, offset != 0 - C :JMPNZ(MSTOREX2) - $ => C :MLOAD(tmpVarCmstore) - ; load bytes to store - $ => A :MLOAD(bytesToStore) - 32 - C => D - ; shift bytes to store - zkPC+1 => RR :JMP(SHRarith); in: [A: value, D: #bytes to right shift] out: [A: shifted result] - zkPC+1 => RR :JMP(SHLarith); in: [A: value, D: #bytes to left shift] out: [A: shifted result] - A => B - ; load from memory - $ => A :MLOAD(MEM:E) - 32 - D => D - ; shift loaded bytes - zkPC+1 => RR :JMP(SHLarith); in: [A: value, D: #bytes to left shift] out: [A: shifted result] - zkPC+1 => RR :JMP(SHRarith); in: [A: value, D: #bytes to right shift] out: [A: shifted result] - A + B :MSTORE(bytesToStore) - A + B => A - 0 => C :JMP(finalMSTORE) - -; used if bytesToStore.length < 32 && offset != 0 -MSTOREX2: - $ => D :MLOAD(tmpVarCmstore) - C + D => D - 32 - D :JMPN(MSTOREX3) - ; if bytesToStore.length < 32 && memory to load is allocated in two different slots - ; load memory from slot E - $ => A :MLOAD(MEM:E) - ; shift loaded memory from slot E - zkPC+1 => RR :JMP(SHLarith); in: [A: value, D: #bytes to left shift] out: [A: shifted result] - $ => D :MLOAD(tmpVarCmstore) - zkPC+1 => RR :JMP(SHRarith); in: [A: value, D: #bytes to right shift] out: [A: shifted result] - A => B - ; load memory from slot E+1 - $ => A :MLOAD(MEM:E+1) - 32 - C => D - ; right shift loaded memory from slot E+1 - zkPC+1 => RR :JMP(SHRarith); in: [A: value, D: #bytes to right shift] out: [A: shifted result] - ; join both results - A + B => B - $ => A :MLOAD(bytesToStore) - $ => D :MLOAD(tmpVarCmstore) - 32 - D => D - ; shift bytes to store - zkPC+1 => RR :JMP(SHRarith); in: [A: value, D: #bytes to right shift] out: [A: shifted result] - zkPC+1 => RR :JMP(SHLarith); in: [A: value, D: #bytes to left shift] out: [A: shifted result] - ; append loaded bytes from concurrent slots - A + B => A :MSTORE(bytesToStore) - :JMP(finalMSTORE) - -; used if bytesToStore.length < 32 && memory to load is allocated in one slot -MSTOREX3: - D - 32 => D - ; load memory from slot E+1 - $ => A :MLOAD(MEM:E+1) - ; shift bytes to store - zkPC+1 => RR :JMP(SHLarith); in: [A: value, D: #bytes to left shift] out: [A: shifted result] - $ => D :MLOAD(tmpVarCmstore) - zkPC+1 => RR :JMP(SHRarith); in: [A: value, D: #bytes to right shift] out: [A: shifted result] - ; join both results - A => B - $ => A :MLOAD(bytesToStore) - $ => D :MLOAD(tmpVarCmstore) - 32 - D => D - ; shift bytes to store - zkPC+1 => RR :JMP(SHRarith); in: [A: value, D: #bytes to right shift] out: [A: shifted result] - zkPC+1 => RR :JMP(SHLarith); in: [A: value, D: #bytes to left shift] out: [A: shifted result] - ; append loaded bytes from concurrent slots - A + B => A :MSTORE(bytesToStore) + ; store C (length) + A :MSTORE(tmpVarA_mstore) -finalMSTORE: - C :JMPNZ(memAlignOptionMSTORE) - $ => A :MLOAD(bytesToStore) - A :MSTORE(MEM:E) - E*32 => E - $ :MLOAD(isMSTOREX),JMPZ(offsetMSTORE32) - $ => C :MLOAD(tmpVarCmstore) - E + C => E - 0 :MSTORE(isMSTOREX),JMP(endMSTORE) + ; setting A as offset (no trust) + $0{E & 0x1F} => A :JMPZ(__MSTORE32_offset_0) -memAlignOptionMSTORE: - E :MSTORE(tmpVarEmstore) + ; at this point A != 0, but could be negative or positive + %MAX_CNT_STEPS - STEP - 30 :JMPN(outOfCountersStep) + %MAX_CNT_MEM_ALIGN - CNT_MEM_ALIGN - 1 :JMPN(outOfCountersMemalign) - $ => A :MLOAD(MEM:E) - $ => B :MLOAD(MEM:E+1) + ; store registers will be used + C :MSTORE(tmpVarLength_mstore) + RR :MSTORE(tmpVarRR_mstore) + B :MSTORE(tmpVarB_mstore) + D :MSTORE(tmpVarD_mstore) - ${memAlignWR_W0(A,mem.bytesToStore,C)} => D ; no trust calculate W0 - ${memAlignWR_W1(B,mem.bytesToStore,C)} => E ; no trust calculate W1 - $ :MEM_ALIGN_WR,MLOAD(bytesToStore) - E => A - $ => E :MLOAD(tmpVarEmstore) - D :MSTORE(MEM:E) ; write W0 - A :MSTORE(MEM:E+1) ; write W1 - E*32 + C => E - $ => A :MLOAD(isMSTOREX), JMPZ(offsetMSTORE32) - $ => C :MLOAD(tmpVarCmstore) - E + C => E - 0 :MSTORE(isMSTOREX), JMP(endMSTORE) + A => C :JMPN(failAssert) ; check C >= 0 (C7..C1 == 0 because use $0) + 31 - C :JMPN(failAssert) ; assert(C < 32) + $0{E >> 5} => RR :JMPN(failAssert) ; RR must be a 32-bits positive value + E => A + RR * 32 + C :ASSERT ; RR * 32 + C = E (use 38 bits secure) + ; validated offset and 256-bit address -offsetMSTORE32: - E + 32 => E + ; [STEP 1]: unnecessary because length = 32 => directly MemAlign + ; [STEP 2]: unnecessary we don't need to mix anything => directly MemAlign -endMSTORE: - $ => A :MLOAD(tmpVarAmstore) - $ => B :MLOAD(tmpVarBmstore) - $ => C :MLOAD(tmpVarCmstore) - $ => RR :MLOAD(tmpZkPCmstore) - $ => D :MLOAD(tmpVarDmstore), RETURN -endMSTOREX: - :RETURN + ; [STEP 3]: with MemAlign calculate (verify) W0,W1 to write on memory + $ => A :MLOAD(MEM:RR) ;M0 + $ => B :MLOAD(MEM:RR+1) ;M1 + ${memAlignWR_W0(A,mem.bytesToStore,C)} => D ; no trust calculate W0 + ${memAlignWR_W1(B,mem.bytesToStore,C)} => E ; no trust calculate W1 + $ :MEM_ALIGN_WR,MLOAD(bytesToStore) + E :MSTORE(MEM:RR+1) + D :MSTORE(MEM:RR) + + ; restore saved registers + $ => A :MLOAD(tmpVarA_mstore) + $ => B :MLOAD(tmpVarB_mstore) + $ => D :MLOAD(tmpVarD_mstore) + + ; Calculate output E = 256-bit address * 32 + offset (C) + length (32) + RR * 32 + C + 32 => E + + ; restore RR and C, this last because C is overwritten with offset + $ => RR :MLOAD(tmpVarRR_mstore) + $ => C :MLOAD(tmpVarLength_mstore), RETURN + + +__MSTORE32_offset_0: + ; short path, offset == 0 (no trust) + ; 32 bytes and offset == 0 ==> no mem align needed + + %MAX_CNT_STEPS - STEP - 10 :JMPN(outOfCountersStep) + + RR :MSTORE(tmpVarRR_mstore) + + ${E >> 5} => RR :JMPN(failAssert) ; RR must be a 32-bits positive value + + RR * 32 => A + E :ASSERT ; RR * 32 = E (use 37 bits secure) check offset = 0 + + ; if offset is 0, and length 32, directly store value on memory + $ => A :MLOAD(bytesToStore) + + ; stored on memory + A :MSTORE(MEM:RR) + + ; Calculate output E = 256-bit address * 32 + offset (0) + length (32) + RR * 32 + 32 => E + + ; restore saved registers and return + $ => RR :MLOAD(tmpVarRR_mstore) + $ => A :MLOAD(tmpVarA_mstore), RETURN VAR GLOBAL tmpVarAmload VAR GLOBAL tmpVarBmload