zkevm-rom 0.0.1-security → 6.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of zkevm-rom might be problematic. Click here for more details.
- package/.eslintrc.js +33 -0
- package/.github/CODEOWNERS +14 -0
- package/.github/ISSUE_TEMPLATE/bug.yml +38 -0
- package/.github/ISSUE_TEMPLATE/feature.yml +26 -0
- package/.github/ISSUE_TEMPLATE/question.yml +26 -0
- package/.github/workflows/main.yaml +40 -0
- package/LICENSE +636 -0
- package/README.md +23 -5
- package/audits/Hexens_Polygon_zkEVM_PUBLIC_27.02.23.pdf +0 -0
- package/audits/Polygon-zkEVM-Public-v1.1-verichains-19-03-2024.pdf +0 -0
- package/audits/zkEVM-ROM-upgrade-1-Spearbit-30-May.pdf +0 -0
- package/audits/zkEVM-ROM-upgrade-2-Spearbit-21-August.pdf +0 -0
- package/audits/zkEVM-engagement-1-Spearbit-27-March.pdf +0 -0
- package/audits/zkEVM-engagement-2-Spearbit-27-March.pdf +0 -0
- package/audits/zkEVM-engagement-3-Spearbit-6-April.pdf +0 -0
- package/counters/README.md +45 -0
- package/counters/counters-executor.js +80 -0
- package/counters/countersConstants.zkasm +370 -0
- package/counters/endIncludes.zkasm +18 -0
- package/counters/initIncludes.zkasm +2 -0
- package/counters/tests/MLOAD32.zkasm +27 -0
- package/counters/tests/MLOADX.zkasm +30 -0
- package/counters/tests/MSTORE32.zkasm +32 -0
- package/counters/tests/MSTOREX.zkasm +36 -0
- package/counters/tests/SHLarith.zkasm +28 -0
- package/counters/tests/SHLarithBit.zkasm +28 -0
- package/counters/tests/SHRarith.zkasm +28 -0
- package/counters/tests/SHRarithBit.zkasm +28 -0
- package/counters/tests/abs.zkasm +29 -0
- package/counters/tests/addBatchHashByteByByte.zkasm +31 -0
- package/counters/tests/computeGasSendCall.zkasm +30 -0
- package/counters/tests/divArith.zkasm +27 -0
- package/counters/tests/expAD.zkasm +30 -0
- package/counters/tests/getLenBits.zkasm +30 -0
- package/counters/tests/getLenBytes.zkasm +32 -0
- package/counters/tests/isEmptyAccount.zkasm +30 -0
- package/counters/tests/mulARITH.zkasm +28 -0
- package/counters/tests/offsetUtil.zkasm +29 -0
- package/counters/tests/opADDMOD.zkasm +28 -0
- package/counters/tests/opAdd.zkasm +27 -0
- package/counters/tests/opBLOCKHASH.zkasm +28 -0
- package/counters/tests/opCALL.zkasm +41 -0
- package/counters/tests/opCALLCODE.zkasm +41 -0
- package/counters/tests/opCALLDATACOPY.zkasm +28 -0
- package/counters/tests/opCALLDATALOAD.zkasm +27 -0
- package/counters/tests/opCODECOPY.zkasm +28 -0
- package/counters/tests/opCREATE.zkasm +35 -0
- package/counters/tests/opCREATE2.zkasm +35 -0
- package/counters/tests/opDELEGATECALL.zkasm +35 -0
- package/counters/tests/opDIV.zkasm +27 -0
- package/counters/tests/opEXP.zkasm +29 -0
- package/counters/tests/opEXTCODECOPY.zkasm +29 -0
- package/counters/tests/opMOD.zkasm +27 -0
- package/counters/tests/opMUL.zkasm +27 -0
- package/counters/tests/opMULMOD.zkasm +28 -0
- package/counters/tests/opRETURN.zkasm +32 -0
- package/counters/tests/opRETURNDATACOPY.zkasm +29 -0
- package/counters/tests/opREVERT.zkasm +32 -0
- package/counters/tests/opSDIV.zkasm +28 -0
- package/counters/tests/opSHA3.zkasm +28 -0
- package/counters/tests/opSIGNEXTEND.zkasm +27 -0
- package/counters/tests/opSMOD.zkasm +28 -0
- package/counters/tests/opSTATICCALL.zkasm +35 -0
- package/counters/tests/opSUB.zkasm +27 -0
- package/counters/tests/saveMem.zkasm +31 -0
- package/docs/opcode-cost-zk-counters.md +315 -0
- package/docs/usage-ecrecover.md +51 -0
- package/index.js +43 -0
- package/main/block-info.zkasm +204 -0
- package/main/constants.zkasm +145 -0
- package/main/ecrecover/addFpEc.zkasm +31 -0
- package/main/ecrecover/checkSqrtFpEc.zkasm +1558 -0
- package/main/ecrecover/constEc.zkasm +13 -0
- package/main/ecrecover/ecrecover.zkasm +280 -0
- package/main/ecrecover/invFnEc.zkasm +44 -0
- package/main/ecrecover/invFpEc.zkasm +45 -0
- package/main/ecrecover/mulFnEc.zkasm +36 -0
- package/main/ecrecover/mulFpEc.zkasm +36 -0
- package/main/ecrecover/mulPointEc.zkasm +311 -0
- package/main/ecrecover/sqFpEc.zkasm +38 -0
- package/main/ecrecover/sqrtFpEc.zkasm +70 -0
- package/main/end.zkasm +4 -0
- package/main/l2-tx-hash.zkasm +159 -0
- package/main/load-change-l2-block-utils.zkasm +11 -0
- package/main/load-change-l2-block.zkasm +28 -0
- package/main/load-tx-rlp-utils.zkasm +72 -0
- package/main/load-tx-rlp.zkasm +431 -0
- package/main/main.zkasm +237 -0
- package/main/map-opcodes.zkasm +274 -0
- package/main/modexp/array_lib/array_add_AGTB.zkasm +123 -0
- package/main/modexp/array_lib/array_add_short.zkasm +85 -0
- package/main/modexp/array_lib/array_div.zkasm +215 -0
- package/main/modexp/array_lib/array_div_long.zkasm +284 -0
- package/main/modexp/array_lib/array_div_short.zkasm +222 -0
- package/main/modexp/array_lib/array_mul.zkasm +97 -0
- package/main/modexp/array_lib/array_mul_long.zkasm +156 -0
- package/main/modexp/array_lib/array_mul_short.zkasm +127 -0
- package/main/modexp/array_lib/array_square.zkasm +246 -0
- package/main/modexp/array_lib/unused/array_add.zkasm +100 -0
- package/main/modexp/array_lib/unused/array_is_odd.zkasm +23 -0
- package/main/modexp/array_lib/unused/array_is_one.zkasm +33 -0
- package/main/modexp/array_lib/unused/array_is_zero.zkasm +34 -0
- package/main/modexp/array_lib/unused/array_sub_AGTB.zkasm +111 -0
- package/main/modexp/array_lib/unused/array_unshift.zkasm +37 -0
- package/main/modexp/array_lib/utils/array_compare.zkasm +82 -0
- package/main/modexp/array_lib/utils/array_trim.zkasm +49 -0
- package/main/modexp/constants.zkasm +5 -0
- package/main/modexp/modexp.zkasm +296 -0
- package/main/modexp/modexp_utils.zkasm +230 -0
- package/main/opcodes/arithmetic.zkasm +357 -0
- package/main/opcodes/block.zkasm +163 -0
- package/main/opcodes/calldata-returndata-code.zkasm +619 -0
- package/main/opcodes/comparison.zkasm +446 -0
- package/main/opcodes/context-information.zkasm +169 -0
- package/main/opcodes/create-terminate-context.zkasm +1011 -0
- package/main/opcodes/crypto.zkasm +96 -0
- package/main/opcodes/flow-control.zkasm +126 -0
- package/main/opcodes/logs.zkasm +193 -0
- package/main/opcodes/stack-operations.zkasm +658 -0
- package/main/opcodes/storage-memory.zkasm +313 -0
- package/main/pairings/BN254/addPointBN254.zkasm +245 -0
- package/main/pairings/BN254/ecAdd.zkasm +312 -0
- package/main/pairings/BN254/ecMul.zkasm +159 -0
- package/main/pairings/BN254/escalarMulBN254.zkasm +155 -0
- package/main/pairings/BN254/lineDiffPointsBN254.zkasm +83 -0
- package/main/pairings/BN254/lineSamePointsBN254.zkasm +96 -0
- package/main/pairings/FP12BN254/CYCLOFP12BN254/compressFp12BN254.zkasm +49 -0
- package/main/pairings/FP12BN254/CYCLOFP12BN254/decompressFp12BN254.zkasm +236 -0
- package/main/pairings/FP12BN254/CYCLOFP12BN254/expByXCompCycloFp12BN254.zkasm +444 -0
- package/main/pairings/FP12BN254/CYCLOFP12BN254/squareCompCycloFp12BN254.zkasm +212 -0
- package/main/pairings/FP12BN254/CYCLOFP12BN254/squareCycloFp12BN254.zkasm +228 -0
- package/main/pairings/FP12BN254/CYCLOFP12BN254/xBinDecompBN254.zkasm +64 -0
- package/main/pairings/FP12BN254/frob2Fp12BN254.zkasm +80 -0
- package/main/pairings/FP12BN254/frob3Fp12BN254.zkasm +96 -0
- package/main/pairings/FP12BN254/frobFp12BN254.zkasm +96 -0
- package/main/pairings/FP12BN254/inverseFp12BN254.zkasm +289 -0
- package/main/pairings/FP12BN254/mulFp12BN254.zkasm +408 -0
- package/main/pairings/FP12BN254/sparseMulAFp12BN254.zkasm +296 -0
- package/main/pairings/FP12BN254/sparseMulBFp12BN254.zkasm +291 -0
- package/main/pairings/FP12BN254/squareFp12BN254.zkasm +376 -0
- package/main/pairings/FP2BN254/addFp2BN254.zkasm +19 -0
- package/main/pairings/FP2BN254/escalarMulFp2BN254.zkasm +20 -0
- package/main/pairings/FP2BN254/invFp2BN254.zkasm +66 -0
- package/main/pairings/FP2BN254/mulFp2BN254.zkasm +19 -0
- package/main/pairings/FP2BN254/squareFp2BN254.zkasm +21 -0
- package/main/pairings/FP2BN254/subFp2BN254.zkasm +19 -0
- package/main/pairings/FP4BN254/squareFp4BN254.zkasm +76 -0
- package/main/pairings/FP6BN254/addFp6BN254.zkasm +59 -0
- package/main/pairings/FP6BN254/escalarMulFp6BN254.zkasm +51 -0
- package/main/pairings/FP6BN254/inverseFp6BN254.zkasm +208 -0
- package/main/pairings/FP6BN254/mulFp6BN254.zkasm +201 -0
- package/main/pairings/FP6BN254/sparseMulAFp6BN254.zkasm +65 -0
- package/main/pairings/FP6BN254/sparseMulBFp6BN254.zkasm +134 -0
- package/main/pairings/FP6BN254/sparseMulCFp6BN254.zkasm +128 -0
- package/main/pairings/FP6BN254/squareFp6BN254.zkasm +147 -0
- package/main/pairings/FP6BN254/subFp6BN254.zkasm +59 -0
- package/main/pairings/FPBN254/addFpBN254.zkasm +29 -0
- package/main/pairings/FPBN254/invFpBN254.zkasm +55 -0
- package/main/pairings/FPBN254/mulFpBN254.zkasm +29 -0
- package/main/pairings/FPBN254/reduceFpBN254.zkasm +25 -0
- package/main/pairings/FPBN254/squareFpBN254.zkasm +31 -0
- package/main/pairings/FPBN254/subFpBN254.zkasm +36 -0
- package/main/pairings/FRBN254/reduceFrBN254.zkasm +25 -0
- package/main/pairings/constants.zkasm +62 -0
- package/main/pairings/ecPairing.zkasm +244 -0
- package/main/pairings/finalExpBN254.zkasm +2095 -0
- package/main/pairings/halfPairingBN254.zkasm +428 -0
- package/main/pairings/loopLengthBN254.zkasm +75 -0
- package/main/pairings/millerLoopBN254.zkasm +741 -0
- package/main/pairings/pairingBN254.zkasm +481 -0
- package/main/pairings/unused/addFp12BN254.zkasm +130 -0
- package/main/pairings/unused/expByXCycloFp12BN254.zkasm +411 -0
- package/main/pairings/unused/expFp12BN254.zkasm +333 -0
- package/main/pairings/unused/subFp12BN254.zkasm +130 -0
- package/main/pairings/unused/xPseudoBinDecompBN254.zkasm +68 -0
- package/main/pairings/utilsTests/expCycloFp12BN254.zkasm +334 -0
- package/main/precompiled/end.zkasm +42 -0
- package/main/precompiled/identity.zkasm +99 -0
- package/main/precompiled/pre-ecAdd.zkasm +84 -0
- package/main/precompiled/pre-ecMul.zkasm +82 -0
- package/main/precompiled/pre-ecPairing.zkasm +72 -0
- package/main/precompiled/pre-ecrecover.zkasm +71 -0
- package/main/precompiled/pre-modexp.zkasm +367 -0
- package/main/precompiled/pre-sha2-256.zkasm +125 -0
- package/main/precompiled/revert-precompiled.zkasm +25 -0
- package/main/precompiled/selector.zkasm +77 -0
- package/main/process-change-l2-block.zkasm +147 -0
- package/main/process-tx.zkasm +587 -0
- package/main/tables/2-exp.zkasm +260 -0
- package/main/touched.zkasm +118 -0
- package/main/utils.zkasm +2335 -0
- package/main/vars.zkasm +117 -0
- package/package.json +62 -3
- package/test/bytes-length.zkasm +39 -0
- package/test/ecrecover.zkasm +538 -0
- package/test/lt4-test.zkasm +38 -0
- package/test/mstorex.zkasm +191 -0
- package/test/opcalldatacopy.ignore.zkasm +331 -0
- package/test/performance/read-push.zkasm +71 -0
- package/test/read-push.zkasm +304 -0
- package/test/testArrayArith.zkasm +1099 -0
- package/test/testArrayUtils.zkasm +335 -0
- package/test/testCycloFp12ArithBN254.zkasm +548 -0
- package/test/testEcAdd.zkasm +252 -0
- package/test/testEcMul.zkasm +231 -0
- package/test/testEcPairing.zkasm +436 -0
- package/test/testFinalExpBn254.zkasm +139 -0
- package/test/testFp12ArithBN254.zkasm +692 -0
- package/test/testFp2ArithBN254.zkasm +185 -0
- package/test/testFp4ArithBN254.zkasm +128 -0
- package/test/testFp6ArithBN254.zkasm +260 -0
- package/test/testFpArithBN254.zkasm +159 -0
- package/test/testFrArithBN254.zkasm +113 -0
- package/test/testHalfPairingBN254.zkasm +285 -0
- package/test/testModExp.zkasm +586 -0
- package/test/testModExpReturn.zkasm +81 -0
- package/test/testPairingBN254.zkasm +463 -0
- package/test/testPointArithBN254.zkasm +270 -0
- package/test/testSHA256.zkasm +27 -0
- package/test/touched-assert.zkasm +59 -0
- package/test/utils-expAD.zkasm +48 -0
- package/test/utils-getLenBytes.zkasm +36 -0
- package/tools/audit-tools/registry-op-checker.js +71 -0
- package/tools/get-not-used-labels.js +31 -0
- package/tools/helpers/helpers.js +47 -0
- package/tools/modexp-utils/README.md +5 -0
- package/tools/modexp-utils/modexp-test-gen.js +168 -0
- package/tools/modexp-utils/modexp-test-int.sage +37 -0
- package/tools/parallel-testing/checker.sh +6 -0
- package/tools/parallel-testing/gen-parallel-tests.js +78 -0
- package/tools/parallel-testing/parallel-tests-sample/sample.test.js +136 -0
- package/tools/run-tests-zkasm.js +83 -0
@@ -0,0 +1,222 @@
|
|
1
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2
|
+
;; PRE: The input arrays have been trimmed.
|
3
|
+
;; POST: The quotient is trimmed.
|
4
|
+
;;
|
5
|
+
;; array_div_short:
|
6
|
+
;; in:
|
7
|
+
;; · C ∈ [1, 32], the len of inA
|
8
|
+
;; · inA ∈ [0, 2²⁵⁶ - 1]^C, the first input array
|
9
|
+
;; · inB ∈ [0, 2²⁵⁶ - 1], the second input
|
10
|
+
;;
|
11
|
+
;; output:
|
12
|
+
;; · [quo,rem] = [inA / inB[0], inA % inB[0]], with len(quo) <= C, len(rem) = 1
|
13
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
14
|
+
|
15
|
+
; function array_div_short(a: bigint[], b: bigint, base: bigint): bigint[] {
|
16
|
+
; if (a === [0n]) {
|
17
|
+
; if (b === 0n) {
|
18
|
+
; throw new Error("Division by zero");
|
19
|
+
; }
|
20
|
+
; return [0n, 0n];
|
21
|
+
; } else if (b === 0n) {
|
22
|
+
; throw new Error("Division by zero");
|
23
|
+
; }
|
24
|
+
;
|
25
|
+
; if (a === b) {
|
26
|
+
; return [1n, 0n];
|
27
|
+
; } else if (a < b) {
|
28
|
+
; return [0n, a];
|
29
|
+
; }
|
30
|
+
; }
|
31
|
+
|
32
|
+
; NOTE: This function receives the actual result from the helper (avoiding the need of computing divisions);
|
33
|
+
; checks the correctness of the result and returns the result to the caller
|
34
|
+
|
35
|
+
VAR GLOBAL array_div_short_inA[%ARRAY_MAX_LEN]
|
36
|
+
VAR GLOBAL array_div_short_inB
|
37
|
+
VAR GLOBAL array_div_short_quo[%ARRAY_MAX_LEN]
|
38
|
+
VAR GLOBAL array_div_short_rem
|
39
|
+
|
40
|
+
VAR GLOBAL array_div_short_len_inA
|
41
|
+
VAR GLOBAL array_div_short_len_quo
|
42
|
+
|
43
|
+
VAR GLOBAL array_div_short_RR
|
44
|
+
|
45
|
+
; ERROR CODES (B)
|
46
|
+
; 0 - no error
|
47
|
+
; 1 - inB is zero
|
48
|
+
|
49
|
+
array_div_short:
|
50
|
+
%MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary)
|
51
|
+
%MAX_CNT_STEPS - STEP - 11 - 3*C - 3 :JMPN(outOfCountersStep)
|
52
|
+
|
53
|
+
RR :MSTORE(array_div_short_RR)
|
54
|
+
|
55
|
+
C :MSTORE(array_div_short_len_inA)
|
56
|
+
C :MSTORE(array_div_short_len_quo)
|
57
|
+
|
58
|
+
; Let's cover the edge cases
|
59
|
+
1 => B
|
60
|
+
; 1] Is C == 1 and inA == 0?
|
61
|
+
C - B :JMPNZ(__array_div_short_inA_continue)
|
62
|
+
$ => A :MLOAD(array_div_short_inA)
|
63
|
+
$ :LT, JMPC(array_div_short_inA_is_zero)
|
64
|
+
__array_div_short_inA_continue:
|
65
|
+
|
66
|
+
; 2] Is inB == 0?
|
67
|
+
$ => A :MLOAD(array_div_short_inB)
|
68
|
+
$ :LT, JMPC(array_div_short_inB_is_zero)
|
69
|
+
|
70
|
+
; Check whether inA = inB or inA < inB
|
71
|
+
C - 1 => RR
|
72
|
+
1 => D
|
73
|
+
array_div_short_inA_to_compare1:
|
74
|
+
$ => A :MLOAD(array_div_short_inA + RR)
|
75
|
+
A :MSTORE(array_compare_inA + RR)
|
76
|
+
RR - 1 => RR :JMPN(array_div_short_inB_to_compare, array_div_short_inA_to_compare1)
|
77
|
+
|
78
|
+
array_div_short_inB_to_compare:
|
79
|
+
$ => A :MLOAD(array_div_short_inB)
|
80
|
+
A :MSTORE(array_compare_inB)
|
81
|
+
|
82
|
+
array_div_short_compare_inA_inB:
|
83
|
+
:CALL(array_compare)
|
84
|
+
|
85
|
+
%MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary)
|
86
|
+
%MAX_CNT_STEPS - STEP - 10 - 4*%ARRAY_MAX_LEN - 3 :JMPN(outOfCountersStep)
|
87
|
+
|
88
|
+
$ => A :MLOAD(array_compare_result), JMPZ(array_div_short_inALTinB)
|
89
|
+
A - 1 :JMPZ(array_div_short_same_input)
|
90
|
+
; From here, inA > inB
|
91
|
+
|
92
|
+
; Strategy: Divide outside and check the result inside
|
93
|
+
$${MPdiv_short(addr.array_div_short_inA,mem.array_div_short_len_inA,mem.array_div_short_inB)}
|
94
|
+
|
95
|
+
:JMP(array_div_short_prepare_mul_quo_inB)
|
96
|
+
|
97
|
+
; Begin of edge cases
|
98
|
+
array_div_short_inA_is_zero:
|
99
|
+
; Is inB == 0? 0/0 is undefined
|
100
|
+
$ => A :MLOAD(array_div_short_inB)
|
101
|
+
$ :LT, JMPC(array_div_short_inB_is_zero)
|
102
|
+
; From here, inB != 0
|
103
|
+
|
104
|
+
; Return [q,r] = [0,0] and len(q) = 1, len(r) = 1
|
105
|
+
0 :MSTORE(array_div_short_quo)
|
106
|
+
0 :MSTORE(array_div_short_rem)
|
107
|
+
1 :MSTORE(array_div_short_len_quo)
|
108
|
+
0 => B :JMP(array_div_short_end)
|
109
|
+
|
110
|
+
array_div_short_inB_is_zero:
|
111
|
+
; Error, you cannot divide by 0
|
112
|
+
1 => B :JMP(array_div_short_end)
|
113
|
+
|
114
|
+
array_div_short_same_input:
|
115
|
+
; If inA = inB, then the result is [1,0] since inA = 1·inB + 0
|
116
|
+
1 :MSTORE(array_div_short_quo)
|
117
|
+
1 :MSTORE(array_div_short_len_quo)
|
118
|
+
0 :MSTORE(array_div_short_rem)
|
119
|
+
0 => B :JMP(array_div_short_end)
|
120
|
+
|
121
|
+
array_div_short_inALTinB:
|
122
|
+
; If inA < inB, then the result is [0, inA] since inA = 0·inB + inA
|
123
|
+
0 :MSTORE(array_div_short_quo)
|
124
|
+
1 :MSTORE(array_div_short_len_quo)
|
125
|
+
$ => A :MLOAD(array_div_short_inA)
|
126
|
+
A :MSTORE(array_div_short_rem)
|
127
|
+
0 => B :JMP(array_div_short_end)
|
128
|
+
; End of edge cases
|
129
|
+
|
130
|
+
array_div_short_prepare_mul_quo_inB:
|
131
|
+
$0{receiveLenQuotient_short()} => C
|
132
|
+
|
133
|
+
; The received length must be between 1 and %ARRAY_MAX_LEN
|
134
|
+
C - 1 => RR :JMPN(failAssert) ; If C = 0, then fail
|
135
|
+
%ARRAY_MAX_LEN - C :JMPN(failAssert) ; If C > %ARRAY_MAX_LEN, then fail
|
136
|
+
; From here, 1 <= C <= %ARRAY_MAX_LEN
|
137
|
+
|
138
|
+
; To avoid non-determinism, we must ensure that the quotient is trimmed
|
139
|
+
; i.e., that its last chunk is not 0
|
140
|
+
${receiveQuotientChunk_short(RR)} => A
|
141
|
+
0 => B
|
142
|
+
0 :EQ
|
143
|
+
; From here, the quotient is trimmed
|
144
|
+
|
145
|
+
C :MSTORE(array_div_short_len_quo)
|
146
|
+
C - 1 => RR
|
147
|
+
|
148
|
+
; save the first non-zero chunk of quo
|
149
|
+
A :MSTORE(array_div_short_quo + RR)
|
150
|
+
A :MSTORE(array_mul_short_inA + RR)
|
151
|
+
RR - 1 => RR :JMPN(array_div_short_inB_to_mul)
|
152
|
+
|
153
|
+
array_div_short_quo_to_mul:
|
154
|
+
${receiveQuotientChunk_short(RR)} => A
|
155
|
+
A :MSTORE(array_div_short_quo + RR)
|
156
|
+
A :MSTORE(array_mul_short_inA + RR)
|
157
|
+
RR - 1 => RR :JMPN(array_div_short_inB_to_mul, array_div_short_quo_to_mul)
|
158
|
+
|
159
|
+
array_div_short_inB_to_mul:
|
160
|
+
$ => A :MLOAD(array_div_short_inB)
|
161
|
+
A :MSTORE(array_mul_short_inB)
|
162
|
+
|
163
|
+
array_div_short_mul_quo_inB:
|
164
|
+
:CALL(array_mul_short)
|
165
|
+
|
166
|
+
%MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary)
|
167
|
+
%MAX_CNT_STEPS - STEP - 2 - 3*%ARRAY_MAX_LEN - 6 :JMPN(outOfCountersStep)
|
168
|
+
|
169
|
+
; prepare next
|
170
|
+
$ => C :MLOAD(array_mul_short_len_out)
|
171
|
+
C - 1 => RR
|
172
|
+
|
173
|
+
array_div_short_result_to_add:
|
174
|
+
$ => A :MLOAD(array_mul_short_out + RR)
|
175
|
+
A :MSTORE(array_add_short_inA + RR)
|
176
|
+
RR - 1 => RR :JMPN(array_div_short_rem_to_add, array_div_short_result_to_add)
|
177
|
+
|
178
|
+
array_div_short_rem_to_add:
|
179
|
+
${receiveRemainderChunk_short()} => A
|
180
|
+
|
181
|
+
; We must ensure the the remaider is lower than inB
|
182
|
+
$ => B :MLOAD(array_div_short_inB)
|
183
|
+
1 :LT
|
184
|
+
|
185
|
+
A :MSTORE(array_div_short_rem)
|
186
|
+
A :MSTORE(array_add_short_inB)
|
187
|
+
|
188
|
+
array_div_short_add_result_rem:
|
189
|
+
:CALL(array_add_short)
|
190
|
+
|
191
|
+
%MAX_CNT_STEPS - STEP - 5 :JMPN(outOfCountersStep)
|
192
|
+
|
193
|
+
; prepare next
|
194
|
+
$ => C :MLOAD(array_add_short_len_out)
|
195
|
+
$ => D :MLOAD(array_div_short_len_inA)
|
196
|
+
C - 1 => RR
|
197
|
+
D - 1 => E
|
198
|
+
|
199
|
+
%MAX_CNT_STEPS - STEP - 3*%ARRAY_MAX_LEN - 3*D - 1 :JMPN(outOfCountersStep)
|
200
|
+
|
201
|
+
array_div_short_result_to_compare:
|
202
|
+
$ => A :MLOAD(array_add_short_out + RR)
|
203
|
+
A :MSTORE(array_compare_inA + RR)
|
204
|
+
RR - 1 => RR :JMPN(array_div_short_inA_to_compare2, array_div_short_result_to_compare)
|
205
|
+
|
206
|
+
array_div_short_inA_to_compare2:
|
207
|
+
$ => A :MLOAD(array_div_short_inA + E)
|
208
|
+
A :MSTORE(array_compare_inB + E)
|
209
|
+
E - 1 => E :JMPN(array_div_short_compare_result_inA, array_div_short_inA_to_compare2)
|
210
|
+
|
211
|
+
array_div_short_compare_result_inA:
|
212
|
+
:CALL(array_compare)
|
213
|
+
|
214
|
+
%MAX_CNT_STEPS - STEP - 4 :JMPN(outOfCountersStep)
|
215
|
+
|
216
|
+
1 :MLOAD(array_compare_result)
|
217
|
+
|
218
|
+
0 => B ; error code
|
219
|
+
|
220
|
+
array_div_short_end:
|
221
|
+
$ => RR :MLOAD(array_div_short_RR)
|
222
|
+
:RETURN
|
@@ -0,0 +1,97 @@
|
|
1
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2
|
+
;; POST: out is trimmed
|
3
|
+
;;
|
4
|
+
;; array_mul:
|
5
|
+
;; in:
|
6
|
+
;; · C ∈ [1, 32], the len of inA
|
7
|
+
;; · D ∈ [1, 32], the len of inB
|
8
|
+
;; · inA ∈ [0, 2²⁵⁶ - 1]^C, the first input array
|
9
|
+
;; · inB ∈ [0, 2²⁵⁶ - 1]^D, the second input array
|
10
|
+
;;
|
11
|
+
;; output:
|
12
|
+
;; · out = inA·inB, with len(out) <= C + D
|
13
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
14
|
+
|
15
|
+
; function array_mul(a: bigint[], b: bigint[], base: bigint): bigint[] {
|
16
|
+
; if (b.length === 1) {
|
17
|
+
; return array_mul_short(a, b, base);
|
18
|
+
; }
|
19
|
+
; return array_mul_long(a, b, base);
|
20
|
+
; }
|
21
|
+
|
22
|
+
VAR GLOBAL array_mul_inA[%ARRAY_MAX_LEN]
|
23
|
+
VAR GLOBAL array_mul_inB[%ARRAY_MAX_LEN]
|
24
|
+
VAR GLOBAL array_mul_out[%ARRAY_MAX_LEN_DOUBLED]
|
25
|
+
VAR GLOBAL array_mul_len_inA
|
26
|
+
VAR GLOBAL array_mul_len_inB
|
27
|
+
VAR GLOBAL array_mul_len_out
|
28
|
+
|
29
|
+
VAR GLOBAL array_mul_RR
|
30
|
+
|
31
|
+
array_mul:
|
32
|
+
%MAX_CNT_STEPS - STEP - 6 - 3*C - 3*D - 1 :JMPN(outOfCountersStep)
|
33
|
+
|
34
|
+
RR :MSTORE(array_mul_RR)
|
35
|
+
|
36
|
+
C :MSTORE(array_mul_len_inA)
|
37
|
+
D :MSTORE(array_mul_len_inB)
|
38
|
+
|
39
|
+
C - 1 => RR
|
40
|
+
D - 1 => E
|
41
|
+
D - 1 :JMPZ(array_mul_inA_to_mul_short) ; worst case is mul long
|
42
|
+
; Long
|
43
|
+
array_mul_inA_to_mul_long:
|
44
|
+
$ => A :MLOAD(array_mul_inA + RR)
|
45
|
+
A :MSTORE(array_mul_long_inA + RR)
|
46
|
+
RR - 1 => RR :JMPN(array_mul_inB_to_mul_long, array_mul_inA_to_mul_long)
|
47
|
+
|
48
|
+
array_mul_inB_to_mul_long:
|
49
|
+
$ => A :MLOAD(array_mul_inB + E)
|
50
|
+
A :MSTORE(array_mul_long_inB + E)
|
51
|
+
E - 1 => E :JMPN(array_mul_compute_long, array_mul_inB_to_mul_long)
|
52
|
+
|
53
|
+
array_mul_compute_long:
|
54
|
+
:CALL(array_mul_long)
|
55
|
+
|
56
|
+
%MAX_CNT_STEPS - STEP - 4 :JMPN(outOfCountersStep)
|
57
|
+
|
58
|
+
$ => C :MLOAD(array_mul_long_len_out)
|
59
|
+
C :MSTORE(array_mul_len_out)
|
60
|
+
C - 1 => RR
|
61
|
+
|
62
|
+
%MAX_CNT_STEPS - STEP - 3*C - 2 :JMPN(outOfCountersStep)
|
63
|
+
|
64
|
+
array_mul_assign_long:
|
65
|
+
$ => A :MLOAD(array_mul_long_out + RR)
|
66
|
+
A :MSTORE(array_mul_out + RR)
|
67
|
+
RR - 1 => RR :JMPN(array_mul_end, array_mul_assign_long)
|
68
|
+
|
69
|
+
; Short
|
70
|
+
array_mul_inA_to_mul_short:
|
71
|
+
$ => A :MLOAD(array_mul_inA + RR)
|
72
|
+
A :MSTORE(array_mul_short_inA + RR)
|
73
|
+
RR - 1 => RR :JMPN(array_mul_inB_to_mul_short, array_mul_inA_to_mul_short)
|
74
|
+
|
75
|
+
array_mul_inB_to_mul_short:
|
76
|
+
$ => A :MLOAD(array_mul_inB)
|
77
|
+
A :MSTORE(array_mul_short_inB)
|
78
|
+
|
79
|
+
array_mul_compute_short:
|
80
|
+
:CALL(array_mul_short)
|
81
|
+
|
82
|
+
%MAX_CNT_STEPS - STEP - 4 :JMPN(outOfCountersStep)
|
83
|
+
|
84
|
+
$ => C :MLOAD(array_mul_short_len_out)
|
85
|
+
C :MSTORE(array_mul_len_out)
|
86
|
+
C - 1 => RR
|
87
|
+
|
88
|
+
%MAX_CNT_STEPS - STEP - 3*C - 2 :JMPN(outOfCountersStep)
|
89
|
+
|
90
|
+
array_mul_assign_short:
|
91
|
+
$ => A :MLOAD(array_mul_short_out + RR)
|
92
|
+
A :MSTORE(array_mul_out + RR)
|
93
|
+
RR - 1 => RR :JMPN(array_mul_end, array_mul_assign_short)
|
94
|
+
|
95
|
+
array_mul_end:
|
96
|
+
$ => RR :MLOAD(array_mul_RR)
|
97
|
+
:RETURN
|
@@ -0,0 +1,156 @@
|
|
1
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2
|
+
;; PRE: len(inB) >= 2
|
3
|
+
;; POST: out is trimmed
|
4
|
+
;;
|
5
|
+
;; array_mul_long:
|
6
|
+
;; in:
|
7
|
+
;; · C ∈ [1, 32], the len of inA
|
8
|
+
;; · D ∈ [1, 32], the len of inB
|
9
|
+
;; · inA ∈ [0, 2²⁵⁶ - 1]^C, the first input array
|
10
|
+
;; · inB ∈ [0, 2²⁵⁶ - 1]^D, the second input array
|
11
|
+
;;
|
12
|
+
;; output:
|
13
|
+
;; · out = inA·inB, with len(out) <= C + D
|
14
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
15
|
+
|
16
|
+
; function array_mul_long(a: bigint[], b: bigint[], base: bigint): bigint[] {
|
17
|
+
; const alen = a.length;
|
18
|
+
; const blen = b.length;
|
19
|
+
; const len = alen + blen;
|
20
|
+
; const result = new Array<bigint>(len).fill(0n);
|
21
|
+
; let product: bigint;
|
22
|
+
; let carry: bigint;
|
23
|
+
; for (let i = 0; i < alen; i++) {
|
24
|
+
; for (let j = 0; j < blen; j++) {
|
25
|
+
; product = a[i] * b[j] + out[i+j];
|
26
|
+
; carry = product / base;
|
27
|
+
; out[i+j] = product - carry * base;
|
28
|
+
; out[i + j + 1] += carry;
|
29
|
+
; }
|
30
|
+
; }
|
31
|
+
; trim(result);
|
32
|
+
; return result;
|
33
|
+
; }
|
34
|
+
|
35
|
+
VAR GLOBAL array_mul_long_inA[%ARRAY_MAX_LEN]
|
36
|
+
VAR GLOBAL array_mul_long_inB[%ARRAY_MAX_LEN]
|
37
|
+
VAR GLOBAL array_mul_long_out[%ARRAY_MAX_LEN_DOUBLED]
|
38
|
+
VAR GLOBAL array_mul_long_len_inA
|
39
|
+
VAR GLOBAL array_mul_long_len_inB
|
40
|
+
VAR GLOBAL array_mul_long_len_out
|
41
|
+
|
42
|
+
VAR GLOBAL array_mul_long_out_chunk_2
|
43
|
+
|
44
|
+
VAR GLOBAL array_mul_long_RR
|
45
|
+
|
46
|
+
array_mul_long:
|
47
|
+
%MAX_CNT_ARITH - CNT_ARITH - 1 :JMPN(outOfCountersArith)
|
48
|
+
%MAX_CNT_STEPS - STEP - 9 :JMPN(outOfCountersStep)
|
49
|
+
|
50
|
+
C => A
|
51
|
+
D => B
|
52
|
+
0 => C,D
|
53
|
+
${A*B} => E :ARITH
|
54
|
+
A => C
|
55
|
+
B => D
|
56
|
+
; E holds C*D
|
57
|
+
|
58
|
+
%MAX_CNT_BINARY - CNT_BINARY - 4*E :JMPN(outOfCountersBinary)
|
59
|
+
%MAX_CNT_ARITH - CNT_ARITH - E :JMPN(outOfCountersArith)
|
60
|
+
%MAX_CNT_STEPS - STEP - 7 - 2*C - 2*D - 33*E - 2 - 3*C - 1 :JMPN(outOfCountersStep)
|
61
|
+
|
62
|
+
RR :MSTORE(array_mul_long_RR)
|
63
|
+
|
64
|
+
C :MSTORE(array_mul_long_len_inA)
|
65
|
+
D :MSTORE(array_mul_long_len_inB)
|
66
|
+
C + D :MSTORE(array_mul_long_len_out)
|
67
|
+
0 :MSTORE(array_mul_long_out_chunk_2) ; initialize the out chunk 2
|
68
|
+
|
69
|
+
C + D - 1 => E ; auxiliar index
|
70
|
+
0 => RCX ; first index in loops
|
71
|
+
0 => RR ; second index in loops
|
72
|
+
|
73
|
+
array_mul_long_clean_out:
|
74
|
+
0 :MSTORE(array_mul_long_out + E)
|
75
|
+
E - 1 => E :JMPN(array_mul_long_loopZero2inB, array_mul_long_clean_out)
|
76
|
+
|
77
|
+
; Begin of branching
|
78
|
+
array_mul_long_loop_index_check:
|
79
|
+
RCX + 1 => RCX
|
80
|
+
$ => B :MLOAD(array_mul_long_len_inA)
|
81
|
+
B - RCX :JMPZ(array_mul_long_prep_trim_in)
|
82
|
+
|
83
|
+
0 => RR ; reset the second index
|
84
|
+
; End of branching
|
85
|
+
|
86
|
+
array_mul_long_loopZero2inB:
|
87
|
+
; The result will be stored as D·base + C
|
88
|
+
|
89
|
+
RCX => E
|
90
|
+
; 1] a[i]·b[j], where a[i],b[j] ∈ [0,base-1]: This number cannot be GT (base - 2)·base + 1, two chunks
|
91
|
+
$ => A :MLOAD(array_mul_long_inA + E)
|
92
|
+
$ => B :MLOAD(array_mul_long_inB + RR)
|
93
|
+
0 => C
|
94
|
+
$${var _arrayLongMul_AB = A*B}
|
95
|
+
${_arrayLongMul_AB >> 256} => D
|
96
|
+
${_arrayLongMul_AB} => E :ARITH
|
97
|
+
|
98
|
+
; 2] product = a[i]·b[j] + out[i+j], where out[i+j] ∈ [0,base-1]: This number cannot be GT (base - 1)·base, two chunks
|
99
|
+
E => A
|
100
|
+
RCX + RR => E
|
101
|
+
$ => B :MLOAD(array_mul_long_out + E)
|
102
|
+
$ => C :ADD, JMPNC(__array_mul_long_no_carry_continue_1)
|
103
|
+
;-----------------
|
104
|
+
; Since here D ∈ [0, base - 2], there cannot be carry in the following addition
|
105
|
+
D => A
|
106
|
+
1 => B
|
107
|
+
$ => D :ADD
|
108
|
+
;-----------------
|
109
|
+
__array_mul_long_no_carry_continue_1:
|
110
|
+
$ => A :MLOAD(array_mul_long_out_chunk_2) ; out_chunk_2 ∈ [0,1]
|
111
|
+
D => B
|
112
|
+
$ => D :ADD ; the number is of two chunks, no carry can be generated here
|
113
|
+
|
114
|
+
; NOTE: It cannot happen that a[i]·b[j] + out[i+j] produces carry and out_chunk_2 is 1.
|
115
|
+
|
116
|
+
; out[i+j] = product - carry·B
|
117
|
+
C :MSTORE(array_mul_long_out + E)
|
118
|
+
|
119
|
+
; out[i+j+1] += carry, where carry ∈ [0,base-1]: This number cannot be GT base + (base-3), two chunks
|
120
|
+
E + 1 => E
|
121
|
+
$ => A :MLOAD(array_mul_long_out + E)
|
122
|
+
D => B
|
123
|
+
$ => C :ADD, JMPNC(__array_mul_long_no_carry_continue_2)
|
124
|
+
;-----------------
|
125
|
+
1 :MSTORE(array_mul_long_out_chunk_2)
|
126
|
+
:JMP(__array_mul_long_carry_continue)
|
127
|
+
__array_mul_long_no_carry_continue_2:
|
128
|
+
0 :MSTORE(array_mul_long_out_chunk_2)
|
129
|
+
__array_mul_long_carry_continue:
|
130
|
+
;-----------------
|
131
|
+
|
132
|
+
C :MSTORE(array_mul_long_out + E)
|
133
|
+
|
134
|
+
RR + 1 => RR
|
135
|
+
$ => B :MLOAD(array_mul_long_len_inB)
|
136
|
+
B - RR :JMPZ(array_mul_long_loop_index_check, array_mul_long_loopZero2inB)
|
137
|
+
|
138
|
+
array_mul_long_prep_trim_in:
|
139
|
+
$ => C :MLOAD(array_mul_long_len_out)
|
140
|
+
C - 1 => E
|
141
|
+
|
142
|
+
array_mul_long_trim_in:
|
143
|
+
$ => A :MLOAD(array_mul_long_out + E)
|
144
|
+
A :MSTORE(array_trim_in + E)
|
145
|
+
E - 1 => E :JMPN(array_mul_long_trim, array_mul_long_trim_in)
|
146
|
+
|
147
|
+
array_mul_long_trim:
|
148
|
+
:CALL(array_trim)
|
149
|
+
|
150
|
+
%MAX_CNT_STEPS - STEP - 3 :JMPN(outOfCountersStep)
|
151
|
+
|
152
|
+
C :MSTORE(array_mul_long_len_out)
|
153
|
+
|
154
|
+
array_mul_long_end:
|
155
|
+
$ => RR :MLOAD(array_mul_long_RR)
|
156
|
+
:RETURN
|
@@ -0,0 +1,127 @@
|
|
1
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2
|
+
;; POST: out is trimmed
|
3
|
+
;;
|
4
|
+
;; array_mul_short:
|
5
|
+
;; in:
|
6
|
+
;; · C ∈ [1, 32], the len of inA
|
7
|
+
;; · inA ∈ [0, 2²⁵⁶ - 1]^C, the first input array
|
8
|
+
;; · inB ∈ [0, 2²⁵⁶ - 1], the second input
|
9
|
+
;;
|
10
|
+
;; output:
|
11
|
+
;; · out = inA·inB, with len(out) <= C + 1
|
12
|
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
13
|
+
|
14
|
+
; function array_mul_short(a: bigint[], b: bigint, base: bigint): bigint[] {
|
15
|
+
; const alen = a.length;
|
16
|
+
; const len = alen;
|
17
|
+
; const result = new Array<bigint>(len).fill(0n);
|
18
|
+
; let product: bigint;
|
19
|
+
; let carry = 0n;
|
20
|
+
; let i;
|
21
|
+
; for (i = 0; i < alen; i++) {
|
22
|
+
; product = a[i] * b + carry;
|
23
|
+
; carry = product / base;
|
24
|
+
; out[i] = product - carry * base;
|
25
|
+
; }
|
26
|
+
|
27
|
+
; if (carry > 0n) {
|
28
|
+
; result.push(carry);
|
29
|
+
; }
|
30
|
+
|
31
|
+
; trim(result);
|
32
|
+
; return result;
|
33
|
+
; }
|
34
|
+
|
35
|
+
VAR GLOBAL array_mul_short_inA[%ARRAY_MAX_LEN]
|
36
|
+
VAR GLOBAL array_mul_short_inB
|
37
|
+
VAR GLOBAL array_mul_short_out[%ARRAY_MAX_LEN_PLUS_ONE]
|
38
|
+
VAR GLOBAL array_mul_short_len_inA
|
39
|
+
VAR GLOBAL array_mul_short_len_out
|
40
|
+
|
41
|
+
VAR GLOBAL array_mul_short_carry
|
42
|
+
|
43
|
+
VAR GLOBAL array_mul_short_RR
|
44
|
+
|
45
|
+
array_mul_short:
|
46
|
+
%MAX_CNT_BINARY - CNT_BINARY - 2*C :JMPN(outOfCountersBinary)
|
47
|
+
%MAX_CNT_ARITH - CNT_ARITH - C :JMPN(outOfCountersArith)
|
48
|
+
%MAX_CNT_STEPS - STEP - 6 - 2*C-2 - 18*C - 6 :JMPN(outOfCountersStep)
|
49
|
+
|
50
|
+
RR :MSTORE(array_mul_short_RR)
|
51
|
+
|
52
|
+
C :MSTORE(array_mul_short_len_inA)
|
53
|
+
C + 1 :MSTORE(array_mul_short_len_out)
|
54
|
+
|
55
|
+
C => E ; auxiliar index
|
56
|
+
0 => RCX ; index in loops
|
57
|
+
0 :MSTORE(array_mul_short_carry)
|
58
|
+
|
59
|
+
array_mul_short_clean_out:
|
60
|
+
0 :MSTORE(array_mul_short_out + E)
|
61
|
+
E - 1 => E :JMPN(array_mul_short_loopZero2inA, array_mul_short_clean_out)
|
62
|
+
|
63
|
+
array_mul_short_loopZero2inA:
|
64
|
+
; The result will be stored as D·base + C
|
65
|
+
|
66
|
+
RCX => E
|
67
|
+
; 1] a[i] * b, where a[i],b ∈ [0,base-1]: This number cannot be GT (base - 2)·base + 1, two chunks
|
68
|
+
$ => A :MLOAD(array_mul_short_inA + E)
|
69
|
+
$ => B :MLOAD(array_mul_short_inB)
|
70
|
+
0 => C
|
71
|
+
$${var _arrayShortMul_AB = A*B}
|
72
|
+
${_arrayShortMul_AB >> 256} => D
|
73
|
+
${_arrayShortMul_AB} => E :ARITH
|
74
|
+
|
75
|
+
; 2] product = a[i] * b + carry, where carry ∈ [0,base-1]: This number cannot be GT (base - 1)·base, two chunks
|
76
|
+
E => A
|
77
|
+
$ => B :MLOAD(array_mul_short_carry)
|
78
|
+
$ => C :ADD, JMPNC(__array_mul_short_no_carry_continue)
|
79
|
+
;-----------------
|
80
|
+
; Since here D ∈ [0, base - 2], there cannot be carry in the following addition
|
81
|
+
D => A
|
82
|
+
1 => B
|
83
|
+
$ => D :ADD
|
84
|
+
;-----------------
|
85
|
+
__array_mul_short_no_carry_continue:
|
86
|
+
|
87
|
+
; carry = product / base
|
88
|
+
D :MSTORE(array_mul_short_carry)
|
89
|
+
|
90
|
+
; out[i] = product - carry·base
|
91
|
+
RCX => E
|
92
|
+
C :MSTORE(array_mul_short_out + E)
|
93
|
+
|
94
|
+
RCX + 1 => RCX
|
95
|
+
$ => B :MLOAD(array_mul_short_len_inA)
|
96
|
+
B - RCX :JMPZ(array_mul_short_carry_check, array_mul_short_loopZero2inA)
|
97
|
+
|
98
|
+
; If the last carry > 0, we need to insert it to the output
|
99
|
+
array_mul_short_carry_check:
|
100
|
+
$ => A :MLOAD(array_mul_short_carry)
|
101
|
+
0 => B
|
102
|
+
$ :EQ, JMPC(array_mul_short_prep_trim_in)
|
103
|
+
|
104
|
+
RCX => E
|
105
|
+
A :MSTORE(array_mul_short_out + E)
|
106
|
+
|
107
|
+
array_mul_short_prep_trim_in:
|
108
|
+
$ => C :MLOAD(array_mul_short_len_out)
|
109
|
+
C - 1 => E
|
110
|
+
|
111
|
+
%MAX_CNT_STEPS - STEP - 3*C - 1 :JMPN(outOfCountersStep)
|
112
|
+
|
113
|
+
array_mul_short_trim_in:
|
114
|
+
$ => A :MLOAD(array_mul_short_out + E)
|
115
|
+
A :MSTORE(array_trim_in + E)
|
116
|
+
E - 1 => E :JMPZ(array_mul_short_trim, array_mul_short_trim_in)
|
117
|
+
|
118
|
+
array_mul_short_trim:
|
119
|
+
:CALL(array_trim)
|
120
|
+
|
121
|
+
%MAX_CNT_STEPS - STEP - 3 :JMPN(outOfCountersStep)
|
122
|
+
|
123
|
+
C :MSTORE(array_mul_short_len_out)
|
124
|
+
|
125
|
+
array_mul_short_end:
|
126
|
+
$ => RR :MLOAD(array_mul_short_RR)
|
127
|
+
:RETURN
|