From 8021659f4eaf32732d3170eddb93d1f1592706c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Masip?= Date: Thu, 3 Oct 2024 16:06:07 +0200 Subject: [PATCH 01/12] Modexp new version --- main/modexp/array_lib/array_add_AGTB.zkasm | 144 +++---- main/modexp/array_lib/array_add_short.zkasm | 99 ++--- main/modexp/array_lib/array_div.zkasm | 215 ---------- main/modexp/array_lib/array_div_long.zkasm | 376 ++++++++++-------- main/modexp/array_lib/array_div_short.zkasm | 206 +++++----- main/modexp/array_lib/array_div_two.zkasm | 185 +++++++++ main/modexp/array_lib/array_mul.zkasm | 97 ----- main/modexp/array_lib/array_mul_long.zkasm | 219 ++++++---- main/modexp/array_lib/array_mul_short.zkasm | 122 ++---- main/modexp/array_lib/array_mul_two.zkasm | 102 +++++ main/modexp/array_lib/array_square.zkasm | 312 ++++++++++----- main/modexp/array_lib/unused/array_add.zkasm | 100 ----- .../array_lib/unused/array_is_odd.zkasm | 23 -- .../array_lib/unused/array_is_one.zkasm | 33 -- .../array_lib/unused/array_is_zero.zkasm | 34 -- .../array_lib/unused/array_sub_AGTB.zkasm | 111 ------ .../array_lib/unused/array_unshift.zkasm | 37 -- .../array_lib/utils/array_compare.zkasm | 82 ---- main/modexp/array_lib/utils/array_trim.zkasm | 49 --- main/modexp/constants.zkasm | 11 +- main/modexp/modexp.zkasm | 280 ++++++++----- 21 files changed, 1304 insertions(+), 1533 deletions(-) delete mode 100644 main/modexp/array_lib/array_div.zkasm create mode 100644 main/modexp/array_lib/array_div_two.zkasm delete mode 100644 main/modexp/array_lib/array_mul.zkasm create mode 100644 main/modexp/array_lib/array_mul_two.zkasm delete mode 100644 main/modexp/array_lib/unused/array_add.zkasm delete mode 100644 main/modexp/array_lib/unused/array_is_odd.zkasm delete mode 100644 main/modexp/array_lib/unused/array_is_one.zkasm delete mode 100644 main/modexp/array_lib/unused/array_is_zero.zkasm delete mode 100644 main/modexp/array_lib/unused/array_sub_AGTB.zkasm delete mode 100644 main/modexp/array_lib/unused/array_unshift.zkasm delete mode 100644 main/modexp/array_lib/utils/array_compare.zkasm delete mode 100644 main/modexp/array_lib/utils/array_trim.zkasm diff --git a/main/modexp/array_lib/array_add_AGTB.zkasm b/main/modexp/array_lib/array_add_AGTB.zkasm index 62816554..5a70c9d0 100644 --- a/main/modexp/array_lib/array_add_AGTB.zkasm +++ b/main/modexp/array_lib/array_add_AGTB.zkasm @@ -1,10 +1,10 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; PRE: len(inA) >= len(inB) -;; +;; PRE: len(inA) >= len(inB) +;; POST: out is trimmed ;; ;; array_add_AGTB: ;; in: -;; · C ∈ [1, 32], the len of inA +;; · C ∈ [1, 64], the len of inA ;; · D ∈ [1, 32], the len of inB ;; · inA ∈ [0, 2²⁵⁶ - 1]^C, the first input array ;; · inB ∈ [0, 2²⁵⁶ - 1]^D, the second input array @@ -13,34 +13,30 @@ ;; · out = inA + inB, with len(out) <= C + 1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; function array_add_AGTB(a: bigint[], b: bigint[], base: bigint): bigint[] { -; const alen = a.length; -; const blen = b.length; -; let result = new Array(alen); -; let sum = 0n; -; let carry = 0n; -; for (let i = 0; i < blen; i++) { -; sum = a[i] + b[i] + carry; -; carry = sum >= base ? 1n : 0n; -; out[i] = sum - carry * base; -; } -; for (let i = blen; i < alen; i++) { -; sum = a[i] + carry; -; carry = sum == base ? 1n : 0n; // the past carry is at most 1n -; out[i] = sum - carry * base; -; } - -; if (carry === 1n) { -; result.push(carry); -; } -; return result; -; } +;; WARNING: This function is tailored for checking that a = q·b + r in the array_div_long function. +;; In can be used for other purposes except for the worst case, i.e. when len(inA) == %ARRAY_MAX_LEN_DOUBLED. +;; Specifically, there is an implicit assumption that the output len of this function cannot be +;; greater than %ARRAY_MAX_LEN_DOUBLED, and do not allow to generate the proof in such case. ; NOTE: It's unoptimized for the case where len(inB) = 1. Use array_add_short instead. -VAR GLOBAL array_add_AGTB_inA[%ARRAY_MAX_LEN] +; code +; -------------------------- +; first_iteration <-- Compute a[0] + b[0] +; while(inB_index_check) { <-- While 0 < i < len(b) +; loop2inB <-- Compute a[i] + b[i] + carry +; } +; while (inA_index_check) { <-- While 0 < i < len(a) +; loop2inA <-- Compute a[i] + carry +; } +; 1] check_carry <-- If there is a carry, append it to the result +; 2] trim <-- Otherwise, trim the result +; end +; -------------------------- + +VAR GLOBAL array_add_AGTB_inA[%ARRAY_MAX_LEN_DOUBLED] VAR GLOBAL array_add_AGTB_inB[%ARRAY_MAX_LEN] -VAR GLOBAL array_add_AGTB_out[%ARRAY_MAX_LEN_PLUS_ONE] +VAR GLOBAL array_add_AGTB_out[%ARRAY_MAX_LEN_DOUBLED] ; This cannot be bigger because we use it for division checking VAR GLOBAL array_add_AGTB_len_inA VAR GLOBAL array_add_AGTB_len_inB VAR GLOBAL array_add_AGTB_len_out @@ -50,74 +46,86 @@ VAR GLOBAL array_add_AGTB_carry VAR GLOBAL array_add_AGTB_RR array_add_AGTB: - %MAX_CNT_BINARY - CNT_BINARY - 2*D - C+ D :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 5 - 14*D - 3 - 9*C+9*D - 8 :JMPN(outOfCountersStep) + %MAX_CNT_BINARY - CNT_BINARY - 1 - 2*%ARRAY_MAX_LEN_MINUS_ONE - 2 :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 10 - 11*%ARRAY_MAX_LEN_MINUS_ONE - 2 - 8 - 5*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE - 3 :JMPN(outOfCountersStep) RR :MSTORE(array_add_AGTB_RR) C :MSTORE(array_add_AGTB_len_inA) D :MSTORE(array_add_AGTB_len_inB) - 0 => E ; index in loops - 0 :MSTORE(array_add_AGTB_carry) +array_add_AGTB_first_iteration: + ; a[0] + b[0], where a[0],b[0] ∈ [0,base-1]: This number cannot be GT base + (base - 2), two chunks + $ => A :MLOAD(array_add_AGTB_inA) + $ => B :MLOAD(array_add_AGTB_inB) + $ :ADD, MSTORE(array_add_AGTB_out), JMPNC(__array_add_AGTB_continue_1) + ;----------------- + 1 => D :MSTORE(array_add_AGTB_carry), JMP(__array_add_AGTB_continue_2) + __array_add_AGTB_continue_1: + 0 => D :MSTORE(array_add_AGTB_carry) + __array_add_AGTB_continue_2: + ;----------------- -array_add_AGTB_loopZero2inB: - ; The result will be stored as D·base + C + 1 => E - 0 => D ; reset the carry chunk +array_add_AGTB_inB_index_check: + $ - E :F_MLOAD(array_add_AGTB_len_inB), JMPZ(array_add_AGTB_inA_index_check) +array_add_AGTB_loop2inB: ; a[i] + b[i], where a[i],b[i] ∈ [0,base-1]: This number cannot be GT base + (base - 2), two chunks $ => A :MLOAD(array_add_AGTB_inA + E) $ => B :MLOAD(array_add_AGTB_inB + E) - $ => C :ADD, JMPNC(__array_add_AGTB_continue_1) - 1 => D - __array_add_AGTB_continue_1: + $ => B :ADD, JMPNC(__array_add_AGTB_continue_3) + ;----------------- + 1 => D :JMP(__array_add_AGTB_continue_4) + __array_add_AGTB_continue_3: + 0 => D + __array_add_AGTB_continue_4: + ;----------------- - ; sum = (a[i] + b[i]) + carry: This number cannot be GT base + (base - 1), two chunks + ; sum = (a[i] + b[i]) + carry, where carry ∈ [0,1]: This number cannot be GT base + (base - 1), two chunks $ => A :MLOAD(array_add_AGTB_carry) - C => B - $ => C :ADD, JMPNC(__array_add_AGTB_continue_2) + $ :ADD, MSTORE(array_add_AGTB_out + E), JMPNC(__array_add_AGTB_continue_5) + ;----------------- 1 => D - __array_add_AGTB_continue_2: + __array_add_AGTB_continue_5: + ;----------------- - C :MSTORE(array_add_AGTB_out + E) - D :MSTORE(array_add_AGTB_carry) + ; NOTE: It cannot happen that a[i] + b[i] produces carry and (a[i] + b[i]) + carry as well at the same time - E + 1 => E,A - $ => B :MLOAD(array_add_AGTB_len_inB) - B - A :JMPZ(array_add_AGTB_loop_index_check, array_add_AGTB_loopZero2inB) + D :MSTORE(array_add_AGTB_carry) -array_add_AGTB_loop_index_check: - $ => B :MLOAD(array_add_AGTB_len_inA) - B - A :JMPZ(array_add_AGTB_check_carry) + E + 1 => E :JMP(array_add_AGTB_inB_index_check) -array_add_AGTB_loopInB2InA: - 0 => D ; reset the carry chunk +array_add_AGTB_inA_index_check: + $ - E :F_MLOAD(array_add_AGTB_len_inA), JMPZ(array_add_AGTB_check_carry) +array_add_AGTB_loop2inA: ; sum = a[i] + carry: This number cannot be GT base, two chunks $ => A :MLOAD(array_add_AGTB_inA + E) - $ => B :MLOAD(array_add_AGTB_carry) - $ => C :ADD, JMPNC(__array_add_AGTB_continue_3) - 1 => D - __array_add_AGTB_continue_3: + D => B + $ :ADD, MSTORE(array_add_AGTB_out + E), JMPNC(__array_add_AGTB_continue_6) + ;----------------- + 1 => D :JMP(__array_add_AGTB_continue_7) + __array_add_AGTB_continue_6: + 0 => D + __array_add_AGTB_continue_7: + ;----------------- - C :MSTORE(array_add_AGTB_out + E) - D :MSTORE(array_add_AGTB_carry) - - E + 1 => E,A - $ => B :MLOAD(array_add_AGTB_len_inA) - B - A :JMPZ(array_add_AGTB_check_carry, array_add_AGTB_loopInB2InA) + E + 1 => E :JMP(array_add_AGTB_inA_index_check) array_add_AGTB_check_carry: - D => A - A :JMPZ(__array_add_AGTB_continue_4) + D :JMPZ(array_add_AGTB_trim) + + ; Carry path + E - %ARRAY_MAX_LEN_DOUBLED :JMPZ(failAssert) + ; In this case, the carry = 1 and we should append it to the result 1 :MSTORE(array_add_AGTB_out + E) - E + 1 :MSTORE(array_add_AGTB_len_out) - :JMP(array_add_AGTB_end) - __array_add_AGTB_continue_4: + E + 1 :MSTORE(array_add_AGTB_len_out), JMP(array_add_AGTB_end) + +array_add_AGTB_trim: E :MSTORE(array_add_AGTB_len_out) array_add_AGTB_end: - $ => RR :MLOAD(array_add_AGTB_RR) - :RETURN \ No newline at end of file + $ => RR :MLOAD(array_add_AGTB_RR), RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_add_short.zkasm b/main/modexp/array_lib/array_add_short.zkasm index 6fe10b0b..38e91465 100644 --- a/main/modexp/array_lib/array_add_short.zkasm +++ b/main/modexp/array_lib/array_add_short.zkasm @@ -1,4 +1,5 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; POST: out is trimmed ;; ;; array_add_short: ;; in: @@ -10,76 +11,82 @@ ;; · out = inA + inB, with len(out) <= C + 1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; function array_add_short(a: bigint[], b: bigint, base: bigint): bigint[] { -; const alen = a.length; -; let result = new Array(alen); -; let sum = 0n; -; let carry = b; -; for (let i = 0; i < alen; i++) { -; sum = a[i] + carry; -; carry = sum >= base ? 1n : 0n; -; out[i] = sum - carry * base; -; } - -; if (carry === 1n) { -; result.push(carry); -; } -; return result; +;; WARNING: This function is tailored for checking that a = q·b + r in the array_div_short function. +;; In can be used for other purposes except for the worst case, i.e. when len(inA) == %ARRAY_MAX_LEN. +;; Specifically, there is an implicit assumption that the output len of this function cannot be +;; greater than %ARRAY_MAX_LEN, and do not allow to generate the proof in such case. + +; code +; -------------------------- +; first_iteration <-- Compute a[0] + b +; while(loop_index_check) { <-- While 0 < i < len(a) +; loop2inA <-- Compute a[i] + carry ; } +; 1] check_carry <-- If there is a carry, append it to the result +; 2] trim <-- Otherwise, trim the result +; end +; -------------------------- VAR GLOBAL array_add_short_inA[%ARRAY_MAX_LEN] VAR GLOBAL array_add_short_inB -VAR GLOBAL array_add_short_out[%ARRAY_MAX_LEN_PLUS_ONE] +VAR GLOBAL array_add_short_out[%ARRAY_MAX_LEN] ; This cannot be bigger because we use it for division checking VAR GLOBAL array_add_short_len_inA VAR GLOBAL array_add_short_len_out -VAR GLOBAL array_add_short_carry - VAR GLOBAL array_add_short_RR array_add_short: - %MAX_CNT_BINARY - CNT_BINARY - C :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 5 - 10*C - 8 :JMPN(outOfCountersStep) + %MAX_CNT_BINARY - CNT_BINARY - 1 - %ARRAY_MAX_LEN_MINUS_ONE :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 10 - 8*%ARRAY_MAX_LEN_MINUS_ONE - 5 :JMPN(outOfCountersStep) RR :MSTORE(array_add_short_RR) C :MSTORE(array_add_short_len_inA) - 0 => E ; index in loops - $ => A :MLOAD(array_add_short_inB) - A :MSTORE(array_add_short_carry) +array_add_short_first_iteration: + ; a[0] + b, where a[0] ∈ [0,base-1]: the number cannot be GT base + (base - 2), two chunks + $ => A :MLOAD(array_add_short_inA) + $ => B :MLOAD(array_add_short_inB) + $ :ADD, MSTORE(array_add_short_out), JMPC(__array_add_short_continue_1) + ; --------------------- + 0 => D :JMP(__array_add_short_continue_2) + __array_add_short_continue_1: + 1 => D + __array_add_short_continue_2: + ; --------------------- -array_add_short_loopZero2inA: - ; The result will be stored as D·base + C + 1 => E - 0 => D ; reset the carry chunk +array_add_short_loop_index_check: + ; C = len_inA + C - E :JMPZ(array_add_short_check_carry) - ; a[i] + carry, where a[i] ∈ [0,base-1]: - ; · If i = 0, then carry = inB and then the number cannot be GT base + (base - 2), two chunks - ; · Otherwise, the number cannot be GT base, two chunks +array_add_short_loop2inA: + ; a[i] + carry, where a[i] ∈ [0,base-1]: the number cannot be GT base, two chunks $ => A :MLOAD(array_add_short_inA + E) - $ => B :MLOAD(array_add_short_carry) - $ => C :ADD, JMPNC(__array_add_short_continue_1) + D => B + $ :ADD, MSTORE(array_add_short_out + E), JMPC(__array_add_short_continue_3) + ; --------------------- + 0 => D :JMP(__array_add_short_continue_4) + __array_add_short_continue_3: 1 => D - __array_add_short_continue_1: + __array_add_short_continue_4: + ; --------------------- - C :MSTORE(array_add_short_out + E) - D :MSTORE(array_add_short_carry) - - E + 1 => E,A - $ => B :MLOAD(array_add_short_len_inA) - B - A :JMPZ(array_add_short_check_carry, array_add_short_loopZero2inA) + E + 1 => E :JMP(array_add_short_loop_index_check) array_add_short_check_carry: - D => A - A :JMPZ(__array_add_short_continue_2) + D :JMPZ(array_add_short_trim) + + ; Carry path + E - %ARRAY_MAX_LEN :JMPZ(failAssert) + ; In this case, the carry = 1 and we should append it to the result 1 :MSTORE(array_add_short_out + E) - E + 1 :MSTORE(array_add_short_len_out) - :JMP(array_add_short_end) - __array_add_short_continue_2: - E :MSTORE(array_add_short_len_out) + E + 1 :MSTORE(array_add_short_len_out), JMP(array_add_short_end) + +array_add_short_trim: + E :MSTORE(array_add_short_len_out) array_add_short_end: - $ => RR :MLOAD(array_add_short_RR) - :RETURN \ No newline at end of file + $ => RR :MLOAD(array_add_short_RR), RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_div.zkasm b/main/modexp/array_lib/array_div.zkasm deleted file mode 100644 index 9a1e4e5e..00000000 --- a/main/modexp/array_lib/array_div.zkasm +++ /dev/null @@ -1,215 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; PRE: The input arrays have been trimmed; -;; POST: The quotient and remainder are trimmed. -;; -;; array_div: -;; in: -;; · C ∈ [1, 32], the len of inA -;; · D ∈ [1, 32], the len of inB -;; · inA ∈ [0, 2²⁵⁶ - 1]^C, the first input array -;; · inB ∈ [0, 2²⁵⁶ - 1]^D, the second input array -;; -;; output: -;; · [quo,rem] = [inA / inB, inA % inB], with len(quo) <= C - D + 1, len(rem) <= D -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; function array_div(a: bigint[], b: bigint[], base: bigint): bigint[] { -; if (a === [0n]) { -; if (b === [0n]) { -; throw new Error("Division by zero"); -; } -; return [0n, 0n]; -; } else if (b === [0n]) { -; throw new Error("Division by zero"); -; } -; -; if (a === b) { -; return [1n, 0n]; -; } else if (a < b) { -; return [0n, a]; -; } -; -; if (b.length === 1) { -; return array_div_short(a, b, base); -; } -; return array_div_long(a, b, base); -; } - -VAR GLOBAL array_div_inA[%ARRAY_MAX_LEN] -VAR GLOBAL array_div_inB[%ARRAY_MAX_LEN] -VAR GLOBAL array_div_quo[%ARRAY_MAX_LEN] -VAR GLOBAL array_div_rem[%ARRAY_MAX_LEN] - -VAR GLOBAL array_div_len_inA -VAR GLOBAL array_div_len_inB -VAR GLOBAL array_div_len_quo -VAR GLOBAL array_div_len_rem - -VAR GLOBAL array_div_RR - -; ERROR CODES (B) -; 0 - no error -; 1 - inB is zero - -array_div: - %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 12 - 3*C - 3*D - 1 :JMPN(outOfCountersStep) - - RR :MSTORE(array_div_RR) - - C :MSTORE(array_div_len_inA) - D :MSTORE(array_div_len_inB) - - ; Let's cover the edge cases - 1 => B - ; 1] Is C == 1 and inA == 0? - C - B :JMPNZ(__array_div_inA_continue) - $ => A :MLOAD(array_div_inA) - $ :LT, JMPC(array_div_inA_is_zero) - __array_div_inA_continue: - - ; 2] Is D == 1 and inB == 0? - D - B :JMPNZ(__array_div_inB_continue_1) - $ => A :MLOAD(array_div_inB) - $ :LT, JMPC(array_div_inB_is_zero) - __array_div_inB_continue_1: - - ; 3] Check if inA = inB or inA < inB - C - 1 => RR - D - 1 => E -array_div_compare_inA: - $ => A :MLOAD(array_div_inA + RR) - A :MSTORE(array_compare_inA + RR) - RR - 1 => RR :JMPN(array_div_compare_inB, array_div_compare_inA) - -array_div_compare_inB: - $ => A :MLOAD(array_div_inB + E) - A :MSTORE(array_compare_inB + E) - E - 1 => E :JMPN(array_div_compare, array_div_compare_inB) - -array_div_compare: - :CALL(array_compare) - - %MAX_CNT_STEPS - STEP - 5 - 3*C - 3*D - 1 :JMPN(outOfCountersStep) - - $ => A :MLOAD(array_compare_result), JMPZ(array_div_prep_inALTinB) - A - 1 :JMPZ(array_div_same_input) - ; From here, inA > inB - - C - 1 => RR - D - 1 => E - D - 1 :JMPZ(array_div_inA_to_div_short, array_div_inA_to_div_long); worst case is div long - -; Begin of edge cases -array_div_inA_is_zero: - ;Is D == 1 and inB == 0? 0/0 is undefined - D - B :JMPNZ(__array_div_inB_continue_2) - $ => A :MLOAD(array_div_inB) - $ :LT, JMPC(array_div_inB_is_zero) - __array_div_inB_continue_2: - ; From here, inB != 0 - - ; Return [q,r] = [0,0] and len(q) = 1, len(r) = 1 - 0 :MSTORE(array_div_quo) - 0 :MSTORE(array_div_rem) - 1 :MSTORE(array_div_len_quo) - 1 :MSTORE(array_div_len_rem) - 0 => B :JMP(array_div_end) - -array_div_inB_is_zero: - ; Error, you cannot divide by 0 - 1 => B :JMP(array_div_end) - -array_div_same_input: - 1 :MSTORE(array_div_quo) - 0 :MSTORE(array_div_rem) - 1 :MSTORE(array_div_len_quo) - 1 :MSTORE(array_div_len_rem) - 0 => B :JMP(array_div_end) - -array_div_prep_inALTinB: - C :MSTORE(array_div_len_rem) - 1 :MSTORE(array_div_len_quo) - - %MAX_CNT_STEPS - STEP - 1 - 4*C - 2 :JMPN(outOfCountersStep) - - C - 1 => RR -array_div_inALTinB: - $ => A :MLOAD(array_div_inA + RR) - A :MSTORE(array_div_rem + RR) - RR - 1 => RR :JMPN(array_div_inALTinB_before_end, array_div_inALTinB) - -array_div_inALTinB_before_end: - 0 :MSTORE(array_div_quo) - 0 => B :JMP(array_div_end) -; End of edge cases - -; Long -array_div_inA_to_div_long: - $ => A :MLOAD(array_div_inA + RR) - A :MSTORE(array_div_long_inA + RR) - RR - 1 => RR :JMPN(array_div_inB_to_div_long, array_div_inA_to_div_long) - -array_div_inB_to_div_long: - $ => A :MLOAD(array_div_inB + E) - A :MSTORE(array_div_long_inB + E) - E - 1 => E :JMPN(array_div_compute_long, array_div_inB_to_div_long) - -array_div_compute_long: - :CALL(array_div_long) - - %MAX_CNT_STEPS - STEP - 7 :JMPN(outOfCountersStep) - - $ => C :MLOAD(array_div_long_len_quo) - $ => D :MLOAD(array_div_long_len_rem) - C :MSTORE(array_div_len_quo) - D :MSTORE(array_div_len_rem) - C - 1 => RR - D - 1 => E - - %MAX_CNT_STEPS - STEP - 3*C - 3*D - 2 :JMPN(outOfCountersStep) - -array_div_assign_long_quo: - $ => A :MLOAD(array_div_long_quo + RR) - A :MSTORE(array_div_quo + RR) - RR - 1 => RR :JMPN(array_div_assign_long_rem, array_div_assign_long_quo) - -array_div_assign_long_rem: - $ => A :MLOAD(array_div_long_rem + E) - A :MSTORE(array_div_rem + E) - E - 1 => E :JMPN(array_div_end, array_div_assign_long_rem) - -; Short -array_div_inA_to_div_short: - $ => A :MLOAD(array_div_inA + RR) - A :MSTORE(array_div_short_inA + RR) - RR - 1 => RR :JMPN(array_div_inB_to_div_short, array_div_inA_to_div_short) - -array_div_inB_to_div_short: - $ => A :MLOAD(array_div_inB) - A :MSTORE(array_div_short_inB) - -array_div_compute_short: - :CALL(array_div_short) - - %MAX_CNT_STEPS - STEP - 5 :JMPN(outOfCountersStep) - - $ => C :MLOAD(array_div_short_len_quo) - C :MSTORE(array_div_len_quo) - 1 :MSTORE(array_div_len_rem) - C - 1 => RR - - %MAX_CNT_STEPS - STEP - 3*C - 4 :JMPN(outOfCountersStep) - -array_div_assign_short_quo: - $ => A :MLOAD(array_div_short_quo + RR) - A :MSTORE(array_div_quo + RR) - RR - 1 => RR :JMPN(array_div_assign_short_rem, array_div_assign_short_quo) - -array_div_assign_short_rem: - $ => A :MLOAD(array_div_short_rem) - A :MSTORE(array_div_rem) - -array_div_end: - $ => RR :MLOAD(array_div_RR) - :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_div_long.zkasm b/main/modexp/array_lib/array_div_long.zkasm index 95d17a08..80ba5bc3 100644 --- a/main/modexp/array_lib/array_div_long.zkasm +++ b/main/modexp/array_lib/array_div_long.zkasm @@ -1,11 +1,11 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; PRE: The input arrays have been trimmed. +;; PRE: The input arrays have been trimmed, len(inB) >= 2 and therefore inB != 0 ;; POST: The quotient and remainder are trimmed. ;; ;; array_div_long: ;; in: -;; · C ∈ [1, 32], the len of inA -;; · D ∈ [1, 32], the len of inB +;; · C ∈ [1, 64], the len of inA +;; · D ∈ [2, 32], the len of inB ;; · inA ∈ [0, 2²⁵⁶ - 1]^C, the first input array ;; · inB ∈ [0, 2²⁵⁶ - 1]^D, the second input array ;; @@ -13,29 +13,52 @@ ;; · [quo,rem] = [inA / inB, inA % inB], with len(quo) <= C - D + 1, len(rem) <= D ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; function array_div_long(a: bigint[], b: bigint[], base: bigint): bigint[] { -; if (a === [0n]) { -; if (b === [0n]) { -; throw new Error("Division by zero"); -; } -; return [0n, 0n]; -; } else if (b === [0n]) { -; throw new Error("Division by zero"); -; } -; -; if (a === b) { -; return [1n, 0n]; -; } else if (a < b) { -; return [0n, a]; -; } +; code +; -------------------------- +; // Edge cases +; if (C == 1) { +; if (inA == 0) { +; inA_is_zero <-- return [0, 0] +; } else { +; prep_inALTinB <-- len(q) = 1, len(r) = len(inA) +; inALTinB <-- return [0, inA] +; } ; } - -; NOTE: This function receives the actual result from the helper (avoiding the need of computing divisions); -; checks the correctness of the result and returns the result to the caller - -VAR GLOBAL array_div_long_inA[%ARRAY_MAX_LEN] +; +; inA_not_zero_two_chunks <-- check whether inA = inB, inA < inB or inA > inB +; if (C < D) { +; prep_inALTinB <-- len(q) = 1, len(r) = len(inA) +; inALTinB <-- return [0, inA] +; } else if (C > D) ----------------------------------------------------------┐ +; | +; if (inA == inB (*)) { │ +; check_inAEQinB <-- check inA[i] == inB[i] for i in [0, len(inA)) │ +; inAEQinB <-- return [1, 0] │ +; } else if (inA < inB) { │ +; return [0, inA] │ +; } │ +; │ +; inAGTinB <----------------------------------------------------------------┘ +; quo_to_mul +; inB_to_mul +; mul_quo_inB +; 1] +; compare_rem +; compare_rem_first +; rem_to_add +; mul_out_to_add +; add_mul_out_rem +; check_rem_not_zero +; 2] +; rem_is_zero +; check_rem_is_zero +; end +; -------------------------- +; (*) This means the condition is trustless, so it must be checked + +VAR GLOBAL array_div_long_inA[%ARRAY_MAX_LEN_DOUBLED] VAR GLOBAL array_div_long_inB[%ARRAY_MAX_LEN] -VAR GLOBAL array_div_long_quo[%ARRAY_MAX_LEN] +VAR GLOBAL array_div_long_quo[%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE] VAR GLOBAL array_div_long_rem[%ARRAY_MAX_LEN] VAR GLOBAL array_div_long_len_inA @@ -45,13 +68,11 @@ VAR GLOBAL array_div_long_len_rem VAR GLOBAL array_div_long_RR -; ERROR CODES (B) -; 0 - no error -; 1 - inB is zero - array_div_long: - %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 12 - 3*C - 3*D - 1 :JMPN(outOfCountersStep) + ; w.c. is when inA > inB and len(inA) >> len(inB) + + %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 24 - 4*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE - 3*%ARRAY_MAX_LEN - 1 :JMPN(outOfCountersStep) ; till array_mul_long RR :MSTORE(array_div_long_RR) @@ -59,108 +80,131 @@ array_div_long: D :MSTORE(array_div_long_len_inB) ; Let's cover the edge cases - 1 => B ; 1] Is C == 1 and inA == 0? - C - B :JMPNZ(__array_div_long_inA_continue) - $ => A :MLOAD(array_div_long_inA) - $ :LT, JMPC(array_div_long_inA_is_zero) - __array_div_long_inA_continue: - - ; 2] Is D == 1 and inB == 0? - D - B :JMPNZ(__array_div_long_inB_continue_1) - $ => A :MLOAD(array_div_long_inB) - $ :LT, JMPC(array_div_long_inB_is_zero) - __array_div_long_inB_continue_1: - - ; 3] Check if inA = inB or inA < inB - C - 1 => RR - D - 1 => E -array_div_long_compare_inA1: - $ => A :MLOAD(array_div_long_inA + RR) - A :MSTORE(array_compare_inA + RR) - RR - 1 => RR :JMPN(array_div_long_compare_inB1, array_div_long_compare_inA1) + C - 1 :JMPNZ(array_div_long_inA_not_zero_two_chunks) + $ => A :MLOAD(array_div_long_inA) ; Here, len(inA) = 1 and len(inB) >= 2 + 0 => B + $ :EQ, JMPC(array_div_long_inA_is_zero, array_div_long_prep_inALTinB) -array_div_long_compare_inB1: - $ => A :MLOAD(array_div_long_inB + E) - A :MSTORE(array_compare_inB + E) - E - 1 => E :JMPN(array_div_long_compare1, array_div_long_compare_inB1) +array_div_long_inA_not_zero_two_chunks: + ; 2] Check if inA = inB, inA < inB or inA > inB -array_div_long_compare1: - :CALL(array_compare) + ; Start by comparing the lengths of the arrays + C - D :JMPN(array_div_long_prep_inALTinB) + D - C :JMPN(array_div_long_inAGTinB) + ; Here, C = D - %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 12 - 4*%ARRAY_MAX_LEN - 3*D - 1 :JMPN(outOfCountersStep) + ; If the lengths are equal, then we must compare them chunk by chunk - $ => A :MLOAD(array_compare_result), JMPZ(array_div_long_prep_inALTinB) - A - 1 :JMPZ(array_div_long_same_input) - ; From here, inA > inB + ; Get the first different chunk and check that is between -len(inA) and len(inA) + $0{signedComparison(addr.array_div_long_inA,addr.array_div_long_inB,mem.array_div_long_len_inA)} => RR :JMPZ(array_div_long_check_inAEQinB) - ; Strategy: Divide outside and check the result inside - $${MPdiv(addr.array_div_long_inA,mem.array_div_long_len_inA,addr.array_div_long_inB,mem.array_div_long_len_inB)} + ; The function does the following: + ; -------------------------------- + ; if inA < inB => return -i-1 + ; if inA > inB => return i+1 + ; if inA = inB => return 0 + ; -------------------------------- + ; where i is the first different chunk from 0 to len(inA) - :JMP(array_div_long_prepare_mul_quo_inB) + RR :JMPN(array_div_long_check_inALTinB) + + C - RR :JMPN(failAssert) ; if C < RR ERROR + + RR - 1 => RR ; Moving from i+1 to i + ; Ensure the received chunk is higher + $ => A :MLOAD(array_div_long_inB + RR) + $ => B :MLOAD(array_div_long_inA + RR) + 1 :LT + + ; Now, we must check that the above chunks are all equal, unless there are none + C - 1 => E +array_div_long_check_inAGTinB_loop: + E - RR :JMPZ(array_div_long_inAGTinB) + $ => A :MLOAD(array_div_long_inA + E) + A :MLOAD(array_div_long_inB + E) + E - 1 => E :JMP(array_div_long_check_inAGTinB_loop) ; Begin of edge cases array_div_long_inA_is_zero: - ; Is D == 1 and inB == 0? 0/0 is undefined - D - B :JMPNZ(__array_div_long_inB_continue_2) - $ => A :MLOAD(array_div_long_inB) - $ :LT, JMPC(array_div_long_inB_is_zero) - __array_div_long_inB_continue_2: - ; From here, inA == 0 and inB != 0 - ; Return [q,r] = [0,0] and len(q) = 1, len(r) = 1 0 :MSTORE(array_div_long_quo) 0 :MSTORE(array_div_long_rem) 1 :MSTORE(array_div_long_len_quo) - 1 :MSTORE(array_div_long_len_rem) - 0 => B :JMP(array_div_long_end) + 1 :MSTORE(array_div_long_len_rem), JMP(array_div_long_end) -array_div_long_inB_is_zero: - ; Error, you cannot divide by 0 - 1 => B :JMP(array_div_long_end) +array_div_long_check_inAEQinB: + C - 1 => RR +array_div_long_check_loop: + $ => A :MLOAD(array_div_long_inA + RR) + A :MLOAD(array_div_long_inB + RR) + RR - 1 => RR :JMPN(array_div_long_inAEQinB, array_div_long_check_loop) -array_div_long_same_input: +array_div_long_inAEQinB: ; if inA = inB, then return [1, 0] and len(q) = 1, len(r) = 1 1 :MSTORE(array_div_long_quo) 0 :MSTORE(array_div_long_rem) 1 :MSTORE(array_div_long_len_quo) - 1 :MSTORE(array_div_long_len_rem) - 0 => B :JMP(array_div_long_end) + 1 :MSTORE(array_div_long_len_rem), JMP(array_div_long_end) + +array_div_long_check_inALTinB: + RR + C :JMPN(failAssert) ; if RR < -C ERROR + + -RR - 1 => RR ; Moving from -i-1 to i + ; Ensure that the received chunk is lower + $ => A :MLOAD(array_div_long_inA + RR) + $ => B :MLOAD(array_div_long_inB + RR) + 1 :LT + + ; Now, we must check that the above chunks are all equal, unless there are none + C - 1 => E +array_div_long_check_inALTinB_loop: + E - RR :JMPZ(array_div_long_prep_inALTinB) + $ => A :MLOAD(array_div_long_inA + E) + A :MLOAD(array_div_long_inB + E) + E - 1 => E :JMP(array_div_long_check_inALTinB_loop) array_div_long_prep_inALTinB: - ; if inA < inB, then return [0, inA] and len(q) = 1, len(r) = C + ; if inA < inB, then return [0, inA] and len(q) = 1, len(r) = len(inA) + 0 :MSTORE(array_div_long_quo) 1 :MSTORE(array_div_long_len_quo) C :MSTORE(array_div_long_len_rem) - - %MAX_CNT_STEPS - STEP - 1 - 3*C - 2 :JMPN(outOfCountersStep) - C - 1 => RR array_div_long_inALTinB: $ => A :MLOAD(array_div_long_inA + RR) A :MSTORE(array_div_long_rem + RR) - RR - 1 => RR :JMPN(array_div_long_inALTinB_before_end, array_div_long_inALTinB) - -array_div_long_inALTinB_before_end: - 0 :MSTORE(array_div_long_quo) - 0 => B :JMP(array_div_long_end) + RR - 1 => RR :JMPN(array_div_long_end, array_div_long_inALTinB) ; End of edge cases -array_div_long_prepare_mul_quo_inB: - $0{receiveLenQuotient()} => C +array_div_long_inAGTinB: + ; From here, inA > inB + + ; Strategy: Divide outside and check the result inside + $${MPdiv(addr.array_div_long_inA,mem.array_div_long_len_inA,addr.array_div_long_inB,mem.array_div_long_len_inB)} + + $0{receiveLenQuotient()} => C ; It cannot be zero because q=0 happens only when inA < inB + + ; 1] len(Q) + len(inB) - 1 <= len(Q·inB) <= len(Q) + len(inB) (generic for multiplication of two integers) + ; 2] 1 <= len(R) <= len(inB) + ; inA = Q·inB + R + ; max{len(Q·inB),len(R)} <= len(inA) + ; len(Q) + len(inB) - 1 <= len(Q·inB) <= len(inA) - ; The received length must be between 1 and %ARRAY_MAX_LEN - C - 1 => RR :JMPN(failAssert) ; If C = 0, then fail - %ARRAY_MAX_LEN - C :JMPN(failAssert) ; If C > %ARRAY_MAX_LEN, then fail - ; From here, 1 <= C <= %ARRAY_MAX_LEN + ; 1] The received length must satisfy 1 <= len(Q) <= len(inA) - len(inB) + 1 + C - 1 => RR :JMPN(failAssert) ; if len(Q) < 1 ERROR + $ => A :MLOAD(array_div_long_len_inA) + $ => B :MLOAD(array_div_long_len_inB) + A - B + 1 - C :JMPN(failAssert) ; if len(inA) - len(inB) + 1 < len(Q) ERROR - ; To avoid non-determinism, we must ensure that the quotient is trimmed + ; 2] To avoid non-determinism, we must ensure that the quotient is trimmed ; i.e., that its last chunk is not 0 - ${receiveQuotientChunk(RR)} => A + ${receiveQuotientChunk(RR)} => A ; It cannot be zero because q=0 happens only when inA < inB 0 => B 0 :EQ ; From here, the quotient is trimmed + ; 3] Let's multiply the quotient by inB + C :MSTORE(array_div_long_len_quo) $ => D :MLOAD(array_div_long_len_inB) C - 1 => RR @@ -168,34 +212,35 @@ array_div_long_prepare_mul_quo_inB: ; save the first non-zero chunk of quo A :MSTORE(array_div_long_quo + RR) - A :MSTORE(array_mul_inA + RR) + A :MSTORE(array_mul_long_inA + RR) RR - 1 => RR :JMPN(array_div_long_inB_to_mul) array_div_long_quo_to_mul: ${receiveQuotientChunk(RR)} => A A :MSTORE(array_div_long_quo + RR) - A :MSTORE(array_mul_inA + RR) + A :MSTORE(array_mul_long_inA + RR) RR - 1 => RR :JMPN(array_div_long_inB_to_mul, array_div_long_quo_to_mul) array_div_long_inB_to_mul: $ => A :MLOAD(array_div_long_inB + E) - A :MSTORE(array_mul_inB + E) + A :MSTORE(array_mul_long_inB + E) E - 1 => E :JMPN(array_div_long_mul_quo_inB, array_div_long_inB_to_mul) array_div_long_mul_quo_inB: - :CALL(array_mul) + :CALL(array_mul_long) ; inputs: [array_mul_long_len_inA: C, array_mul_long_len_inB: D, array_mul_long_inA: array_div_long_quo, array_mul_long_inB: array_div_long_inB] + ; outputs: [array_mul_long_len_out, array_mul_long_out] - $ => D :MLOAD(array_div_long_len_inB) - %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 8 - 3*%ARRAY_MAX_LEN - 3*D - 1 :JMPN(outOfCountersStep) + ; w.c. is when rem is not zero + %MAX_CNT_BINARY - CNT_BINARY - 1 - 1 :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 14 - 5*%ARRAY_MAX_LEN_MINUS_ONE - 2 - 3 - 3*%ARRAY_MAX_LEN_DOUBLED - 1 :JMPN(outOfCountersStep) ; till array_add_AGTB ; Check the remainder - $0{receiveLenRemainder()} => D + $0{receiveLenRemainder()} => D :JMPZ(array_div_long_rem_is_zero) - ; 1] The received length must be between 1 and %ARRAY_MAX_LEN - D - 1 => E :JMPN(failAssert) ; If D = 0, then fail - %ARRAY_MAX_LEN - D :JMPN(failAssert) ; If D > %ARRAY_MAX_LEN, then fail - ; From here, 1 <= D <= %ARRAY_MAX_LEN + ; 1] The received length must satisfy 1 <= len(R) <= len(inB) <= len(inA) + D - 1 => E :JMPN(failAssert) ; if len(R) < 1 ERROR + $ => C :MLOAD(array_div_long_len_inB) + C - D :JMPN(failAssert) ; if len(inB) < len(R) ERROR ; 2] To avoid non-determinism, we must ensure that the remainder is trimmed ; i.e., that its last chunk is not 0 @@ -204,81 +249,84 @@ array_div_long_mul_quo_inB: 0 :EQ ; From here, the remainder is trimmed - ; 3] Finally, we must ensure that the remainder is lower than inB - $ => C :MLOAD(array_div_long_len_inB) - C - 1 => RR - D - 1 => E + ; 3] Moreover, we must ensure that the remainder is lower than inB - ; save the first non-zero chunk of rem - A :MSTORE(array_compare_inB + E) - E - 1 => E :JMPN(array_div_long_compare_inB2) + ; save the expected length of the remainder and the associated chunk + D :MSTORE(array_div_long_len_rem) + A :MSTORE(array_div_long_rem + E) + A :MSTORE(array_add_AGTB_inB + E) -array_div_long_compare_rem: - ${receiveRemainderChunk(E)} => A - A :MSTORE(array_compare_inB + E) - E - 1 => E :JMPN(array_div_long_compare_inB2, array_div_long_compare_rem) + ; If len(R) < len(B), then we are done + D - C :JMPN(array_div_long_rem_to_add) -array_div_long_compare_inB2: - $ => A :MLOAD(array_div_long_inB + RR) - A :MSTORE(array_compare_inA + RR) - RR - 1 => RR :JMPN(array_div_long_compare2, array_div_long_compare_inB2) + ; If len(R) == len(B), then we must compare them chunk by chunk + ${getFirstDiffChunkRem(addr.array_div_long_inB,mem.array_div_long_len_inB)} => RR :JMPN(failAssert) + D - 1 - RR :JMPN(failAssert) ; if D - 1 < RR ERROR -array_div_long_compare2: - :CALL(array_compare) + ; if it is the last chunk, then we are done + E - RR :JMPZ(array_div_long_compare_rem_first) - %MAX_CNT_STEPS - STEP - 5 - 3*%ARRAY_MAX_LEN - 4*%ARRAY_MAX_LEN - 1 :JMPN(outOfCountersStep) +array_div_long_compare_rem: + A :MLOAD(array_div_long_inB + E) + E - 1 => E + ${receiveRemainderChunk(E)} => A :MSTORE(array_div_long_rem + E) + A :MSTORE(array_add_AGTB_inB + E) + E - RR :JMPNZ(array_div_long_compare_rem) - 2 :MLOAD(array_compare_result) +array_div_long_compare_rem_first: + $ => B :MLOAD(array_div_long_inB + E) + 1 :LT - D :MSTORE(array_div_long_len_rem) +array_div_long_rem_to_add: + ; From here, we have checked that the R < inB + E - 1 => E :JMPN(array_div_long_add_check) + ${receiveRemainderChunk(E)} => A :MSTORE(array_div_long_rem + E) + A :MSTORE(array_add_AGTB_inB + E) + E :JMPNZ(array_div_long_rem_to_add) - ; prepare output and remainder to be added - $ => C :MLOAD(array_mul_len_out) - C - 1 => RR - D - 1 => E +array_div_long_add_check: -array_div_long_res_to_add: - $ => A :MLOAD(array_mul_out + RR) - A :MSTORE(array_add_AGTB_inA + RR) - RR - 1 => RR :JMPN(array_div_long_rem_to_add, array_div_long_res_to_add) + ; 4] Let's add the remainder to the multiplication result -array_div_long_rem_to_add: - $ => A :MLOAD(array_compare_inB + E) ; Load the remainder used in the comparison - A :MSTORE(array_div_long_rem + E) - A :MSTORE(array_add_AGTB_inB + E) - E - 1 => E :JMPN(array_div_long_add_res_rem, array_div_long_rem_to_add) + $ => C :MLOAD(array_mul_long_len_out) + C - 1 => RR +array_div_long_mul_out_to_add: + $ => A :MLOAD(array_mul_long_out + RR) + A :MSTORE(array_add_AGTB_inA + RR) + RR - 1 => RR :JMPN(array_div_long_add_mul_out_rem, array_div_long_mul_out_to_add) -array_div_long_add_res_rem: - :CALL(array_add_AGTB) +array_div_long_add_mul_out_rem: + :CALL(array_add_AGTB) ; inputs: [array_add_AGTB_len_inA: C, array_add_AGTB_len_inB: D, array_add_AGTB_inA: array_mul_long_out, array_add_AGTB_inB: array_div_long_rem] + ; outputs: [array_add_AGTB_len_out, array_add_AGTB_out] - %MAX_CNT_STEPS - STEP - 5 :JMPN(outOfCountersStep) + %MAX_CNT_STEPS - STEP - 3 - 3*%ARRAY_MAX_LEN_DOUBLED - 2 :JMPN(outOfCountersStep) - ; prepare next - $ => C :MLOAD(array_add_AGTB_len_out) - $ => D :MLOAD(array_div_long_len_inA) + ; The length of q·b + r must be the same as the input of a + $ => C :MLOAD(array_add_AGTB_len_out) + C :MLOAD(array_div_long_len_inA) C - 1 => RR - D - 1 => E - - %MAX_CNT_STEPS - STEP - 3*%ARRAY_MAX_LEN - 3*D - 1 :JMPN(outOfCountersStep) -array_div_long_compare_inA2: +; Check that a == q·b + r +array_div_long_check_rem_not_zero: $ => A :MLOAD(array_add_AGTB_out + RR) - A :MSTORE(array_compare_inA + RR) - RR - 1 => RR :JMPN(array_div_long_compare_inB3, array_div_long_compare_inA2) - -array_div_long_compare_inB3: - $ => A :MLOAD(array_div_long_inA + E) - A :MSTORE(array_compare_inB + E) - E - 1 => E :JMPN(array_div_long_compare3, array_div_long_compare_inB3) + A :MLOAD(array_div_long_inA + RR) + RR - 1 => RR :JMPN(array_div_long_end, array_div_long_check_rem_not_zero) -array_div_long_compare3: - :CALL(array_compare) +; Path with remainder equal to 0 +array_div_long_rem_is_zero: + 1 :MSTORE(array_div_long_len_rem) + 0 :MSTORE(array_div_long_rem) - %MAX_CNT_STEPS - STEP - 4 :JMPN(outOfCountersStep) + ; The length of q·b must be the same as the input of a + $ => C :MLOAD(array_div_long_len_inA) + C :MLOAD(array_mul_long_len_out) - 1 :MLOAD(array_compare_result) - 0 => B + ; Check that a == q·b + 0 + C - 1 => RR +array_div_long_check_rem_is_zero: + $ => A :MLOAD(array_mul_long_out + RR) + A :MLOAD(array_div_long_inA + RR) + RR - 1 => RR :JMPN(array_div_long_end, array_div_long_check_rem_is_zero) array_div_long_end: - $ => RR :MLOAD(array_div_long_RR) - :RETURN \ No newline at end of file + $ => RR :MLOAD(array_div_long_RR), RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_div_short.zkasm b/main/modexp/array_lib/array_div_short.zkasm index 577b57ad..a7b3b67e 100644 --- a/main/modexp/array_lib/array_div_short.zkasm +++ b/main/modexp/array_lib/array_div_short.zkasm @@ -1,5 +1,5 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; PRE: The input arrays have been trimmed. +;; PRE: The input arrays have been trimmed and inB != 0. ;; POST: The quotient is trimmed. ;; ;; array_div_short: @@ -12,26 +12,6 @@ ;; · [quo,rem] = [inA / inB[0], inA % inB[0]], with len(quo) <= C, len(rem) = 1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; function array_div_short(a: bigint[], b: bigint, base: bigint): bigint[] { -; if (a === [0n]) { -; if (b === 0n) { -; throw new Error("Division by zero"); -; } -; return [0n, 0n]; -; } else if (b === 0n) { -; throw new Error("Division by zero"); -; } -; -; if (a === b) { -; return [1n, 0n]; -; } else if (a < b) { -; return [0n, a]; -; } -; } - -; NOTE: This function receives the actual result from the helper (avoiding the need of computing divisions); -; checks the correctness of the result and returns the result to the caller - VAR GLOBAL array_div_short_inA[%ARRAY_MAX_LEN] VAR GLOBAL array_div_short_inB VAR GLOBAL array_div_short_quo[%ARRAY_MAX_LEN] @@ -42,13 +22,11 @@ VAR GLOBAL array_div_short_len_quo VAR GLOBAL array_div_short_RR -; ERROR CODES (B) -; 0 - no error -; 1 - inB is zero - array_div_short: - %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 11 - 3*C - 3 :JMPN(outOfCountersStep) + ; w.c. is when len(inA) >> len(inB) + + %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 20 - 4*%ARRAY_MAX_LEN_MINUS_ONE - 3 :JMPN(outOfCountersStep) ; till array_mul_short RR :MSTORE(array_div_short_RR) @@ -56,92 +34,90 @@ array_div_short: C :MSTORE(array_div_short_len_quo) ; Let's cover the edge cases - 1 => B ; 1] Is C == 1 and inA == 0? - C - B :JMPNZ(__array_div_short_inA_continue) - $ => A :MLOAD(array_div_short_inA) - $ :LT, JMPC(array_div_short_inA_is_zero) + C - 1 :JMPNZ(array_div_short_inAGTinB) ; If len(inA) > 1, then we already know that inA > inB + $ => A :MLOAD(array_div_short_inA); Here, len(inA) = len(inB) = 1 + 0 => B + $ :EQ, JMPC(array_div_short_inA_is_zero, array_div_short_equal_len) __array_div_short_inA_continue: - ; 2] Is inB == 0? - $ => A :MLOAD(array_div_short_inB) - $ :LT, JMPC(array_div_short_inB_is_zero) + ; 2] Check if inA = inB, inA < inB or inA > inB - ; Check whether inA = inB or inA < inB - C - 1 => RR - 1 => D -array_div_short_inA_to_compare1: - $ => A :MLOAD(array_div_short_inA + RR) - A :MSTORE(array_compare_inA + RR) - RR - 1 => RR :JMPN(array_div_short_inB_to_compare, array_div_short_inA_to_compare1) +array_div_short_equal_len: + ; Here, C = 1 -array_div_short_inB_to_compare: - $ => A :MLOAD(array_div_short_inB) - A :MSTORE(array_compare_inB) - -array_div_short_compare_inA_inB: - :CALL(array_compare) + ; If the lengths are equal, then we must compare the only chunk + $0{signedComparison(addr.array_div_short_inA,addr.array_div_short_inB)} => RR :JMPZ(array_div_short_check_same_input) - %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 10 - 4*%ARRAY_MAX_LEN - 3 :JMPN(outOfCountersStep) + ; The function does the following: + ; -------------------------------- + ; if inA < inB => return -1 + ; if inA > inB => return 1 + ; if inA = inB => return 0 + ; -------------------------------- - $ => A :MLOAD(array_compare_result), JMPZ(array_div_short_inALTinB) - A - 1 :JMPZ(array_div_short_same_input) - ; From here, inA > inB + RR :JMPN(array_div_short_check_inALTinB) - ; Strategy: Divide outside and check the result inside - $${MPdiv_short(addr.array_div_short_inA,mem.array_div_short_len_inA,mem.array_div_short_inB)} + 1 - RR :JMPN(failAssert) ; if 1 < RR ERROR - :JMP(array_div_short_prepare_mul_quo_inB) + ; Ensure that the chunk is higher + $ => A :MLOAD(array_div_short_inB) + $ => B :MLOAD(array_div_short_inA) + 1 :LT, JMP(array_div_short_inAGTinB) ; Begin of edge cases array_div_short_inA_is_zero: - ; Is inB == 0? 0/0 is undefined - $ => A :MLOAD(array_div_short_inB) - $ :LT, JMPC(array_div_short_inB_is_zero) - ; From here, inB != 0 - ; Return [q,r] = [0,0] and len(q) = 1, len(r) = 1 0 :MSTORE(array_div_short_quo) 0 :MSTORE(array_div_short_rem) - 1 :MSTORE(array_div_short_len_quo) - 0 => B :JMP(array_div_short_end) + 1 :MSTORE(array_div_short_len_quo), JMP(array_div_short_end) -array_div_short_inB_is_zero: - ; Error, you cannot divide by 0 - 1 => B :JMP(array_div_short_end) +array_div_short_check_same_input: + $ => A :MLOAD(array_div_short_inA) + A :MLOAD(array_div_short_inB) array_div_short_same_input: ; If inA = inB, then the result is [1,0] since inA = 1·inB + 0 - 1 :MSTORE(array_div_short_quo) + 1 :MSTORE(array_div_short_quo) 1 :MSTORE(array_div_short_len_quo) - 0 :MSTORE(array_div_short_rem) - 0 => B :JMP(array_div_short_end) + 0 :MSTORE(array_div_short_rem), JMP(array_div_short_end) + +array_div_short_check_inALTinB: + RR + 1 :JMPN(failAssert) ; if RR < -1 ERROR + + $ => A :MLOAD(array_div_short_inA) + $ => B :MLOAD(array_div_short_inB) + 1 :LT array_div_short_inALTinB: ; If inA < inB, then the result is [0, inA] since inA = 0·inB + inA 0 :MSTORE(array_div_short_quo) 1 :MSTORE(array_div_short_len_quo) $ => A :MLOAD(array_div_short_inA) - A :MSTORE(array_div_short_rem) - 0 => B :JMP(array_div_short_end) + A :MSTORE(array_div_short_rem), JMP(array_div_short_end) ; End of edge cases -array_div_short_prepare_mul_quo_inB: - $0{receiveLenQuotient_short()} => C +array_div_short_inAGTinB: + ; From here, inA > inB + + ; Strategy: Divide outside and check the result inside + $${MPdiv_short(addr.array_div_short_inA,mem.array_div_short_len_inA,mem.array_div_short_inB)} + + $0{receiveLenQuotient_short()} => C ; It cannot be zero because q=0 happens only when inA < inB - ; The received length must be between 1 and %ARRAY_MAX_LEN - C - 1 => RR :JMPN(failAssert) ; If C = 0, then fail - %ARRAY_MAX_LEN - C :JMPN(failAssert) ; If C > %ARRAY_MAX_LEN, then fail - ; From here, 1 <= C <= %ARRAY_MAX_LEN + ; 1] The received length must satisfy 1 <= len(Q) <= len(inA) + C - 1 => RR :JMPN(failAssert) ; if len(Q) < 1 ERROR + $ - C :F_MLOAD(array_div_short_len_inA), JMPN(failAssert) ; if len(inA) < len(Q) ERROR - ; To avoid non-determinism, we must ensure that the quotient is trimmed + ; 2] To avoid non-determinism, we must ensure that the quotient is trimmed ; i.e., that its last chunk is not 0 - ${receiveQuotientChunk_short(RR)} => A + ${receiveQuotientChunk_short(RR)} => A ; It cannot be zero because q=0 happens only when inA < inB 0 => B 0 :EQ ; From here, the quotient is trimmed + ; 3] Let's multiply the quotient by inB + C :MSTORE(array_div_short_len_quo) C - 1 => RR @@ -161,22 +137,21 @@ array_div_short_inB_to_mul: A :MSTORE(array_mul_short_inB) array_div_short_mul_quo_inB: - :CALL(array_mul_short) + :CALL(array_mul_short); inputs: [array_mul_short_len_inA: C, array_mul_short_inA: array_div_short_quo, array_mul_short_inB: array_div_short_inB] + ; outputs: [array_mul_short_len_out, array_mul_short_out] - %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 2 - 3*%ARRAY_MAX_LEN - 6 :JMPN(outOfCountersStep) + ; w.c. is when rem is not zero + %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 10 - 3*%ARRAY_MAX_LEN_MINUS_ONE - 1 :JMPN(outOfCountersStep) ; till array_add_short - ; prepare next - $ => C :MLOAD(array_mul_short_len_out) - C - 1 => RR + ; Check the remainder + ${receiveRemainderChunk_short()} => A -array_div_short_result_to_add: - $ => A :MLOAD(array_mul_short_out + RR) - A :MSTORE(array_add_short_inA + RR) - RR - 1 => RR :JMPN(array_div_short_rem_to_add, array_div_short_result_to_add) + ${A == 0} :JMPNZ(array_div_short_rem_is_zero) -array_div_short_rem_to_add: - ${receiveRemainderChunk_short()} => A + ; Check that the remainder is not zero + 0 => B + 0 :EQ ; We must ensure the the remaider is lower than inB $ => B :MLOAD(array_div_short_inB) @@ -185,38 +160,45 @@ array_div_short_rem_to_add: A :MSTORE(array_div_short_rem) A :MSTORE(array_add_short_inB) + $ => C :MLOAD(array_mul_short_len_out) + C - 1 => RR +array_div_short_result_to_add: + $ => A :MLOAD(array_mul_short_out + RR) + A :MSTORE(array_add_short_inA + RR) + RR - 1 => RR :JMPN(array_div_short_add_result_rem, array_div_short_result_to_add) + array_div_short_add_result_rem: - :CALL(array_add_short) + :CALL(array_add_short) ; inputs: [array_add_short_len_inA: C, array_add_short_inA: array_mul_short_out, array_add_short_inB: array_div_short_inB] + ; outputs: [array_add_short_len_out, array_add_short_out] - %MAX_CNT_STEPS - STEP - 5 :JMPN(outOfCountersStep) + %MAX_CNT_STEPS - STEP - 3 - 3*%ARRAY_MAX_LEN - 2 :JMPN(outOfCountersStep) - ; prepare next + ; The length of q·b + r must be the same as the input of a $ => C :MLOAD(array_add_short_len_out) - $ => D :MLOAD(array_div_short_len_inA) + C :MLOAD(array_div_short_len_inA) C - 1 => RR - D - 1 => E - - %MAX_CNT_STEPS - STEP - 3*%ARRAY_MAX_LEN - 3*D - 1 :JMPN(outOfCountersStep) -array_div_short_result_to_compare: +; Check that a == q·b + r +array_div_short_check_result_eq_inA1: $ => A :MLOAD(array_add_short_out + RR) - A :MSTORE(array_compare_inA + RR) - RR - 1 => RR :JMPN(array_div_short_inA_to_compare2, array_div_short_result_to_compare) + A :MLOAD(array_div_short_inA + RR) + RR - 1 => RR :JMPN(array_div_short_end, array_div_short_check_result_eq_inA1) -array_div_short_inA_to_compare2: - $ => A :MLOAD(array_div_short_inA + E) - A :MSTORE(array_compare_inB + E) - E - 1 => E :JMPN(array_div_short_compare_result_inA, array_div_short_inA_to_compare2) -array_div_short_compare_result_inA: - :CALL(array_compare) +; Path with remainder equal to 0 +array_div_short_rem_is_zero: + 0 :ASSERT, MSTORE(array_div_short_rem) - %MAX_CNT_STEPS - STEP - 4 :JMPN(outOfCountersStep) + ; The length of q·b must be the same as the input of a + $ => C :MLOAD(array_div_short_len_inA) + C :MLOAD(array_mul_short_len_out) - 1 :MLOAD(array_compare_result) - - 0 => B ; error code + ; Check that a == q·b + 0 + C - 1 => RR +array_div_short_check_result_eq_inA2: + $ => A :MLOAD(array_mul_short_out + RR) + A :MLOAD(array_div_short_inA + RR) + RR - 1 => RR :JMPN(array_div_short_end, array_div_short_check_result_eq_inA2) array_div_short_end: - $ => RR :MLOAD(array_div_short_RR) - :RETURN \ No newline at end of file + $ => RR :MLOAD(array_div_short_RR), RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_div_two.zkasm b/main/modexp/array_lib/array_div_two.zkasm new file mode 100644 index 00000000..de382ce0 --- /dev/null +++ b/main/modexp/array_lib/array_div_two.zkasm @@ -0,0 +1,185 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; PRE: The input array has been trimmed. +;; POST: The quotient is trimmed. +;; +;; array_div_two: +;; input: +;; · C ∈ [1, 32], the len of in +;; · in ∈ [0, 2²⁵⁶ - 1]^C, the first input array +;; +;; output: +;; · quo = in // 2, with len(quo) <= C +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +VAR GLOBAL array_div_two_in[%ARRAY_MAX_LEN] +VAR GLOBAL array_div_two_quo[%ARRAY_MAX_LEN] + +VAR GLOBAL array_div_two_len_in +VAR GLOBAL array_div_two_len_quo + +VAR GLOBAL array_div_two_RR + +array_div_two: + ; w.c. is when len(in) >> len(2) + + %MAX_CNT_BINARY - CNT_BINARY - 3 :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 26 - 4*%ARRAY_MAX_LEN_MINUS_ONE - 1 :JMPN(outOfCountersStep) ; till array_mul_two + + RR :MSTORE(array_div_two_RR) + + C :MSTORE(array_div_two_len_in) + C :MSTORE(array_div_two_len_quo) + + ; Let's cover the edge cases + 0 => B + ; 1] Is C == 1 and in == 0? + C - 1 :JMPNZ(array_div_two_inAGTinB) ; If len(in) > 1, then we already know that in > 2 + $ => A :MLOAD(array_div_two_in); Here, len(in) = 1 + $ :EQ, JMPC(array_div_two_inALTinB) + ; Here, len(in) = 1 + + ; 2] Check if in = 2, in < 2 or in > 2 + ; If the lengths are equal, then we must compare the only chunk + $0{signedComparisonWithConst(addr.array_div_two_in,2)} => RR :JMPZ(array_div_two_check_same_input) + + ; The function does the following: + ; -------------------------------- + ; if in < 2 => return -1 + ; if in > 2 => return 1 + ; if in = 2 => return 0 + ; -------------------------------- + + RR :JMPN(array_div_two_check_inALTtwo) + + 1 - RR :JMPN(failAssert) ; if 1 < RR ERROR + + ; Ensure that the chunk is higher + 2 => A + $ => B :MLOAD(array_div_two_in) + 1 :LT, JMP(array_div_two_inAGTinB) + +; Begin of edge cases +array_div_two_check_same_input: + 2 :MLOAD(array_div_two_in) + +array_div_two_same_input: + ; If in = 2, then the result is 1 + 1 :MSTORE(array_div_two_quo) + 1 :MSTORE(array_div_two_len_quo), JMP(array_div_two_end) + +array_div_two_check_inALTtwo: + RR + 1 :JMPN(failAssert) ; if RR < -1 ERROR + + $ => A :MLOAD(array_div_two_in) + 2 => B + 1 :LT + +array_div_two_inALTinB: + ; If in < 2, then the result is 0 + 0 :MSTORE(array_div_two_quo) + 1 :MSTORE(array_div_two_len_quo), JMP(array_div_two_end) +; End of edge cases + +array_div_two_inAGTinB: + ; From here, in > 2 + + ; Strategy: Divide outside and check the result inside + $${MPdiv_short(addr.array_div_two_in,mem.array_div_two_len_in,2)} + + $0{receiveLenQuotient_short()} => C ; It cannot be zero because q=0 happens only when in < 2 + + ; 1] The received length must satisfy 1 <= len(Q) <= len(in) + C - 1 => RR :JMPN(failAssert) ; if len(Q) < 1 ERROR + $ => A :MLOAD(array_div_two_len_in) + A - C :JMPN(failAssert) ; if len(in) < len(Q) ERROR + + ; 2] To avoid non-determinism, we must ensure that the quotient is trimmed + ; i.e., that its last chunk is not 0 + ${receiveQuotientChunk_short(RR)} => A ; It cannot be zero because q=0 happens only when in < 2 + 0 => B + 0 :EQ + ; From here, the quotient is trimmed + + ; 3] Let's multiply the quotient by 2 + + C :MSTORE(array_div_two_len_quo) + C => D + C - 1 => RR + + ; save the first non-zero chunk of quo + A :MSTORE(array_div_two_quo + RR) + A :MSTORE(array_mul_two_in + RR) + RR - 1 => RR :JMPN(array_div_two_mul_quo_inB) + ; w.c. [steps: 26, bin: 3] + +array_div_two_quo_to_mul: + ${receiveQuotientChunk_short(RR)} => A + A :MSTORE(array_div_two_quo + RR) + A :MSTORE(array_mul_two_in + RR) + RR - 1 => RR :JMPN(array_div_two_mul_quo_inB, array_div_two_quo_to_mul) + +array_div_two_mul_quo_inB: + :CALL(array_mul_two) ; inputs: [array_mul_two_len_in: C, array_mul_two_in: array_div_two_quo] + ; outputs: [array_mul_two_len_out, array_mul_two_out] + + ; w.c. is when rem is not zero + %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 9 - 3*%ARRAY_MAX_LEN_MINUS_ONE - 1 :JMPN(outOfCountersStep) ; till array_add_short + + ; Check the remainder + ${receiveRemainderChunk_short()} => A + + ${A == 0} :JMPNZ(array_div_two_rem_is_zero) + + ; Check that the remainder is not zero + 0 => B + 0 :EQ + + ; We must ensure the the remaider is lower than 2 + 2 => B + 1 :LT + + A :MSTORE(array_add_short_inB) + + $ => C :MLOAD(array_mul_two_len_out) + C - 1 => RR +array_div_two_result_to_add: + $ => A :MLOAD(array_mul_two_out + RR) + A :MSTORE(array_add_short_inA + RR) + RR - 1 => RR :JMPN(array_div_two_add_result_rem, array_div_two_result_to_add) + +array_div_two_add_result_rem: + :CALL(array_add_short) ; inputs: [array_add_short_len_inA: C, array_add_short_inA: array_mul_two_out, array_add_short_inB: A] + ; outputs: [array_add_short_len_out, array_add_short_out] + + %MAX_CNT_STEPS - STEP - 3 - 3*%ARRAY_MAX_LEN - 2 :JMPN(outOfCountersStep) + + ; The length of q·b + r must be the same as the input of a + $ => C :MLOAD(array_add_short_len_out) + C :MLOAD(array_div_two_len_in) + C - 1 => RR + +; Check that in == 2·q + r +array_div_two_check_result_eq_inA1: + $ => A :MLOAD(array_add_short_out + RR) + A :MLOAD(array_div_two_in + RR) + RR - 1 => RR :JMPN(array_div_two_end, array_div_two_check_result_eq_inA1) + + +; Path with remainder equal to 0 +array_div_two_rem_is_zero: + 0 :ASSERT + + ; The length of q·b must be the same as the input of a + $ => C :MLOAD(array_div_two_len_in) + C :MLOAD(array_mul_two_len_out) + + ; Check that input == 2·quo + 0 + C - 1 => RR +array_div_two_check_result_eq_inA2: + $ => A :MLOAD(array_mul_two_out + RR) + A :MLOAD(array_div_two_in + RR) + RR - 1 => RR :JMPN(array_div_two_end, array_div_two_check_result_eq_inA2) + +array_div_two_end: + $ => RR :MLOAD(array_div_two_RR), RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_mul.zkasm b/main/modexp/array_lib/array_mul.zkasm deleted file mode 100644 index e4551c1b..00000000 --- a/main/modexp/array_lib/array_mul.zkasm +++ /dev/null @@ -1,97 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; POST: out is trimmed -;; -;; array_mul: -;; in: -;; · C ∈ [1, 32], the len of inA -;; · D ∈ [1, 32], the len of inB -;; · inA ∈ [0, 2²⁵⁶ - 1]^C, the first input array -;; · inB ∈ [0, 2²⁵⁶ - 1]^D, the second input array -;; -;; output: -;; · out = inA·inB, with len(out) <= C + D -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; function array_mul(a: bigint[], b: bigint[], base: bigint): bigint[] { -; if (b.length === 1) { -; return array_mul_short(a, b, base); -; } -; return array_mul_long(a, b, base); -; } - -VAR GLOBAL array_mul_inA[%ARRAY_MAX_LEN] -VAR GLOBAL array_mul_inB[%ARRAY_MAX_LEN] -VAR GLOBAL array_mul_out[%ARRAY_MAX_LEN_DOUBLED] -VAR GLOBAL array_mul_len_inA -VAR GLOBAL array_mul_len_inB -VAR GLOBAL array_mul_len_out - -VAR GLOBAL array_mul_RR - -array_mul: - %MAX_CNT_STEPS - STEP - 6 - 3*C - 3*D - 1 :JMPN(outOfCountersStep) - - RR :MSTORE(array_mul_RR) - - C :MSTORE(array_mul_len_inA) - D :MSTORE(array_mul_len_inB) - - C - 1 => RR - D - 1 => E - D - 1 :JMPZ(array_mul_inA_to_mul_short) ; worst case is mul long -; Long -array_mul_inA_to_mul_long: - $ => A :MLOAD(array_mul_inA + RR) - A :MSTORE(array_mul_long_inA + RR) - RR - 1 => RR :JMPN(array_mul_inB_to_mul_long, array_mul_inA_to_mul_long) - -array_mul_inB_to_mul_long: - $ => A :MLOAD(array_mul_inB + E) - A :MSTORE(array_mul_long_inB + E) - E - 1 => E :JMPN(array_mul_compute_long, array_mul_inB_to_mul_long) - -array_mul_compute_long: - :CALL(array_mul_long) - - %MAX_CNT_STEPS - STEP - 4 :JMPN(outOfCountersStep) - - $ => C :MLOAD(array_mul_long_len_out) - C :MSTORE(array_mul_len_out) - C - 1 => RR - - %MAX_CNT_STEPS - STEP - 3*C - 2 :JMPN(outOfCountersStep) - -array_mul_assign_long: - $ => A :MLOAD(array_mul_long_out + RR) - A :MSTORE(array_mul_out + RR) - RR - 1 => RR :JMPN(array_mul_end, array_mul_assign_long) - -; Short -array_mul_inA_to_mul_short: - $ => A :MLOAD(array_mul_inA + RR) - A :MSTORE(array_mul_short_inA + RR) - RR - 1 => RR :JMPN(array_mul_inB_to_mul_short, array_mul_inA_to_mul_short) - -array_mul_inB_to_mul_short: - $ => A :MLOAD(array_mul_inB) - A :MSTORE(array_mul_short_inB) - -array_mul_compute_short: - :CALL(array_mul_short) - - %MAX_CNT_STEPS - STEP - 4 :JMPN(outOfCountersStep) - - $ => C :MLOAD(array_mul_short_len_out) - C :MSTORE(array_mul_len_out) - C - 1 => RR - - %MAX_CNT_STEPS - STEP - 3*C - 2 :JMPN(outOfCountersStep) - -array_mul_assign_short: - $ => A :MLOAD(array_mul_short_out + RR) - A :MSTORE(array_mul_out + RR) - RR - 1 => RR :JMPN(array_mul_end, array_mul_assign_short) - -array_mul_end: - $ => RR :MLOAD(array_mul_RR) - :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_mul_long.zkasm b/main/modexp/array_lib/array_mul_long.zkasm index 28dea0ef..a1663811 100644 --- a/main/modexp/array_lib/array_mul_long.zkasm +++ b/main/modexp/array_lib/array_mul_long.zkasm @@ -4,8 +4,8 @@ ;; ;; array_mul_long: ;; in: -;; · C ∈ [1, 32], the len of inA -;; · D ∈ [1, 32], the len of inB +;; · C ∈ [1, 64], the len of inA +;; · D ∈ [2, 32], the len of inB ;; · inA ∈ [0, 2²⁵⁶ - 1]^C, the first input array ;; · inB ∈ [0, 2²⁵⁶ - 1]^D, the second input array ;; @@ -13,28 +13,31 @@ ;; · out = inA·inB, with len(out) <= C + D ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; function array_mul_long(a: bigint[], b: bigint[], base: bigint): bigint[] { -; const alen = a.length; -; const blen = b.length; -; const len = alen + blen; -; const result = new Array(len).fill(0n); -; let product: bigint; -; let carry: bigint; -; for (let i = 0; i < alen; i++) { -; for (let j = 0; j < blen; j++) { -; product = a[i] * b[j] + out[i+j]; -; carry = product / base; -; out[i+j] = product - carry * base; -; out[i + j + 1] += carry; -; } -; } -; trim(result); -; return result; +;; WARNING: This function is tailored for checking that a = q·b + r in the array_div_long function. +;; In can be used for other purposes except for the worst case, i.e. when len(inA) == %ARRAY_MAX_LEN_DOUBLED. +;; Specifically, there is an implicit assumption that the output len of this function cannot be +;; greater than %ARRAY_MAX_LEN_DOUBLED, and do not allow to generate the proof in such case. + +; code +; -------------------------- +; first_iteration_first_row <-- Compute a[0]·b[0] +; do { +; finish_first_row <-- Compute a[0]·b[j] + out[j] +; } while(inB_index_check) <-- While 0 < j < len(b) +; while(inA_index_check) { <-- While 0 < i < len(a) +; while (inB_index_check) { <-- While 0 <= j < len(b) - 1 +; loop2inB <-- Compute a[i]·b[j] + out[i+j] +; } +; loop2inB_last <-- Compute a[i]·b[len(b)-1] + out[i+len(b)-1] ; } +; 1] check_carry <-- If there is a carry, append it to the result +; 2] trim <-- Otherwise, trim the result +; end +; -------------------------- -VAR GLOBAL array_mul_long_inA[%ARRAY_MAX_LEN] +VAR GLOBAL array_mul_long_inA[%ARRAY_MAX_LEN_DOUBLED] VAR GLOBAL array_mul_long_inB[%ARRAY_MAX_LEN] -VAR GLOBAL array_mul_long_out[%ARRAY_MAX_LEN_DOUBLED] +VAR GLOBAL array_mul_long_out[%ARRAY_MAX_LEN_DOUBLED] ; This cannot be bigger because we use it for division checking VAR GLOBAL array_mul_long_len_inA VAR GLOBAL array_mul_long_len_inB VAR GLOBAL array_mul_long_len_out @@ -44,75 +47,93 @@ VAR GLOBAL array_mul_long_out_chunk_2 VAR GLOBAL array_mul_long_RR array_mul_long: - %MAX_CNT_ARITH - CNT_ARITH - 1 :JMPN(outOfCountersArith) - %MAX_CNT_STEPS - STEP - 9 :JMPN(outOfCountersStep) + ; big loop costs (len(inA) - 1)*((len(inB) - 1) * [steps: 21, binary: 2, arith: 1] + [steps: 18, binary: 1, arith: 1]) - C => A - D => B - 0 => C,D - ${A*B} => E :ARITH - A => C - B => D - ; E holds C*D - - %MAX_CNT_BINARY - CNT_BINARY - 4*E :JMPN(outOfCountersBinary) - %MAX_CNT_ARITH - CNT_ARITH - E :JMPN(outOfCountersArith) - %MAX_CNT_STEPS - STEP - 7 - 2*C - 2*D - 33*E - 2 - 3*C - 1 :JMPN(outOfCountersStep) + %MAX_CNT_ARITH - CNT_ARITH - 1 - %ARRAY_MAX_LEN_MINUS_ONE - %ARRAY_MAX_LEN_TIMES_DOUBLED - %ARRAY_MAX_LEN_DOUBLED_MINUS_ONE :JMPN(outOfCountersArith) + %MAX_CNT_BINARY - CNT_BINARY - 2*%ARRAY_MAX_LEN_TIMES_DOUBLED - %ARRAY_MAX_LEN_DOUBLED_MINUS_ONE - 1 :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 12 - 9*%ARRAY_MAX_LEN_MINUS_ONE - 21*%ARRAY_MAX_LEN_TIMES_DOUBLED - 18*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE - 7 :JMPN(outOfCountersStep) RR :MSTORE(array_mul_long_RR) C :MSTORE(array_mul_long_len_inA) D :MSTORE(array_mul_long_len_inB) - C + D :MSTORE(array_mul_long_len_out) - 0 :MSTORE(array_mul_long_out_chunk_2) ; initialize the out chunk 2 - C + D - 1 => E ; auxiliar index - 0 => RCX ; first index in loops - 0 => RR ; second index in loops + 0 => RCX,RR ; first and second indexes in loops + +array_mul_long_first_iteration_first_row: + ; The result will be stored as D·base + C -array_mul_long_clean_out: - 0 :MSTORE(array_mul_long_out + E) - E - 1 => E :JMPN(array_mul_long_loopZero2inB, array_mul_long_clean_out) + ; a[0]·b[0], where a[0],b[0] ∈ [0,base-1]: This number cannot be GT (base - 1)·base, two chunks + $ => A :MLOAD(array_mul_long_inA) + $ => B :MLOAD(array_mul_long_inB) + 0 => C + $${var _arrayLongMul_AB = A*B} + ${_arrayLongMul_AB >> 256} => D + ${_arrayLongMul_AB} => C :ARITH -; Begin of branching -array_mul_long_loop_index_check: - RCX + 1 => RCX - $ => B :MLOAD(array_mul_long_len_inA) - B - RCX :JMPZ(array_mul_long_prep_trim_in) + ; out[0] = product - carry·B + C :MSTORE(array_mul_long_out) - 0 => RR ; reset the second index -; End of branching + ; out[1] = carry + 1 => RR + D => C :MSTORE(array_mul_long_out + RR) + +array_mul_long_finish_first_row: + ; The result will be stored as D·base + C + + ; a[0]·b[j] + out[j], where a[0],b[j],out[j] ∈ [0,base-1]: This number cannot be GT (base - 1)·base, two chunks + $ => B :MLOAD(array_mul_long_inB + RR) + $${var _arrayLongMul_AB = A*B + C} + ${_arrayLongMul_AB >> 256} => D + ${_arrayLongMul_AB} => C :ARITH + + ; C = result, D = carry + + ; out[j] = product - carry·B + C :MSTORE(array_mul_long_out + RR) + + ; out[j+1] = carry + RR + 1 => RR,E + D => C :MSTORE(array_mul_long_out + RR) + + ; C = D = carry + +array_mul_long_inB_index_check: + $ - RR :F_MLOAD(array_mul_long_len_inB), JMPNZ(array_mul_long_finish_first_row) + +array_mul_long_inA_index_check: + ; D = carry, E = last_index_out + $ - RCX - 1 :F_MLOAD(array_mul_long_len_inA), JMPZ(array_mul_long_check_carry) + + RCX + 1 => RCX ; update the first index + 0 => RR :MSTORE(array_mul_long_out_chunk_2) ; reset the second index and the out chunk 2 + +array_mul_long_loop2inB: + ; costs [steps: 21, binary: 2, arith: 1] -array_mul_long_loopZero2inB: ; The result will be stored as D·base + C RCX => E - ; 1] a[i]·b[j], where a[i],b[j] ∈ [0,base-1]: This number cannot be GT (base - 2)·base + 1, two chunks + ; a[i]·b[j] + out[i+j], where a[i],b[j],out[i+j] ∈ [0,base-1]: This number cannot be GT (base - 1)·base, two chunks $ => A :MLOAD(array_mul_long_inA + E) $ => B :MLOAD(array_mul_long_inB + RR) - 0 => C - $${var _arrayLongMul_AB = A*B} + RCX + RR => E + $ => C :MLOAD(array_mul_long_out + E) + $${var _arrayLongMul_AB = A*B + C} ${_arrayLongMul_AB >> 256} => D - ${_arrayLongMul_AB} => E :ARITH + ${_arrayLongMul_AB} => C :ARITH - ; 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 - E => A - RCX + RR => E - $ => B :MLOAD(array_mul_long_out + E) - $ => C :ADD, JMPNC(__array_mul_long_no_carry_continue_1) + $ => A :MLOAD(array_mul_long_out_chunk_2), JMPZ(__array_mul_long_c2isZ_continue) ; out_chunk_2 ∈ [0,1] ;----------------- - ; Since here D ∈ [0, base - 2], there cannot be carry in the following addition - D => A - 1 => B - $ => D :ADD - ;----------------- - __array_mul_long_no_carry_continue_1: - $ => A :MLOAD(array_mul_long_out_chunk_2) ; out_chunk_2 ∈ [0,1] D => B $ => D :ADD ; the number is of two chunks, no carry can be generated here + __array_mul_long_c2isZ_continue: + ;----------------- ; NOTE: It cannot happen that a[i]·b[j] + out[i+j] produces carry and out_chunk_2 is 1. + ; C = result, D = carry + ; out[i+j] = product - carry·B C :MSTORE(array_mul_long_out + E) @@ -129,28 +150,64 @@ array_mul_long_loopZero2inB: __array_mul_long_carry_continue: ;----------------- + ; C = carry + C :MSTORE(array_mul_long_out + E) RR + 1 => RR - $ => B :MLOAD(array_mul_long_len_inB) - B - RR :JMPZ(array_mul_long_loop_index_check, array_mul_long_loopZero2inB) + $ - RR - 1 :F_MLOAD(array_mul_long_len_inB), JMPZ(array_mul_long_loop2inB_last, array_mul_long_loop2inB) -array_mul_long_prep_trim_in: - $ => C :MLOAD(array_mul_long_len_out) - C - 1 => E +array_mul_long_loop2inB_last: + ; costs [steps: 13, binary: 1, arith: 1] -array_mul_long_trim_in: - $ => A :MLOAD(array_mul_long_out + E) - A :MSTORE(array_trim_in + E) - E - 1 => E :JMPN(array_mul_long_trim, array_mul_long_trim_in) + ; The result will be stored as D·base + C -array_mul_long_trim: - :CALL(array_trim) + RCX => E + ; a[i]·b[lenB] + out[i+lenB], where a[i],b[lenB],out[i+lenB] ∈ [0,base-1]: This number cannot be GT (base - 1)·base, two chunks + $ => A :MLOAD(array_mul_long_inA + E) + $ => B :MLOAD(array_mul_long_inB + RR) + RCX + RR => E + $ => C :MLOAD(array_mul_long_out + E) + $${var _arrayLongMul_AB = A*B + C} + ${_arrayLongMul_AB >> 256} => D + ${_arrayLongMul_AB} => C :ARITH - %MAX_CNT_STEPS - STEP - 3 :JMPN(outOfCountersStep) + $ => A :MLOAD(array_mul_long_out_chunk_2), JMPZ(__array_mul_long_c2isZ_continue2) ; out_chunk_2 ∈ [0,1] + ;----------------- + D => B + $ => D :ADD ; the number is of two chunks, no carry can be generated here + __array_mul_long_c2isZ_continue2: + ;----------------- - C :MSTORE(array_mul_long_len_out) + ; NOTE: It cannot happen that a[i]·b[lenB] + out[i+lenB] produces carry and out_chunk_2 is 1. + + ; out[i+lenB] = product - carry·B + C :MSTORE(array_mul_long_out + E) + + ; out[i+lenB+1] = carry, where carry ∈ [0,base-1] + E + 1 => E + + ; D = carry, E = last_index_out + + ; In the exceptional case where we reached the allowed limit, we proceed to the carry check + E - %ARRAY_MAX_LEN_DOUBLED :JMPZ(array_mul_long_check_carry) + + D :MSTORE(array_mul_long_out + E), JMP(array_mul_long_inA_index_check) + +array_mul_long_check_carry: + ; D = carry, E = last_index_out + D => A + 0 => B + $ :EQ, JMPC(array_mul_long_trim) + + ; out[E] != 0, then len(out) = E + 1 + E - %ARRAY_MAX_LEN_DOUBLED :JMPZ(failAssert) + + E + 1 :MSTORE(array_mul_long_len_out), JMP(array_mul_long_end) + +array_mul_long_trim: + ; out[E] = 0, then len(out) = E + E :MSTORE(array_mul_long_len_out) array_mul_long_end: - $ => RR :MLOAD(array_mul_long_RR) - :RETURN \ No newline at end of file + $ => RR :MLOAD(array_mul_long_RR), RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_mul_short.zkasm b/main/modexp/array_lib/array_mul_short.zkasm index d850064c..5c9f8236 100644 --- a/main/modexp/array_lib/array_mul_short.zkasm +++ b/main/modexp/array_lib/array_mul_short.zkasm @@ -11,26 +11,16 @@ ;; · out = inA·inB, with len(out) <= C + 1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; function array_mul_short(a: bigint[], b: bigint, base: bigint): bigint[] { -; const alen = a.length; -; const len = alen; -; const result = new Array(len).fill(0n); -; let product: bigint; -; let carry = 0n; -; let i; -; for (i = 0; i < alen; i++) { -; product = a[i] * b + carry; -; carry = product / base; -; out[i] = product - carry * base; -; } - -; if (carry > 0n) { -; result.push(carry); -; } - -; trim(result); -; return result; +; code +; -------------------------- +; first_iteration <-- a[0]·b +; while(loop_index_check) { <-- While 0 < i < len(a) +; loop2inA <-- Compute a[i]·b + carry ; } +; 1] check_carry <-- If there is a carry, append it to the result +; 2] trim <-- Otherwise, trim the result +; end +; -------------------------- VAR GLOBAL array_mul_short_inA[%ARRAY_MAX_LEN] VAR GLOBAL array_mul_short_inB @@ -38,90 +28,62 @@ VAR GLOBAL array_mul_short_out[%ARRAY_MAX_LEN_PLUS_ONE] VAR GLOBAL array_mul_short_len_inA VAR GLOBAL array_mul_short_len_out -VAR GLOBAL array_mul_short_carry - VAR GLOBAL array_mul_short_RR array_mul_short: - %MAX_CNT_BINARY - CNT_BINARY - 2*C :JMPN(outOfCountersBinary) - %MAX_CNT_ARITH - CNT_ARITH - C :JMPN(outOfCountersArith) - %MAX_CNT_STEPS - STEP - 6 - 2*C-2 - 18*C - 6 :JMPN(outOfCountersStep) + %MAX_CNT_ARITH - CNT_ARITH - 1 - %ARRAY_MAX_LEN_MINUS_ONE :JMPN(outOfCountersArith) + %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 11 - 8*%ARRAY_MAX_LEN_MINUS_ONE - 7 :JMPN(outOfCountersStep) RR :MSTORE(array_mul_short_RR) C :MSTORE(array_mul_short_len_inA) - C + 1 :MSTORE(array_mul_short_len_out) - - C => E ; auxiliar index - 0 => RCX ; index in loops - 0 :MSTORE(array_mul_short_carry) - -array_mul_short_clean_out: - 0 :MSTORE(array_mul_short_out + E) - E - 1 => E :JMPN(array_mul_short_loopZero2inA, array_mul_short_clean_out) -array_mul_short_loopZero2inA: +array_mul_short_first_iteration: ; The result will be stored as D·base + C - RCX => E - ; 1] a[i] * b, where a[i],b ∈ [0,base-1]: This number cannot be GT (base - 2)·base + 1, two chunks - $ => A :MLOAD(array_mul_short_inA + E) + ; 1] a[0] * b, where a[0],b ∈ [0,base-1]: This number cannot be GT (base - 1)·base, two chunks + $ => A :MLOAD(array_mul_short_inA) $ => B :MLOAD(array_mul_short_inB) 0 => C $${var _arrayShortMul_AB = A*B} - ${_arrayShortMul_AB >> 256} => D - ${_arrayShortMul_AB} => E :ARITH - - ; 2] product = a[i] * b + carry, where carry ∈ [0,base-1]: This number cannot be GT (base - 1)·base, two chunks - E => A - $ => B :MLOAD(array_mul_short_carry) - $ => C :ADD, JMPNC(__array_mul_short_no_carry_continue) - ;----------------- - ; Since here D ∈ [0, base - 2], there cannot be carry in the following addition - D => A - 1 => B - $ => D :ADD - ;----------------- - __array_mul_short_no_carry_continue: + ${_arrayShortMul_AB >> 256} => D ; this is used as the next carry + ${_arrayShortMul_AB} => C :ARITH - ; carry = product / base - D :MSTORE(array_mul_short_carry) + ; out[0] = product - carry·base + C :MSTORE(array_mul_short_out) + + 1 => E + +array_mul_short_loop_index_check: + $ - E :F_MLOAD(array_mul_short_len_inA), JMPZ(array_mul_short_check_carry) + +array_mul_short_loop2inA: + ; The result will be stored as D·base + C + + ; 1] a[i] * b + carry, where a[i],b,carry ∈ [0,base-1]: This number cannot be GT (base - 1)·base, two chunks + $ => A :MLOAD(array_mul_short_inA + E) + D => C + $${var _arrayShortMul_AB = A*B + C} + ${_arrayShortMul_AB >> 256} => D ; this is used as the next carr + ${_arrayShortMul_AB} => C :ARITH ; out[i] = product - carry·base - RCX => E C :MSTORE(array_mul_short_out + E) - RCX + 1 => RCX - $ => B :MLOAD(array_mul_short_len_inA) - B - RCX :JMPZ(array_mul_short_carry_check, array_mul_short_loopZero2inA) + E + 1 => E :JMP(array_mul_short_loop_index_check) ; If the last carry > 0, we need to insert it to the output -array_mul_short_carry_check: - $ => A :MLOAD(array_mul_short_carry) +array_mul_short_check_carry: + D => A 0 => B - $ :EQ, JMPC(array_mul_short_prep_trim_in) - - RCX => E - A :MSTORE(array_mul_short_out + E) + $ :EQ, JMPC(array_mul_short_trim) -array_mul_short_prep_trim_in: - $ => C :MLOAD(array_mul_short_len_out) - C - 1 => E - - %MAX_CNT_STEPS - STEP - 3*C - 1 :JMPN(outOfCountersStep) - -array_mul_short_trim_in: - $ => A :MLOAD(array_mul_short_out + E) - A :MSTORE(array_trim_in + E) - E - 1 => E :JMPZ(array_mul_short_trim, array_mul_short_trim_in) + D :MSTORE(array_mul_short_out + E) + E + 1 :MSTORE(array_mul_short_len_out), JMP(array_mul_short_end) array_mul_short_trim: - :CALL(array_trim) - - %MAX_CNT_STEPS - STEP - 3 :JMPN(outOfCountersStep) - - C :MSTORE(array_mul_short_len_out) + E :MSTORE(array_mul_short_len_out) array_mul_short_end: - $ => RR :MLOAD(array_mul_short_RR) - :RETURN \ No newline at end of file + $ => RR :MLOAD(array_mul_short_RR), RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_mul_two.zkasm b/main/modexp/array_lib/array_mul_two.zkasm new file mode 100644 index 00000000..a5bb8b1d --- /dev/null +++ b/main/modexp/array_lib/array_mul_two.zkasm @@ -0,0 +1,102 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; POST: out is trimmed +;; +;; array_mul_two: +;; input: +;; · C ∈ [1, 64], the len of in +;; · in ∈ [0, 2²⁵⁶ - 1]^C, the input array +;; +;; output: +;; · out = 2·in = in + in, with len(out) <= C + 1 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; WARNING: This function is tailored for checking that a = q·b + r in the array_div_two function. +;; In can be used for other purposes except for the worst case, i.e. when len(inA) == %ARRAY_MAX_LEN. +;; Specifically, there is an implicit assumption that the output len of this function cannot be +;; greater than %ARRAY_MAX_LEN, and do not allow to generate the proof in such case. + +; code +; -------------------------- +; first_iteration <-- a[0] + a[0] +; while(loop_index_check) { <-- While 0 < i < len(a) +; loop2in <-- Compute a[i] + a[i] + carry +; } +; 1] check_carry <-- If there is a carry, append it to the result +; 2] trim <-- Otherwise, trim the result +; end +; -------------------------- + +VAR GLOBAL array_mul_two_in[%ARRAY_MAX_LEN] +VAR GLOBAL array_mul_two_out[%ARRAY_MAX_LEN] ; This cannot be bigger because we use it for division checking + +VAR GLOBAL array_mul_two_len_in +VAR GLOBAL array_mul_two_len_out + +VAR GLOBAL array_mul_two_carry + +VAR GLOBAL array_mul_two_RR + +array_mul_two: + %MAX_CNT_BINARY - CNT_BINARY - 1 - 2*%ARRAY_MAX_LEN_MINUS_ONE :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 9 - 11*%ARRAY_MAX_LEN_MINUS_ONE - 7 :JMPN(outOfCountersStep) + + RR :MSTORE(array_mul_two_RR) + + C :MSTORE(array_mul_two_len_in) + +array_mul_two_first_iteration: + ; a[0] + a[0], where a[0] ∈ [0,base-1]: This number cannot be GT base + (base - 2), two chunks + $ => A,B :MLOAD(array_mul_two_in) + $ :ADD, MSTORE(array_mul_two_out), JMPNC(__array_mul_two_continue_1) + ;----------------- + 1 => D :MSTORE(array_mul_two_carry), JMP(__array_mul_two_continue_2) + __array_mul_two_continue_1: + 0 => D :MSTORE(array_mul_two_carry) + __array_mul_two_continue_2: + ;----------------- + + 1 => E + +array_mul_two_loop_index_check: + $ - E :F_MLOAD(array_mul_two_len_in), JMPZ(array_mul_two_check_carry) + +array_mul_two_loop2in: + ; a[i] + a[i], where a[i] ∈ [0,base-1]: This number cannot be GT base + (base - 2), two chunks + $ => A,B :MLOAD(array_mul_two_in + E) + $ => B :ADD, JMPNC(__array_mul_two_continue_3) + ;----------------- + 1 => D :JMP(__array_mul_two_continue_4) + __array_mul_two_continue_3: + 0 => D + __array_mul_two_continue_4: + ;----------------- + + ; sum = (a[i] + a[i]) + carry, where carry ∈ [0,1]: This number cannot be GT base + (base - 1), two chunks + $ => A :MLOAD(array_mul_two_carry) + $ :ADD, MSTORE(array_mul_two_out + E), JMPNC(__array_mul_two_continue_5) + ;----------------- + 1 => D + __array_mul_two_continue_5: + ;----------------- + + ; NOTE: It cannot happen that a[i] + a[i] produces carry and (a[i] + a[i]) + carry as well at the same time + + D :MSTORE(array_mul_two_carry) + + E + 1 => E :JMP(array_mul_two_loop_index_check) + +array_mul_two_check_carry: + D :JMPZ(array_mul_two_trim) + + ; Carry path + E - %ARRAY_MAX_LEN :JMPZ(failAssert) + + ; In this case, the carry = 1 and we should append it to the result + 1 :MSTORE(array_mul_two_out + E) + E + 1 :MSTORE(array_mul_two_len_out), JMP(array_mul_two_end) + +array_mul_two_trim: + E :MSTORE(array_mul_two_len_out) + +array_mul_two_end: + $ => RR :MLOAD(array_mul_two_RR), RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_square.zkasm b/main/modexp/array_lib/array_square.zkasm index e42ed6a5..1aea892d 100644 --- a/main/modexp/array_lib/array_square.zkasm +++ b/main/modexp/array_lib/array_square.zkasm @@ -10,27 +10,25 @@ ;; · out = in², with len(out) <= 2·C ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; function array_square(a: bigint[], base: bigint): bigint[] { -; let len = a.length; -; let out = new Array(2*len).fill(0n); -; let product: bigint; -; let carry: bigint; -; for (let i = 0; i < len; i++) { -; carry = 0n - a[i] * a[i]; -; for (var j = i; j < len; j++) { -; product = 2n * (a[i] * a[j]) + out[i+j] + carry; -; carry = product / base; - -; out[i+j] = product - carry * base; -; } -; out[i + len] = carry; -; } -; trim(out); -; return out; -; } - ; Matrix visualization: https://hackmd.io/C9KQPGoaSICStIQQFweBlw?view +; code +; -------------------------- +; first_iteration_first_row <-- Compute a[0]·b[0] +; do { +; finish_first_row <-- Compute a[0]·b[j] + out[j] +; } while(inB_index_check) <-- While 0 < j < len(b) +; while(inA_index_check) { <-- While 0 < i < len(a) +; while (inB_index_check) { <-- While 0 <= j < len(b) - 1 +; loop2inB <-- Compute a[i]·b[j] + out[i+j] +; } +; loop2inB_last <-- Compute a[i]·b[len(b)-1] + out[i+len(b)-1] +; } +; 1] check_carry <-- If there is a carry, append it to the result +; 2] trim <-- Otherwise, trim the result +; end +; -------------------------- + VAR GLOBAL array_square_in[%ARRAY_MAX_LEN] VAR GLOBAL array_square_out[%ARRAY_MAX_LEN_DOUBLED] VAR GLOBAL array_square_len_in @@ -38,7 +36,6 @@ VAR GLOBAL array_square_len_out VAR GLOBAL array_square_carry_chunk_1 VAR GLOBAL array_square_carry_chunk_2 -VAR GLOBAL array_square_carry_sign ; 0 if negative, 1 if positive VAR GLOBAL array_square_chunk_3 VAR GLOBAL array_square_aiaj_chunk_2 VAR GLOBAL array_square_out_chunk_2 @@ -46,18 +43,12 @@ VAR GLOBAL array_square_out_chunk_2 VAR GLOBAL array_square_RR array_square: - %MAX_CNT_ARITH - CNT_ARITH - 1 :JMPN(outOfCountersArith) - %MAX_CNT_STEPS - STEP - 7 :JMPN(outOfCountersStep) - - C => A,B - 0 => C,D - ${A*A} => E :ARITH - A => C - ; E holds C*C - - %MAX_CNT_BINARY - CNT_BINARY - 9*E :JMPN(outOfCountersBinary) - %MAX_CNT_ARITH - CNT_ARITH - 1 - 2*E :JMPN(outOfCountersArith) - %MAX_CNT_STEPS - STEP - 5 - 2*C - 68*E - 2 :JMPN(outOfCountersStep) + ; costs: [steps: 6, binary: 0, arith: 0] + [steps: 9, binary: 0, arith: 1] + (len(in) - 1)*[steps: 35, binary: 6, arith: 1] <--- Init and first row + ; + (len(in) - 1)*([steps: 7, binary: 0, arith: 0] + [steps: 6, binary: 0, arith: 1] + [steps: 29, binary: 3, arith: 1] + (len(in) - 1)*[steps: 51, binary: 9, arith: 1]) <--- Rest of the rows + ; [steps: 8, binary: 1, arith: 0] <--- Ending + %MAX_CNT_ARITH - CNT_ARITH - 1 - %ARRAY_MAX_LEN_MINUS_ONE - 2*%ARRAY_MAX_LEN_MINUS_ONE - %ARRAY_MAX_LEN_SQ :JMPN(outOfCountersArith) + %MAX_CNT_BINARY - CNT_BINARY - 6*%ARRAY_MAX_LEN_MINUS_ONE - 3*%ARRAY_MAX_LEN_MINUS_ONE - 9*%ARRAY_MAX_LEN_SQ - 1 :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 15 - 35*%ARRAY_MAX_LEN_MINUS_ONE - 42*%ARRAY_MAX_LEN_MINUS_ONE - 51*%ARRAY_MAX_LEN_SQ - 8 :JMPN(outOfCountersStep) RR :MSTORE(array_square_RR) @@ -67,35 +58,12 @@ array_square: 0 :MSTORE(array_square_chunk_3) ; initialize the third chunk 0 :MSTORE(array_square_out_chunk_2) ; initialize the second chunk of out - 0 => RCX,RR ; first and second indexes in loops - C + C - 1 => E -array_square_clean_out: - 0 :MSTORE(array_square_out + E) - E - 1 => E :JMPN(array_square_ai_times_ai, array_square_clean_out) + 0 => RCX,RR :JMP(array_square_first_iteration_first_row) ; first and second indexes in loops ; Begin of branching -; We perform subtraction of a value with three chunks -; Therefore, the subtraction can produce carry until the highest chunk -; e.g. (base² + y) - (y+1) = 0 -array_square_is_negative_1: - $ => C :SUB, JMPNC(__return_array_square_is_negative_1) - ;----------------- - D => A - 1 => B - $ => D :SUB, JMPNC(__return_array_square_is_negative_1) - 0 :MSTORE(array_square_chunk_3) - :JMP(__return_array_square_is_negative_1) - ;----------------- - - -array_square_is_negative_2: - $ => D :SUB, JMPNC(__return_array_square_is_negative_2) - ;----------------- - 0 :MSTORE(array_square_chunk_3) - :JMP(__return_array_square_is_negative_2) - ;----------------- - array_square_loop_index_check: + ; costs [steps: 7, binary: 0, arith: 0] + ; out[i + len] = carry $ => A :MLOAD(array_square_carry_chunk_1) RCX + B => E @@ -106,22 +74,175 @@ array_square_loop_index_check: ; update indices RCX + 1 => RCX,RR,A - B - A :JMPZ(array_square_prep_trim_in) ; This subtraction is safe + B - A :JMPZ(array_square_prep_trim, array_square_ai_times_ai) ; End of branching +; Begin of first row +array_square_first_iteration_first_row: + ; costs [steps: 9, binary: 0, arith: 1] + + ; The result will be stored as D·base + C + + ; 1] a[0]·a[0] + $ => A,B :MLOAD(array_square_in) + 0 => C + $${var _arraySquare_a0a0 = A*B} + ${_arraySquare_a0a0 >> 256} => D + ${_arraySquare_a0a0} => C :ARITH + + ; carry = product / base + D :MSTORE(array_square_carry_chunk_1) + + ; out[0] = product - carry·base + C :MSTORE(array_square_out) + + ; update the index + 1 => RR + $ => B :MLOAD(array_square_len_in) + B - RR :JMPZ(array_square_loop_index_check) + +array_square_finish_first_row: + ; costs [steps: 35, binary: 6, arith: 1] + + ; The result will be stored as D·base + C + + ; 1] a[0]·a[j] + $ => A :MLOAD(array_square_in) + $ => B :MLOAD(array_square_in + RR) + 0 => C + $${var _arraySquare_a0a0 = A*B} + ${_arraySquare_a0a0 >> 256} => D + ${_arraySquare_a0a0} => C :ARITH + D :MSTORE(array_square_aiaj_chunk_2) + + ; 2] 2·a[0]·a[j] + C => A,B + $ => C :ADD, JMPNC(__array_square_no_carry_continue_1) + ;----------------- + ; Since here D ∈ [0, base - 2], there cannot be carry in the following addition + D => A + 1 => B + $ => D :ADD + ;----------------- + __array_square_no_carry_continue_1: + + $ => A :MLOAD(array_square_aiaj_chunk_2) + D => B + $ => D :ADD, JMPNC(__array_square_no_carry_continue_2) + ;----------------- + 1 :MSTORE(array_square_chunk_3) + ;----------------- + __array_square_no_carry_continue_2: + + ; 3] 2·a[0]·a[j] + carry + C => A + $ => B :MLOAD(array_square_carry_chunk_1) + $ => C :ADD, JMPNC(__array_square_no_carry_continue_3) + ;----------------- + ; Since here D ∈ [0, base - 1], there can be carry in the following addition + D => A + 1 => B + $ => D :ADD, JMPNC(__array_square_no_carry_continue_3) + 1 :MSTORE(array_square_chunk_3) + ;----------------- + __array_square_no_carry_continue_3: + + D => A + $ => B :MLOAD(array_square_carry_chunk_2) + $ => D :ADD, JMPNC(__array_square_no_carry_continue_4) + ;----------------- + 1 :MSTORE(array_square_chunk_3) + ;----------------- + __array_square_no_carry_continue_4: + + ; carry = product / base + D :MSTORE(array_square_carry_chunk_1) + $ => A :MLOAD(array_square_chunk_3) + A :MSTORE(array_square_carry_chunk_2) + + ; out[j] = product - carry·base + RR => E + C :MSTORE(array_square_out + E) + 0 :MSTORE(array_square_chunk_3) ; reset the third chunk + + ; update the index + RR + 1 => RR + $ => B :MLOAD(array_square_len_in) + B - RR :JMPZ(array_square_loop_index_check, array_square_finish_first_row) +; End of first row + array_square_ai_times_ai: + ; costs [steps: 6, binary: 0, arith: 1] + ; carry = 0 - a[i]·a[i] ; a[i]·a[i], where a[i] ∈ [0,base-1]: This number cannot be GT (base - 2)·base + 1, two chunks $ => A,B :MLOAD(array_square_in + RR) 0 => C $${var _arraySquare_aiai = A*B} ${_arraySquare_aiai >> 256} => D - ${_arraySquare_aiai} => E :ARITH - E :MSTORE(array_square_carry_chunk_1) + ${_arraySquare_aiai} => C :ARITH + C :MSTORE(array_square_carry_chunk_1) D :MSTORE(array_square_carry_chunk_2) - 0 :MSTORE(array_square_carry_sign) + +array_square_first_iteration_loopRR2len: + ; costs [steps: 29, binary: 3, arith: 1] + + ; product = a[i]·a[i] + out[2i] (in the worst case, this is a 3-chunk number) + ; The result will be stored as array_square_chunk_3·base² + D·base + C + + ; 1] a[i]·a[i] + $ => A,B :MLOAD(array_square_in + RR) + 0 => C + $${var _arraySquare_ai = A*B} + ${_arraySquare_ai >> 256} => D + ${_arraySquare_ai} => C :ARITH + D :MSTORE(array_square_aiaj_chunk_2) + + ; 3] a[i]·a[i] + out[2i] + 2*RR => E + $ => A :MLOAD(array_square_out + E) + C => B + $ => C :ADD, JMPNC(__array_square_no_carry_continue_5) + ;----------------- + ; Since here D ∈ [0, base - 1], there can be carry in the following addition + D => A + 1 => B + $ => D :ADD, JMPNC(__array_square_no_carry_continue_5) + 1 :MSTORE(array_square_chunk_3) + ;----------------- + __array_square_no_carry_continue_5: + + ; The output can have two chunks only if i == len-1, so we must jump the following block of code if i < len-1 + RR + 1 => A + $ => B :MLOAD(array_square_len_in) + B - A :JMPNZ(__array_square_no_carry_continue_6) + ; Add the second output chunk + $ => A :MLOAD(array_square_out_chunk_2) + D => B + $ => D :ADD, JMPNC(__array_square_no_carry_continue_6) + ;----------------- + 1 :MSTORE(array_square_chunk_3) + ;----------------- + __array_square_no_carry_continue_6: + + ; carry = product / base + D :MSTORE(array_square_carry_chunk_1) + $ => A :MLOAD(array_square_chunk_3) + A :MSTORE(array_square_carry_chunk_2) + + ; out[i+j] = product - carry·base + RCX + RR => E + C :MSTORE(array_square_out + E) + 0 :MSTORE(array_square_chunk_3) ; reset the third chunk + + ; update the index + RR + 1 => RR + $ => B :MLOAD(array_square_len_in) + B - RR :JMPZ(array_square_loop_index_check) array_square_loopRR2len: + ; costs [steps: 51, binary: 9, arith: 1] + ; product = 2·(a[i]·a[j]) + out[i+j] + carry (in the worst case, this is a 3-chunk number) ; The result will be stored as array_square_chunk_3·base² + D·base + C @@ -132,26 +253,27 @@ array_square_loopRR2len: 0 => C $${var _arraySquare_aiaj = A*B} ${_arraySquare_aiaj >> 256} => D - ${_arraySquare_aiaj} => E :ARITH + ${_arraySquare_aiaj} => C :ARITH D :MSTORE(array_square_aiaj_chunk_2) ; 2] 2·a[i]·a[j]: This number cannot be GT base² + (base - 4)·base + 2, three chunks - E => A,B - $ => C :ADD, JMPNC(__array_square_no_carry_continue_1) + C => A,B + $ => C :ADD, JMPNC(__array_square_no_carry_continue_7) ;----------------- ; Since here D ∈ [0, base - 2], there cannot be carry in the following addition D => A 1 => B $ => D :ADD ;----------------- - __array_square_no_carry_continue_1: + __array_square_no_carry_continue_7: + $ => A :MLOAD(array_square_aiaj_chunk_2) D => B - $ => D :ADD, JMPNC(__array_square_no_carry_continue_2) + $ => D :ADD, JMPNC(__array_square_no_carry_continue_8) ;----------------- 1 :MSTORE(array_square_chunk_3) ;----------------- - __array_square_no_carry_continue_2: + __array_square_no_carry_continue_8: ; 3] 2·a[i]·a[j] + out[i+j]: ; a) j < len-1: This number cannot be GT base² + (base - 3)·base + 1, as out[i+j] < base @@ -160,87 +282,81 @@ array_square_loopRR2len: RCX + RR => E $ => A :MLOAD(array_square_out + E) C => B - $ => C :ADD, JMPNC(__array_square_no_carry_continue_3) + $ => C :ADD, JMPNC(__array_square_no_carry_continue_9) ;----------------- ; Since here D ∈ [0, base - 1], there can be carry in the following addition D => A 1 => B - $ => D :ADD, JMPNC(__array_square_no_carry_continue_3) + $ => D :ADD, JMPNC(__array_square_no_carry_continue_9) 1 :MSTORE(array_square_chunk_3) ;----------------- - __array_square_no_carry_continue_3: + __array_square_no_carry_continue_9: ; The output can have two chunks only if j == len-1, so we must jump the following block of code if j < len-1 RR + 1 => A $ => B :MLOAD(array_square_len_in) - B - A :JMPNZ(__array_square_no_carry_continue_4) ; This subtraction is safe + B - A :JMPNZ(__array_square_no_carry_continue_10) ; Add the second output chunk $ => A :MLOAD(array_square_out_chunk_2) D => B - $ => D :ADD, JMPNC(__array_square_no_carry_continue_4) + $ => D :ADD, JMPNC(__array_square_no_carry_continue_10) ;----------------- 1 :MSTORE(array_square_chunk_3) ;----------------- - __array_square_no_carry_continue_4: + __array_square_no_carry_continue_10: ; 4] product = 2·a[i]·a[j] + out[i+j] + carry: This number cannot be GT base² + (base - 2)·base, three chunks C => A $ => B :MLOAD(array_square_carry_chunk_1) - $ :MLOAD(array_square_carry_sign), JMPZ(array_square_is_negative_1) - $ => C :ADD, JMPNC(__array_square_no_carry_continue_5) + $ => C :ADD, JMPNC(__array_square_no_carry_continue_11) ;----------------- ; Since here D ∈ [0, base - 1], there can be carry in the following addition D => A 1 => B - $ => D :ADD, JMPNC(__array_square_no_carry_continue_5) + $ => D :ADD, JMPNC(__array_square_no_carry_continue_11) 1 :MSTORE(array_square_chunk_3) ;----------------- - __array_square_no_carry_continue_5: - __return_array_square_is_negative_1: + __array_square_no_carry_continue_11: D => A $ => B :MLOAD(array_square_carry_chunk_2) - $ :MLOAD(array_square_carry_sign), JMPZ(array_square_is_negative_2) - $ => D :ADD, JMPNC(__array_square_no_carry_continue_6) + $ => D :ADD, JMPNC(__array_square_no_carry_continue_12) ;----------------- 1 :MSTORE(array_square_chunk_3) ;----------------- - __array_square_no_carry_continue_6: - __return_array_square_is_negative_2: + __array_square_no_carry_continue_12: ; carry = product / base; This number cannot be greater than base + (base - 2) D :MSTORE(array_square_carry_chunk_1) $ => A :MLOAD(array_square_chunk_3) A :MSTORE(array_square_carry_chunk_2) - 1 :MSTORE(array_square_carry_sign) ; out[i+j] = product - carry·base; RCX + RR => E C :MSTORE(array_square_out + E) 0 :MSTORE(array_square_chunk_3) ; reset the third chunk + ; update the index RR + 1 => RR $ => B :MLOAD(array_square_len_in) - B - RR :JMPZ(array_square_loop_index_check, array_square_loopRR2len) ; This subtraction is safe - -array_square_prep_trim_in: - $ => C :MLOAD(array_square_len_out) + B - RR :JMPZ(array_square_loop_index_check, array_square_loopRR2len) - %MAX_CNT_STEPS - STEP - 1 - 3*C - 1 :JMPN(outOfCountersStep) +array_square_prep_trim: + ; costs [steps: 8, binary: 1, arith: 0] + $ => C :MLOAD(array_square_len_out) C - 1 => E -array_square_trim_in: $ => A :MLOAD(array_square_out + E) - A :MSTORE(array_trim_in + E) - E - 1 => E :JMPN(array_square_trim, array_square_trim_in) -array_square_trim: - :CALL(array_trim) + ; Check whether the last chunk is zero + ${A == 0} :JMPNZ(array_square_trim) - %MAX_CNT_STEPS - STEP - 3 :JMPN(outOfCountersStep) + 0 => B + 0 :EQ, JMP(array_square_end) - C :MSTORE(array_square_len_out) +array_square_trim: + 0 :ASSERT + C - 1 :MSTORE(array_square_len_out) array_square_end: - $ => RR :MLOAD(array_square_RR) - :RETURN \ No newline at end of file + $ => RR :MLOAD(array_square_RR), RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/unused/array_add.zkasm b/main/modexp/array_lib/unused/array_add.zkasm deleted file mode 100644 index 1ef8df4e..00000000 --- a/main/modexp/array_lib/unused/array_add.zkasm +++ /dev/null @@ -1,100 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; array_add: -;; in: -;; · C ∈ [1, 32], the len of inA -;; · D ∈ [1, 32], the len of inB -;; · inA ∈ [0, 2²⁵⁶ - 1]^C, the first input array -;; · inB ∈ [0, 2²⁵⁶ - 1]^D, the second input array -;; -;; output: -;; · out = inA + inB, with len(out) <= C + 1 -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -VAR GLOBAL array_add_inA[%ARRAY_MAX_LEN] -VAR GLOBAL array_add_inB[%ARRAY_MAX_LEN] -VAR GLOBAL array_add_out[%ARRAY_MAX_LEN_PLUS_ONE] -VAR GLOBAL array_add_len_inA -VAR GLOBAL array_add_len_inB -VAR GLOBAL array_add_len_out - -VAR GLOBAL array_add_RR - -array_add: - RR :MSTORE(array_add_RR) - C :MSTORE(array_add_len_inA) - D :MSTORE(array_add_len_inB) - 0 => RR,E - - D => A - C => B - $ :LT, JMPC(array_add_inA_to_add_AGTB) - -; BGTA -array_add_prep_BGTA: - C => A - D => C - A => D - -array_add_inA_to_add_BGTA: - $ => A :MLOAD(array_add_inB + RR) - A :MSTORE(array_add_AGTB_inA + RR) - RR + 1 => RR - RR => A - D => B - $ :EQ, JMPC(array_add_inB_to_add_BGTA, array_add_inA_to_add_BGTA) - -array_add_inB_to_add_BGTA: - $ => A :MLOAD(array_add_inA + E) - A :MSTORE(array_add_AGTB_inB + E) - E + 1 => E - E => A - C => B - $ :EQ, JMPC(array_add_compute_BGTA, array_add_inB_to_add_BGTA) - -array_add_compute_BGTA: - :CALL(array_add_AGTB) - $ => C :MLOAD(array_add_AGTB_len_out) - C :MSTORE(array_add_len_out) - 0 => RR -array_add_assign_BGTA: - $ => A :MLOAD(array_add_AGTB_out + RR) - A :MSTORE(array_add_out + RR) - RR + 1 => RR - RR => A - C => B - $ :EQ, JMPC(array_add_end, array_add_assign_BGTA) - -; AGTB -array_add_inA_to_add_AGTB: - $ => A :MLOAD(array_add_inA + RR) - A :MSTORE(array_add_AGTB_inA + RR) - RR + 1 => RR - RR => A - C => B - $ :EQ, JMPC(array_add_inB_to_add_AGTB, array_add_inA_to_add_AGTB) - -array_add_inB_to_add_AGTB: - $ => A :MLOAD(array_add_inB + E) - A :MSTORE(array_add_AGTB_inB + E) - E + 1 => E - E => A - D => B - $ :EQ, JMPC(array_add_compute_AGTB, array_add_inB_to_add_AGTB) - -array_add_compute_AGTB: - :CALL(array_add_AGTB) - $ => C :MLOAD(array_add_AGTB_len_out) - C :MSTORE(array_add_len_out) - 0 => RR -array_add_assign_AGTB: - $ => A :MLOAD(array_add_AGTB_out + RR) - A :MSTORE(array_add_out + RR) - RR + 1 => RR - RR => A - C => B - $ :EQ, JMPC(array_add_end, array_add_assign_AGTB) - -array_add_end: - $ => RR :MLOAD(array_add_RR) - :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/unused/array_is_odd.zkasm b/main/modexp/array_lib/unused/array_is_odd.zkasm deleted file mode 100644 index d28a60be..00000000 --- a/main/modexp/array_lib/unused/array_is_odd.zkasm +++ /dev/null @@ -1,23 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; PRE: The input arrays have been trimmed. -;; -;; array_is_odd: -;; in: -;; · in ∈ [0, 2²⁵⁶ - 1]*, the input array -;; output: -;; · 1, if in is an odd number -;; · 0, otherwise -;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; NOTE: The base is 2^256, so I only need to check if the first chunk is odd to conclude that the whole number is odd. - -VAR GLOBAL array_is_odd_in -VAR GLOBAL array_is_odd_result - -array_is_odd: - $ => A :MLOAD(array_is_odd_in) - 1 => B - $ => A :AND - A :MSTORE(array_is_odd_result) - :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/unused/array_is_one.zkasm b/main/modexp/array_lib/unused/array_is_one.zkasm deleted file mode 100644 index 90f86d8d..00000000 --- a/main/modexp/array_lib/unused/array_is_one.zkasm +++ /dev/null @@ -1,33 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; PRE: The input arrays have been trimmed. -;; -;; array_is_one: -;; in: -;; · C ∈ [1, 32], the len of in -;; · in ∈ [0, 2²⁵⁶ - 1]^C, the input array -;; output: -;; · 1, if in = 1 -;; · 0, otherwise -;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -VAR GLOBAL array_is_one_in -VAR GLOBAL array_is_one_result - -array_is_one: - ; Is C == 1 and in == 1? - C => A - 1 => B - $ :EQ, JMPNC(__array_is_one_continue) - $ => A :MLOAD(array_is_one_in) - $ :EQ, JMPC(array_is_one_sure) - __array_is_one_continue: - - 0 :MSTORE(array_is_one_result) - :JMP(array_is_one_end) - -array_is_one_sure: - 1 :MSTORE(array_is_one_result) - -array_is_one_end: - :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/unused/array_is_zero.zkasm b/main/modexp/array_lib/unused/array_is_zero.zkasm deleted file mode 100644 index 022f310f..00000000 --- a/main/modexp/array_lib/unused/array_is_zero.zkasm +++ /dev/null @@ -1,34 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; PRE: The input arrays have been trimmed. -;; -;; array_is_zero: -;; in: -;; · C ∈ [1, 32], the len of in -;; · in ∈ [0, 2²⁵⁶ - 1]^C, the input array -;; output: -;; · 1, if in = 0 -;; · 0, otherwise -;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -VAR GLOBAL array_is_zero_in -VAR GLOBAL array_is_zero_result - -array_is_zero: - ; Is C == 1 and in == 0? - C => A - 1 => B - $ :EQ, JMPNC(__array_is_zero_continue) - 0 => B - $ => A :MLOAD(array_is_zero_in) - $ :EQ, JMPC(array_is_zero_sure) - __array_is_zero_continue: - - 0 :MSTORE(array_is_zero_result) - :JMP(array_is_zero_end) - -array_is_zero_sure: - 1 :MSTORE(array_is_zero_result) - -array_is_zero_end: - :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/unused/array_sub_AGTB.zkasm b/main/modexp/array_lib/unused/array_sub_AGTB.zkasm deleted file mode 100644 index 6f292c82..00000000 --- a/main/modexp/array_lib/unused/array_sub_AGTB.zkasm +++ /dev/null @@ -1,111 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; PRE: inA >= inB -;; -;; array_sub_AGTB: -;; in: -;; · C ∈ [1, 32], the len of inA -;; · D ∈ [1, 32], the len of inB -;; · inA ∈ [0, 2²⁵⁶ - 1]^C, the first input array -;; · inB ∈ [0, 2²⁵⁶ - 1]^D, the second input array -;; -;; output: -;; · out = inA - inB, with len(out) <= C -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -VAR GLOBAL array_sub_AGTB_inA[%ARRAY_MAX_LEN] -VAR GLOBAL array_sub_AGTB_inB[%ARRAY_MAX_LEN] -VAR GLOBAL array_sub_AGTB_out[%ARRAY_MAX_LEN] -VAR GLOBAL array_sub_AGTB_len_inA -VAR GLOBAL array_sub_AGTB_len_inB - -VAR GLOBAL array_sub_AGTB_carry - -VAR GLOBAL array_sub_AGTB_RR - -array_sub_AGTB: - RR :MSTORE(array_sub_AGTB_RR) - C :MSTORE(array_sub_AGTB_len_inA) - D :MSTORE(array_sub_AGTB_len_inB) - - 0 => E ; index in loops - 0 :MSTORE(array_sub_AGTB_carry) - :JMP(array_sub_AGTB_loopZero2inB) - -array_sub_AGTB_add_carry: - 1 => D - :JMP(return_array_sub_AGTB_add_carry) - -array_sub_AGTB_sub_carry: - D => A - 1 => B - $ :SUB, JMPC(array_sub_AGTB_set_carry_to_1, array_sub_AGTB_set_carry_tp_0) - -array_sub_AGTB_set_carry_to_1: - 1 :MSTORE(array_sub_AGTB_carry) - :JMP(return_array_sub_AGTB_sub_carry) - -array_sub_AGTB_set_carry_tp_0: - 0 :MSTORE(array_sub_AGTB_carry) - :JMP(return_array_sub_AGTB_sub_carry) - -array_sub_AGTB_loopZero2inB: - 0 => D ; cleanup - - ; diff = a[i] - (b[i] + carry) - $ => A :MLOAD(array_sub_AGTB_inB + E) - $ => B :MLOAD(array_sub_AGTB_carry) - $ => C :ADD, JMPC(array_sub_AGTB_add_carry) - return_array_sub_AGTB_add_carry: - - $ => A :MLOAD(array_sub_AGTB_inA + E) - C => B - $ => C :SUB, JMPC(array_sub_AGTB_sub_carry) - 0 :MSTORE(array_sub_AGTB_carry) - return_array_sub_AGTB_sub_carry: - - C :MSTORE(array_sub_AGTB_out + E) - - E + 1 => E - E => A - $ => B :MLOAD(array_sub_AGTB_len_inB) - $ :EQ, JMPC(array_sub_AGTB_loop_index_check1, array_sub_AGTB_loopZero2inB) - -array_sub_AGTB_loop_index_check1: - E => A - $ => B :MLOAD(array_sub_AGTB_len_inA) - $ :EQ, JMPC(array_sub_AGTB_end) - -array_sub_AGTB_loopInB2InA: - ; diff = a[i] - carry - $ => A :MLOAD(array_sub_AGTB_inA + E) - $ => B :MLOAD(array_sub_AGTB_carry) - $ => C :SUB, JMPC(array_sub_AGTB_loopInB2InA_cont) - C :MSTORE(array_sub_AGTB_out + E) - E + 1 => E - :JMP(array_sub_AGTB_loop_index_check2) - -array_sub_AGTB_loopInB2InA_cont: - C :MSTORE(array_sub_AGTB_out + E) - - E + 1 => E - E => A - $ => B :MLOAD(array_sub_AGTB_len_inA) - $ :EQ, JMPC(array_sub_AGTB_end, array_sub_AGTB_loopInB2InA) - -array_sub_AGTB_loop_index_check2: - E => A - $ => B :MLOAD(array_sub_AGTB_len_inA) - $ :EQ, JMPC(array_sub_AGTB_end) - -array_sub_AGTB_loop_final: - $ => A :MLOAD(array_sub_AGTB_inA + E) - A :MSTORE(array_sub_AGTB_out + E) - - E + 1 => E - E => A - $ => B :MLOAD(array_sub_AGTB_len_inA) - $ :EQ, JMPC(array_sub_AGTB_end, array_sub_AGTB_loop_final) - -array_sub_AGTB_end: - $ => RR :MLOAD(array_sub_AGTB_RR) - :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/unused/array_unshift.zkasm b/main/modexp/array_lib/unused/array_unshift.zkasm deleted file mode 100644 index a42033c2..00000000 --- a/main/modexp/array_lib/unused/array_unshift.zkasm +++ /dev/null @@ -1,37 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; array_unshift: -;; in: -;; · C ∈ [1, 32], the len of in = [in[0], in[1], ..., in[C - 1]] -;; · in ∈ [0, 2²⁵⁶ - 1]^C, the input array -;; · D ∈ [0, 2²⁵⁶ - 1], the element to unshift -;; -;; output: -;; · in = [D, in[0], in[1], ..., in[C - 1]] -;; · len = C + 1 -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -VAR GLOBAL array_unshift_in[%ARRAY_MAX_LEN] -VAR GLOBAL array_unshift_len - -VAR GLOBAL array_unshift_RR - -array_unshift: - RR :MSTORE(array_unshift_RR) - - C + 1 :MSTORE(array_unshift_len) - - C :JMPZ(array_unshift_end) - -array_unshift_loop: - C - 1 => E - $ => A :MLOAD(array_unshift_in + E) - C => E - A :MSTORE(array_unshift_in + E) - C - 1 => C :JMPZ(array_unshift_end) - :JMP(array_unshift_loop) - -array_unshift_end: - D :MSTORE(array_unshift_in) - $ => RR :MLOAD(array_unshift_RR) - :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/utils/array_compare.zkasm b/main/modexp/array_lib/utils/array_compare.zkasm deleted file mode 100644 index 39388f56..00000000 --- a/main/modexp/array_lib/utils/array_compare.zkasm +++ /dev/null @@ -1,82 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; PRE: The input arrays have been trimmed. -;; -;; array_compare: -;; in: -;; · C ∈ [1, 32], the len of inA -;; · D ∈ [1, 32], the len of inB -;; · inA ∈ [0, 2²⁵⁶ - 1]^C, the first input array -;; · inB ∈ [0, 2²⁵⁶ - 1]^D, the second input array -;; -;; output: -;; · 2, if inA > inB -;; · 1, if inA = inB -;; · 0, if inA < inB -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; function array_compare(a: bigint[], b: bigint[]): number { -; const alen = a.length; -; const blen = b.length; -; if (alen !== blen) { -; return alen >= blen ? 1 : -1; -; } -; for (let i = alen - 1; i >= 0; i--) { -; if (a[i] !== b[i]) { -; return a[i] > b[i] ? 1 : -1; -; } -; } -; return 0; -; } - -; ---------------------------------- -; Five possible paths: -; · inA > inB and lenA > lenB. -; · inA > inB and lenA = lenB. -; · inA = inB. (worst case) -; · inA < inB and lenA < lenB. -; · inA < inB and lenA = lenB. -; ---------------------------------- - -VAR GLOBAL array_compare_inA[%ARRAY_MAX_LEN] -VAR GLOBAL array_compare_inB[%ARRAY_MAX_LEN] - -VAR GLOBAL array_compare_result - -VAR GLOBAL array_compare_RR - -array_compare: - %MAX_CNT_BINARY - CNT_BINARY - 2*C :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 4 - 7*C - 4 :JMPN(outOfCountersStep) - - RR :MSTORE(array_compare_RR) - - ; Start by comparing the lengths of the arrays - C - D :JMPN(array_compare_ALTB) - D - C :JMPN(array_compare_AGTB) - - C - 1 => E -array_compare_same_len: - $ => A :MLOAD(array_compare_inA + E) - $ => B :MLOAD(array_compare_inB + E) - $ :LT, JMPC(array_compare_ALTB) - - $ => A :MLOAD(array_compare_inB + E) - $ => B :MLOAD(array_compare_inA + E) - $ :LT, JMPC(array_compare_AGTB) - - E - 1 => E :JMPN(array_compare_AEQB, array_compare_same_len) - -array_compare_AGTB: - 2 :MSTORE(array_compare_result) - :JMP(array_compare_end) - -array_compare_AEQB: - 1 :MSTORE(array_compare_result) - :JMP(array_compare_end) - -array_compare_ALTB: - 0 :MSTORE(array_compare_result) - -array_compare_end: - $ => RR :MLOAD(array_compare_RR) - :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/utils/array_trim.zkasm b/main/modexp/array_lib/utils/array_trim.zkasm deleted file mode 100644 index efb9b750..00000000 --- a/main/modexp/array_lib/utils/array_trim.zkasm +++ /dev/null @@ -1,49 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; -;; array_trim: -;; in: -;; · C ∈ [1, 3636], the len of in -;; · in ∈ [0, 2²⁵⁶ - 1]^C, the input array -;; -;; output: -;; · C, the new length of in -;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; function array_trim(a: bigint[]): void { -; let i = a.length; -; -; while (a[--i] === 0n); -; -; a.length = i + 1; -; } - -VAR GLOBAL array_trim_in[%ARRAY_MAX_LEN_DOUBLED] - -VAR GLOBAL array_trim_RR - -array_trim: - %MAX_CNT_STEPS - STEP - 5 :JMPN(outOfCountersStep) - - RR :MSTORE(array_trim_RR) - - 0 => B ; used for comparison in the whole loop - - C => E - ; scan from the last chunk to the first chunks until we find a non-zero chunk - ; in case of zero input array, we return 1 -array_trim_loop: - %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 3 :JMPN(outOfCountersStep) - - E - 1 => E :JMPZ(array_trim_end) - - $ => A :MLOAD(array_trim_in + E) - $ :EQ, JMPZ(array_trim_end, array_trim_loop) - -array_trim_end: - %MAX_CNT_STEPS - STEP - 2 :JMPN(outOfCountersStep) - - $ => RR :MLOAD(array_trim_RR) - - E + 1 => C :RETURN diff --git a/main/modexp/constants.zkasm b/main/modexp/constants.zkasm index 37c22310..89e91143 100644 --- a/main/modexp/constants.zkasm +++ b/main/modexp/constants.zkasm @@ -1,5 +1,10 @@ ; See the discussion [https://github.com/0xPolygonHermez/zkevm-rom-internal/issues/43] for more details. CONST %ARRAY_MAX_LEN = 32 -CONST %ARRAY_MAX_LEN_PLUS_ONE = 33 -CONST %ARRAY_MAX_LEN_DOUBLED = 64 -CONST %MODEXP_MAX_LEN = 32 \ No newline at end of file +CONST %ARRAY_MAX_LEN_MINUS_ONE = %ARRAY_MAX_LEN - 1 +CONST %ARRAY_MAX_LEN_PLUS_ONE = %ARRAY_MAX_LEN + 1 +CONST %ARRAY_MAX_LEN_DOUBLED = 2*%ARRAY_MAX_LEN +CONST %ARRAY_MAX_LEN_DOUBLED_MINUS_ONE = %ARRAY_MAX_LEN_DOUBLED - 1 +CONST %ARRAY_MAX_LEN_SQ = (%ARRAY_MAX_LEN - 1) * (%ARRAY_MAX_LEN - 1) +CONST %ARRAY_MAX_LEN_TIMES_DOUBLED = (%ARRAY_MAX_LEN - 1) * (%ARRAY_MAX_LEN_DOUBLED - 1) + +CONST %MODEXP_MAX_LEN = %ARRAY_MAX_LEN \ No newline at end of file diff --git a/main/modexp/modexp.zkasm b/main/modexp/modexp.zkasm index 6491c42a..74685287 100644 --- a/main/modexp/modexp.zkasm +++ b/main/modexp/modexp.zkasm @@ -17,21 +17,21 @@ ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; function modexp(b: bigint[], exp: bigint[], mod: bigint[], base: bigint): bigint[] { +;; function modexp(base: bigint[], exp: bigint[], mod: bigint[]): bigint[] { ;; if (array_is_zero(mod) || array_is_one(mod)) return [0n]; -;; if (array_is_zero(b)) return [0n]; -;; if (array_is_one(b)) return [1n]; +;; if (array_is_zero(base)) return [0n]; +;; if (array_is_one(base)) return [1n]; ;; if (array_is_zero(e)) return [1n]; ;; -;; let r = [1n]; -;; let base = array_div(b, mod, base)[1]; +;; let out = [1n]; +;; let base = array_div(base, mod)[1]; ;; while (!array_is_zero(exp)) { ;; if (array_is_zero(base)) return [0n]; ;; if (isOdd(exp)) { -;; r = array_div(array_mul(r, base, base),mod,base)[1]; +;; out = array_div(array_mul(out, base),mod)[1]; ;; } -;; exp = array_div_short(exp, 2n, base)[0]; -;; base = array_div(array_square(base, base),mod,base)[1]; +;; exp = array_div_two(exp); +;; base = array_div(array_square(base),mod)[1]; ;; } ;; return r; ;; }; @@ -62,7 +62,7 @@ VAR GLOBAL modexp_RR modexp: - %MAX_CNT_STEPS - STEP - 8 :JMPN(outOfCountersStep) + %MAX_CNT_STEPS - STEP - 7 - 3*%ARRAY_MAX_LEN - 3*%ARRAY_MAX_LEN - 1 :JMPN(outOfCountersStep) ; init and array div long RR :MSTORE(modexp_RR) @@ -76,35 +76,54 @@ modexp: $ => C :MLOAD(modexp_Blen) $ => D :MLOAD(modexp_Mlen) C - 1 => RR - D - 1 => E - - %MAX_CNT_STEPS - STEP - 3*C - 3*D - 1 :JMPN(outOfCountersStep) + D - 1 => E :JMPNZ(modexp_B_to_div_long) ; Compute B = B % M ; ------------------- -modexp_B_to_div: +; 1] Short path +modexp_B_to_div_short: + $ => A :MLOAD(modexp_B + RR) + A :MSTORE(array_div_short_inA + RR) + RR - 1 => RR :JMPN(modexp_M_to_div_short1, modexp_B_to_div_short) + +modexp_M_to_div_short1: + $ => A :MLOAD(modexp_M) + A :MSTORE(array_div_short_inB) + +modexp_div_short_B_and_M: + :CALL(array_div_short) ; inputs: [array_div_short_len_inA: C, array_div_short_inA: modexp_B, array_div_short_inB: modexp_M] + ; outputs: [array_div_short_rem] + + %MAX_CNT_STEPS - STEP - 5 :JMPN(outOfCountersStep) ; till pre_loop + + 1 :MSTORE(modexp_Blen) + $ => A :MLOAD(array_div_short_rem) + A :MSTORE(modexp_B), JMP(modexp_pre_loop) + +; 2] Long path +modexp_B_to_div_long: $ => A :MLOAD(modexp_B + RR) - A :MSTORE(array_div_inA + RR) - RR - 1 => RR :JMPN(modexp_M_to_div1, modexp_B_to_div) + A :MSTORE(array_div_long_inA + RR) + RR - 1 => RR :JMPN(modexp_M_to_div_long1, modexp_B_to_div_long) -modexp_M_to_div1: +modexp_M_to_div_long1: $ => A :MLOAD(modexp_M + E) - A :MSTORE(array_div_inB + E) - E - 1 => E :JMPN(modexp_div_B_and_M, modexp_M_to_div1) + A :MSTORE(array_div_long_inB + E) + E - 1 => E :JMPN(modexp_div_long_B_and_M, modexp_M_to_div_long1) + +modexp_div_long_B_and_M: + :CALL(array_div_long) ; inputs: [array_div_long_len_inA: C, array_div_long_len_inB: D, array_div_long_inA: modexp_B, array_div_long_inB: modexp_M] + ; outputs: [array_div_long_len_rem, array_div_long_rem] -modexp_div_B_and_M: - :CALL(array_div) + $ => C :MLOAD(array_div_long_len_rem) - %MAX_CNT_STEPS - STEP - 4 :JMPN(outOfCountersStep) + %MAX_CNT_STEPS - STEP - 2 - 3*%ARRAY_MAX_LEN - 2 :JMPN(outOfCountersStep) ; till pre_loop - $ => C :MLOAD(array_div_len_rem) C :MSTORE(modexp_Blen) C - 1 => RR - %MAX_CNT_STEPS - STEP - 3*C :JMPN(outOfCountersStep) - modexp_rem_from_div1: - $ => A :MLOAD(array_div_rem + RR) + $ => A :MLOAD(array_div_long_rem + RR) A :MSTORE(modexp_B + RR) RR - 1 => RR :JMPN(modexp_pre_loop, modexp_rem_from_div1) ; ------------------- @@ -118,124 +137,169 @@ modexp_B_is_zero: ; Begin of branching modexp_loop_multiply: + ; w.c. happens when both B and the result of out*B are long + $ => C :MLOAD(modexp_outlen) $ => D :MLOAD(modexp_Blen) C - 1 => RR - D - 1 => E - - %MAX_CNT_STEPS - STEP - 3*C - 3*D - 1 :JMPN(outOfCountersStep) + D - 1 => E :JMPNZ(modexp_out_to_mul_long) ; Compute out * B ; ------------------- +; 1] Short path +modexp_out_to_mul_short: + $ => A :MLOAD(modexp_out + RR) + A :MSTORE(array_mul_short_inA + RR) + RR - 1 => RR :JMPN(modexp_B_to_mul_short, modexp_out_to_mul_short) + +modexp_B_to_mul_short: + $ => A :MLOAD(modexp_B) + A :MSTORE(array_mul_short_inB) + +modexp_mul_short_out_and_B: + :CALL(array_mul_short) ; inputs: [array_mul_short_len_inA: C, array_mul_short_inA: modexp_out, array_mul_short_inB: modexp_B] + ; outputs: [array_mul_short_len_out, array_mul_short_out] + + %MAX_CNT_STEPS - STEP - 4 - 3*%ARRAY_MAX_LEN - 3*%ARRAY_MAX_LEN - 1 :JMPN(outOfCountersStep) + + $ => C :MLOAD(array_mul_short_len_out) + $ => D :MLOAD(modexp_Mlen) + C - 1 => RR + D - 1 => E :JMPNZ(modexp_mul_short_out_to_div_long, modexp_mul_short_out_to_div_short) + +; 2] Long path modexp_out_to_mul_long: $ => A :MLOAD(modexp_out + RR) - A :MSTORE(array_mul_inA + RR) + A :MSTORE(array_mul_long_inA + RR) RR - 1 => RR :JMPN(modexp_B_to_mul_long, modexp_out_to_mul_long) modexp_B_to_mul_long: $ => A :MLOAD(modexp_B + E) - A :MSTORE(array_mul_inB + E) + A :MSTORE(array_mul_long_inB + E) E - 1 => E :JMPN(modexp_mul_long_out_and_B, modexp_B_to_mul_long) modexp_mul_long_out_and_B: - :CALL(array_mul) + :CALL(array_mul_long) ; inputs: [array_mul_long_len_inA: C, array_mul_long_len_inB: D, array_mul_long_inA: modexp_out, array_mul_long_inB: modexp_B] + ; outputs: [array_mul_long_len_out, array_mul_long_out] - %MAX_CNT_STEPS - STEP - 5 :JMPN(outOfCountersStep) + %MAX_CNT_STEPS - STEP - 4 - 3*%ARRAY_MAX_LEN - 3*%ARRAY_MAX_LEN - 1 :JMPN(outOfCountersStep) - $ => C :MLOAD(array_mul_len_out) + $ => C :MLOAD(array_mul_long_len_out) $ => D :MLOAD(modexp_Mlen) C - 1 => RR - D - 1 => E - - %MAX_CNT_STEPS - STEP - 3*C - 3*D - 1 :JMPN(outOfCountersStep) + D - 1 => E :JMPNZ(modexp_mul_long_out_to_div_long, modexp_mul_long_out_to_div_short) ; Compute out = (out * B) % M -modexp_out_to_div1: - $ => A :MLOAD(array_mul_out + RR) - A :MSTORE(array_div_inA + RR) - RR - 1 => RR :JMPN(modexp_M_to_div, modexp_out_to_div1) +;-------------------------------- +; 1] Mul short out to div short +modexp_mul_short_out_to_div_short: + $ => A :MLOAD(array_mul_short_out + RR) + A :MSTORE(array_div_short_inA + RR) + RR - 1 => RR :JMPN(modexp_M_to_div_short2, modexp_mul_short_out_to_div_short) -modexp_M_to_div: +; 2] Mul long out to div short +modexp_mul_long_out_to_div_short: + $ => A :MLOAD(array_mul_long_out + RR) + A :MSTORE(array_div_short_inA + RR) + RR - 1 => RR :JMPN(modexp_M_to_div_short2, modexp_mul_long_out_to_div_short) + +modexp_M_to_div_short2: + $ => A :MLOAD(modexp_M) + A :MSTORE(array_div_short_inB) + +modexp_div_short_out_and_M1: + :CALL(array_div_short) ; inputs: [array_div_short_len_inA: C, array_div_short_inA: array_mul_long_out, array_div_short_inB: modexp_M] + ; outputs: [array_div_short_rem] + + %MAX_CNT_STEPS - STEP - 3 - 2 - 3*%ARRAY_MAX_LEN - 2 :JMPN(outOfCountersStep) ; till array_div_short by 2 + + 1 :MSTORE(modexp_outlen) + $ => A :MLOAD(array_div_short_rem) + A :MSTORE(modexp_out), JMP(return_modexp_loop_multiply) + +; 3] Mul short out to div long +modexp_mul_short_out_to_div_long: + $ => A :MLOAD(array_mul_short_out + RR) + A :MSTORE(array_div_long_inA + RR) + RR - 1 => RR :JMPN(modexp_M_to_div_long2, modexp_mul_short_out_to_div_long) + +; 4] Mul long out to div long +modexp_mul_long_out_to_div_long: + $ => A :MLOAD(array_mul_long_out + RR) + A :MSTORE(array_div_long_inA + RR) + RR - 1 => RR :JMPN(modexp_M_to_div_long2, modexp_mul_long_out_to_div_long) + +modexp_M_to_div_long2: $ => A :MLOAD(modexp_M + E) - A :MSTORE(array_div_inB + E) - E - 1 => E :JMPN(modexp_div_out_and_M2, modexp_M_to_div) + A :MSTORE(array_div_long_inB + E) + E - 1 => E :JMPN(modexp_div_long_out_and_M1, modexp_M_to_div_long2) -modexp_div_out_and_M2: - :CALL(array_div) +modexp_div_long_out_and_M1: + :CALL(array_div_long) ; inputs: [array_div_long_len_inA: C, array_div_long_inA: array_mul_long_out, array_div_long_inB: modexp_M] + ; outputs: [array_div_long_len_rem, array_div_long_rem] - %MAX_CNT_STEPS - STEP - 4 :JMPN(outOfCountersStep) + %MAX_CNT_STEPS - STEP - 3 - 3*%ARRAY_MAX_LEN - 2 - 3*%ARRAY_MAX_LEN - 2 :JMPN(outOfCountersStep) ; till array_div_short by 2 - $ => C :MLOAD(array_div_len_rem) + $ => C :MLOAD(array_div_long_len_rem) C :MSTORE(modexp_outlen) C - 1 => RR - %MAX_CNT_STEPS - STEP - 3*C - 1 :JMPN(outOfCountersStep) - modexp_rem_from_div2: - $ => A :MLOAD(array_div_rem + RR) + $ => A :MLOAD(array_div_long_rem + RR) A :MSTORE(modexp_out + RR) RR - 1 => RR :JMPN(return_modexp_loop_multiply, modexp_rem_from_div2) ; ------------------- ; End of branching modexp_pre_loop: -; In the worst case, the exponent is odd in each iteration - %MAX_CNT_BINARY - CNT_BINARY - 3 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 13 :JMPN(outOfCountersStep) + %MAX_CNT_BINARY - CNT_BINARY - 3 :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 12 - 4 - 3*%ARRAY_MAX_LEN - 3*%ARRAY_MAX_LEN - 1 :JMPN(outOfCountersStep) ; till array_mul_long of loop_multiply ; Is Elen = 1 and E = 0? - 1 => B - $ => A :MLOAD(modexp_Elen) - A - B :JMPNZ(__modexp_E_continue) + 0 => B + $ - 1 :F_MLOAD(modexp_Elen), JMPNZ(__modexp_E_continue) $ => A :MLOAD(modexp_E) - $ :LT, JMPC(modexp_end) ; we are done + $ :EQ, JMPC(modexp_end) ; we are done __modexp_E_continue: modexp_loop: ; Is Blen = 1 and B = 0? - $ => A :MLOAD(modexp_Blen) - A - B :JMPNZ(__modexp_B_continue) + $ - 1 :F_MLOAD(modexp_Blen), JMPNZ(__modexp_B_continue) $ => A :MLOAD(modexp_B) - $ :LT, JMPC(modexp_B_is_zero) + $ :EQ, JMPC(modexp_B_is_zero) __modexp_B_continue: ; Is E is odd? ; The base is 2^256, so I only need to check if the first chunk is odd to conclude that the whole number is odd. $ => A :MLOAD(modexp_E) 1 => B - $ :AND, JMPNZ(modexp_loop_multiply) + $ :AND, JMPC(modexp_loop_multiply) ; In the worst case, the exponent is odd in each iteration return_modexp_loop_multiply: - %MAX_CNT_STEPS - STEP - 3 :JMPN(outOfCountersStep) - $ => C :MLOAD(modexp_Elen) C - 1 => RR - %MAX_CNT_STEPS - STEP - 3*C - 2 :JMPN(outOfCountersStep) - ; Compute E = E // 2 ; ------------------- -modexp_E_to_div_short: +modexp_E_to_div_two: $ => A :MLOAD(modexp_E + RR) - A :MSTORE(array_div_short_inA + RR) - RR - 1 => RR :JMPN(modexp_div_E_and_2, modexp_E_to_div_short) + A :MSTORE(array_div_two_in + RR) + RR - 1 => RR :JMPN(modexp_div_E_and_two, modexp_E_to_div_two) -modexp_div_E_and_2: - 2 :MSTORE(array_div_short_inB) - :CALL(array_div_short) +modexp_div_E_and_two: + :CALL(array_div_two) ; inputs: [array_div_two_len_in: C, array_div_two_in: modexp_E] + ; outputs: [array_div_two_len_quo, array_div_two_quo] - %MAX_CNT_STEPS - STEP - 4 :JMPN(outOfCountersStep) + %MAX_CNT_STEPS - STEP - 3 - 3*%ARRAY_MAX_LEN - 2 - 3*%ARRAY_MAX_LEN - 1 :JMPN(outOfCountersStep) ; till array_square - $ => C :MLOAD(array_div_short_len_quo) + $ => C :MLOAD(array_div_two_len_quo) C :MSTORE(modexp_Elen) C - 1 => RR - %MAX_CNT_STEPS - STEP - 3*C - 3 :JMPN(outOfCountersStep) - -modexp_quo_from_div_short: - $ => A :MLOAD(array_div_short_quo + RR) +modexp_quo_from_div_two: + $ => A :MLOAD(array_div_two_quo + RR) A :MSTORE(modexp_E + RR) - RR - 1 => RR :JMPN(modexp_pre_B_square, modexp_quo_from_div_short) + RR - 1 => RR :JMPN(modexp_pre_B_square, modexp_quo_from_div_two) ; ------------------- ; Compute B^2 @@ -244,53 +308,69 @@ modexp_pre_B_square: $ => C :MLOAD(modexp_Blen) C - 1 => RR - %MAX_CNT_STEPS - STEP - 3*C - 1 :JMPN(outOfCountersStep) - modexp_B_to_square1: $ => A :MLOAD(modexp_B + RR) A :MSTORE(array_square_in + RR) RR - 1 => RR :JMPN(modexp_square_B, modexp_B_to_square1) modexp_square_B: - :CALL(array_square) + :CALL(array_square) ; inputs: [array_square_len_in: C, array_square_in: modexp_B] + ; outputs: [array_square_len_out, array_square_out] - %MAX_CNT_STEPS - STEP - 5 :JMPN(outOfCountersStep) + %MAX_CNT_STEPS - STEP - 4 - 3*%ARRAY_MAX_LEN - 3*%ARRAY_MAX_LEN - 1 :JMPN(outOfCountersStep) $ => C :MLOAD(array_square_len_out) $ => D :MLOAD(modexp_Mlen) C - 1 => RR - D - 1 => E - - %MAX_CNT_STEPS - STEP - 3*C - 3*D - 1 :JMPN(outOfCountersStep) + D - 1 => E :JMPNZ(modexp_out_to_div_long2) ; Compute B = (B^2) % M -modexp_out_to_div2: +; 1] Short path +modexp_out_to_div_short2: $ => A :MLOAD(array_square_out + RR) - A :MSTORE(array_div_inA + RR) - RR - 1 => RR :JMPN(modexp_M_to_div2, modexp_out_to_div2) + A :MSTORE(array_div_short_inA + RR) + RR - 1 => RR :JMPN(modexp_M_to_div_short3, modexp_out_to_div_short2) + +modexp_M_to_div_short3: + $ => A :MLOAD(modexp_M) + A :MSTORE(array_div_short_inB) + +modexp_div_short_out_and_M2: + :CALL(array_div_short) ; inputs: [array_div_short_len_inA: C, array_div_short_inA: array_square_out, array_div_short_inB: modexp_M] + ; outputs: [array_div_short_rem] -modexp_M_to_div2: + %MAX_CNT_STEPS - STEP - 3 - 2 :JMPN(outOfCountersStep) ; till begginning of modexp_pre_loop + + 1 :MSTORE(modexp_Blen) + $ => A :MLOAD(array_div_short_rem) + A :MSTORE(modexp_B), JMP(modexp_pre_loop) + +; 2] Long path +modexp_out_to_div_long2: + $ => A :MLOAD(array_square_out + RR) + A :MSTORE(array_div_long_inA + RR) + RR - 1 => RR :JMPN(modexp_M_to_div_long3, modexp_out_to_div_long2) + +modexp_M_to_div_long3: $ => A :MLOAD(modexp_M + E) - A :MSTORE(array_div_inB + E) - E - 1 => E :JMPN(modexp_div_out_and_M1, modexp_M_to_div2) + A :MSTORE(array_div_long_inB + E) + E - 1 => E :JMPN(modexp_div_long_out_and_M2, modexp_M_to_div_long3) -modexp_div_out_and_M1: - :CALL(array_div) +modexp_div_long_out_and_M2: + :CALL(array_div_long) ; inputs: [array_div_long_len_inA: C, array_div_long_len_inB: D, array_div_long_inA: array_square_out, array_div_long_inB: modexp_M] + ; outputs: [array_div_long_len_rem, array_div_long_rem] - %MAX_CNT_STEPS - STEP - 4 :JMPN(outOfCountersStep) + %MAX_CNT_STEPS - STEP - 3 - 3*%ARRAY_MAX_LEN - 2 :JMPN(outOfCountersStep) ; till begginning of modexp_pre_loop - $ => C :MLOAD(array_div_len_rem) + $ => C :MLOAD(array_div_long_len_rem) C :MSTORE(modexp_Blen) C - 1 => RR - %MAX_CNT_STEPS - STEP - 3*C - 2 :JMPN(outOfCountersStep) - modexp_rem_from_div3: - $ => A :MLOAD(array_div_rem + RR) + $ => A :MLOAD(array_div_long_rem + RR) A :MSTORE(modexp_B + RR) RR - 1 => RR :JMPN(modexp_pre_loop, modexp_rem_from_div3) ; ------------------- modexp_end: - $ => RR :MLOAD(modexp_RR) - :RETURN + $ => RR :MLOAD(modexp_RR), RETURN \ No newline at end of file From 768e2b11b14fe6407b5e3f828ab9741cc36a8de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Masip?= Date: Thu, 3 Oct 2024 16:13:22 +0200 Subject: [PATCH 02/12] Updating tests --- test/testArrayArith.zkasm | 1465 +++++++++++++++++++++---------------- test/testArrayUtils.zkasm | 335 --------- test/testModExp.zkasm | 1291 +++++++++++++++++++++++++------- 3 files changed, 1864 insertions(+), 1227 deletions(-) delete mode 100644 test/testArrayUtils.zkasm diff --git a/test/testArrayArith.zkasm b/test/testArrayArith.zkasm index 2374a8de..c0b97c54 100644 --- a/test/testArrayArith.zkasm +++ b/test/testArrayArith.zkasm @@ -1,7 +1,14 @@ ; constants needed by executor C++ INCLUDE "../main/constants.zkasm" +INCLUDE "../main/modexp/constants.zkasm" -CONSTL %ARRAY_BASE_MINUS_ONE = 115792089237316195423570985008687907853269984665640564039457584007913129639935n ; 2^256 +CONSTL %ARRAY_BASE_MINUS_ONE = 115792089237316195423570985008687907853269984665640564039457584007913129639935n ; 2^256-1 +CONSTL %ARRAY_BASE_MINUS_TWO = 115792089237316195423570985008687907853269984665640564039457584007913129639934n ; 2^256-2 +CONSTL %ARRAY_BASE_MINUS_THREE = 115792089237316195423570985008687907853269984665640564039457584007913129639933n ; 2^256-3 +CONSTL %ARRAY_BASE_HALF = 57896044618658097711785492504343953926634992332820282019728792003956564819968n ; 2^255 +CONSTL %ARRAY_BASE_HALF_MINUS_ONE = 57896044618658097711785492504343953926634992332820282019728792003956564819967n ; 2^255-1 +CONST %ARRAY_MAX_LEN_DOUBLED_MINUS_TWO = %ARRAY_MAX_LEN_DOUBLED - 2 +CONST %ARRAY_MAX_LEN_DIV_BY_TWO = %ARRAY_MAX_LEN / 2 VAR GLOBAL lastHashKId VAR GLOBAL lastHashPId @@ -45,38 +52,129 @@ start: ; addition with len(inA) >= len(inB) ; --------------------------------------------------------------- - ; 1] [2**256-1,2**256-1,2**256-1] + [2**256-1,2**256-1] + ; 1] inA = inB and len(inA) = len(inB) = 1 + 1 => C + 1 => D + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inA) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inB) + :CALL(array_add_AGTB) + %ARRAY_BASE_MINUS_TWO :MLOAD(array_add_AGTB_out) + 1 => E + 1 :MLOAD(array_add_AGTB_out + E) + 2 :MLOAD(array_add_AGTB_len_out) + + ; 2] inA < inB and len(inA) = len(inB) = 1 + 1 => C + 1 => D + %ARRAY_BASE_MINUS_TWO :MSTORE(array_add_AGTB_inA) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inB) + :CALL(array_add_AGTB) + %ARRAY_BASE_MINUS_THREE :MLOAD(array_add_AGTB_out) + 1 => E + 1 :MLOAD(array_add_AGTB_out + E) + 2 :MLOAD(array_add_AGTB_len_out) + + ; 3] [2**256-1,2**256-1,2**256-1] + [2**256-1,2**256-1] 3 => C 2 => D - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_AGTB_inA) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inA) 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_AGTB_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inA + E) 2 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_AGTB_inA + E) - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_AGTB_inB) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inB) 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_AGTB_inB + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inB + E) :CALL(array_add_AGTB) - 115792089237316195423570985008687907853269984665640564039457584007913129639934n :MLOAD(array_add_AGTB_out) + %ARRAY_BASE_MINUS_TWO :MLOAD(array_add_AGTB_out) 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MLOAD(array_add_AGTB_out + E) + %ARRAY_BASE_MINUS_ONE :MLOAD(array_add_AGTB_out + E) 2 => E 0n :MLOAD(array_add_AGTB_out + E) 3 => E 1n :MLOAD(array_add_AGTB_out + E) 4 :MLOAD(array_add_AGTB_len_out) + + ; 3] [2**256-1,2**256-1,2**256-1,2**256-1] + [0,1] + 4 => C + 2 => D + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inA) + 1 => E + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inA + E) + 2 => E + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inA + E) + 3 => E + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inA + E) + 0 :MSTORE(array_add_AGTB_inB) + 1 => E + 1 :MSTORE(array_add_AGTB_inB + E) + :CALL(array_add_AGTB) + %ARRAY_BASE_MINUS_ONE :MLOAD(array_add_AGTB_out) + 1 => E + 0 :MLOAD(array_add_AGTB_out + E) + 2 => E + 0n :MLOAD(array_add_AGTB_out + E) + 3 => E + 0n :MLOAD(array_add_AGTB_out + E) + 4 => E + 1n :MLOAD(array_add_AGTB_out + E) + 5 :MLOAD(array_add_AGTB_len_out) + + ; 4] [2**256-2]*%ARRAY_MAX_LEN_DOUBLED + [1]*%ARRAY_MAX_LEN + %ARRAY_MAX_LEN_DOUBLED => C + %ARRAY_MAX_LEN => D + C - 1 => E + D - 1 => RR + array_add_AGTB_wc_test_inA: + %ARRAY_BASE_MINUS_TWO :MSTORE(array_add_AGTB_inA + E) + E - 1 => E :JMPN(array_add_AGTB_wc_test_inB,array_add_AGTB_wc_test_inA) + array_add_AGTB_wc_test_inB: + 1n :MSTORE(array_add_AGTB_inB + RR) + RR - 1 => RR :JMPN(array_add_AGTB_wc_test_compute,array_add_AGTB_wc_test_inB) + array_add_AGTB_wc_test_compute: + :CALL(array_add_AGTB) + %ARRAY_MAX_LEN_DOUBLED => E :MLOAD(array_add_AGTB_len_out) + E - 1 => E + array_add_AGTB_wc_test_check1: + %ARRAY_BASE_MINUS_TWO :MLOAD(array_add_AGTB_out + E) + E - 1 => E + E - %ARRAY_MAX_LEN :JMPN(array_add_AGTB_wc_test_check2,array_add_AGTB_wc_test_check1) + array_add_AGTB_wc_test_check2: + %ARRAY_BASE_MINUS_ONE :MLOAD(array_add_AGTB_out + E) + E - 1 => E :JMPN(array_add_AGTB_wc_test_end,array_add_AGTB_wc_test_check2) + array_add_AGTB_wc_test_end: ; --------------------------------------------------------------- ; short addition ; --------------------------------------------------------------- - ; 1] [2**256-1,2**256-1,2**256-1] + [2**256-1] + ; 1] inA = inB and len(inA) = len(inB) = 1 + 1 => C + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_short_inA) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_short_inB) + :CALL(array_add_short) + %ARRAY_BASE_MINUS_TWO :MLOAD(array_add_short_out) + 1 => E + 1 :MLOAD(array_add_short_out + E) + 2 :MLOAD(array_add_short_len_out) + + ; 2] inA < inB and len(inA) = len(inB) = 1 + 1 => C + %ARRAY_BASE_MINUS_TWO :MSTORE(array_add_short_inA) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_short_inB) + :CALL(array_add_short) + %ARRAY_BASE_MINUS_THREE :MLOAD(array_add_short_out) + 1 => E + 1 :MLOAD(array_add_short_out + E) + 2 :MLOAD(array_add_short_len_out) + + ; 3] [2**256-1,2**256-1,2**256-1] + [2**256-1] 3 => C - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_short_inA) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_short_inA) 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_short_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_short_inA + E) 2 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_short_inA + E) - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_short_inB) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_short_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_short_inB) :CALL(array_add_short) 115792089237316195423570985008687907853269984665640564039457584007913129639934n :MLOAD(array_add_short_out) 1 => E @@ -86,107 +184,314 @@ start: 3 => E 1n :MLOAD(array_add_short_out + E) 4 :MLOAD(array_add_short_len_out) + + ;[2**256-1,2**256-1,2**256-1,2**256-1,2**256-1] + [1] + 5 => C + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_short_inA) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_short_inA + 1) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_short_inA + 2) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_short_inA + 3) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_short_inA + 4) + 1 :MSTORE(array_add_short_inB) + :CALL(array_add_short) + 0n :MLOAD(array_add_short_out) + 0n :MLOAD(array_add_short_out + 1) + 0n :MLOAD(array_add_short_out + 2) + 0n :MLOAD(array_add_short_out + 3) + 0n :MLOAD(array_add_short_out + 4) + 1n :MLOAD(array_add_short_out + 5) + 6 :MLOAD(array_add_short_len_out) + + ; 4] [2**256-1]*%ARRAY_MAX_LEN + [1] + %ARRAY_MAX_LEN_MINUS_ONE => C + C - 1 => E + array_add_short_wc_test_inA: + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_short_inA + E) + E - 1 => E :JMPN(array_add_short_wc_test_compute,array_add_short_wc_test_inA) + array_add_short_wc_test_compute: + 1n :MSTORE(array_add_short_inB) + :CALL(array_add_short) + %ARRAY_MAX_LEN => E :MLOAD(array_add_short_len_out) + E - 1 => E + 1n :MLOAD(array_add_short_out + E) + E - 1 => E + array_add_short_wc_test_check: + 0n :MLOAD(array_add_short_out + E) + E - 1 => E :JMPN(array_add_short_wc_test_end,array_add_short_wc_test_check) + array_add_short_wc_test_end: ; --------------------------------------------------------------- - ; multiplication + ; long multiplication ; --------------------------------------------------------------- - ; 1] len(inB) = len(inA) and inB > inA + ; 1] len(inA) = len(inB) and inA = inB + 2 => C + 2 => D + 5n :MSTORE(array_mul_long_inA) + 1 => E + 6n :MSTORE(array_mul_long_inA + E) + 5n :MSTORE(array_mul_long_inB) + 1 => E + 6n :MSTORE(array_mul_long_inB + E) + :CALL(array_mul_long) + 25n :MLOAD(array_mul_long_out) + 1 => E + 60n :MLOAD(array_mul_long_out + E) + 2 => E + 36n :MLOAD(array_mul_long_out + E) + 3 :MLOAD(array_mul_long_len_out) + + ; 2] len(inA) = len(inB) and inA < inB + 2 => C + 2 => D + 5n :MSTORE(array_mul_long_inA) + 1 => E + 5n :MSTORE(array_mul_long_inA + E) + 5n :MSTORE(array_mul_long_inB) + 1 => E + 6n :MSTORE(array_mul_long_inB + E) + :CALL(array_mul_long) + 25n :MLOAD(array_mul_long_out) + 1 => E + 55n :MLOAD(array_mul_long_out + E) + 2 => E + 30n :MLOAD(array_mul_long_out + E) + 3 :MLOAD(array_mul_long_len_out) + + ; 3] len(inA) = len(inB) and inA < inB 3 => C 3 => D - 5n :MSTORE(array_mul_inA) + 5n :MSTORE(array_mul_long_inA) 1 => E - 6n :MSTORE(array_mul_inA + E) + 6n :MSTORE(array_mul_long_inA + E) 2 => E - 7n :MSTORE(array_mul_inA + E) + 7n :MSTORE(array_mul_long_inA + E) - 2n :MSTORE(array_mul_inB) + 2n :MSTORE(array_mul_long_inB) 1 => E - 3n :MSTORE(array_mul_inB + E) + 3n :MSTORE(array_mul_long_inB + E) 2 => E - 4n :MSTORE(array_mul_inB + E) - :CALL(array_mul) - 10n :MLOAD(array_mul_out) + 4n :MSTORE(array_mul_long_inB + E) + :CALL(array_mul_long) + 10n :MLOAD(array_mul_long_out) 1 => E - 27n :MLOAD(array_mul_out + E) + 27n :MLOAD(array_mul_long_out + E) 2 => E - 52n :MLOAD(array_mul_out + E) + 52n :MLOAD(array_mul_long_out + E) 3 => E - 45n :MLOAD(array_mul_out + E) + 45n :MLOAD(array_mul_long_out + E) 4 => E - 28n :MLOAD(array_mul_out + E) - 5 :MLOAD(array_mul_len_out) + 28n :MLOAD(array_mul_long_out + E) + 5 :MLOAD(array_mul_long_len_out) - ; 2] len(inB) != len(inA) + ; 4] len(inA) < len(inB) 2 => C 3 => D - 5n :MSTORE(array_mul_inA) + 5n :MSTORE(array_mul_long_inA) 1 => E - 6n :MSTORE(array_mul_inA + E) + 6n :MSTORE(array_mul_long_inA + E) - 11n :MSTORE(array_mul_inB) + 11n :MSTORE(array_mul_long_inB) 1 => E - 21n :MSTORE(array_mul_inB + E) + 21n :MSTORE(array_mul_long_inB + E) 2 => E - 16n :MSTORE(array_mul_inB + E) - :CALL(array_mul) - 55n :MLOAD(array_mul_out) + 16n :MSTORE(array_mul_long_inB + E) + :CALL(array_mul_long) + 55n :MLOAD(array_mul_long_out) 1 => E - 171n :MLOAD(array_mul_out + E) + 171n :MLOAD(array_mul_long_out + E) 2 => E - 206n :MLOAD(array_mul_out + E) + 206n :MLOAD(array_mul_long_out + E) 3 => E - 96n :MLOAD(array_mul_out + E) - 4 :MLOAD(array_mul_len_out) + 96n :MLOAD(array_mul_long_out + E) + 4 :MLOAD(array_mul_long_len_out) + + ; 5] [2**256-1] || [0]*%ARRAY_MAX_LEN_DOUBLED_MINUS_TWO * [1]*2 + %ARRAY_MAX_LEN_DOUBLED_MINUS_ONE => C + 2 => D + C - 1 => E + D - 1 => RR + %ARRAY_BASE_MINUS_ONE :MSTORE(array_mul_long_inA + E) + E - 1 => E + array_mul_long_wc_test_inA: + 0n :MSTORE(array_mul_long_inA + E) + E - 1 => E :JMPN(array_mul_long_wc_test_inB,array_mul_long_wc_test_inA) + array_mul_long_wc_test_inB: + 1n :MSTORE(array_mul_long_inB + RR) + RR - 1 => RR :JMPN(array_mul_long_wc_test_compute,array_mul_long_wc_test_inB) + array_mul_long_wc_test_compute: + :CALL(array_mul_long) + %ARRAY_MAX_LEN_DOUBLED => E :MLOAD(array_mul_long_len_out) + E - 1 => E + array_mul_long_wc_test_check1: + %ARRAY_BASE_MINUS_ONE :MLOAD(array_mul_long_out + E) + E - 1 => E + E - 62 :JMPN(array_mul_long_wc_test_check2,array_mul_long_wc_test_check1) + array_mul_long_wc_test_check2: + 0n :MLOAD(array_mul_long_out + E) + E - 1 => E :JMPN(array_mul_long_wc_test_end,array_mul_long_wc_test_check2) + array_mul_long_wc_test_end: ; --------------------------------------------------------------- ; short multiplication ; --------------------------------------------------------------- - ; 1] [a, a, a] * a + ; 1] [2**256-1] * 2**256-1 + 1 => C + %ARRAY_BASE_MINUS_ONE :MSTORE(array_mul_short_inA) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_mul_short_inB) + :CALL(array_mul_short) + 1n :MLOAD(array_mul_short_out) + 1 => E + %ARRAY_BASE_MINUS_TWO :MLOAD(array_mul_short_out + E) + 2 :MLOAD(array_mul_short_len_out) + + ; 2] [2**256-2] * 2**256-1 + 1 => C + %ARRAY_BASE_MINUS_TWO :MSTORE(array_mul_short_inA) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_mul_short_inB) + :CALL(array_mul_short) + 2n :MLOAD(array_mul_short_out) + 1 => E + %ARRAY_BASE_MINUS_THREE :MLOAD(array_mul_short_out + E) + 2 :MLOAD(array_mul_short_len_out) + + ; 3] [2**256-1, 2**256-1, 2**256-1] * 2**256-1 3 => C - 1 => D - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_mul_inA) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_mul_short_inA) 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_mul_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_mul_short_inA + E) 2 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_mul_inA + E) - - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_mul_inB) - :CALL(array_mul) - 1n :MLOAD(array_mul_out) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_mul_short_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_mul_short_inB) + :CALL(array_mul_short) + 1n :MLOAD(array_mul_short_out) 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MLOAD(array_mul_out + E) + %ARRAY_BASE_MINUS_ONE :MLOAD(array_mul_short_out + E) 2 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MLOAD(array_mul_out + E) + %ARRAY_BASE_MINUS_ONE :MLOAD(array_mul_short_out + E) 3 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639934n :MLOAD(array_mul_out + E) - 4 :MLOAD(array_mul_len_out) + %ARRAY_BASE_MINUS_TWO :MLOAD(array_mul_short_out + E) + 4 :MLOAD(array_mul_short_len_out) - ; 2] [a, 100, a, 6] * 400 + ; 2] [2**256-1, 100, 2**256-1, 6] * 400 4 => C - 1 => D - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_mul_inA) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_mul_short_inA) 1 => E - 100n :MSTORE(array_mul_inA + E) + 100n :MSTORE(array_mul_short_inA + E) 2 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_mul_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_mul_short_inA + E) 3 => E - 6n :MSTORE(array_mul_inA + E) - - 400n :MSTORE(array_mul_inB) - :CALL(array_mul) - 115792089237316195423570985008687907853269984665640564039457584007913129639536n :MLOAD(array_mul_out) + 6n :MSTORE(array_mul_short_inA + E) + 400n :MSTORE(array_mul_short_inB) + :CALL(array_mul_short) + 115792089237316195423570985008687907853269984665640564039457584007913129639536n :MLOAD(array_mul_short_out) 1 => E - 40399n :MLOAD(array_mul_out + E) + 40399n :MLOAD(array_mul_short_out + E) 2 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639536n :MLOAD(array_mul_out + E) + 115792089237316195423570985008687907853269984665640564039457584007913129639536n :MLOAD(array_mul_short_out + E) 3 => E - 2799n :MLOAD(array_mul_out + E) - 4 :MLOAD(array_mul_len_out) + 2799n :MLOAD(array_mul_short_out + E) + 4 :MLOAD(array_mul_short_len_out) + + ; 3] [2**255]*%ARRAY_MAX_LEN * [2] + %ARRAY_MAX_LEN => C + C - 1 => E + array_mul_short_wc_test_inA: + %ARRAY_BASE_HALF :MSTORE(array_mul_short_inA + E) + E - 1 => E :JMPN(array_mul_short_wc_test_compute,array_mul_short_wc_test_inA) + array_mul_short_wc_test_compute: + 2n :MSTORE(array_mul_short_inB) + :CALL(array_mul_short) + %ARRAY_MAX_LEN_PLUS_ONE => E :MLOAD(array_mul_short_len_out) + E - 1 => E + array_mul_short_wc_test_check: + 1n :MLOAD(array_mul_short_out + E) + E - 1 => E :JMPZ(array_mul_short_wc_test_end,array_mul_short_wc_test_check) + array_mul_short_wc_test_end: + 0n :MLOAD(array_mul_short_out + E) + ; --------------------------------------------------------------- + + ; multiplication by two + ; --------------------------------------------------------------- + ; 1] [0n] + 1 => C + 0n :MSTORE(array_mul_two_in) + :CALL(array_mul_two) + 0n :MLOAD(array_mul_two_out) + 1 :MLOAD(array_mul_two_len_out) + + ; 2] [1n] + 1 => C + 1n :MSTORE(array_mul_two_in) + :CALL(array_mul_two) + 2n :MLOAD(array_mul_two_out) + 1 :MLOAD(array_mul_two_len_out) + + ; 3] [4n] + 1 => C + 4n :MSTORE(array_mul_two_in) + :CALL(array_mul_two) + 8n :MLOAD(array_mul_two_out) + 1 :MLOAD(array_mul_two_len_out) + + ; 4] [4n, 4n] + 2 => C + 4n :MSTORE(array_mul_two_in) + 1 => E + 4n :MSTORE(array_mul_two_in + E) + :CALL(array_mul_two) + 8n :MLOAD(array_mul_two_out) + 1 => E + 8n :MLOAD(array_mul_two_out + E) + 2 :MLOAD(array_mul_two_len_out) + + ; 5] [2^255, 2^255] + 2 => C + %ARRAY_BASE_HALF :MSTORE(array_mul_two_in) + 1 => E + %ARRAY_BASE_HALF :MSTORE(array_mul_two_in + E) + :CALL(array_mul_two) + 0n :MLOAD(array_mul_two_out) + 1 => E + 1n :MLOAD(array_mul_two_out + E) + 2 => E + 1n :MLOAD(array_mul_two_out + E) + 3 :MLOAD(array_mul_two_len_out) + + ; 6] [2^255-1] * %ARRAY_MAX_LEN + %ARRAY_MAX_LEN => C + C - 1 => E + array_mul_two_wc_test: + %ARRAY_BASE_HALF_MINUS_ONE :MSTORE(array_mul_two_in + E) + E - 1 => E :JMPN(array_mul_two_wc_test_compute,array_mul_two_wc_test) + array_mul_two_wc_test_compute: + :CALL(array_mul_two) + %ARRAY_MAX_LEN => E :MLOAD(array_mul_two_len_out) + E - 1 => E + array_mul_two_wc_test_check: + %ARRAY_BASE_MINUS_TWO :MLOAD(array_mul_two_out + E) + E - 1 => E :JMPN(array_mul_two_wc_test_end,array_mul_two_wc_test_check) + array_mul_two_wc_test_end: ; --------------------------------------------------------------- ; squaring ; --------------------------------------------------------------- - ; 1] [4n, 4n, 4n, 3n, 2n, 4n] + ; 1] [5] + 1 => C + 5n :MSTORE(array_square_in) + :CALL(array_square) + 25n :MLOAD(array_square_out) + 1 :MLOAD(array_square_len_out) + + ; 2] [2**256-1] + 1 => C + %ARRAY_BASE_MINUS_ONE :MSTORE(array_square_in) + :CALL(array_square) + 1n :MLOAD(array_square_out) + 1 => E + %ARRAY_BASE_MINUS_TWO :MLOAD(array_square_out + E) + 2 :MLOAD(array_square_len_out) + + ; 3] [4n, 4n, 4n, 3n, 2n, 4n] 6 => C 4n :MSTORE(array_square_in) 1 => E @@ -223,7 +528,7 @@ start: 16n :MLOAD(array_square_out + E) 11 :MLOAD(array_square_len_out) - ; 2] [49625181101706940895816136432294817651401421999560241731196107431962769845690n, 16541727033902313631938712144098272550467140666520080577065369143987589948564n, 2n] + ; 4] [49625181101706940895816136432294817651401421999560241731196107431962769845690n, 16541727033902313631938712144098272550467140666520080577065369143987589948564n, 2n] 3 => C 49625181101706940895816136432294817651401421999560241731196107431962769845690n :MSTORE(array_square_in) 1 => E @@ -242,7 +547,7 @@ start: 4n :MLOAD(array_square_out + E) 5 :MLOAD(array_square_len_out) - ; 3] [108509871213644914495224788117262720812102234692915980461799068728781566717980n, 97610657482852136417037764955262109743864410230427530868747251158690618238750n, 3n] + ; 5] [108509871213644914495224788117262720812102234692915980461799068728781566717980n, 97610657482852136417037764955262109743864410230427530868747251158690618238750n, 3n] 3 => C 108509871213644914495224788117262720812102234692915980461799068728781566717980n :MSTORE(array_square_in) 1 => E @@ -261,7 +566,7 @@ start: 14n :MLOAD(array_square_out + E) 5 :MLOAD(array_square_len_out) - ; 4] [94296684984090328915786319894647341212298256830891608529662243544763352873524n,85801804490443701075961240310880668636621463408258506144468684495763969931231n] + ; 6] [94296684984090328915786319894647341212298256830891608529662243544763352873524n,85801804490443701075961240310880668636621463408258506144468684495763969931231n] 2 => C 94296684984090328915786319894647341212298256830891608529662243544763352873524n :MSTORE(array_square_in) 1 => E @@ -276,10 +581,10 @@ start: 63579038104476977130956937454941822659502127575865339775268690127769381598323n :MLOAD(array_square_out + E) 4 :MLOAD(array_square_len_out) - ; 5] [ARRAY_BASE-1,ARRAY_BASE/2+1,ARRAY_BASE-2] + ; 7] [ARRAY_BASE-1,ARRAY_BASE/2+1,ARRAY_BASE-2] ; this covers the edge case where the addition 2·a_i·a_j + out[i + j] produces a third chunk carry 3 => C - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_square_in) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_square_in) 1 => E 57896044618658097711785492504343953926634992332820282019728792003956564819969n :MSTORE(array_square_in + E) 2 => E @@ -298,7 +603,7 @@ start: 115792089237316195423570985008687907853269984665640564039457584007913129639933n :MLOAD(array_square_out + E) 6 :MLOAD(array_square_len_out) - ; 6] [ARRAY_BASE/2+1,ARRAY_BASE/2+1,ARRAY_BASE-2] + ; 8] [ARRAY_BASE/2+1,ARRAY_BASE/2+1,ARRAY_BASE-2] ; this covers the edge case where out[i + j] has a non-zero second chunk (i.e., when j == len -1) ; and it produces carry when added to the second chunk of 2·a_i·a_j 3 => C @@ -321,13 +626,13 @@ start: 115792089237316195423570985008687907853269984665640564039457584007913129639933n :MLOAD(array_square_out + E) 6 :MLOAD(array_square_len_out) - ; 7] [ARRAY_BASE/2+1,ARRAY_BASE-1,ARRAY_BASE-2] + ; 9] [ARRAY_BASE/2+1,ARRAY_BASE-1,ARRAY_BASE-2] ; this covers the edge case where carry has a non-zero second chunk ; and it produces carry when added to the second chunk of 2·a_i·a_j + out[i + j] 3 => C 57896044618658097711785492504343953926634992332820282019728792003956564819969n :MSTORE(array_square_in) 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_square_in + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_square_in + E) 2 => E 115792089237316195423570985008687907853269984665640564039457584007913129639934n :MSTORE(array_square_in + E) :CALL(array_square) @@ -344,7 +649,7 @@ start: 115792089237316195423570985008687907853269984665640564039457584007913129639934n :MLOAD(array_square_out + E) 6 :MLOAD(array_square_len_out) - ; 8] [272043482145244634591109928786079352n,81877371507464127617551201542979628307507432471243237061821853600756754782485n,176318528146701254200802196825427983451687n] + ; 10] [272043482145244634591109928786079352n,81877371507464127617551201542979628307507432471243237061821853600756754782485n,176318528146701254200802196825427983451687n] ; this covers the edge case where carry is of the form -a_i·a_i ; and it produces carry when added to the second chunk of 2·a_i·a_i + out[i + i] ; e.g., when the subtraction is of the form (base² + y) - (y+1) = 0 @@ -375,669 +680,615 @@ start: 5 => E 268483n :MLOAD(array_square_out + E) 6 :MLOAD(array_square_len_out) - ; --------------------------------------------------------------- - ; division + ; 11] [2**256-1] || [0]*%ARRAY_MAX_LEN_MINUS_ONE + %ARRAY_MAX_LEN => C + C - 1 => E + %ARRAY_BASE_MINUS_ONE :MSTORE(array_square_in + E) + E - 1 => E + array_square_wc_test_inA: + 0n :MSTORE(array_square_in + E) + E - 1 => E :JMPN(array_square_wc_test_compute,array_square_wc_test_inA) + array_square_wc_test_compute: + :CALL(array_square) + %ARRAY_MAX_LEN_DOUBLED => E :MLOAD(array_square_len_out) + E - 1 => E + %ARRAY_BASE_MINUS_TWO :MLOAD(array_square_out + E) + E - 1 => E + 1n :MLOAD(array_square_out + E) + E - 1 => E + array_square_wc_test_check: + 0n :MLOAD(array_square_out + E) + E - 1 => E :JMPN(array_square_wc_test_end,array_square_wc_test_check) + array_square_wc_test_end: ; --------------------------------------------------------------- - ; 1] [9n, 8n, 7n, 6n] / 8n - 4 => C - 1 => D - 9n :MSTORE(array_div_inA) - 1 => E - 8n :MSTORE(array_div_inA + E) - 2 => E - 7n :MSTORE(array_div_inA + E) - 3 => E - 6n :MSTORE(array_div_inA + E) - - 8n :MSTORE(array_div_inB) - :CALL(array_div) - 1n :MLOAD(array_div_quo) - 1 => E - 101318078082651670995624611882601919371611236582435493534525386006923988434945n :MLOAD(array_div_quo + E) - 2 => E - 86844066927987146567678238756515930889952488499230423029593188005934847229952n :MLOAD(array_div_quo + E) - 1n :MLOAD(array_div_rem) - 3 :MLOAD(array_div_len_quo) - - ; 2] [a, 7n, a, 12n, a, 20n, a, 80n] / a - 8 => C - 1 => D - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inA) - 1 => E - 7n :MSTORE(array_div_inA + E) - 2 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inA + E) - 3 => E - 12n :MSTORE(array_div_inA + E) - 4 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inA + E) - 5 => E - 20n :MSTORE(array_div_inA + E) - 6 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inA + E) - 7 => E - 80n :MSTORE(array_div_inA + E) - - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inB) - :CALL(array_div) - 120n :MLOAD(array_div_quo) - 1 => E - 112n :MLOAD(array_div_quo + E) - 2 => E - 113n :MLOAD(array_div_quo + E) - 3 => E - 100n :MLOAD(array_div_quo + E) - 4 => E - 101n :MLOAD(array_div_quo + E) - 5 => E - 80n :MLOAD(array_div_quo + E) - 6 => E - 81n :MLOAD(array_div_quo + E) - 119n :MLOAD(array_div_rem) - 7 :MLOAD(array_div_len_quo) - - ; 3] inA == 0, inB != 0, len(inB) == 1 - 1 => C - 1 => D - 0n :MSTORE(array_div_inA) - - 8n :MSTORE(array_div_inB) - :CALL(array_div) - 0n :MLOAD(array_div_quo) - 0n :MLOAD(array_div_rem) - 1 :MLOAD(array_div_len_quo) - - 1 => C - 1 => D - 0n :MSTORE(array_div_short_inA) - 8n :MSTORE(array_div_short_inB) - :CALL(array_div_short) - 0n :MLOAD(array_div_short_quo) - 0n :MLOAD(array_div_short_rem) - 1 :MLOAD(array_div_short_len_quo) - - ; 4] inA == 0, inB != 0, len(inB) > 1 - 1 => C - 2 => D - 0n :MSTORE(array_div_inA) - - 8n :MSTORE(array_div_inB) - 1 => E - 1n :MSTORE(array_div_inB + E) - :CALL(array_div) - 0n :MLOAD(array_div_quo) - 0n :MLOAD(array_div_rem) + ; long division + ; --------------------------------------------------------------- + ; 1] inA == 0, inB != 0, len(inB) > 1 1 => C 2 => D 0n :MSTORE(array_div_long_inA) 8n :MSTORE(array_div_long_inB) 1 => E - 8n :MSTORE(array_div_long_inB + E) + 1n :MSTORE(array_div_long_inB + E) :CALL(array_div_long) 0n :MLOAD(array_div_long_quo) 0n :MLOAD(array_div_long_rem) 1 :MLOAD(array_div_long_len_quo) + 1 :MLOAD(array_div_long_len_rem) - ; 5] inA != 0, inB == 0 -> error + ; 2] inA < inB, 1 == len(inA) < len(inB) 1 => C - 1 => D - 8n :MSTORE(array_div_long_inA) - 0n :MSTORE(array_div_long_inB) + 2 => D + 7n :MSTORE(array_div_long_inA) + 7719472615821079694904732333912527190217998977709370935963838933860875309329n :MSTORE(array_div_long_inB) + 1 => E + 17n :MSTORE(array_div_long_inB + E) :CALL(array_div_long) - 1 => A - B :ASSERT + 0n :MLOAD(array_div_long_quo) + 7n :MLOAD(array_div_long_rem) + 1 :MLOAD(array_div_long_len_quo) + 1 :MLOAD(array_div_long_len_rem) + ; 3] inA < inB, 1 < len(inA) < len(inB) 2 => C - 1 => D - 0n :MSTORE(array_div_inA) + 3 => D + 10n :MSTORE(array_div_long_inA) 1 => E - 30n :MSTORE(array_div_inA + E) - - 0n :MSTORE(array_div_inB) - :CALL(array_div) - 1 => A - B :ASSERT - - ; 6] inA == inB == 0 -> error - 1 => C - 1 => D - 0n :MSTORE(array_div_long_inA) - 0n :MSTORE(array_div_long_inB) + 30n :MSTORE(array_div_long_inA + E) + 6n :MSTORE(array_div_long_inB) + 1 => E + 7n :MSTORE(array_div_long_inB + E) + 2 => E + 8n :MSTORE(array_div_long_inB + E) :CALL(array_div_long) - 1 => A - B :ASSERT - - 1 => C - 1 => D - 0n :MSTORE(array_div_short_inA) - 0n :MSTORE(array_div_short_inB) - :CALL(array_div_short) - 1 => A - B :ASSERT - - ; 7] inA == inB - 1 => C - 1 => D - 10n :MSTORE(array_div_inA) - 10n :MSTORE(array_div_inB) - :CALL(array_div) - 1n :MLOAD(array_div_quo) - 0n :MLOAD(array_div_rem) - 1 :MLOAD(array_div_len_quo) + 0n :MLOAD(array_div_long_quo) + 10n :MLOAD(array_div_long_rem) + 1 => E + 30n :MSTORE(array_div_long_rem + E) + 1n :MLOAD(array_div_long_len_quo) + 2n :MLOAD(array_div_long_len_rem) + ; 4] inA == inB, len(inA),len(inB) > 1 2 => C 2 => D - 10n :MSTORE(array_div_inA) - 1 => E - 30n :MSTORE(array_div_inA + E) - - 10n :MSTORE(array_div_inB) - 1 => E - 30n :MSTORE(array_div_inB + E) - :CALL(array_div) - 1n :MLOAD(array_div_quo) - 0n :MLOAD(array_div_rem) - - 1 => C - 1 => D 10n :MSTORE(array_div_long_inA) + 1 => E + 30n :MSTORE(array_div_long_inA + E) 10n :MSTORE(array_div_long_inB) + 1 => E + 30n :MSTORE(array_div_long_inB + E) :CALL(array_div_long) 1n :MLOAD(array_div_long_quo) 0n :MLOAD(array_div_long_rem) 1 :MLOAD(array_div_long_len_quo) + 1 :MLOAD(array_div_long_len_rem) - 1 => C - 1 => D - 10n :MSTORE(array_div_short_inA) - 10n :MSTORE(array_div_short_inB) - :CALL(array_div_short) - 1n :MLOAD(array_div_short_quo) - 0n :MLOAD(array_div_short_rem) - 1 :MLOAD(array_div_short_len_quo) - - ; 8] inA < inB - 1 => C - 1 => D - 10n :MSTORE(array_div_inA) - 11n :MSTORE(array_div_inB) - :CALL(array_div) - 0n :MLOAD(array_div_quo) - 10n :MLOAD(array_div_rem) - 1 :MLOAD(array_div_len_quo) - + ; 5] inA == k·inB, len(inA),len(inB) > 1 2 => C - 3 => D - 10n :MSTORE(array_div_inA) - 1 => E - 30n :MSTORE(array_div_inA + E) - - 6n :MSTORE(array_div_inB) + 2 => D + 4n :MSTORE(array_div_long_inA) 1 => E - 7n :MSTORE(array_div_inB + E) - 2 => E - 8n :MSTORE(array_div_inB + E) - :CALL(array_div) - 0n :MLOAD(array_div_quo) - 10n :MLOAD(array_div_rem) + 4n :MSTORE(array_div_long_inA + E) + 2n :MSTORE(array_div_long_inB) 1 => E - 30n :MSTORE(array_div_rem + E) - - 1 => C - 1 => D - 10n :MSTORE(array_div_long_inA) - 11n :MSTORE(array_div_long_inB) + 2n :MSTORE(array_div_long_inB + E) :CALL(array_div_long) - 0n :MLOAD(array_div_long_quo) - 10n :MLOAD(array_div_long_rem) + 2n :MLOAD(array_div_long_quo) + 0n :MLOAD(array_div_long_rem) 1 :MLOAD(array_div_long_len_quo) + 1 :MLOAD(array_div_long_len_rem) - 1 => C - 1 => D - 10n :MSTORE(array_div_short_inA) - 11n :MSTORE(array_div_short_inB) - :CALL(array_div_short) - 0n :MLOAD(array_div_short_quo) - 10n :MLOAD(array_div_short_rem) - 1 :MLOAD(array_div_short_len_quo) - - ; 9] [28948022309329048855892746252171976963317496166410141009864396001978282409984n, 1n] / 2 - 2 => C - 1 => D - 28948022309329048855892746252171976963317496166410141009864396001978282409984n :MSTORE(array_div_inA) - 1 => E - 1n :MSTORE(array_div_inA + E) - - 2n :MSTORE(array_div_inB) - :CALL(array_div) - 72370055773322622139731865630429942408293740416025352524660990004945706024960n :MLOAD(array_div_quo) - 1 :MLOAD(array_div_len_quo) - - ; 10] [72370055773322622139731865630429942408293740416025352524660990004945706024960n] / 2 - 1 => C - 1 => D - 72370055773322622139731865630429942408293740416025352524660990004945706024960n :MSTORE(array_div_inA) - 2n :MSTORE(array_div_inB) - :CALL(array_div) - 36185027886661311069865932815214971204146870208012676262330495002472853012480n :MLOAD(array_div_quo) - 1 :MLOAD(array_div_len_quo) - - ; 11] len(inB) = len(inA) and inB > inA + ; 6] inA > inB, len(inA) > len(inB) > 1 4 => C 2 => D - 9n :MSTORE(array_div_inA) + 9n :MSTORE(array_div_long_inA) 1 => E - 8n :MSTORE(array_div_inA + E) + 8n :MSTORE(array_div_long_inA + E) 2 => E - 7n :MSTORE(array_div_inA + E) + 7n :MSTORE(array_div_long_inA + E) 3 => E - 6n :MSTORE(array_div_inA + E) - - 8n :MSTORE(array_div_inB) + 6n :MSTORE(array_div_long_inA + E) + 8n :MSTORE(array_div_long_inB) 1 => E - 1n :MSTORE(array_div_inB + E) - :CALL(array_div) - 335n :MLOAD(array_div_quo) + 1n :MSTORE(array_div_long_inB + E) + :CALL(array_div_long) + 335n :MLOAD(array_div_long_quo) 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639895n :MLOAD(array_div_quo + E) + 115792089237316195423570985008687907853269984665640564039457584007913129639895n :MLOAD(array_div_long_quo + E) 2 => E - 5n :MLOAD(array_div_quo + E) - 115792089237316195423570985008687907853269984665640564039457584007913129637265n :MLOAD(array_div_rem) + 5n :MLOAD(array_div_long_quo + E) + 115792089237316195423570985008687907853269984665640564039457584007913129637265n :MLOAD(array_div_long_rem) + 3 :MLOAD(array_div_long_len_quo) + 1 :MLOAD(array_div_long_len_rem) - ; 12] [a, 7n, a, 12n, a, 20n, a, 80n] / [a, a, a, a, 100n] + ; 7] [2**256-1, 7n, 2**256-1, 12n, 2**256-1, 20n, 2**256-1, 80n] / [2**256-1, 2**256-1, 2**256-1, 2**256-1, 100n] 8 => C 5 => D - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inA) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inA) 1 => E - 7n :MSTORE(array_div_inA + E) + 7n :MSTORE(array_div_long_inA + E) 2 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inA + E) 3 => E - 12n :MSTORE(array_div_inA + E) + 12n :MSTORE(array_div_long_inA + E) 4 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inA + E) 5 => E - 20n :MSTORE(array_div_inA + E) + 20n :MSTORE(array_div_long_inA + E) 6 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inA + E) 7 => E - 80n :MSTORE(array_div_inA + E) - - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inB) + 80n :MSTORE(array_div_long_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inB) 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inB + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inB + E) 2 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inB + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inB + E) 3 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inB + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inB + E) 4 => E - 100n :MSTORE(array_div_inB + E) - :CALL(array_div) - 87130681010257731209815790699606742543054641926620622445532439451498988639951n :MLOAD(array_div_quo) + 100n :MSTORE(array_div_long_inB + E) + :CALL(array_div_long) + 87130681010257731209815790699606742543054641926620622445532439451498988639951n :MLOAD(array_div_long_quo) 1 => E - 76812574048516684092863920748337523031377118540573443471719387411189897879957n :MLOAD(array_div_quo + E) + 76812574048516684092863920748337523031377118540573443471719387411189897879957n :MLOAD(array_div_long_quo + E) 2 => E - 92862962655669424052566829561422975605097710474424610764317468362781816839948n :MLOAD(array_div_quo + E) - 87130681010257731209815790699606742543054641926620622445532439451498988639950n :MLOAD(array_div_rem) + 92862962655669424052566829561422975605097710474424610764317468362781816839948n :MLOAD(array_div_long_quo + E) + 87130681010257731209815790699606742543054641926620622445532439451498988639950n :MLOAD(array_div_long_rem) 1 => E - 76812574048516684092863920748337523031377118540573443471719387411189897879965n :MLOAD(array_div_rem + E) + 76812574048516684092863920748337523031377118540573443471719387411189897879965n :MLOAD(array_div_long_rem + E) 2 => E - 92862962655669424052566829561422975605097710474424610764317468362781816839947n :MLOAD(array_div_rem + E) + 92862962655669424052566829561422975605097710474424610764317468362781816839947n :MLOAD(array_div_long_rem + E) 3 => E - 13n :MLOAD(array_div_rem + E) + 13n :MLOAD(array_div_long_rem + E) 4 => E - 84n :MLOAD(array_div_rem + E) + 84n :MLOAD(array_div_long_rem + E) + 3 :MLOAD(array_div_long_len_quo) + 5 :MLOAD(array_div_long_len_rem) - ; 13] [82987931714326364316120253427931880709278140571418487333162713377057429160720n,4257238595720679277571917967782652353394431698489248379634099239588181418140n,15209178211456919413336795740141505754388379695813905932093982440742677791802n,88987534839350135473536361176867192550264928852523682165693061442019881855583n,14n], [4n, 6n, 7n] + ; 8] [82987931714326364316120253427931880709278140571418487333162713377057429160720n,4257238595720679277571917967782652353394431698489248379634099239588181418140n,15209178211456919413336795740141505754388379695813905932093982440742677791802n,88987534839350135473536361176867192550264928852523682165693061442019881855583n,14n], [4n, 6n, 7n] 5 => C 3 => D - 82987931714326364316120253427931880709278140571418487333162713377057429160720n :MSTORE(array_div_inA) + 82987931714326364316120253427931880709278140571418487333162713377057429160720n :MSTORE(array_div_long_inA) 1 => E - 4257238595720679277571917967782652353394431698489248379634099239588181418140n :MSTORE(array_div_inA + E) + 4257238595720679277571917967782652353394431698489248379634099239588181418140n :MSTORE(array_div_long_inA + E) 2 => E - 15209178211456919413336795740141505754388379695813905932093982440742677791802n :MSTORE(array_div_inA + E) + 15209178211456919413336795740141505754388379695813905932093982440742677791802n :MSTORE(array_div_long_inA + E) 3 => E - 88987534839350135473536361176867192550264928852523682165693061442019881855583n :MSTORE(array_div_inA + E) + 88987534839350135473536361176867192550264928852523682165693061442019881855583n :MSTORE(array_div_long_inA + E) 4 => E - 14n :MSTORE(array_div_inA + E) - - 4n :MSTORE(array_div_inB) + 14n :MSTORE(array_div_long_inA + E) + 4n :MSTORE(array_div_long_inB) 1 => E - 6n :MSTORE(array_div_inB + E) + 6n :MSTORE(array_div_long_inB + E) 2 => E - 7n :MSTORE(array_div_inB + E) - :CALL(array_div) - 90526669110436282262084097418054683975846294708417529350769755852355732618090n :MLOAD(array_div_quo) + 7n :MSTORE(array_div_long_inB + E) + :CALL(array_div_long) + 90526669110436282262084097418054683975846294708417529350769755852355732618090n :MLOAD(array_div_long_quo) 1 => E - 12712504977050019353362337310981027507180704121789097452241865920288554550795n :MLOAD(array_div_quo + E) + 12712504977050019353362337310981027507180704121789097452241865920288554550795n :MLOAD(array_div_long_quo + E) 2 => E - 2n :MLOAD(array_div_quo + E) - 68257522984529821538496818781776868365702915734670062048456441991373887608168n :MLOAD(array_div_rem) + 2n :MLOAD(array_div_long_quo + E) + 68257522984529821538496818781776868365702915734670062048456441991373887608168n :MLOAD(array_div_long_rem) 1 => E - 104999739448800080833043894267657885589213754954671066702793604491778345346033n :MSTORE(array_div_rem + E) + 104999739448800080833043894267657885589213754954671066702793604491778345346033n :MSTORE(array_div_long_rem + E) 2 => E - 4n :MSTORE(array_div_rem + E) - 3 :MLOAD(array_div_len_quo) - 3 :MLOAD(array_div_len_rem) + 4n :MSTORE(array_div_long_rem + E) + 3 :MLOAD(array_div_long_len_quo) + 3 :MLOAD(array_div_long_len_rem) - ; 14] [0n,0n,0n,0n,87552057494100699607633960453116574392480272162273084008350826812719088235449n,29405388739667337424543497575767709934732594998639086405406332616399343873602n,370491411790392985199n], [0n, 0n, 8238129386n, 23102318237n] + ; 9] [0n,0n,0n,0n,87552057494100699607633960453116574392480272162273084008350826812719088235449n,29405388739667337424543497575767709934732594998639086405406332616399343873602n,370491411790392985199n], [0n, 0n, 8238129386n, 23102318237n] 7 => C 4 => D - 0n :MSTORE(array_div_inA) + 0n :MSTORE(array_div_long_inA) 1 => E - 0n :MSTORE(array_div_inA + E) + 0n :MSTORE(array_div_long_inA + E) 2 => E - 0n :MSTORE(array_div_inA + E) + 0n :MSTORE(array_div_long_inA + E) 3 => E - 0n :MSTORE(array_div_inA + E) + 0n :MSTORE(array_div_long_inA + E) 4 => E - 87552057494100699607633960453116574392480272162273084008350826812719088235449n :MSTORE(array_div_inA + E) + 87552057494100699607633960453116574392480272162273084008350826812719088235449n :MSTORE(array_div_long_inA + E) 5 => E - 29405388739667337424543497575767709934732594998639086405406332616399343873602n :MSTORE(array_div_inA + E) + 29405388739667337424543497575767709934732594998639086405406332616399343873602n :MSTORE(array_div_long_inA + E) 6 => E - 370491411790392985199n :MSTORE(array_div_inA + E) - - 0n :MSTORE(array_div_inB) + 370491411790392985199n :MSTORE(array_div_long_inA + E) + 0n :MSTORE(array_div_long_inB) 1 => E - 0n :MSTORE(array_div_inB + E) + 0n :MSTORE(array_div_long_inB + E) 2 => E - 8238129386n :MSTORE(array_div_inB + E) + 8238129386n :MSTORE(array_div_long_inB + E) 3 => E - 23102318237n :MSTORE(array_div_inB + E) - :CALL(array_div) - 10624890954144362706283399919870985530330343554129711486796784890935496833177n :MLOAD(array_div_quo) + 23102318237n :MSTORE(array_div_long_inB + E) + :CALL(array_div_long) + 10624890954144362706283399919870985530330343554129711486796784890935496833177n :MLOAD(array_div_long_quo) 1 => E - 12699239907746414269759600684072701206520647567004427767570235373004025148518n :MLOAD(array_div_quo + E) + 12699239907746414269759600684072701206520647567004427767570235373004025148518n :MLOAD(array_div_long_quo + E) 2 => E - 62973947849727744055941265906651873030488901951864462234513788026171769471385n :MLOAD(array_div_quo + E) + 62973947849727744055941265906651873030488901951864462234513788026171769471385n :MLOAD(array_div_long_quo + E) 3 => E - 16036979838n :MLOAD(array_div_quo + E) - 0n :MLOAD(array_div_rem) + 16036979838n :MLOAD(array_div_long_quo + E) + 0n :MLOAD(array_div_long_rem) 1 => E - 0n :MSTORE(array_div_rem + E) + 0n :MSTORE(array_div_long_rem + E) 2 => E - 43811746908501644357293832343774991028053014234938611947183500936834952782886n :MSTORE(array_div_rem + E) + 43811746908501644357293832343774991028053014234938611947183500936834952782886n :MSTORE(array_div_long_rem + E) 3 => E - 6019321230n :MSTORE(array_div_rem + E) - 4 :MLOAD(array_div_len_quo) - 4 :MLOAD(array_div_len_rem) - - ; 15] [7n], [7719472615821079694904732333912527190217998977709370935963838933860875309329n, 17n] - 1 => C - 2 => D - 7n :MSTORE(array_div_inA) - 7719472615821079694904732333912527190217998977709370935963838933860875309329n :MSTORE(array_div_inB) - 1 => E - 17n :MSTORE(array_div_inB + E) - :CALL(array_div) - 0n :MLOAD(array_div_quo) - 7n :MLOAD(array_div_rem) - 1 :MLOAD(array_div_len_quo) - 1 :MLOAD(array_div_len_rem) + 6019321230n :MSTORE(array_div_long_rem + E) + 4 :MLOAD(array_div_long_len_quo) + 4 :MLOAD(array_div_long_len_rem) - ; 16] [9,12,16,2,0,2**256-4], [2**256-1,2**256-1] + ; 10] [9,12,16,2,0,2**256-4], [2**256-1,2**256-1] 6 => C 2 => D - 9n :MSTORE(array_div_inA) - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inB) + 9n :MSTORE(array_div_long_inA) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inB) 1 => E - 12n :MSTORE(array_div_inA + E) - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_div_inB + E) + 12n :MSTORE(array_div_long_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inB + E) 2 => E - 16n :MSTORE(array_div_inA + E) + 16n :MSTORE(array_div_long_inA + E) 3 => E - 2n :MSTORE(array_div_inA + E) + 2n :MSTORE(array_div_long_inA + E) 4 => E - 0n :MSTORE(array_div_inA + E) + 0n :MSTORE(array_div_long_inA + E) 5 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639932n :MSTORE(array_div_inA + E) - :CALL(array_div) - 4 :MLOAD(array_div_len_quo) - 2 :MLOAD(array_div_len_rem) - 17n :MLOAD(array_div_quo) - 26n :MLOAD(array_div_rem) - 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639934n :MLOAD(array_div_quo + E) - 10n :MLOAD(array_div_rem + E) + 115792089237316195423570985008687907853269984665640564039457584007913129639932n :MSTORE(array_div_long_inA + E) + :CALL(array_div_long) + 17n :MLOAD(array_div_long_quo) + 26n :MLOAD(array_div_long_rem) + 1 => E + 115792089237316195423570985008687907853269984665640564039457584007913129639934n :MLOAD(array_div_long_quo + E) + 10n :MLOAD(array_div_long_rem + E) 2 => E - 0n :MLOAD(array_div_quo + E) + 0n :MLOAD(array_div_long_quo + E) 3 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639932n :MLOAD(array_div_quo + E) + 115792089237316195423570985008687907853269984665640564039457584007913129639932n :MLOAD(array_div_long_quo + E) + 4 :MLOAD(array_div_long_len_quo) + 2 :MLOAD(array_div_long_len_rem) + + ; 11] [2**256-1]*%ARRAY_MAX_LEN_DOUBLED / [1,1] + %ARRAY_MAX_LEN_DOUBLED => C + 2 => D + C - 1 => E + D - 1 => RR + array_div_long_wc1_test_inA: + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inA + E) + E - 1 => E :JMPN(array_div_long_wc1_test_inB,array_div_long_wc1_test_inA) + array_div_long_wc1_test_inB: + 1n :MSTORE(array_div_long_inB + RR) + RR - 1 => RR :JMPN(array_div_long_wc1_test_compute,array_div_long_wc1_test_inB) + array_div_long_wc1_test_compute: + :CALL(array_div_long) + %ARRAY_MAX_LEN_DOUBLED_MINUS_ONE => E :MLOAD(array_div_long_len_quo) + 1 :MLOAD(array_div_long_len_rem) + E - 1 => E + %ARRAY_BASE_MINUS_ONE :MLOAD(array_div_long_quo + E) + E - 1 => E + array_div_long_wc1_test_check1: + 0n :MLOAD(array_div_long_quo + E) + E - 1 => E :JMPN(array_div_long_wc1_test_check2) + %ARRAY_BASE_MINUS_ONE :MLOAD(array_div_long_quo + E) + E - 1 => E :JMPN(array_div_long_wc1_test_check2,array_div_long_wc1_test_check1) + array_div_long_wc1_test_check2: + 0n :MLOAD(array_div_long_rem) + + ; 12] [2**256-1]*%ARRAY_MAX_LEN_DOUBLED / [1]*%ARRAY_MAX_LEN + %ARRAY_MAX_LEN_DOUBLED => C + %ARRAY_MAX_LEN => D + C - 1 => E + D - 1 => RR + array_div_long_wc2_test_inA: + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inA + E) + E - 1 => E :JMPN(array_div_long_wc2_test_inB,array_div_long_wc2_test_inA) + array_div_long_wc2_test_inB: + 1n :MSTORE(array_div_long_inB + RR) + RR - 1 => RR :JMPN(array_div_long_wc2_test_compute,array_div_long_wc2_test_inB) + array_div_long_wc2_test_compute: + :CALL(array_div_long) + %ARRAY_MAX_LEN_PLUS_ONE => E :MLOAD(array_div_long_len_quo) + 1 :MLOAD(array_div_long_len_rem) + E - 1 => E + %ARRAY_BASE_MINUS_ONE :MLOAD(array_div_long_quo + E) + E - 1 => E + array_div_long_wc2_test_check1: + 0n :MLOAD(array_div_long_quo + E) + E - 1 => E :JMPZ(array_div_long_wc2_test_check2,array_div_long_wc2_test_check1) + array_div_long_wc2_test_check2: + %ARRAY_BASE_MINUS_ONE :MLOAD(array_div_long_quo + E) + 0n :MLOAD(array_div_long_rem) + + ; 13] [2**256-2]*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE || [2**256-1] / [1]*%ARRAY_MAX_LEN + %ARRAY_MAX_LEN_DOUBLED => C + %ARRAY_MAX_LEN => D + C - 1 => E + D - 1 => RR + array_div_long_wc3_test_inA: + %ARRAY_BASE_MINUS_TWO :MSTORE(array_div_long_inA + E) + E - 1 => E :JMPZ(array_div_long_wc3_test_inA_part2,array_div_long_wc3_test_inA) + array_div_long_wc3_test_inA_part2: + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inA + E) + array_div_long_wc3_test_inB: + 1n :MSTORE(array_div_long_inB + RR) + RR - 1 => RR :JMPN(array_div_long_wc3_test_compute,array_div_long_wc3_test_inB) + array_div_long_wc3_test_compute: + :CALL(array_div_long) + %ARRAY_MAX_LEN_PLUS_ONE => E :MLOAD(array_div_long_len_quo) + 1 :MLOAD(array_div_long_len_rem) + E - 1 => E + %ARRAY_BASE_MINUS_TWO :MLOAD(array_div_long_quo + E) + E - 1 => E + array_div_long_wc3_test_check1: + 0n :MLOAD(array_div_long_quo + E) + E - 1 => E :JMPZ(array_div_long_wc3_test_check2,array_div_long_wc3_test_check1) + array_div_long_wc3_test_check2: + %ARRAY_BASE_MINUS_TWO :MLOAD(array_div_long_quo + E) + 1n :MLOAD(array_div_long_rem) + + ; 14] [2**256-2]*%ARRAY_MAX_LEN_DOUBLED_MINUS_TWO || [2**256-1, 2**256-1] / [2]*%ARRAY_MAX_LEN + %ARRAY_MAX_LEN_DOUBLED => C + %ARRAY_MAX_LEN => D + C - 1 => E + D - 1 => RR + array_div_long_wc4_test_inA: + %ARRAY_BASE_MINUS_TWO :MSTORE(array_div_long_inA + E) + E - 1 => E + E - 1 :JMPZ(array_div_long_wc4_test_inA_part2,array_div_long_wc4_test_inA) + array_div_long_wc4_test_inA_part2: + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_long_inA) + array_div_long_wc4_test_inB: + 2n :MSTORE(array_div_long_inB + RR) + RR - 1 => RR :JMPN(array_div_long_wc4_test_compute,array_div_long_wc4_test_inB) + array_div_long_wc4_test_compute: + :CALL(array_div_long) + %ARRAY_MAX_LEN_PLUS_ONE => E :MLOAD(array_div_long_len_quo) + 2 :MLOAD(array_div_long_len_rem) + E - 1 => E + %ARRAY_BASE_HALF_MINUS_ONE :MLOAD(array_div_long_quo + E) + E - 1 => E + array_div_long_wc4_test_check1: + 0n :MLOAD(array_div_long_quo + E) + E - 1 => E :JMPZ(array_div_long_wc4_test_check2,array_div_long_wc4_test_check1) + array_div_long_wc4_test_check2: + %ARRAY_BASE_HALF_MINUS_ONE :MLOAD(array_div_long_quo + E) + 1 => E + 1n :MLOAD(array_div_long_rem + E) + 1n :MLOAD(array_div_long_rem) ; --------------------------------------------------------------- - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ;; UNUSED - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ; addition + ; short division ; --------------------------------------------------------------- - ; 1] len(inA) = len(inB) - 3 => C - 3 => D - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_inA) - 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_inA + E) - 2 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_inA + E) - - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_inB) - 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_inB + E) - 2 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_inB + E) - :CALL(array_add) - 115792089237316195423570985008687907853269984665640564039457584007913129639934n :MLOAD(array_add_out) - 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MLOAD(array_add_out + E) - 2 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MLOAD(array_add_out + E) - 3 => E - 1n :MLOAD(array_add_out + E) - 4 :MLOAD(array_add_len_out) + ; 1] inA == 0, inB != 0 + 1 => C + 1 => D + 0n :MSTORE(array_div_short_inA) + 8n :MSTORE(array_div_short_inB) + :CALL(array_div_short) + 0n :MLOAD(array_div_short_quo) + 0n :MLOAD(array_div_short_rem) + 1 :MLOAD(array_div_short_len_quo) - ; 2] len(inA) = len(inB) + 1 - 3 => C - 2 => D - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_inA) - 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_inA + E) - 2 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_inA + E) + ; 2] inA < inB + 1 => C + 1 => D + 10n :MSTORE(array_div_short_inA) + 11n :MSTORE(array_div_short_inB) + :CALL(array_div_short) + 0n :MLOAD(array_div_short_quo) + 10n :MLOAD(array_div_short_rem) + 1 :MLOAD(array_div_short_len_quo) - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_inB) - 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(array_add_inB + E) - :CALL(array_add) - 115792089237316195423570985008687907853269984665640564039457584007913129639934n :MLOAD(array_add_out) - 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MLOAD(array_add_out + E) - 2 => E - 0n :MLOAD(array_add_out + E) - 3 => E - 1n :MLOAD(array_add_out + E) - 4 :MLOAD(array_add_len_out) + ; 3] inA == inB + 1 => C + 1 => D + 10n :MSTORE(array_div_short_inA) + 10n :MSTORE(array_div_short_inB) + :CALL(array_div_short) + 1n :MLOAD(array_div_short_quo) + 0n :MLOAD(array_div_short_rem) + 1 :MLOAD(array_div_short_len_quo) - ; 3] len(inA) = len(inB) + 3 - 7 => C - 4 => D - 0n :MSTORE(array_add_inA) - 1 => E - 0n :MSTORE(array_add_inA + E) - 2 => E - 71980342328814551066277152664912916825216970430701952092274083071078176857050n :MSTORE(array_add_inA + E) - 3 => E - 115792089237316195423570985008687907853269984665640564039457584007907110318705n :MSTORE(array_add_inA + E) - 4 => E - 87552057494100699607633960453116574392480272162273084008350826812719088235448n :MSTORE(array_add_inA + E) - 5 => E - 29405388739667337424543497575767709934732594998639086405406332616399343873602n :MSTORE(array_add_inA + E) - 6 => E - 370491411790392985199n :MSTORE(array_add_inA + E) + ; 4] inA = k·inB + 1 => C + 1 => D + 4n :MSTORE(array_div_short_inA) + 2n :MSTORE(array_div_short_inB) + :CALL(array_div_short) + 2n :MLOAD(array_div_short_quo) + 0n :MLOAD(array_div_short_rem) + 1 :MLOAD(array_div_short_len_quo) - 0n :MSTORE(array_add_inB) - 1 => E - 0n :MSTORE(array_add_inB + E) - 2 => E - 43811746908501644357293832343774991028053014234938611947183500936834952782886n :MSTORE(array_add_inB + E) - 3 => E - 6019321230n :MSTORE(array_add_inB + E) - :CALL(array_add) - 0n :MLOAD(array_add_out) + ; 5] [9n, 8n, 7n, 6n] / 8n + 4 => C + 1 => D + 9n :MSTORE(array_div_short_inA) 1 => E - 0n :MLOAD(array_add_out + E) + 8n :MSTORE(array_div_short_inA + E) 2 => E - 0n :MLOAD(array_add_out + E) + 7n :MSTORE(array_div_short_inA + E) 3 => E - 0n :MLOAD(array_add_out + E) - 4 => E - 87552057494100699607633960453116574392480272162273084008350826812719088235449n :MLOAD(array_add_out + E) - 5 => E - 29405388739667337424543497575767709934732594998639086405406332616399343873602n :MLOAD(array_add_out + E) - 6 => E - 370491411790392985199n :MLOAD(array_add_out + E) - 7 :MLOAD(array_add_len_out) - - ; 4] len(inA) = len(inB) - 3 - 4 => C - 7 => D - 0n :MSTORE(array_add_inA) + 6n :MSTORE(array_div_short_inA + E) + 8n :MSTORE(array_div_short_inB) + :CALL(array_div_short) + 1n :MLOAD(array_div_short_quo) 1 => E - 0n :MSTORE(array_add_inA + E) + 101318078082651670995624611882601919371611236582435493534525386006923988434945n :MLOAD(array_div_short_quo + E) 2 => E - 43811746908501644357293832343774991028053014234938611947183500936834952782886n :MSTORE(array_add_inA + E) - 3 => E - 6019321230n :MSTORE(array_add_inA + E) + 86844066927987146567678238756515930889952488499230423029593188005934847229952n :MLOAD(array_div_short_quo + E) + 1n :MLOAD(array_div_short_rem) + 3 :MLOAD(array_div_short_len_quo) - 0n :MSTORE(array_add_inB) + ; 6] [2**256-1, 7n, 2**256-1, 12n, 2**256-1, 20n, 2**256-1, 80n] / 2**256-1 + 8 => C + 1 => D + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_short_inA) 1 => E - 0n :MSTORE(array_add_inB + E) + 7n :MSTORE(array_div_short_inA + E) 2 => E - 71980342328814551066277152664912916825216970430701952092274083071078176857050n :MSTORE(array_add_inB + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_short_inA + E) 3 => E - 115792089237316195423570985008687907853269984665640564039457584007907110318705n :MSTORE(array_add_inB + E) + 12n :MSTORE(array_div_short_inA + E) 4 => E - 87552057494100699607633960453116574392480272162273084008350826812719088235448n :MSTORE(array_add_inB + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_short_inA + E) 5 => E - 29405388739667337424543497575767709934732594998639086405406332616399343873602n :MSTORE(array_add_inB + E) + 20n :MSTORE(array_div_short_inA + E) 6 => E - 370491411790392985199n :MSTORE(array_add_inB + E) - :CALL(array_add) - 0n :MLOAD(array_add_out) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_short_inA + E) + 7 => E + 80n :MSTORE(array_div_short_inA + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_short_inB) + :CALL(array_div_short) + 120n :MLOAD(array_div_short_quo) 1 => E - 0n :MLOAD(array_add_out + E) + 112n :MLOAD(array_div_short_quo + E) 2 => E - 0n :MLOAD(array_add_out + E) + 113n :MLOAD(array_div_short_quo + E) 3 => E - 0n :MLOAD(array_add_out + E) + 100n :MLOAD(array_div_short_quo + E) 4 => E - 87552057494100699607633960453116574392480272162273084008350826812719088235449n :MLOAD(array_add_out + E) + 101n :MLOAD(array_div_short_quo + E) 5 => E - 29405388739667337424543497575767709934732594998639086405406332616399343873602n :MLOAD(array_add_out + E) + 80n :MLOAD(array_div_short_quo + E) 6 => E - 370491411790392985199n :MLOAD(array_add_out + E) - 7 :MLOAD(array_add_len_out) - ; --------------------------------------------------------------- - - ; subtraction with len(inA) >= len(inB) - ; --------------------------------------------------------------- - ; 1] len(inA) > len(inB) and inA_i >= inb_i for all i - 3 => C - 2 => D - 5n :MSTORE(array_sub_AGTB_inA) - 1 => E - 6n :MSTORE(array_sub_AGTB_inA + E) - 2 => E - 7n :MSTORE(array_sub_AGTB_inA + E) + 81n :MLOAD(array_div_short_quo + E) + 119n :MLOAD(array_div_short_rem) + 7 :MLOAD(array_div_short_len_quo) - 2n :MSTORE(array_sub_AGTB_inB) - 1 => E - 3n :MSTORE(array_sub_AGTB_inB + E) - :CALL(array_sub_AGTB) - 3n :MLOAD(array_sub_AGTB_out) + ; 7] [28948022309329048855892746252171976963317496166410141009864396001978282409984n, 1n] / 2 + 2 => C + 1 => D + 28948022309329048855892746252171976963317496166410141009864396001978282409984n :MSTORE(array_div_short_inA) 1 => E - 3n :MLOAD(array_sub_AGTB_out + E) - 2 => E - 7n :MLOAD(array_sub_AGTB_out + E) + 1n :MSTORE(array_div_short_inA + E) - ; 2] len(inA) > len(inB) and inA_i < inb_i for some i - 3 => C - 2 => D - 5n :MSTORE(array_sub_AGTB_inA) - 1 => E - 6n :MSTORE(array_sub_AGTB_inA + E) - 2 => E - 7n :MSTORE(array_sub_AGTB_inA + E) + 2n :MSTORE(array_div_short_inB) + :CALL(array_div_short) + 72370055773322622139731865630429942408293740416025352524660990004945706024960n :MLOAD(array_div_short_quo) + 1 :MLOAD(array_div_short_len_quo) - 6n :MSTORE(array_sub_AGTB_inB) - 1 => E - 3n :MSTORE(array_sub_AGTB_inB + E) - :CALL(array_sub_AGTB) - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MLOAD(array_sub_AGTB_out) - 1 => E - 2n :MLOAD(array_sub_AGTB_out + E) - 2 => E - 7n :MLOAD(array_sub_AGTB_out + E) + ; 8] [72370055773322622139731865630429942408293740416025352524660990004945706024960n] / 2 + 1 => C + 1 => D + 72370055773322622139731865630429942408293740416025352524660990004945706024960n :MSTORE(array_div_short_inA) + 2n :MSTORE(array_div_short_inB) + :CALL(array_div_short) + 36185027886661311069865932815214971204146870208012676262330495002472853012480n :MLOAD(array_div_short_quo) + 1 :MLOAD(array_div_short_len_quo) - ; 3] len(inA) > len(inB) and inA_i < inB_i for all i lower than len(inA) - 3 => C - 2 => D - 5n :MSTORE(array_sub_AGTB_inA) - 1 => E - 1n :MSTORE(array_sub_AGTB_inA + E) - 2 => E - 7n :MSTORE(array_sub_AGTB_inA + E) + ; 9] [2**256-2]*%ARRAY_MAX_LEN / [2] + %ARRAY_MAX_LEN => C + C - 1 => E + array_div_short_wc_test_inA: + %ARRAY_BASE_MINUS_TWO :MSTORE(array_div_short_inA + E) + E - 1 => E :JMPN(array_div_short_wc_test_compute,array_div_short_wc_test_inA) + array_div_short_wc_test_compute: + 2n :MSTORE(array_div_short_inB) + :CALL(array_div_short) + %ARRAY_MAX_LEN => E :MLOAD(array_div_short_len_quo) + E - 1 => E + array_div_short_wc_test_check1: + %ARRAY_BASE_HALF_MINUS_ONE :MLOAD(array_div_short_quo + E) + E - 1 => E :JMPN(array_div_short_wc_test_check2,array_div_short_wc_test_check1) + array_div_short_wc_test_check2: + 0n :MLOAD(array_div_short_rem) + + ; 10] [1]*%ARRAY_MAX_LEN / [2] + %ARRAY_MAX_LEN => C + C - 1 => E + array_div_short_wc2_test_inA: + 1n :MSTORE(array_div_short_inA + E) + E - 1 => E :JMPN(array_div_short_wc2_test_compute,array_div_short_wc2_test_inA) + array_div_short_wc2_test_compute: + 2n :MSTORE(array_div_short_inB) + :CALL(array_div_short) + %ARRAY_MAX_LEN_MINUS_ONE => E :MLOAD(array_div_short_len_quo) + E - 1 => E + array_div_short_wc2_test_check1: + %ARRAY_BASE_HALF :MLOAD(array_div_short_quo + E) + E - 1 => E :JMPN(array_div_short_wc2_test_check2,array_div_short_wc2_test_check1) + array_div_short_wc2_test_check2: + 1n :MLOAD(array_div_short_rem) + + ; 11] [2**256-2]*%ARRAY_MAX_LEN_MINUS_ONE || [2**256-1] / [2] + %ARRAY_MAX_LEN => C + C - 1 => E + array_div_short_wc3_test_inA: + %ARRAY_BASE_MINUS_TWO :MSTORE(array_div_short_inA + E) + E - 1 => E :JMPZ(array_div_short_wc3_test_inA_part2,array_div_short_wc3_test_inA) + array_div_short_wc3_test_inA_part2: + %ARRAY_BASE_MINUS_ONE :MSTORE(array_div_short_inA + E) + array_div_short_wc3_test_inB: + 2n :MSTORE(array_div_short_inB) + :CALL(array_div_short) + %ARRAY_MAX_LEN => E :MLOAD(array_div_short_len_quo) + E - 1 => E + array_div_short_wc3_test_check1: + %ARRAY_BASE_HALF_MINUS_ONE :MLOAD(array_div_short_quo + E) + E - 1 => E :JMPZ(array_div_short_wc3_test_check2,array_div_short_wc3_test_check1) + array_div_short_wc3_test_check2: + %ARRAY_BASE_HALF_MINUS_ONE :MLOAD(array_div_short_quo + E) + 1n :MLOAD(array_div_short_rem) + ; --------------------------------------------------------------- - 6n :MSTORE(array_sub_AGTB_inB) - 1 => E - 8n :MSTORE(array_sub_AGTB_inB + E) - :CALL(array_sub_AGTB) - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MLOAD(array_sub_AGTB_out) - 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639928n :MLOAD(array_sub_AGTB_out + E) - 2 => E - 6n :MLOAD(array_sub_AGTB_out + E) + ; division by two + ; --------------------------------------------------------------- + ; 1] [0n] + 1 => C + 0n :MSTORE(array_div_two_in) + :CALL(array_div_two) + 0n :MLOAD(array_div_two_quo) + 1 :MLOAD(array_div_two_len_quo) - ; 4] len(inB) > len(inA) and inB_i < inA_i for all i lower than len(inB) - 3 => C - 2 => D - 6n :MSTORE(array_sub_AGTB_inB) - 1 => E - 8n :MSTORE(array_sub_AGTB_inB + E) + ; 2] [1n] + 1 => C + 1n :MSTORE(array_div_two_in) + :CALL(array_div_two) + 0n :MLOAD(array_div_two_quo) + 1 :MLOAD(array_div_two_len_quo) - 5n :MSTORE(array_sub_AGTB_inA) - 1 => E - 1n :MSTORE(array_sub_AGTB_inA + E) - 2 => E - 7n :MSTORE(array_sub_AGTB_inA + E) - :CALL(array_sub_AGTB) - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MLOAD(array_sub_AGTB_out) - 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639928n :MLOAD(array_sub_AGTB_out + E) - 2 => E - 6n :MLOAD(array_sub_AGTB_out + E) + ; 3] [2n] + 1 => C + 2n :MSTORE(array_div_two_in) + :CALL(array_div_two) + 1n :MLOAD(array_div_two_quo) + 1 :MLOAD(array_div_two_len_quo) - ; 5] len(inB) = len(inA) and inB > inA - 3 => C - 3 => D - 6n :MSTORE(array_sub_AGTB_inB) - 1 => E - 8n :MSTORE(array_sub_AGTB_inB + E) - 2 => E - 8n :MSTORE(array_sub_AGTB_inB + E) + ; 4] [4n] + 1 => C + 4n :MSTORE(array_div_two_in) + :CALL(array_div_two) + 2n :MLOAD(array_div_two_quo) + 1 :MLOAD(array_div_two_len_quo) - 7n :MSTORE(array_sub_AGTB_inA) - 1 => E - 8n :MSTORE(array_sub_AGTB_inA + E) - 2 => E - 8n :MSTORE(array_sub_AGTB_inA + E) - :CALL(array_sub_AGTB) - 1n :MLOAD(array_sub_AGTB_out) - 1 => E - 0n :MLOAD(array_sub_AGTB_out + E) - 2 => E - 0n :MLOAD(array_sub_AGTB_out + E) + ; 5] [4n, 4n] + 2 => C + 4n :MSTORE(array_div_two_in) + 1 => E + 4n :MSTORE(array_div_two_in + E) + :CALL(array_div_two) + 2n :MLOAD(array_div_two_quo) + 1 => E + 2n :MLOAD(array_div_two_quo + E) + 2 :MLOAD(array_div_two_len_quo) + + ; 6] [4n] * %ARRAY_MAX_LEN + %ARRAY_MAX_LEN => C + C - 1 => E + array_div_two_wc_test: + 4n :MSTORE(array_div_two_in + E) + E - 1 => E :JMPN(array_div_two_wc_test_compute,array_div_two_wc_test) + array_div_two_wc_test_compute: + :CALL(array_div_two) + %ARRAY_MAX_LEN => E :MLOAD(array_div_two_len_quo) + E - 1 => E + array_div_two_wc_test_check: + 2n :MLOAD(array_div_two_quo + E) + E - 1 => E :JMPN(array_div_two_wc_test_end,array_div_two_wc_test_check) + array_div_two_wc_test_end: ; --------------------------------------------------------------- :JMP(end) @@ -1080,20 +1331,12 @@ opINVALID: checkAndSaveFrom: :JMP(opINVALID) -INCLUDE "../main/modexp/constants.zkasm" - -INCLUDE "../main/modexp/array_lib/utils/array_trim.zkasm" -INCLUDE "../main/modexp/array_lib/utils/array_compare.zkasm" - INCLUDE "../main/modexp/array_lib/array_add_short.zkasm" INCLUDE "../main/modexp/array_lib/array_add_AGTB.zkasm" INCLUDE "../main/modexp/array_lib/array_mul_long.zkasm" INCLUDE "../main/modexp/array_lib/array_mul_short.zkasm" -INCLUDE "../main/modexp/array_lib/array_mul.zkasm" +INCLUDE "../main/modexp/array_lib/array_mul_two.zkasm" INCLUDE "../main/modexp/array_lib/array_square.zkasm" INCLUDE "../main/modexp/array_lib/array_div_long.zkasm" INCLUDE "../main/modexp/array_lib/array_div_short.zkasm" -INCLUDE "../main/modexp/array_lib/array_div.zkasm" - -INCLUDE "../main/modexp/array_lib/unused/array_sub_AGTB.zkasm" -INCLUDE "../main/modexp/array_lib/unused/array_add.zkasm" \ No newline at end of file +INCLUDE "../main/modexp/array_lib/array_div_two.zkasm" \ No newline at end of file diff --git a/test/testArrayUtils.zkasm b/test/testArrayUtils.zkasm deleted file mode 100644 index 2cc3dc13..00000000 --- a/test/testArrayUtils.zkasm +++ /dev/null @@ -1,335 +0,0 @@ -; constants needed by executor C++ -INCLUDE "../main/constants.zkasm" - -VAR GLOBAL lastHashKId -VAR GLOBAL lastHashPId - -VAR GLOBAL initial_A -VAR GLOBAL initial_B -VAR GLOBAL initial_C -VAR GLOBAL initial_D -VAR GLOBAL initial_E -VAR GLOBAL initial_CTX -VAR GLOBAL initial_SP -VAR GLOBAL initial_PC -VAR GLOBAL initial_GAS -VAR GLOBAL initial_SR -VAR GLOBAL initial_RR -VAR GLOBAL initial_HASHPOS -VAR GLOBAL initial_RCX - -; Fix better notation for the above - -start: - - STEP => A - 0 :ASSERT - - A :MSTORE(initial_A) - B :MSTORE(initial_B) - C :MSTORE(initial_C) - D :MSTORE(initial_D) - E :MSTORE(initial_E) - CTX :MSTORE(initial_CTX) - SP :MSTORE(initial_SP) - PC :MSTORE(initial_PC) - GAS :MSTORE(initial_GAS) - SR :MSTORE(initial_SR) - RR :MSTORE(initial_RR) - HASHPOS :MSTORE(initial_HASHPOS) - RCX :MSTORE(initial_RCX) - 0 => A,B,C,D,E,CTX, SP, PC, GAS, SR, RR, HASHPOS, RCX - - -1 :MSTORE(lastHashKId) - -1 :MSTORE(lastHashPId) - -; array_compare -; --------------------------------------------------------------- -; 1] inA = [5,6,7], inB = [2,3]. len(inA) > len(inB) should return 2 -array_compare_test_1: - 3 => C - 2 => D - 5n :MSTORE(array_compare_inA) - 1 => E - 6n :MSTORE(array_compare_inA + E) - 2 => E - 7n :MSTORE(array_compare_inA + E) - 2n :MSTORE(array_compare_inB) - 1 => E - 3n :MSTORE(array_compare_inB + E) - :CALL(array_compare) - 2 :MLOAD(array_compare_result) - -; 2] inA = [5,6], inB = [2,3,4]. len(inA) < len(inB) should return 0 -array_compare_test_2: - 2 => C - 3 => D - 5n :MSTORE(array_compare_inA) - 1 => E - 6n :MSTORE(array_compare_inA + E) - 2n :MSTORE(array_compare_inB) - 1 => E - 3n :MSTORE(array_compare_inB + E) - 2 => E - 4n :MSTORE(array_compare_inB + E) - :CALL(array_compare) - 0 :MLOAD(array_compare_result) - - - -; 3] inA = [5,6,7], inB = [5,6,6]. len(inA) = len(inB) but inA > inB should return 2 -array_compare_test_3: - 3 => C - 3 => D - 5n :MSTORE(array_compare_inA) - 1 => E - 6n :MSTORE(array_compare_inA + E) - 2 => E - 7n :MSTORE(array_compare_inA + E) - 5n :MSTORE(array_compare_inB) - 1 => E - 6n :MSTORE(array_compare_inB + E) - 2 => E - 6n :MSTORE(array_compare_inB + E) - :CALL(array_compare) - 2 :MLOAD(array_compare_result) - -; 4] inA = [5,6,6], inB = [5,6,7]. len(inA) = len(inB) but inA < inB should return 0 -array_compare_test_4: - 3 => C - 3 => D - 5n :MSTORE(array_compare_inA) - 1 => E - 6n :MSTORE(array_compare_inA + E) - 2 => E - 6n :MSTORE(array_compare_inA + E) - - 5n :MSTORE(array_compare_inB) - 1 => E - 6n :MSTORE(array_compare_inB + E) - 2 => E - 7n :MSTORE(array_compare_inB + E) - :CALL(array_compare) - 0 :MLOAD(array_compare_result) - -; 5] inA = [5,6,6], inB = [5,6,6]. inA = inB should return 1 -array_compare_test_5: - 3 => C - 3 => D - 5n :MSTORE(array_compare_inA) - 1 => E - 6n :MSTORE(array_compare_inA + E) - 2 => E - 6n :MSTORE(array_compare_inA + E) - 5n :MSTORE(array_compare_inB) - 1 => E - 6n :MSTORE(array_compare_inB + E) - 2 => E - 6n :MSTORE(array_compare_inB + E) - :CALL(array_compare) - 1 :MLOAD(array_compare_result) -; --------------------------------------------------------------- - -; array unshift -; --------------------------------------------------------------- -; 1] in = [3] and D = 5 => in = [5,3] -array_unshift_test_1: - 1 => C - 3n :MSTORE(array_unshift_in) - 5 => D - :CALL(array_unshift) - 5n :MLOAD(array_unshift_in) - 1 => E - 3n :MLOAD(array_unshift_in + E) - 2 :MLOAD(array_unshift_len) - -; 2] in = [2,1,1] and D = 5 => in = [5,2,1,1] -array_unshift_test_2: - 3 => C - 5 => D - 2n :MSTORE(array_unshift_in) - 1 => E - 1n :MSTORE(array_unshift_in + E) - 2 => E - 1n :MSTORE(array_unshift_in + E) - :CALL(array_unshift) - 5n :MLOAD(array_unshift_in) - 1 => E - 2n :MLOAD(array_unshift_in + E) - 2 => E - 1n :MLOAD(array_unshift_in + E) - 3 => E - 1n :MLOAD(array_unshift_in + E) - 4 :MLOAD(array_unshift_len) -; --------------------------------------------------------------- - -; array trim -; --------------------------------------------------------------- -; 1] [2,1,0] should return 2 -array_trim_test_1: - 3 => C - 2n :MSTORE(array_trim_in) - 1 => E - 1n :MSTORE(array_trim_in + E) - 2 => E - 0n :MSTORE(array_trim_in + E) - :CALL(array_trim) - 2 => A - C :ASSERT - -; 2] [2,1,0,2] should return 4 -array_trim_test_2: - 4 => C - 2n :MSTORE(array_trim_in) - 1 => E - 1n :MSTORE(array_trim_in + E) - 2 => E - 0n :MSTORE(array_trim_in + E) - 3 => E - 2n :MSTORE(array_trim_in + E) - :CALL(array_trim) - 4 => A - C :ASSERT - -; 3] [0,0,0,0,0,0] should return 1 -array_trim_test_3: - 6 => C - 0n :MSTORE(array_trim_in) - 1 => E - 0n :MSTORE(array_trim_in + E) - 2 => E - 0n :MSTORE(array_trim_in + E) - 3 => E - 0n :MSTORE(array_trim_in + E) - 4 => E - 0n :MSTORE(array_trim_in + E) - 5 => E - 0n :MSTORE(array_trim_in + E) - :CALL(array_trim) - 1 => A - C :ASSERT - -; 4] [0] should return 1 -array_trim_test_4: - 1 => C - 0n :MSTORE(array_trim_in) - :CALL(array_trim) - 1 => A - C :ASSERT -; --------------------------------------------------------------- - -; array is zero -; --------------------------------------------------------------- -; 1] [2,1] should return 0 -array_is_zero_test_1: - 2 => C - 2n :MSTORE(array_is_zero_in) - 1 => E - 1n :MSTORE(array_is_zero_in + E) - :CALL(array_is_zero) - 0 :MLOAD(array_is_zero_result) - -; 2] [0] should return 1 -array_is_zero_test_2: - 1 => C - 0n :MSTORE(array_is_zero_in) - :CALL(array_is_zero) - 1 :MLOAD(array_is_zero_result) - -; 3] [5] should return 0 -array_is_zero_test_3: - 1 => C - 5n :MSTORE(array_is_zero_in) - :CALL(array_is_zero) - 0 :MLOAD(array_is_zero_result) -; --------------------------------------------------------------- - -; array is one -; --------------------------------------------------------------- -; 1] [2,1] should return 0 -array_is_one_test_1: - 2 => C - 2n :MSTORE(array_is_one_in) - 1 => E - 1n :MSTORE(array_is_one_in + E) - :CALL(array_is_one) - 0 :MLOAD(array_is_one_result) - -; 2] [1] should return 1 -array_is_one_test_2: - 1 => C - 1n :MSTORE(array_is_one_in) - :CALL(array_is_one) - 1 :MLOAD(array_is_one_result) - -; 3] [5] should return 0 -array_is_one_test_3: - 1 => C - 5n :MSTORE(array_is_one_in) - :CALL(array_is_one) - 0 :MLOAD(array_is_one_result) -; --------------------------------------------------------------- - -; array is odd -; --------------------------------------------------------------- -; 1] [2,1] should return 0 -array_is_odd_test_1: - 2n :MSTORE(array_is_odd_in) - 1 => E - 1n :MSTORE(array_is_odd_in + E) - :CALL(array_is_odd) - 0 :MLOAD(array_is_odd_result) - -; 2] [5] should return 1 -array_is_odd_test_2: - 5n :MSTORE(array_is_odd_in) - :CALL(array_is_odd) - 1 :MLOAD(array_is_odd_result) - -; 2] [3, 2] should return 1 -array_is_odd_test_3: - 3n :MSTORE(array_is_odd_in) - 1 => E - 2n :MSTORE(array_is_odd_in + E) - :CALL(array_is_odd) - 1 :MLOAD(array_is_odd_result) -; --------------------------------------------------------------- - -outOfCountersBinary: -outOfCountersStep: - -end: - - $ => A :MLOAD(initial_A) - $ => B :MLOAD(initial_B) - $ => C :MLOAD(initial_C) - $ => D :MLOAD(initial_D) - $ => E :MLOAD(initial_E) - $ => CTX :MLOAD(initial_CTX) - $ => SP :MLOAD(initial_SP) - $ => PC :MLOAD(initial_PC) - $ => GAS :MLOAD(initial_GAS) - $ => SR :MLOAD(initial_SR) - $ => RR :MLOAD(initial_RR) - $ => HASHPOS :MLOAD(initial_HASHPOS) - $ => RCX :MLOAD(initial_RCX) - -; label finalizeExecution needed by executor C++ -finalizeExecution: - ${beforeLast()} :JMPN(finalizeExecution) - - :JMP(start) -opINVALID: -; label checkAndSaveFrom needed by executor C++ -checkAndSaveFrom: - :JMP(opINVALID) - -INCLUDE "../main/modexp/constants.zkasm" - -INCLUDE "../main/modexp/array_lib/utils/array_compare.zkasm" -INCLUDE "../main/modexp/array_lib/utils/array_trim.zkasm" - -INCLUDE "../main/modexp/array_lib/unused/array_is_zero.zkasm" -INCLUDE "../main/modexp/array_lib/unused/array_is_one.zkasm" -INCLUDE "../main/modexp/array_lib/unused/array_is_odd.zkasm" -INCLUDE "../main/modexp/array_lib/unused/array_unshift.zkasm" \ No newline at end of file diff --git a/test/testModExp.zkasm b/test/testModExp.zkasm index 1b3c6095..9165c0d1 100644 --- a/test/testModExp.zkasm +++ b/test/testModExp.zkasm @@ -18,6 +18,8 @@ VAR GLOBAL initial_RR VAR GLOBAL initial_HASHPOS VAR GLOBAL initial_RCX +CONSTL %ARRAY_BASE_MINUS_ONE = 115792089237316195423570985008687907853269984665640564039457584007913129639935n ; 2^256-1 + start: STEP => A @@ -41,7 +43,1012 @@ start: -1 :MSTORE(lastHashKId) -1 :MSTORE(lastHashPId) - ; ; UPDATE: Edge cases are not handled by the modexp function directly + ; 256 BITS EXPONENT TESTS + ; --------------------------------------------------------------------------------------------- + ; 1] B == k·M (at any point of the exponentiations) should return 0 + 1 :MSTORE(modexp_Blen) + 1 :MSTORE(modexp_Elen) + 1 :MSTORE(modexp_Mlen) + 4n :MSTORE(modexp_B) + 78n :MSTORE(modexp_E) + 4n :MSTORE(modexp_M) + :CALL(modexp) + 0n :MLOAD(modexp_out) + 1 :MLOAD(modexp_outlen) + + 1 :MSTORE(modexp_Blen) + 1 :MSTORE(modexp_Elen) + 1 :MSTORE(modexp_Mlen) + 8n :MSTORE(modexp_B) + 78n :MSTORE(modexp_E) + 4n :MSTORE(modexp_M) + :CALL(modexp) + 0n :MLOAD(modexp_out) + 1 :MLOAD(modexp_outlen) + + 1 :MSTORE(modexp_Blen) + 1 :MSTORE(modexp_Elen) + 1 :MSTORE(modexp_Mlen) + 2n :MSTORE(modexp_B) + 2n :MSTORE(modexp_E) + 4n :MSTORE(modexp_M) + :CALL(modexp) + 0n :MLOAD(modexp_out) + 1 :MLOAD(modexp_outlen) + + ; Larger inputs + 2 :MSTORE(modexp_Blen) + 1 :MSTORE(modexp_Elen) + 1 :MSTORE(modexp_Mlen) + 0n :MSTORE(modexp_B) + 1 => E + 8n :MSTORE(modexp_B + E) + 78n :MSTORE(modexp_E) + 4n :MSTORE(modexp_M) + :CALL(modexp) + 0n :MLOAD(modexp_out) + 1 :MLOAD(modexp_outlen) + + 2 :MSTORE(modexp_Blen) + 1 :MSTORE(modexp_Elen) + 2 :MSTORE(modexp_Mlen) + 8n :MSTORE(modexp_B) + 1 => E + 8n :MSTORE(modexp_B + E) + 78n :MSTORE(modexp_E) + 4n :MSTORE(modexp_M) + 1 => E + 4n :MSTORE(modexp_M + E) + :CALL(modexp) + 0n :MLOAD(modexp_out) + 1 :MLOAD(modexp_outlen) + + ; 2] B = [100n, 2831023n, 0n, 73916234139162n], E = [2n**256n - 1n], M = [0n, 0n, 8238129386n, 23102318237n] + ; Hamming weight of E is 256 + 4 :MSTORE(modexp_Blen) + 1 :MSTORE(modexp_Elen) + 4 :MSTORE(modexp_Mlen) + + 100n :MSTORE(modexp_B) + 1 => E + 2831023n :MSTORE(modexp_B + E) + 2 => E + 0n :MSTORE(modexp_B + E) + 3 => E + 73916234139162n :MSTORE(modexp_B + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(modexp_E) + 0n :MSTORE(modexp_M) + 1 => E + 0n :MSTORE(modexp_M + E) + 2 => E + 8238129386n :MSTORE(modexp_M + E) + 3 => E + 23102318237n :MSTORE(modexp_M + E) + :CALL(modexp) + 0n :MLOAD(modexp_out) + 1 => E + 0n :MLOAD(modexp_out + E) + 2 => E + 25636070175539943947777314844209202718110211581133019863886488575898865601868n :MLOAD(modexp_out + E) + 3 => E + 4679155145n :MLOAD(modexp_out + E) + 4 :MLOAD(modexp_outlen) + + ; 3] B = [100n, 2831023n, 0n, 73916234139162n, 100n, 2831023n, 0n, 73916234139162n,100n, 2831023n, 0n, 73916234139162n], E = [903741926349715234612309461283471234n], M = [0n, 0n, 8238129386n, 23102318237n, 1892397612351n, 7246598123051n, 8238129386n, 1264591241237897123126n] + ; Hamming weight of E is 120 + 12 :MSTORE(modexp_Blen) + 1 :MSTORE(modexp_Elen) + 8 :MSTORE(modexp_Mlen) + + 100n :MSTORE(modexp_B) + 1 => E + 2831023n :MSTORE(modexp_B + E) + 2 => E + 0n :MSTORE(modexp_B + E) + 3 => E + 73916234139162n :MSTORE(modexp_B + E) + 4 => E + 100n :MSTORE(modexp_B + E) + 5 => E + 2831023n :MSTORE(modexp_B + E) + 6 => E + 0n :MSTORE(modexp_B + E) + 7 => E + 73916234139162n :MSTORE(modexp_B + E) + 8 => E + 100n :MSTORE(modexp_B + E) + 9 => E + 2831023n :MSTORE(modexp_B + E) + 10 => E + 0n :MSTORE(modexp_B + E) + 11 => E + 73916234139162n :MSTORE(modexp_B + E) + 903741926349715234612309461283471234n :MSTORE(modexp_E) + 0n :MSTORE(modexp_M) + 1 => E + 0n :MSTORE(modexp_M + E) + 2 => E + 8238129386n :MSTORE(modexp_M + E) + 3 => E + 23102318237n :MSTORE(modexp_M + E) + 4 => E + 1892397612351n :MSTORE(modexp_M + E) + 5 => E + 7246598123051n :MSTORE(modexp_M + E) + 6 => E + 8238129386n :MSTORE(modexp_M + E) + 7 => E + 1264591241237897123126n :MSTORE(modexp_M + E) + :CALL(modexp) + 0n :MLOAD(modexp_out) + 1 => E + 0n :MLOAD(modexp_out + E) + 2 => E + 14984469305990977542353827078899382678368215018946198341845725551977623627446n :MLOAD(modexp_out + E) + 3 => E + 68986200907052834988812862957862042564780541926701277492865197684364096948359n :MLOAD(modexp_out + E) + 4 => E + 19960171666179366961875030436152164148711578520678689062449823687317995303656n :MLOAD(modexp_out + E) + 5 => E + 10163909190618518832451417682132582498490814809943760852308996448668923869413n :MLOAD(modexp_out + E) + 6 => E + 29735535392706191114764336807325502135962613879333248096358552087717155148899n :MLOAD(modexp_out + E) + 7 => E + 511131288598502431475n :MLOAD(modexp_out + E) + 8 :MLOAD(modexp_outlen) + + ; 4] B = [7n], E = [110n], M = [7719472615821079694904732333912527190217998977709370935963838933860875309329n, 17n] + ; Hamming weight of E is 5 + 1 :MSTORE(modexp_Blen) + 1 :MSTORE(modexp_Elen) + 2 :MSTORE(modexp_Mlen) + + 7n :MSTORE(modexp_B) + 110n :MSTORE(modexp_E) + 7719472615821079694904732333912527190217998977709370935963838933860875309329n :MSTORE(modexp_M) + 1 => E + 17n :MSTORE(modexp_M + E) + :CALL(modexp) + 81730215206688390341255830729934766338330049967253209305087427132484271882414n :MLOAD(modexp_out) + 1 => E + 13n :MLOAD(modexp_out + E) + 2 :MLOAD(modexp_outlen) + ; --------------------------------------------------------------------------------------------- + + ; 512 BITS EXPONENT TESTS + ; --------------------------------------------------------------------------------------------- + ; 1] B = [2n, 1n, 1n, 1n], E = [3n, 5n], M = [4n, 6n, 7n] + ; Hamming weight of E is 4 + 4 :MSTORE(modexp_Blen) + 2 :MSTORE(modexp_Elen) + 3 :MSTORE(modexp_Mlen) + + 2n :MSTORE(modexp_B) + 1 => E + 1n :MSTORE(modexp_B + E) + 2 => E + 1n :MSTORE(modexp_B + E) + 3 => E + 1n :MSTORE(modexp_B + E) + 3n :MSTORE(modexp_E) + 1 => E + 5n :MSTORE(modexp_E + E) + 4n :MSTORE(modexp_M) + 1 => E + 6n :MSTORE(modexp_M + E) + 2 => E + 7n :MSTORE(modexp_M + E) + :CALL(modexp) + 16799222018138169590613227618843456355247327644003751420511040302320945803948n :MLOAD(modexp_out) + 1 => E + 67226185770814561827024093064262870237432709513661454124124794094744315370418n :MLOAD(modexp_out + E) + 2 => E + 1n :MLOAD(modexp_out + E) + 3 :MLOAD(modexp_outlen) + + ; 2] B = [2n, 1n, 1n, 1n], E = [2n**256n - 1n, 2n**256n - 1n], M = [4n, 6n, 7n] + ; Hamming weight of E is 512 + 4 :MSTORE(modexp_Blen) + 2 :MSTORE(modexp_Elen) + 3 :MSTORE(modexp_Mlen) + + 2n :MSTORE(modexp_B) + 1 => E + 1n :MSTORE(modexp_B + E) + 2 => E + 1n :MSTORE(modexp_B + E) + 3 => E + 1n :MSTORE(modexp_B + E) + %ARRAY_BASE_MINUS_ONE :MSTORE(modexp_E) + 1 => E + %ARRAY_BASE_MINUS_ONE :MSTORE(modexp_E + E) + 4n :MSTORE(modexp_M) + 1 => E + 6n :MSTORE(modexp_M + E) + 2 => E + 7n :MSTORE(modexp_M + E) + :CALL(modexp) + 111873638420780286093512129901489267041413036926649390648147612881355784341812n :MLOAD(modexp_out) + 1 => E + 11181991619082508729788448443921623930160246165837402400671610626538926623319n :MLOAD(modexp_out + E) + 2 => E + 2n :MLOAD(modexp_out + E) + 3 :MLOAD(modexp_outlen) + ; --------------------------------------------------------------------------------------------- + + + ; 768 BITS TESTS + ; --------------------------------------------------------------------------------------------- + ; --------------------------------------------------------------------------------------------- + + ; 1024 BITS TESTS + ; --------------------------------------------------------------------------------------------- + ; --------------------------------------------------------------------------------------------- + + ; 4096 BITS TESTS + ; --------------------------------------------------------------------------------------------- + ; 1] Blen = 16, Elen = Mlen = 1 + 16 :MSTORE(modexp_Blen) + 1 :MSTORE(modexp_Elen) + 1 :MSTORE(modexp_Mlen) + + 79682313232473470607411611222799169674661221361161508682342262669488472802709n :MSTORE(modexp_B) + 1 => E + 64543272570765854206172333138181582698966088677167578455572643857223443534221n :MSTORE(modexp_B + E) + 2 => E + 41013368700952433297770792072436823191831060400631854801523739861587759544n :MSTORE(modexp_B + E) + 3 => E + 35685038273887359064520668555491444960261997659381360895406712100398597357348n :MSTORE(modexp_B + E) + 4 => E + 133029975877400389180684841929675726606225035043435332360926901580693680262n :MSTORE(modexp_B + E) + 5 => E + 24563713026162797682484577709932170008895098676856309352834837082479016179272n :MSTORE(modexp_B + E) + 6 => E + 74074900993951345578817327213689306543998883645091080472921659936688993486778n :MSTORE(modexp_B + E) + 7 => E + 80197086448923126029525338783196583240907328704000619936506876255613296721615n :MSTORE(modexp_B + E) + 8 => E + 71792675465944011723747087486637283576956028838699944447902066138168469136654n :MSTORE(modexp_B + E) + 9 => E + 13877126779728100032847034788589797183498695976504905479337327737291047807791n :MSTORE(modexp_B + E) + 10 => E + 88495657359265959492596595516772192563108933750709883595366806688862143659110n :MSTORE(modexp_B + E) + 11 => E + 6300958885869768199259392943087237730895172768580010656821154212937168995267n :MSTORE(modexp_B + E) + 12 => E + 77281623846760171486628064643958778573473599256077586688285526608233051545986n :MSTORE(modexp_B + E) + 13 => E + 36709413932085823372334931605995244972005987179409640967639352549999163316625n :MSTORE(modexp_B + E) + 14 => E + 84889305564417480047528247902585206147036955681764230541024345604513927199967n :MSTORE(modexp_B + E) + 15 => E + 96319562792967333917044767543841059308132754624213291319966533781680198329387n :MSTORE(modexp_B + E) + 65537n :MSTORE(modexp_E) + 72847221021874037642769569132275164094322040442822821773040516004504186942893n :MSTORE(modexp_M) + :CALL(modexp) + 39835447779732380359272840551895169222953615526693818881919202322941555284426n :MLOAD(modexp_out) + 1n :MLOAD(modexp_outlen) + + ; ; 2] Blen = Elen = 16, Mlen = 1 + ; 16 :MSTORE(modexp_Blen) + ; 16 :MSTORE(modexp_Elen) + ; 1 :MSTORE(modexp_Mlen) + + ; 71050553794075590751574565232558453983936710433844505437607055862219229593147n :MSTORE(modexp_B) + ; 1 => E + ; 2311119566291524187052166030450225884982623802621020117704297191344877127324n :MSTORE(modexp_B + E) + ; 2 => E + ; 41425637949145657150896102319789119277799005821234114655819013119845168507004n :MSTORE(modexp_B + E) + ; 3 => E + ; 27432710158553418316382709013332653477402126158654571642096340165629813029148n :MSTORE(modexp_B + E) + ; 4 => E + ; 64855884914613940606159196869973315039653219108138872452885841451518173265926n :MSTORE(modexp_B + E) + ; 5 => E + ; 114179790520345212766915619197467741272399299487910365242276569807467315404460n :MSTORE(modexp_B + E) + ; 6 => E + ; 65433702517710946687148011723629536032259451607684846408212066673476383092855n :MSTORE(modexp_B + E) + ; 7 => E + ; 70912716282826624595547370701759759731957555830364521210068342278799344565354n :MSTORE(modexp_B + E) + ; 8 => E + ; 108962111922998507767637931201156050693693415833391822856491978062799221246004n :MSTORE(modexp_B + E) + ; 9 => E + ; 104919585803459441841628264650790198163260957103390723319754136236152506833795n :MSTORE(modexp_B + E) + ; 10 => E + ; 110778956830016126801877727623601484344357351150676372632563206106301131401659n :MSTORE(modexp_B + E) + ; 11 => E + ; 89805706387954343243725098969923544675293643610200110483949051893210964773484n :MSTORE(modexp_B + E) + ; 12 => E + ; 49441605214112775122575373711011375251104561280549611203366244610082183044580n :MSTORE(modexp_B + E) + ; 13 => E + ; 26738415432508710188833636324578379506748044875782481656544300498146163965995n :MSTORE(modexp_B + E) + ; 14 => E + ; 90061541830655577695920973192174012989086252925414785698224068317321571729683n :MSTORE(modexp_B + E) + ; 15 => E + ; 104046988730536690188259038943188458054688225850879043983462419897284556724245n :MSTORE(modexp_B + E) + ; 33971987921089971027144158880891217042643607281942501312815993279017754450637n :MSTORE(modexp_E) + ; 1 => E + ; 77922126445326164100848586215041815373826676904825562964371979228582873146694n :MSTORE(modexp_E + E) + ; 2 => E + ; 60053697457808056554587360378419884407306536959014338063828446574565751432749n :MSTORE(modexp_E + E) + ; 3 => E + ; 28505380659520440046066098541123671022002393699148132115736787164585927247154n :MSTORE(modexp_E + E) + ; 4 => E + ; 41420006249269960396026897034749989742389552840934426583540014227156932178509n :MSTORE(modexp_E + E) + ; 5 => E + ; 84788843709997712483448811225886083983449165173145871553902051971557591287552n :MSTORE(modexp_E + E) + ; 6 => E + ; 9710547385215512619762583843673811942425979810509832827691520725760713874609n :MSTORE(modexp_E + E) + ; 7 => E + ; 109524086897880409398706197038562166850217293443113563123462332128403500288135n :MSTORE(modexp_E + E) + ; 8 => E + ; 108766537508841097413327200421979351836702529307991413835619315128358666804902n :MSTORE(modexp_E + E) + ; 9 => E + ; 97423474307374249213245664777066065954923092308871167915194183816491405037758n :MSTORE(modexp_E + E) + ; 10 => E + ; 57520346884019806080242434487721962336733788608211778941734017993493361230006n :MSTORE(modexp_E + E) + ; 11 => E + ; 96939514396867440752505254025053268738361428692795115144833619080874132113659n :MSTORE(modexp_E + E) + ; 12 => E + ; 106940305798126701930452039042389517483718997182868267407362650816121421348695n :MSTORE(modexp_E + E) + ; 13 => E + ; 93016388750996612536508398332036279514362682040309020531649384676220760236859n :MSTORE(modexp_E + E) + ; 14 => E + ; 31557796771274301393544096332573459628658833249730842037307167942246706851427n :MSTORE(modexp_E + E) + ; 15 => E + ; 82556706461393888060953398750707647347450236004144410511709274016258909496983n :MSTORE(modexp_E + E) + ; 72847221021874037642769569132275164094322040442822821773040516004504186942893n :MSTORE(modexp_M) + ; :CALL(modexp) + ; 70030934173990436633040632542141848011108687892358966752788121730214829297187n :MLOAD(modexp_out) + ; 1n :MLOAD(modexp_outlen) + + ; 3] Blen = Mlen = 16, Elen = 1 + ; 3.1] + 16 :MSTORE(modexp_Blen) + 1 :MSTORE(modexp_Elen) + 16 :MSTORE(modexp_Mlen) + + 37924229408289482165803031675401013124901204286470402501334310819425856080769n :MSTORE(modexp_B) + 1 => E + 68230554850406790393335622985000862560412869841790282370567989273189176853944n :MSTORE(modexp_B + E) + 2 => E + 18739220654407561511874385410342272003979993829094184733735102210684894197360n :MSTORE(modexp_B + E) + 3 => E + 104625700450534358765215410730104048961222066068915559406617272097604826348437n :MSTORE(modexp_B + E) + 4 => E + 51567802805698379422939389175055821627525780369641743070246650840596365975847n :MSTORE(modexp_B + E) + 5 => E + 36376329820029959961059111209614438636772206095543453919642843050454582814679n :MSTORE(modexp_B + E) + 6 => E + 44522495152966940943585404072003181369127388558540531535861861951483372641560n :MSTORE(modexp_B + E) + 7 => E + 24318250107596801022055177598514809706589223658732683705740708158769957778387n :MSTORE(modexp_B + E) + 8 => E + 92454610886044395311393075699340229384301806849232216376720819164839986860624n :MSTORE(modexp_B + E) + 9 => E + 88528324716442370493104391640983024212241659273083705959452539513826125667133n :MSTORE(modexp_B + E) + 10 => E + 105333534619699493802180629465274795585665601176722460276973393348887271614948n :MSTORE(modexp_B + E) + 11 => E + 64876030133878208912134468604708622595384009691230250196764254417962709486067n :MSTORE(modexp_B + E) + 12 => E + 91225894261375645229792693749534518967710703465611009253921289138268358394469n :MSTORE(modexp_B + E) + 13 => E + 90348546611829849796484333307241739807810147984211446095491573977793020352322n :MSTORE(modexp_B + E) + 14 => E + 46241614006125728465318582820711043122940783638154174404536596332581026395360n :MSTORE(modexp_B + E) + 15 => E + 99149831603124336236439483084339386134406219101862706996762378257981741912736n :MSTORE(modexp_B + E) + 4368560466608909307598443030984237722400255124870596561938643117188181152143n :MSTORE(modexp_M) + 1 => E + 28204143169940543083491525897627603188033527858690769701170201940374221601245n :MSTORE(modexp_M + E) + 2 => E + 61217952914925378005374398553074630693728204065011340731170364550878214659815n :MSTORE(modexp_M + E) + 3 => E + 88118295973651813182703915416869725420348423583318199620990966714598238251552n :MSTORE(modexp_M + E) + 4 => E + 56204502858079831000146201011573821513739086570348047358071347832618798255717n :MSTORE(modexp_M + E) + 5 => E + 112725224422902909858467186270562227302175772670104568236470325207555377396666n :MSTORE(modexp_M + E) + 6 => E + 73339905915381957604898271520718074720658794539748632014341137820762993147466n :MSTORE(modexp_M + E) + 7 => E + 106528985384520019150189393412999362927371304554912360991203065081415045924966n :MSTORE(modexp_M + E) + 8 => E + 4694661456344419148913147297494031210082969714867234747900860197119323201863n :MSTORE(modexp_M + E) + 9 => E + 105539502916971480578816789738846550555830898514461324042801197877663191565909n :MSTORE(modexp_M + E) + 10 => E + 80665310393851221179007517265906288568261739729516922153119869080362910046925n :MSTORE(modexp_M + E) + 11 => E + 62925213013801927973636224311530332352379988774606203481041004347356521229626n :MSTORE(modexp_M + E) + 12 => E + 86615192813531756003302541387953267287184373448109857650547804088087305453939n :MSTORE(modexp_M + E) + 13 => E + 101432686246979103425668225617022809239473124804448904101486818738156404729830n :MSTORE(modexp_M + E) + 14 => E + 81185454731627141874646679535037788294928264888432136644606175703270853977033n :MSTORE(modexp_M + E) + 15 => E + 100952807471413669397287143861650720025441441686015619291329552671298687021944n :MSTORE(modexp_M + E) + 3n :MSTORE(modexp_E) + :CALL(modexp) + 39060232210842192865255693643895726380948007613006305279510511321192759611068n :MLOAD(modexp_out) + 1 => E + 99284533350540419680425679405964684423174339711679803248391935245805209923070n :MLOAD(modexp_out + E) + 2 => E + 109169237310323530752810777432399949029517390082816750351605208567352805910677n :MLOAD(modexp_out + E) + 3 => E + 62930166743444693059729355133738944005624699172943263143372681634024231410398n :MLOAD(modexp_out + E) + 4 => E + 3645377994753503508887388083164875289643316400491295083459296003996043600952n :MLOAD(modexp_out + E) + 5 => E + 19149461293685740447012477409803281881850209016975673872328641759185258898454n :MLOAD(modexp_out + E) + 6 => E + 6128211511014754458026757836656478094157704942188309990669408013208226331134n :MLOAD(modexp_out + E) + 7 => E + 81263218759677486762604599653369440233231715375456338238514334355349665229893n :MLOAD(modexp_out + E) + 8 => E + 34592371546276592252462635832386263358515320192906350313686959573959463448218n :MLOAD(modexp_out + E) + 9 => E + 51989835959341673110873745322329233415144893755105568753554688560801263631574n :MLOAD(modexp_out + E) + 10 => E + 84810801189689344625326584029855645866210550678064651986321335696210733246626n :MLOAD(modexp_out + E) + 11 => E + 58954497922212024692687026951546733784088063092392876596435949364763456205126n :MLOAD(modexp_out + E) + 12 => E + 21216023529240327629295276841208141672149657467287315214945207723145873906218n :MLOAD(modexp_out + E) + 13 => E + 67969553507141474422942950202188631862759071608105134505514789540935945400734n :MLOAD(modexp_out + E) + 14 => E + 114165984354566243427589886061604906090475523036306719160700002176798973642185n :MLOAD(modexp_out + E) + 15 => E + 40775987737607964514397594694708916064548205466165308850057770980957535279190n :MLOAD(modexp_out + E) + 16 :MLOAD(modexp_outlen) + + ; 3.2] + 16 :MSTORE(modexp_Blen) + 1 :MSTORE(modexp_Elen) + 16 :MSTORE(modexp_Mlen) + 37924229408289482165803031675401013124901204286470402501334310819425856080769n :MSTORE(modexp_B) + 1 => E + 68230554850406790393335622985000862560412869841790282370567989273189176853944n :MSTORE(modexp_B + E) + 2 => E + 18739220654407561511874385410342272003979993829094184733735102210684894197360n :MSTORE(modexp_B + E) + 3 => E + 104625700450534358765215410730104048961222066068915559406617272097604826348437n :MSTORE(modexp_B + E) + 4 => E + 51567802805698379422939389175055821627525780369641743070246650840596365975847n :MSTORE(modexp_B + E) + 5 => E + 36376329820029959961059111209614438636772206095543453919642843050454582814679n :MSTORE(modexp_B + E) + 6 => E + 44522495152966940943585404072003181369127388558540531535861861951483372641560n :MSTORE(modexp_B + E) + 7 => E + 24318250107596801022055177598514809706589223658732683705740708158769957778387n :MSTORE(modexp_B + E) + 8 => E + 92454610886044395311393075699340229384301806849232216376720819164839986860624n :MSTORE(modexp_B + E) + 9 => E + 88528324716442370493104391640983024212241659273083705959452539513826125667133n :MSTORE(modexp_B + E) + 10 => E + 105333534619699493802180629465274795585665601176722460276973393348887271614948n :MSTORE(modexp_B + E) + 11 => E + 64876030133878208912134468604708622595384009691230250196764254417962709486067n :MSTORE(modexp_B + E) + 12 => E + 91225894261375645229792693749534518967710703465611009253921289138268358394469n :MSTORE(modexp_B + E) + 13 => E + 90348546611829849796484333307241739807810147984211446095491573977793020352322n :MSTORE(modexp_B + E) + 14 => E + 46241614006125728465318582820711043122940783638154174404536596332581026395360n :MSTORE(modexp_B + E) + 15 => E + 99149831603124336236439483084339386134406219101862706996762378257981741912736n :MSTORE(modexp_B + E) + 4368560466608909307598443030984237722400255124870596561938643117188181152143n :MSTORE(modexp_M) + 1 => E + 28204143169940543083491525897627603188033527858690769701170201940374221601245n :MSTORE(modexp_M + E) + 2 => E + 61217952914925378005374398553074630693728204065011340731170364550878214659815n :MSTORE(modexp_M + E) + 3 => E + 88118295973651813182703915416869725420348423583318199620990966714598238251552n :MSTORE(modexp_M + E) + 4 => E + 56204502858079831000146201011573821513739086570348047358071347832618798255717n :MSTORE(modexp_M + E) + 5 => E + 112725224422902909858467186270562227302175772670104568236470325207555377396666n :MSTORE(modexp_M + E) + 6 => E + 73339905915381957604898271520718074720658794539748632014341137820762993147466n :MSTORE(modexp_M + E) + 7 => E + 106528985384520019150189393412999362927371304554912360991203065081415045924966n :MSTORE(modexp_M + E) + 8 => E + 4694661456344419148913147297494031210082969714867234747900860197119323201863n :MSTORE(modexp_M + E) + 9 => E + 105539502916971480578816789738846550555830898514461324042801197877663191565909n :MSTORE(modexp_M + E) + 10 => E + 80665310393851221179007517265906288568261739729516922153119869080362910046925n :MSTORE(modexp_M + E) + 11 => E + 62925213013801927973636224311530332352379988774606203481041004347356521229626n :MSTORE(modexp_M + E) + 12 => E + 86615192813531756003302541387953267287184373448109857650547804088087305453939n :MSTORE(modexp_M + E) + 13 => E + 101432686246979103425668225617022809239473124804448904101486818738156404729830n :MSTORE(modexp_M + E) + 14 => E + 81185454731627141874646679535037788294928264888432136644606175703270853977033n :MSTORE(modexp_M + E) + 15 => E + 100952807471413669397287143861650720025441441686015619291329552671298687021944n :MSTORE(modexp_M + E) + 65537n :MSTORE(modexp_E) + :CALL(modexp) + 30186209231779725290287967878560956226809426123422184270357951605304373492067n :MLOAD(modexp_out) + 1 => E + 56378602148099721798763724843127971047819132930616646821928609636019413997437n :MLOAD(modexp_out + E) + 2 => E + 104585421667308091086697809268225553655561004775475565616585559469649707166583n :MLOAD(modexp_out + E) + 3 => E + 57332553509658954797422316649665205659038504022777901721859372117975729331395n :MLOAD(modexp_out + E) + 4 => E + 71160297366919404927767288677170830349524526764837835922422603335883060426633n :MLOAD(modexp_out + E) + 5 => E + 37663010872419315993941035885076737840046461693519376763312965751826491412058n :MLOAD(modexp_out + E) + 6 => E + 85628163729819079301781131353278733742337215762503145451804427508737406550408n :MLOAD(modexp_out + E) + 7 => E + 30122934402101644981192140697944460397631812699255947934421267884882036531808n :MLOAD(modexp_out + E) + 8 => E + 41911641200707400216973090481225463949464966052218601350140915847730936274314n :MLOAD(modexp_out + E) + 9 => E + 3254957425564395182030426420906148204247695309319941830248629836779514130052n :MLOAD(modexp_out + E) + 10 => E + 17568574233555430000188504552854565100909697566384677405455446953742520903763n :MLOAD(modexp_out + E) + 11 => E + 90056336203638444622631463374562301388678031242213951682950635716230152633476n :MLOAD(modexp_out + E) + 12 => E + 37896075558567471590653368546276409068345631897352750329686231175382953792907n :MLOAD(modexp_out + E) + 13 => E + 91591557354240243363173128273762107236440333112750521721800907157515037764317n :MLOAD(modexp_out + E) + 14 => E + 20378189238029856538380830142696517952134481015835070624474088662045027158261n :MLOAD(modexp_out + E) + 15 => E + 86322360060109307422998669696656057232757405495821912040329317119021810406962n :MLOAD(modexp_out + E) + ; --------------------------------------------------------------------------------------------- + + ; 8192 BITS TESTS + ; --------------------------------------------------------------------------------------------- + ; ; 1] Blen = 16, Elen = 32, Mlen = 1 + ; 16 :MSTORE(modexp_Blen) + ; 32 :MSTORE(modexp_Elen) + ; 1 :MSTORE(modexp_Mlen) + + ; 71050553794075590751574565232558453983936710433844505437607055862219229593147n :MSTORE(modexp_B) + ; 1 => E + ; 2311119566291524187052166030450225884982623802621020117704297191344877127324n :MSTORE(modexp_B + E) + ; 2 => E + ; 41425637949145657150896102319789119277799005821234114655819013119845168507004n :MSTORE(modexp_B + E) + ; 3 => E + ; 27432710158553418316382709013332653477402126158654571642096340165629813029148n :MSTORE(modexp_B + E) + ; 4 => E + ; 64855884914613940606159196869973315039653219108138872452885841451518173265926n :MSTORE(modexp_B + E) + ; 5 => E + ; 114179790520345212766915619197467741272399299487910365242276569807467315404460n :MSTORE(modexp_B + E) + ; 6 => E + ; 65433702517710946687148011723629536032259451607684846408212066673476383092855n :MSTORE(modexp_B + E) + ; 7 => E + ; 70912716282826624595547370701759759731957555830364521210068342278799344565354n :MSTORE(modexp_B + E) + ; 8 => E + ; 108962111922998507767637931201156050693693415833391822856491978062799221246004n :MSTORE(modexp_B + E) + ; 9 => E + ; 104919585803459441841628264650790198163260957103390723319754136236152506833795n :MSTORE(modexp_B + E) + ; 10 => E + ; 110778956830016126801877727623601484344357351150676372632563206106301131401659n :MSTORE(modexp_B + E) + ; 11 => E + ; 89805706387954343243725098969923544675293643610200110483949051893210964773484n :MSTORE(modexp_B + E) + ; 12 => E + ; 49441605214112775122575373711011375251104561280549611203366244610082183044580n :MSTORE(modexp_B + E) + ; 13 => E + ; 26738415432508710188833636324578379506748044875782481656544300498146163965995n :MSTORE(modexp_B + E) + ; 14 => E + ; 90061541830655577695920973192174012989086252925414785698224068317321571729683n :MSTORE(modexp_B + E) + ; 15 => E + ; 104046988730536690188259038943188458054688225850879043983462419897284556724245n :MSTORE(modexp_B + E) + ; 76258746201283982645587901332414432739909461826418801220672878663730191795232n :MSTORE(modexp_E) + ; 1 => E + ; 14229851287285170470957155497391834688082201047771074134798987350533788031156n :MSTORE(modexp_E + E) + ; 2 => E + ; 81533024151778482749430962632322707313027767811611043054284702515386692950687n :MSTORE(modexp_E + E) + ; 3 => E + ; 8141633281699943824118714450443164005237941232831125215672559000204210600323n :MSTORE(modexp_E + E) + ; 4 => E + ; 51007176328061781717633699014696552750308240998656875784646019437161248510022n :MSTORE(modexp_E + E) + ; 5 => E + ; 106071722837234389798554094250828902452432434958153184667260839994459611837342n :MSTORE(modexp_E + E) + ; 6 => E + ; 100230489419677240887089362285203274928102899381652393983569186777557382541779n :MSTORE(modexp_E + E) + ; 7 => E + ; 87879154397947210087106966625197397862735130068646261788426652869771820509616n :MSTORE(modexp_E + E) + ; 8 => E + ; 95910832308024171851618993150481921937992827628570313141587551679301205787653n :MSTORE(modexp_E + E) + ; 9 => E + ; 56325490982677115149543544844429795450475174532268174744912442604171234520684n :MSTORE(modexp_E + E) + ; 10 => E + ; 92279587189196615790442243986095965191470136365218749875229554640748067293976n :MSTORE(modexp_E + E) + ; 11 => E + ; 101742530126141978985767956519943040369255818260170518234107534125239287715046n :MSTORE(modexp_E + E) + ; 12 => E + ; 18149831723885501834780453590048252669895784725869946779703689051215053924210n :MSTORE(modexp_E + E) + ; 13 => E + ; 108418536966335240982622603956904261958086087919448511653867960379666919908120n :MSTORE(modexp_E + E) + ; 14 => E + ; 85375756794768575331981790806560537915310410200315059084018867147198618911418n :MSTORE(modexp_E + E) + ; 15 => E + ; 4695535736413777673751638434146051749639519180545966899214955707210798143404n :MSTORE(modexp_E + E) + ; 16 => E + ; 107686936858044396353050394658951316054078664889790433925695428956196469052437n :MSTORE(modexp_E + E) + ; 17 => E + ; 98992960576649555193444049029191167448401916204443503157924491330688962707702n :MSTORE(modexp_E + E) + ; 18 => E + ; 28831341215365523183447349462928123109504892029366550505460556810244324688706n :MSTORE(modexp_E + E) + ; 19 => E + ; 6244403745121382062454832675509908005308090603466196964416686333235882672199n :MSTORE(modexp_E + E) + ; 20 => E + ; 84799957950134760904298775966516653696788779125526887835464675373737783466153n :MSTORE(modexp_E + E) + ; 21 => E + ; 48627951917191223340396480673320944356213903780640361562966310872761294409321n :MSTORE(modexp_E + E) + ; 22 => E + ; 1998455226609775634086429009803184701438555046525800041821541457512703578341n :MSTORE(modexp_E + E) + ; 23 => E + ; 17111686167104302872480175539141080358546990013870782555784830287161441763067n :MSTORE(modexp_E + E) + ; 24 => E + ; 76956086582271522349024399008827385337580012142740773586608621303394806968931n :MSTORE(modexp_E + E) + ; 25 => E + ; 30820225218026058791918508922913533862480649168455006349251399787799910264751n :MSTORE(modexp_E + E) + ; 26 => E + ; 39574930535822637947710846048091464501920884049550344516411346668145380285447n :MSTORE(modexp_E + E) + ; 27 => E + ; 29958804646464351833720585683972135554033036811000625339867082338282377810146n :MSTORE(modexp_E + E) + ; 28 => E + ; 31855784112983104278650198470116821131218972166134981173356451075709599588548n :MSTORE(modexp_E + E) + ; 29 => E + ; 77693939667794234483665826472458446626151021029641861158955235311230466345870n :MSTORE(modexp_E + E) + ; 30 => E + ; 76470792390833156560070798913966866475970097043371344204493796403126663372415n :MSTORE(modexp_E + E) + ; 31 => E + ; 114988869843408178999479197752358298421236312058743976013813966822126396167278n :MSTORE(modexp_E + E) + ; 72847221021874037642769569132275164094322040442822821773040516004504186942893n :MSTORE(modexp_M) + ; :CALL(modexp) + ; 39485175434713692833767794600629031124832788746937134372850464715072794794365n :MLOAD(modexp_out) + ; 1n :MLOAD(modexp_outlen) + + ; 2] Blen = 32, Elen = 1, Mlen = 2 + 32 :MSTORE(modexp_Blen) + 1 :MSTORE(modexp_Elen) + 2 :MSTORE(modexp_Mlen) + + 58582339313272081541741091700594438953240612446085692295415022086283220626753n :MSTORE(modexp_B) + 1 => E + 1082278792311219594083944885733732785223732334635289578358568460157040451417n :MSTORE(modexp_B + E) + 2 => E + 19613517917404142784873662366229906237596579118836502522712489678006364018137n :MSTORE(modexp_B + E) + 3 => E + 94585942647244454954435025568500649221875007164723745245117096456516601199618n :MSTORE(modexp_B + E) + 4 => E + 35639633678852084060200900997468850162084312453050227618889913284300596838199n :MSTORE(modexp_B + E) + 5 => E + 78099865031131508842883969354441126147665120063157525313709234612881360425292n :MSTORE(modexp_B + E) + 6 => E + 3465260013338549695646534731938806191895940454762761143209085341490292094583n :MSTORE(modexp_B + E) + 7 => E + 83240820227760283646014632355413985150832638693530940639158230460807255356621n :MSTORE(modexp_B + E) + 8 => E + 62051656904790802038019733921610445956666260367244273275496729381748290153955n :MSTORE(modexp_B + E) + 9 => E + 45666393393776004451398686220386880450315878280561353594540553199247513386595n :MSTORE(modexp_B + E) + 10 => E + 101785040741538888903354844773182179352722786538112190484679500250614319751259n :MSTORE(modexp_B + E) + 11 => E + 110652338015694281068707365417090078516695327755424649221664897939524884103417n :MSTORE(modexp_B + E) + 12 => E + 49243470232752527078453874556325179294416166539728462357711709398098439589335n :MSTORE(modexp_B + E) + 13 => E + 92761635604125986140178553355595569536048741412993352818243357282258747219597n :MSTORE(modexp_B + E) + 14 => E + 107125026528073614477778162400448845380679887461023000294123673028489410115428n :MSTORE(modexp_B + E) + 15 => E + 50015491922034682795400667595741184186461047999761793737177234529134772742883n :MSTORE(modexp_B + E) + 16 => E + 93839364887903211464040378523451721648365970883493581494218955280319875788856n :MSTORE(modexp_B + E) + 17 => E + 17091472401859236813752505473711584993054095047275178116344296041292612882277n :MSTORE(modexp_B + E) + 18 => E + 33133235434716137789301333902142435942934988584475245270513939078566706035139n :MSTORE(modexp_B + E) + 19 => E + 8618563902985774097645699060359830371796371389216077101052936350915552332541n :MSTORE(modexp_B + E) + 20 => E + 32959204030626041166684100562123025735545974992282090777516360003585051763609n :MSTORE(modexp_B + E) + 21 => E + 82767509598720527511245866314874791036239553482587678455676791496639924352817n :MSTORE(modexp_B + E) + 22 => E + 24581016226774148963550354927392864083633602722111543645399304218924673583653n :MSTORE(modexp_B + E) + 23 => E + 54907909205416467790958752093550345903140417587581313515617803654573424767356n :MSTORE(modexp_B + E) + 24 => E + 100791016977344006113073169055960011281141395301059720257405619893429714167341n :MSTORE(modexp_B + E) + 25 => E + 24941924336732284648883856125208379683444168476081791710711797807642735673908n :MSTORE(modexp_B + E) + 26 => E + 84084005778965612817305629593090007081360298325328658417757739306412791334620n :MSTORE(modexp_B + E) + 27 => E + 57802445510214963192751495314468666350299014243361752557159297425362287711690n :MSTORE(modexp_B + E) + 28 => E + 71604073139668550693524183042211626872574021539160119710031007420261347015402n :MSTORE(modexp_B + E) + 29 => E + 112794949372007878255901773641270094155501693398414692888840800526209520944761n :MSTORE(modexp_B + E) + 30 => E + 70731187935137252399476378656555562056546473720901706122635244057158114695508n :MSTORE(modexp_B + E) + 31 => E + 3352858292656216054449205160393741706300333423229119841653557821211210632061n :MSTORE(modexp_B + E) + 65537n :MSTORE(modexp_E) + 39851039703995454411192288480134431431581770200184123399645359412272832511626n :MSTORE(modexp_M) + 1 => E + 37752885539763212929058244732198218613925905715762498172556148837284915557195n :MSTORE(modexp_M + E) + :CALL(modexp) + 56022410747783146699662217269120785748464099550239963682054680910629578115775n :MLOAD(modexp_out) + 1 => E + 14493810196578292049955796525564942375140358401736189058384961357909052370153n :MLOAD(modexp_out + E) + 2 :MLOAD(modexp_outlen) + + ; 3] Blen = Mlen = 32, Elen = 1 + 32 :MSTORE(modexp_Blen) + 1 :MSTORE(modexp_Elen) + 32 :MSTORE(modexp_Mlen) + 92206843202422108295909528035550457464239320812270316776092313402308890408911n :MSTORE(modexp_B) + 1 => E + 40047772076258452565877196627420165964878704505255944176438631996680615030611n :MSTORE(modexp_B + E) + 2 => E + 55102040540711402889102967093617552676427432935425286148682018808976201507778n :MSTORE(modexp_B + E) + 3 => E + 35977955280462673410065921775534746257488802258911143491412287540616950769160n :MSTORE(modexp_B + E) + 4 => E + 37644026846003786822663244057143575378558522684877331457964638586784769687834n :MSTORE(modexp_B + E) + 5 => E + 95028989117142459258134747419890072384642803238895763244914849595506863386645n :MSTORE(modexp_B + E) + 6 => E + 98752559915078375248706497466993285247357859991905637655508437702664948471657n :MSTORE(modexp_B + E) + 7 => E + 57556090597927384265879763338486069464019514834099187336411030352822407281500n :MSTORE(modexp_B + E) + 8 => E + 43245974976750172864772520889451618739117437705914718778809420871482727125874n :MSTORE(modexp_B + E) + 9 => E + 37816491176919635104738211146369245940065309375200509983093469423384094112063n :MSTORE(modexp_B + E) + 10 => E + 20970663255814660086902645966751426055028722148631626981362495496877355851737n :MSTORE(modexp_B + E) + 11 => E + 98188032184022250155917923589680287518584405350588578347292998398753174211131n :MSTORE(modexp_B + E) + 12 => E + 25669385787317930981514354902647200932766434979448204542393628100520533481378n :MSTORE(modexp_B + E) + 13 => E + 68814029900175265564145503634188485940902886536475131975501235640271933000917n :MSTORE(modexp_B + E) + 14 => E + 87160340236243582192548479249681726729426388277620719812174126540286740215268n :MSTORE(modexp_B + E) + 15 => E + 29692821174578757130874540207778004864893877954579183917960766336158356467894n :MSTORE(modexp_B + E) + 16 => E + 73039028043650402284653870956294802036450850175073538200565082725180560418907n :MSTORE(modexp_B + E) + 17 => E + 11668112155824627458775018373205936935581049325992845160492054092186046358857n :MSTORE(modexp_B + E) + 18 => E + 7054109538479788725498636965308049949839728294281187091777313524644702701653n :MSTORE(modexp_B + E) + 19 => E + 101118203028338998071114272484985720901803997816981804606080272352029643017768n :MSTORE(modexp_B + E) + 20 => E + 106804875640632221507429078060933974218903538309320795560242169811823501762267n :MSTORE(modexp_B + E) + 21 => E + 76099296226965961367040388859656785469695879825602049246736152150184380430612n :MSTORE(modexp_B + E) + 22 => E + 43812961873041613946199674284046527360672846592749061754017962280360251277355n :MSTORE(modexp_B + E) + 23 => E + 7062347313150321268502311461014160635849079926696159188177206139634892948139n :MSTORE(modexp_B + E) + 24 => E + 8633876293298165655127866110656903949530672877542367025725070246145898674563n :MSTORE(modexp_B + E) + 25 => E + 110372118966868761743522615580597421512083491043211030463191844113573169356901n :MSTORE(modexp_B + E) + 26 => E + 80444563886753262124629748205979575562005096448183330362371710369722907876501n :MSTORE(modexp_B + E) + 27 => E + 42973803045570795229868100199252568426210462234822006788269243160598575230641n :MSTORE(modexp_B + E) + 28 => E + 11924876837570961813808882528583392494850602245530414004520515070262642005471n :MSTORE(modexp_B + E) + 29 => E + 36143537899184300246105940770452042497670815178998869929403492308830551975876n :MSTORE(modexp_B + E) + 30 => E + 264588434667051108106558461267166102941301300012456816625201418909343549391n :MSTORE(modexp_B + E) + 31 => E + 89390763868221043648698068187735204588647734710461878957221698506204833642203n :MSTORE(modexp_B + E) + 65537n :MSTORE(modexp_E) + 72847221021874037642769569132275164094322040442822821773040516004504186942893n :MSTORE(modexp_M) + 1 => E + 69731219719976001030717402405830121891735509392988721738752072035354190365546n :MSTORE(modexp_M + E) + 2 => E + 71031544988545942319520910296463939232109013876586145075301566927609834669888n :MSTORE(modexp_M + E) + 3 => E + 26988903963140438794051518198668495502883507750878003573810648320004277706214n :MSTORE(modexp_M + E) + 4 => E + 26923009822476899667478662828545659748880207850162126352168369071390890626682n :MSTORE(modexp_M + E) + 5 => E + 96931265726466364911193175927701052794262069284608352964995015999732939352960n :MSTORE(modexp_M + E) + 6 => E + 98173748339862731302780344170956651996850166987441306225289378135087663102392n :MSTORE(modexp_M + E) + 7 => E + 68934287332388240451226243957707369220107762473159962455924263324767609116793n :MSTORE(modexp_M + E) + 8 => E + 1832504478079764331915743572886117120628365701742117947359542627373405406328n :MSTORE(modexp_M + E) + 9 => E + 68301288638357799144485921485489776253909531615993802867385359644936169382323n :MSTORE(modexp_M + E) + 10 => E + 50972743615540071729221881664796921748468189686351130644316265553337483524672n :MSTORE(modexp_M + E) + 11 => E + 15207443544656988850347729198275516539450007609685086978085959593060693030487n :MSTORE(modexp_M + E) + 12 => E + 5433038755888594263181690062917757730627703937725727343727151020245663368439n :MSTORE(modexp_M + E) + 13 => E + 13791242616407995591280216657127566393158300752530618316359975533848759348327n :MSTORE(modexp_M + E) + 14 => E + 46359208899322282320547392249270149043047396707829214050316719979015506309260n :MSTORE(modexp_M + E) + 15 => E + 4136285261198097287643094585085999496114764918441405377568065465080433286535n :MSTORE(modexp_M + E) + 16 => E + 101010623283584921497494674625278283482597149142501317611342536338650919847285n :MSTORE(modexp_M + E) + 17 => E + 71718184868458030700513008557233607166388496070600773105990878610566352668478n :MSTORE(modexp_M + E) + 18 => E + 58835915852484627531546395518481357741140083996335714932736008557799387806379n :MSTORE(modexp_M + E) + 19 => E + 110990609890790220505193608739997845349191779958492236054709193460408621504669n :MSTORE(modexp_M + E) + 20 => E + 96379496026765561813937988417405440162695262824201145254831686004222812216418n :MSTORE(modexp_M + E) + 21 => E + 82925026338043992721120049617193479691714841002654113449473181778596956082920n :MSTORE(modexp_M + E) + 22 => E + 100023901102385901973724374201876255032845338138580308882617263003615020308810n :MSTORE(modexp_M + E) + 23 => E + 95952213078202102225468090590217757485597979953604518053194588551562232005328n :MSTORE(modexp_M + E) + 24 => E + 3577026816335999968748395316796404869630041860090349190142189122043709889551n :MSTORE(modexp_M + E) + 25 => E + 109063498273720822329401504720108142219864403250117040531373131752282931463324n :MSTORE(modexp_M + E) + 26 => E + 27979004844780866654085603865732315060118803050644142741740092959358337388274n :MSTORE(modexp_M + E) + 27 => E + 24825258000785841949542820675205430709826458566611547296010427802043033991005n :MSTORE(modexp_M + E) + 28 => E + 49031301463517022513899268811000038114693491982961073699105948652240780094456n :MSTORE(modexp_M + E) + 29 => E + 114204515557203015266974583011383895979566987933197495441844505245979656755929n :MSTORE(modexp_M + E) + 30 => E + 78491904893089992686529903837940897519206435582635929630386408975070579157365n :MSTORE(modexp_M + E) + 31 => E + 102675521321841909801053294363031989532243193264355291794310082365691483423498n :MSTORE(modexp_M + E) + :CALL(modexp) + 677894576676631978762225005345398803352392083933732578515354226985023681792n :MLOAD(modexp_out) + 1 => E + 30983700189750465957952042435955105754963199835136808771081585991196056603533n :MLOAD(modexp_out + E) + 2 => E + 96977624522594450801541733995544628971015390835463187143212961973552500720710n :MLOAD(modexp_out + E) + 3 => E + 56114900155652441916464774637573049435630604518898416817685636860353438904690n :MLOAD(modexp_out + E) + 4 => E + 26654824404634087607897029500347455956982618454171914029346215577013032668874n :MLOAD(modexp_out + E) + 5 => E + 82588806309433243368106809807628870406466678061433605795202724077569780612666n :MLOAD(modexp_out + E) + 6 => E + 97933618002683983699820462412182946416951394764940011329348416882228004555192n :MLOAD(modexp_out + E) + 7 => E + 91974656276525162864490852539001571486994660590533935810085276565543825792935n :MLOAD(modexp_out + E) + 8 => E + 14136595934712265420422087179017462511247051603950489074490810742177656003907n :MLOAD(modexp_out + E) + 9 => E + 48125222252921746199762482100491455173844534471982929161438685737650186283704n :MLOAD(modexp_out + E) + 10 => E + 48107851915594109975315423983766253025680196062973422346056328244340733385970n :MLOAD(modexp_out + E) + 11 => E + 86954418248654364144745131584472622053075114694263175729171643632936297192862n :MLOAD(modexp_out + E) + 12 => E + 109691144365836675943146054875317393326628140256492700988957490200625823775185n :MLOAD(modexp_out + E) + 13 => E + 32292512431244590061446854088456146854345648248097217451888860871153877828563n :MLOAD(modexp_out + E) + 14 => E + 65792790710630644347879244464254837532349265508035775328499355449612521734549n :MLOAD(modexp_out + E) + 15 => E + 89765858380763137329673491280409498253435611301713781654835842065015314105304n :MLOAD(modexp_out + E) + 16 => E + 35171816476825758331036644979464255466931468945835176682525048220517607291864n :MLOAD(modexp_out + E) + 17 => E + 87898794801683267042131251427895513029310648885531121798980287601368853382291n :MLOAD(modexp_out + E) + 18 => E + 64388675366825537694841610983948205362927385527175427273890935480735460523881n :MLOAD(modexp_out + E) + 19 => E + 99955447086715432279557400852227643751624133140601483306492249769432748925953n :MLOAD(modexp_out + E) + 20 => E + 24476073658846379337950527005029962650889618395597987670121609506999218493048n :MLOAD(modexp_out + E) + 21 => E + 111763844358629697753193373290688595861299431022701437954908278806392751790575n :MLOAD(modexp_out + E) + 22 => E + 79904940302542711327641239100871361685141987738151011046821092049887467991286n :MLOAD(modexp_out + E) + 23 => E + 43707225392916562210253783663272091369045047071043018557053394387471461416479n :MLOAD(modexp_out + E) + 24 => E + 98308041900501354334940003472357888716582517911775035256283753134795218938611n :MLOAD(modexp_out + E) + 25 => E + 65935384960991952146654815676745484728495550460251405131997483203896289078769n :MLOAD(modexp_out + E) + 26 => E + 20130837003505484436463566444811036744003990239310189118996363703596530902859n :MLOAD(modexp_out + E) + 27 => E + 16957048272619737139490804874038052955006088486308702807491576262642577133096n :MLOAD(modexp_out + E) + 28 => E + 11616018929629640269971042218145996725282129064687370436521646879832529443317n :MLOAD(modexp_out + E) + 29 => E + 63617577915798873005195071463719881573415608074827000652669926242766448670534n :MLOAD(modexp_out + E) + 30 => E + 12384180274645355595105366212522790398784832091160640277349754557987863589673n :MLOAD(modexp_out + E) + 31 => E + 40734125863026273932428199995766034988856785758079943910749929611210985198371n :MLOAD(modexp_out + E) + 32 :MLOAD(modexp_outlen) + ; --------------------------------------------------------------------------------------------- + + ; ; SINGLETON TESTS TO ENSURE THE MAXIMUM INPUT LENGTH WE CAN ACHIEVE IN EACH OF BASE, EXPONENT + ; ; AND MODULUS WITHOUT OVERFLOWING EITHER THE ARITH, BINARY OF STEPS COUNTERS + ; ; --------------------------------------------------------------------------------------------- + ; ; 1] B = [2n:1818n], E = [1n], M = [2n] + ; ; Hamming weight of E is 1 + ; 1818 :MSTORE(modexp_Blen) + ; 1 :MSTORE(modexp_Elen) + ; 1 :MSTORE(modexp_Mlen) + + ; 1818 => E + ; singleton_test1_copy_in_loop: + ; E - 1 => E + ; 2 :MSTORE(modexp_B + E) + ; E :JMPZ(singleton_test1_modexp, singleton_test1_copy_in_loop) + + ; singleton_test1_modexp: + ; 1n :MSTORE(modexp_E) + ; 2n :MSTORE(modexp_M) + ; :CALL(modexp) + ; 0n :MLOAD(modexp_out) + ; 1 :MLOAD(modexp_outlen) + + ; ; 2] B = [2n], E = [1n], M = [2n:1818] + ; ; Hamming weight of E is 1 + ; 1 :MSTORE(modexp_Blen) + ; 1 :MSTORE(modexp_Elen) + ; 1818 :MSTORE(modexp_Mlen) + + ; 1818 => E + ; singleton_test2_copy_in_loop: + ; E - 1 => E + ; 1 :MSTORE(modexp_M + E) + ; E :JMPZ(singleton_test2_modexp, singleton_test2_copy_in_loop) + + ; singleton_test2_modexp: + ; 2n :MSTORE(modexp_B) + ; 1n :MSTORE(modexp_E) + ; :CALL(modexp) + ; 2n :MLOAD(modexp_out) + ; 1 :MLOAD(modexp_outlen) + + ; ; 3] B = [2n], E = [1n:1818], M = [2n] + ; ; Hamming weight of E is 1818 + ; 1 :MSTORE(modexp_Blen) + ; 1818 :MSTORE(modexp_Elen) + ; 1 :MSTORE(modexp_Mlen) + + ; 1818 => E + ; singleton_test3_copy_in_loop: + ; E - 1 => E + ; 1 :MSTORE(modexp_E + E) + ; E :JMPZ(singleton_test3_modexp, singleton_test3_copy_in_loop) + + ; singleton_test3_modexp: + ; 2n :MSTORE(modexp_B) + ; 2n :MSTORE(modexp_M) + ; :CALL(modexp) + ; 0n :MLOAD(modexp_out) + ; 1 :MLOAD(modexp_outlen) + ; ; --------------------------------------------------------------------------------------------- + + ; ; UPDATE: Edge cases are not handled by the modexp function directly anymore ; ; EDGE CASES TESTS ; ; --------------------------------------------------------------------------------------------- ; ; 1] B == 0, E != 0, M != 0 should return 0 @@ -253,281 +1260,6 @@ start: ; 1 :MLOAD(modexp_outlen) ; ; --------------------------------------------------------------------------------------------- - ; 256 BITS EXPONENT TESTS - ; --------------------------------------------------------------------------------------------- - ; 1] B == k·M (at any point of the exponentiations) should return 0 - 1 :MSTORE(modexp_Blen) - 1 :MSTORE(modexp_Elen) - 1 :MSTORE(modexp_Mlen) - 4n :MSTORE(modexp_B) - 78n :MSTORE(modexp_E) - 4n :MSTORE(modexp_M) - :CALL(modexp) - 0n :MLOAD(modexp_out) - 1 :MLOAD(modexp_outlen) - - 1 :MSTORE(modexp_Blen) - 1 :MSTORE(modexp_Elen) - 1 :MSTORE(modexp_Mlen) - 8n :MSTORE(modexp_B) - 78n :MSTORE(modexp_E) - 4n :MSTORE(modexp_M) - :CALL(modexp) - 0n :MLOAD(modexp_out) - 1 :MLOAD(modexp_outlen) - - 1 :MSTORE(modexp_Blen) - 1 :MSTORE(modexp_Elen) - 1 :MSTORE(modexp_Mlen) - 2n :MSTORE(modexp_B) - 2n :MSTORE(modexp_E) - 4n :MSTORE(modexp_M) - :CALL(modexp) - 0n :MLOAD(modexp_out) - 1 :MLOAD(modexp_outlen) - - ; 2] B = [100n, 2831023n, 0n, 73916234139162n], E = [2n**256n - 1n], M = [0n, 0n, 8238129386n, 23102318237n] - ; Hamming weight of E is 256 - 4 :MSTORE(modexp_Blen) - 1 :MSTORE(modexp_Elen) - 4 :MSTORE(modexp_Mlen) - - 100n :MSTORE(modexp_B) - 1 => E - 2831023n :MSTORE(modexp_B + E) - 2 => E - 0n :MSTORE(modexp_B + E) - 3 => E - 73916234139162n :MSTORE(modexp_B + E) - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(modexp_E) - 0n :MSTORE(modexp_M) - 1 => E - 0n :MSTORE(modexp_M + E) - 2 => E - 8238129386n :MSTORE(modexp_M + E) - 3 => E - 23102318237n :MSTORE(modexp_M + E) - :CALL(modexp) - 0n :MLOAD(modexp_out) - 1 => E - 0n :MLOAD(modexp_out + E) - 2 => E - 25636070175539943947777314844209202718110211581133019863886488575898865601868n :MLOAD(modexp_out + E) - 3 => E - 4679155145n :MLOAD(modexp_out + E) - 4 :MLOAD(modexp_outlen) - - ; 3] B = [100n, 2831023n, 0n, 73916234139162n, 100n, 2831023n, 0n, 73916234139162n,100n, 2831023n, 0n, 73916234139162n], E = [903741926349715234612309461283471234n], M = [0n, 0n, 8238129386n, 23102318237n, 1892397612351n, 7246598123051n, 8238129386n, 1264591241237897123126n] - ; Hamming weight of E is 120 - 12 :MSTORE(modexp_Blen) - 1 :MSTORE(modexp_Elen) - 8 :MSTORE(modexp_Mlen) - - 100n :MSTORE(modexp_B) - 1 => E - 2831023n :MSTORE(modexp_B + E) - 2 => E - 0n :MSTORE(modexp_B + E) - 3 => E - 73916234139162n :MSTORE(modexp_B + E) - 4 => E - 100n :MSTORE(modexp_B + E) - 5 => E - 2831023n :MSTORE(modexp_B + E) - 6 => E - 0n :MSTORE(modexp_B + E) - 7 => E - 73916234139162n :MSTORE(modexp_B + E) - 8 => E - 100n :MSTORE(modexp_B + E) - 9 => E - 2831023n :MSTORE(modexp_B + E) - 10 => E - 0n :MSTORE(modexp_B + E) - 11 => E - 73916234139162n :MSTORE(modexp_B + E) - 903741926349715234612309461283471234n :MSTORE(modexp_E) - 0n :MSTORE(modexp_M) - 1 => E - 0n :MSTORE(modexp_M + E) - 2 => E - 8238129386n :MSTORE(modexp_M + E) - 3 => E - 23102318237n :MSTORE(modexp_M + E) - 4 => E - 1892397612351n :MSTORE(modexp_M + E) - 5 => E - 7246598123051n :MSTORE(modexp_M + E) - 6 => E - 8238129386n :MSTORE(modexp_M + E) - 7 => E - 1264591241237897123126n :MSTORE(modexp_M + E) - :CALL(modexp) - 0n :MLOAD(modexp_out) - 1 => E - 0n :MLOAD(modexp_out + E) - 2 => E - 14984469305990977542353827078899382678368215018946198341845725551977623627446n :MLOAD(modexp_out + E) - 3 => E - 68986200907052834988812862957862042564780541926701277492865197684364096948359n :MLOAD(modexp_out + E) - 4 => E - 19960171666179366961875030436152164148711578520678689062449823687317995303656n :MLOAD(modexp_out + E) - 5 => E - 10163909190618518832451417682132582498490814809943760852308996448668923869413n :MLOAD(modexp_out + E) - 6 => E - 29735535392706191114764336807325502135962613879333248096358552087717155148899n :MLOAD(modexp_out + E) - 7 => E - 511131288598502431475n :MLOAD(modexp_out + E) - 8 :MLOAD(modexp_outlen) - - ; 4] B = [7n], E = [110n], M = [7719472615821079694904732333912527190217998977709370935963838933860875309329n, 17n] - ; Hamming weight of E is 5 - 1 :MSTORE(modexp_Blen) - 1 :MSTORE(modexp_Elen) - 2 :MSTORE(modexp_Mlen) - - 7n :MSTORE(modexp_B) - 110n :MSTORE(modexp_E) - 7719472615821079694904732333912527190217998977709370935963838933860875309329n :MSTORE(modexp_M) - 1 => E - 17n :MSTORE(modexp_M + E) - :CALL(modexp) - 81730215206688390341255830729934766338330049967253209305087427132484271882414n :MLOAD(modexp_out) - 1 => E - 13n :MLOAD(modexp_out + E) - 2 :MLOAD(modexp_outlen) - ; --------------------------------------------------------------------------------------------- - - ; 512 BITS EXPONENT TESTS - ; --------------------------------------------------------------------------------------------- - ; 1] B = [2n, 1n, 1n, 1n], E = [3n, 5n], M = [4n, 6n, 7n] - ; Hamming weight of E is 4 - 4 :MSTORE(modexp_Blen) - 2 :MSTORE(modexp_Elen) - 3 :MSTORE(modexp_Mlen) - - 2n :MSTORE(modexp_B) - 1 => E - 1n :MSTORE(modexp_B + E) - 2 => E - 1n :MSTORE(modexp_B + E) - 3 => E - 1n :MSTORE(modexp_B + E) - 3n :MSTORE(modexp_E) - 1 => E - 5n :MSTORE(modexp_E + E) - 4n :MSTORE(modexp_M) - 1 => E - 6n :MSTORE(modexp_M + E) - 2 => E - 7n :MSTORE(modexp_M + E) - :CALL(modexp) - 16799222018138169590613227618843456355247327644003751420511040302320945803948n :MLOAD(modexp_out) - 1 => E - 67226185770814561827024093064262870237432709513661454124124794094744315370418n :MLOAD(modexp_out + E) - 2 => E - 1n :MLOAD(modexp_out + E) - 3 :MLOAD(modexp_outlen) - - ; 2] B = [2n, 1n, 1n, 1n], E = [2n**256n - 1n, 2n**256n - 1n], M = [4n, 6n, 7n] - ; Hamming weight of E is 512 - 4 :MSTORE(modexp_Blen) - 2 :MSTORE(modexp_Elen) - 3 :MSTORE(modexp_Mlen) - - 2n :MSTORE(modexp_B) - 1 => E - 1n :MSTORE(modexp_B + E) - 2 => E - 1n :MSTORE(modexp_B + E) - 3 => E - 1n :MSTORE(modexp_B + E) - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(modexp_E) - 1 => E - 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MSTORE(modexp_E + E) - 4n :MSTORE(modexp_M) - 1 => E - 6n :MSTORE(modexp_M + E) - 2 => E - 7n :MSTORE(modexp_M + E) - :CALL(modexp) - 111873638420780286093512129901489267041413036926649390648147612881355784341812n :MLOAD(modexp_out) - 1 => E - 11181991619082508729788448443921623930160246165837402400671610626538926623319n :MLOAD(modexp_out + E) - 2 => E - 2n :MLOAD(modexp_out + E) - 3 :MLOAD(modexp_outlen) - ; --------------------------------------------------------------------------------------------- - - ; 768 BITS EXPONENT TESTS - ; --------------------------------------------------------------------------------------------- - ; --------------------------------------------------------------------------------------------- - - ; 1024 BITS EXPONENT TESTS - ; --------------------------------------------------------------------------------------------- - ; --------------------------------------------------------------------------------------------- - -; ; SINGLETON TESTS TO ENSURE THE MAXIMUM INPUT LENGTH WE CAN ACHIEVE IN EACH OF BASE, EXPONENT -; ; AND MODULUS WITHOUT OVERFLOWING EITHER THE ARITH, BINARY OF STEPS COUNTERS -; ; --------------------------------------------------------------------------------------------- -; ; 1] B = [2n:1818n], E = [1n], M = [2n] -; ; Hamming weight of E is 1 -; 1818 :MSTORE(modexp_Blen) -; 1 :MSTORE(modexp_Elen) -; 1 :MSTORE(modexp_Mlen) - -; 1818 => E -; singleton_test1_copy_in_loop: -; E - 1 => E -; 2 :MSTORE(modexp_B + E) -; E :JMPZ(singleton_test1_modexp, singleton_test1_copy_in_loop) - -; singleton_test1_modexp: -; 1n :MSTORE(modexp_E) -; 2n :MSTORE(modexp_M) -; :CALL(modexp) -; 0n :MLOAD(modexp_out) -; 1 :MLOAD(modexp_outlen) - -; ; 2] B = [2n], E = [1n], M = [2n:1818] -; ; Hamming weight of E is 1 -; 1 :MSTORE(modexp_Blen) -; 1 :MSTORE(modexp_Elen) -; 1818 :MSTORE(modexp_Mlen) - -; 1818 => E -; singleton_test2_copy_in_loop: -; E - 1 => E -; 1 :MSTORE(modexp_M + E) -; E :JMPZ(singleton_test2_modexp, singleton_test2_copy_in_loop) - -; singleton_test2_modexp: -; 2n :MSTORE(modexp_B) -; 1n :MSTORE(modexp_E) -; :CALL(modexp) -; 2n :MLOAD(modexp_out) -; 1 :MLOAD(modexp_outlen) - -; ; 3] B = [2n], E = [1n:1818], M = [2n] -; ; Hamming weight of E is 1818 -; 1 :MSTORE(modexp_Blen) -; 1818 :MSTORE(modexp_Elen) -; 1 :MSTORE(modexp_Mlen) - -; 1818 => E -; singleton_test3_copy_in_loop: -; E - 1 => E -; 1 :MSTORE(modexp_E + E) -; E :JMPZ(singleton_test3_modexp, singleton_test3_copy_in_loop) - -; singleton_test3_modexp: -; 2n :MSTORE(modexp_B) -; 2n :MSTORE(modexp_M) -; :CALL(modexp) -; 0n :MLOAD(modexp_out) -; 1 :MLOAD(modexp_outlen) -; ; --------------------------------------------------------------------------------------------- - :JMP(end) outOfCountersBinary: @@ -570,17 +1302,14 @@ checkAndSaveFrom: INCLUDE "../main/modexp/constants.zkasm" -INCLUDE "../main/modexp/array_lib/utils/array_trim.zkasm" -INCLUDE "../main/modexp/array_lib/utils/array_compare.zkasm" - INCLUDE "../main/modexp/array_lib/array_add_AGTB.zkasm" INCLUDE "../main/modexp/array_lib/array_add_short.zkasm" INCLUDE "../main/modexp/array_lib/array_mul_long.zkasm" INCLUDE "../main/modexp/array_lib/array_mul_short.zkasm" -INCLUDE "../main/modexp/array_lib/array_mul.zkasm" +INCLUDE "../main/modexp/array_lib/array_mul_two.zkasm" INCLUDE "../main/modexp/array_lib/array_square.zkasm" INCLUDE "../main/modexp/array_lib/array_div_short.zkasm" +INCLUDE "../main/modexp/array_lib/array_div_two.zkasm" INCLUDE "../main/modexp/array_lib/array_div_long.zkasm" -INCLUDE "../main/modexp/array_lib/array_div.zkasm" INCLUDE "../main/modexp/modexp.zkasm" \ No newline at end of file From 675e3aea4ff490fb5ff1944455b9177b884ce8ad Mon Sep 17 00:00:00 2001 From: Laia Soler Date: Wed, 2 Oct 2024 12:52:58 +0200 Subject: [PATCH 03/12] update constant forkId = 13 --- main/constants.zkasm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/constants.zkasm b/main/constants.zkasm index be9dc87e..d66a2570 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 = 12 +CONST %FORK_ID = 13 CONST %L1INFO_TREE_LEVELS = 32 CONST %CALLDATA_RESERVED_CTX = 1 CONSTL %FOUR_GOLDILOCKS = 0xffffffff00000001ffffffff00000001ffffffff00000001ffffffff00000001n From b7904d4711155972c568b27da8a22710e574ac06 Mon Sep 17 00:00:00 2001 From: Lua Date: Fri, 22 Mar 2024 18:08:26 +0100 Subject: [PATCH 04/12] last fixes pre-modexp --- main/precompiled/pre-modexp.zkasm | 77 ++++++++++++++++--------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/main/precompiled/pre-modexp.zkasm b/main/precompiled/pre-modexp.zkasm index 7bcd9271..09c51a8f 100644 --- a/main/precompiled/pre-modexp.zkasm +++ b/main/precompiled/pre-modexp.zkasm @@ -38,9 +38,9 @@ VAR GLOBAL modexp_Mend VAR GLOBAL modexp_offset VAR GLOBAL modexp_returnIndex VAR GLOBAL modexp_returnFirstIndex -VAR GLOBAL modexp_returnIndexRem VAR GLOBAL expLenBits VAR GLOBAL retCopyLen +VAR GLOBAL offsetCopyReturn funcModexp: @@ -273,33 +273,48 @@ finalMODEXP: B => A finalMODEXPreturn: - ; write data into memory + ; save lower between retCallLength and modexd_Msize in retCopyLen A :MSTORE(retCopyLen) + + ; write data into memory 0 => B + ; memory length === Msize $ => C :MLOAD(modexp_Msize) C :MSTORE(arithA) 32 :MSTORE(arithB), CALL(divARITH) + ; number of chunks (32 bytes) to copy from modexp_out to memory $ => E :MLOAD(arithRes1) + ; first index of modexp_out is the biggest --> 0x | modexp_out+N | .... | modexp_out+0 E :MSTORE(modexp_returnFirstIndex) $ => A :MLOAD(arithRes2) - A :MSTORE(modexp_returnIndexRem), JMPZ(memoryLoop) + A :JMPZ(memoryLoop) + ; if Msize % 32 > 0, copy last bytes, else --> memoryLoop A => C + ; A = 0x0000000000000000000000000000000000000000XXXXXXXXXXXXXXXXXXXXXXXX + ; C = lenght X's $ => A :MLOAD(modexp_out+E) 32 - C => D :CALL(SHLarith) + ; A = 0xXXXXXXXXXXXXXXXXXXXXXXXX0000000000000000000000000000000000000000 A :MSTORE(bytesToStore) + A :MSTORE(modexp_out+E) B => E + ; MSTORE X with C = lenght X's :CALL(MSTOREX) ; in: [bytesToStore, E: offset, C: length] out: [E: new offset] + ; E == new offset (0 + length X's) E => B $ => A :MLOAD(modexp_Msize) A - C => C :JMPZ(modexpReturn) + ; C new_size = total_size - total_size%32 $ => E :MLOAD(modexp_returnFirstIndex) memoryLoop: + ; loop chunks of 32 bytes to memory %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) %MAX_CNT_STEPS - STEP - 50 :JMPN(outOfCountersStep) + ; E = update index modexp_out E - 1 => E :MSTORE(modexp_returnIndex) $ => A :MLOAD(modexp_out+E) A :MSTORE(bytesToStore) @@ -316,47 +331,33 @@ modexpReturn: 0 :MSTORE(retDataOffset) $ => C :MLOAD(modexp_Msize) C :MSTORE(retDataLength) - $ => B :MLOAD(retCallOffset) + $ => D :MLOAD(retCallOffset) + D :MSTORE(offsetCopyReturn) $ => A :MLOAD(originCTX), JMPZ(handleGas) ; set retDataCTX - $ => E :MLOAD(currentCTX) + $ => B :MLOAD(currentCTX) A => CTX - E :MSTORE(retDataCTX) - + B :MSTORE(retDataCTX) $ => C :MLOAD(retCopyLen) - $ => E :MLOAD(modexp_returnFirstIndex) - $ => A :MLOAD(modexp_returnIndexRem), JMPZ(returnLoop) - A => C - $ => A :MLOAD(modexp_out+E) - 32 - C => D :CALL(SHLarith) - A :MSTORE(bytesToStore) - B => E - :CALL(MSTOREX) ; in: [bytesToStore, E: offset, C: length] out: [E: new offset] - E => B - $ => A :MLOAD(retCopyLen) - A - C => C :JMPZ(endMODEXP) - $ => E :MLOAD(modexp_returnFirstIndex) - -returnLoop: - %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 50 :JMPN(outOfCountersStep) - - E - 1 => E :MSTORE(modexp_returnIndex) - C - 32 :JMPN(returnLoopFinal) - $ => A :MLOAD(modexp_out+E) + 0 => E + ; copy retCopyLen from memory (currentCTX) to retCallOffset (originCTX) +modexpReturnLoop: + C - 32 :JMPN(modexpReturnFinal) + B => CTX :CALL(MLOAD32) + E => D + $ => CTX :MLOAD(originCTX) A :MSTORE(bytesToStore) - B => E - :CALL(MSTORE32) ; in: [bytesToStore, E: offset] out: [E: new offset] - E => B - $ => E :MLOAD(modexp_returnIndex) - C - 32 => C :JMPZ(endMODEXP, returnLoop) - -returnLoopFinal: - $ => A :MLOAD(modexp_out+E) - 32 - C => D :CALL(SHLarith) + $ => E :MLOAD(offsetCopyReturn) + :CALL(MSTORE32) + E :MSTORE(offsetCopyReturn) + D => E + C - 32 => C :JMPZ(endMODEXP, modexpReturnLoop) + +modexpReturnFinal: + B => CTX :CALL(MLOADX) + $ => CTX :MLOAD(originCTX) A :MSTORE(bytesToStore) - B => E - :CALL(MSTOREX) ; in: [bytesToStore, E: offset, C: length] out: [E: new offset] + $ => E :MLOAD(offsetCopyReturn),CALL(MSTOREX) :JMP(endMODEXP) preEndMODEXP: From c592be1eefaeb85c68eade63698c1b959beea5e2 Mon Sep 17 00:00:00 2001 From: Laia Soler Date: Wed, 2 Oct 2024 17:22:00 +0200 Subject: [PATCH 05/12] update selector modexp & fix comment --- main/precompiled/pre-modexp.zkasm | 2 +- main/precompiled/selector.zkasm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main/precompiled/pre-modexp.zkasm b/main/precompiled/pre-modexp.zkasm index 09c51a8f..fca9a208 100644 --- a/main/precompiled/pre-modexp.zkasm +++ b/main/precompiled/pre-modexp.zkasm @@ -206,7 +206,7 @@ lastChecks: $ :EQ, JMPC(save0out) ; if Bsize = 0 --> save0out ; Bsize > 0 from here - ; Check maximum length allowed in the zkEVM reagrding the modExp + ; Check maximum length allowed in the zkEVM regarding the modExp ; If parameters (length > %MAX_SIZE_MODEXP) --> zkEVM does a revert returning all the gas consumed %MAX_SIZE_MODEXP => A $ => B :MLOAD(modexp_Bsize) 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) From 436105ae0a9426fa6200e264ff8d4f761e071d12 Mon Sep 17 00:00:00 2001 From: Laia Soler Date: Thu, 3 Oct 2024 14:18:01 +0200 Subject: [PATCH 06/12] update test-vectors forkid 13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 809ee4c0..41155a27 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "devDependencies": { "@0xpolygonhermez/zkevm-commonjs": "github:0xPolygonHermez/zkevm-commonjs#v8.0.0-fork.12", "@0xpolygonhermez/zkevm-proverjs": "github:0xPolygonHermez/zkevm-proverjs#v8.0.0-fork.12", - "@0xpolygonhermez/zkevm-testvectors": "github:0xPolygonHermez/zkevm-testvectors#v8.0.0-fork.12", + "@0xpolygonhermez/zkevm-testvectors": "github:0xPolygonHermez/zkevm-testvectors#feature/fork-13", "chai": "^4.3.6", "chalk": "^3.0.0", "eslint": "^8.25.0", From 8164ea7367add72febcdec4899855fc34d4900e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Masip?= Date: Fri, 4 Oct 2024 16:49:58 +0200 Subject: [PATCH 07/12] Fixing package --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 41155a27..bf7e1503 100644 --- a/package.json +++ b/package.json @@ -39,12 +39,12 @@ "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-durian", "yargs": "^17.5.1" }, "devDependencies": { "@0xpolygonhermez/zkevm-commonjs": "github:0xPolygonHermez/zkevm-commonjs#v8.0.0-fork.12", - "@0xpolygonhermez/zkevm-proverjs": "github:0xPolygonHermez/zkevm-proverjs#v8.0.0-fork.12", + "@0xpolygonhermez/zkevm-proverjs": "github:0xPolygonHermez/zkevm-proverjs#develop-durian", "@0xpolygonhermez/zkevm-testvectors": "github:0xPolygonHermez/zkevm-testvectors#feature/fork-13", "chai": "^4.3.6", "chalk": "^3.0.0", From ee45fd22026fd799b739f2d1caf095cc7de32b73 Mon Sep 17 00:00:00 2001 From: Laia Soler Date: Fri, 4 Oct 2024 17:22:53 +0200 Subject: [PATCH 08/12] update pre-modexp includes --- main/precompiled/pre-modexp.zkasm | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/main/precompiled/pre-modexp.zkasm b/main/precompiled/pre-modexp.zkasm index fca9a208..4a924836 100644 --- a/main/precompiled/pre-modexp.zkasm +++ b/main/precompiled/pre-modexp.zkasm @@ -16,18 +16,15 @@ INCLUDE "../modexp/constants.zkasm" INCLUDE "../modexp/modexp.zkasm" INCLUDE "../modexp/modexp_utils.zkasm" -INCLUDE "../modexp/array_lib/utils/array_trim.zkasm" -INCLUDE "../modexp/array_lib/utils/array_compare.zkasm" - +INCLUDE "../modexp/array_lib/array_mul_two.zkasm" +INCLUDE "../modexp/array_lib/array_div_two.zkasm" INCLUDE "../modexp/array_lib/array_add_AGTB.zkasm" INCLUDE "../modexp/array_lib/array_add_short.zkasm" INCLUDE "../modexp/array_lib/array_mul_long.zkasm" INCLUDE "../modexp/array_lib/array_mul_short.zkasm" -INCLUDE "../modexp/array_lib/array_mul.zkasm" INCLUDE "../modexp/array_lib/array_square.zkasm" INCLUDE "../modexp/array_lib/array_div_short.zkasm" INCLUDE "../modexp/array_lib/array_div_long.zkasm" -INCLUDE "../modexp/array_lib/array_div.zkasm" VAR GLOBAL multiplication_complexity From 127a08d648a76fe32e22bffaf414ac8e6b2064f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Masip?= Date: Mon, 7 Oct 2024 17:52:03 +0200 Subject: [PATCH 09/12] Moving the return correctly --- main/modexp/array_lib/array_add_AGTB.zkasm | 3 ++- main/modexp/array_lib/array_add_short.zkasm | 3 ++- main/modexp/array_lib/array_div_long.zkasm | 3 ++- main/modexp/array_lib/array_div_short.zkasm | 3 ++- main/modexp/array_lib/array_div_two.zkasm | 3 ++- main/modexp/array_lib/array_mul_long.zkasm | 3 ++- main/modexp/array_lib/array_mul_short.zkasm | 3 ++- main/modexp/array_lib/array_mul_two.zkasm | 3 ++- main/modexp/array_lib/array_square.zkasm | 3 ++- main/modexp/modexp.zkasm | 3 ++- 10 files changed, 20 insertions(+), 10 deletions(-) diff --git a/main/modexp/array_lib/array_add_AGTB.zkasm b/main/modexp/array_lib/array_add_AGTB.zkasm index 5a70c9d0..ce7b6e3f 100644 --- a/main/modexp/array_lib/array_add_AGTB.zkasm +++ b/main/modexp/array_lib/array_add_AGTB.zkasm @@ -128,4 +128,5 @@ array_add_AGTB_trim: E :MSTORE(array_add_AGTB_len_out) array_add_AGTB_end: - $ => RR :MLOAD(array_add_AGTB_RR), RETURN \ No newline at end of file + $ => RR :MLOAD(array_add_AGTB_RR) + :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_add_short.zkasm b/main/modexp/array_lib/array_add_short.zkasm index 38e91465..961a44be 100644 --- a/main/modexp/array_lib/array_add_short.zkasm +++ b/main/modexp/array_lib/array_add_short.zkasm @@ -89,4 +89,5 @@ array_add_short_trim: E :MSTORE(array_add_short_len_out) array_add_short_end: - $ => RR :MLOAD(array_add_short_RR), RETURN \ No newline at end of file + $ => RR :MLOAD(array_add_short_RR) + :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_div_long.zkasm b/main/modexp/array_lib/array_div_long.zkasm index 80ba5bc3..677b7995 100644 --- a/main/modexp/array_lib/array_div_long.zkasm +++ b/main/modexp/array_lib/array_div_long.zkasm @@ -329,4 +329,5 @@ array_div_long_check_rem_is_zero: RR - 1 => RR :JMPN(array_div_long_end, array_div_long_check_rem_is_zero) array_div_long_end: - $ => RR :MLOAD(array_div_long_RR), RETURN \ No newline at end of file + $ => RR :MLOAD(array_div_long_RR) + :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_div_short.zkasm b/main/modexp/array_lib/array_div_short.zkasm index a7b3b67e..48bcc2b4 100644 --- a/main/modexp/array_lib/array_div_short.zkasm +++ b/main/modexp/array_lib/array_div_short.zkasm @@ -201,4 +201,5 @@ array_div_short_check_result_eq_inA2: RR - 1 => RR :JMPN(array_div_short_end, array_div_short_check_result_eq_inA2) array_div_short_end: - $ => RR :MLOAD(array_div_short_RR), RETURN \ No newline at end of file + $ => RR :MLOAD(array_div_short_RR) + :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_div_two.zkasm b/main/modexp/array_lib/array_div_two.zkasm index de382ce0..203cb794 100644 --- a/main/modexp/array_lib/array_div_two.zkasm +++ b/main/modexp/array_lib/array_div_two.zkasm @@ -182,4 +182,5 @@ array_div_two_check_result_eq_inA2: RR - 1 => RR :JMPN(array_div_two_end, array_div_two_check_result_eq_inA2) array_div_two_end: - $ => RR :MLOAD(array_div_two_RR), RETURN \ No newline at end of file + $ => RR :MLOAD(array_div_two_RR) + :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_mul_long.zkasm b/main/modexp/array_lib/array_mul_long.zkasm index a1663811..c841b14d 100644 --- a/main/modexp/array_lib/array_mul_long.zkasm +++ b/main/modexp/array_lib/array_mul_long.zkasm @@ -210,4 +210,5 @@ array_mul_long_trim: E :MSTORE(array_mul_long_len_out) array_mul_long_end: - $ => RR :MLOAD(array_mul_long_RR), RETURN \ No newline at end of file + $ => RR :MLOAD(array_mul_long_RR) + :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_mul_short.zkasm b/main/modexp/array_lib/array_mul_short.zkasm index 5c9f8236..5d9399c6 100644 --- a/main/modexp/array_lib/array_mul_short.zkasm +++ b/main/modexp/array_lib/array_mul_short.zkasm @@ -86,4 +86,5 @@ array_mul_short_trim: E :MSTORE(array_mul_short_len_out) array_mul_short_end: - $ => RR :MLOAD(array_mul_short_RR), RETURN \ No newline at end of file + $ => RR :MLOAD(array_mul_short_RR) + :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_mul_two.zkasm b/main/modexp/array_lib/array_mul_two.zkasm index a5bb8b1d..4a4f10b4 100644 --- a/main/modexp/array_lib/array_mul_two.zkasm +++ b/main/modexp/array_lib/array_mul_two.zkasm @@ -99,4 +99,5 @@ array_mul_two_trim: E :MSTORE(array_mul_two_len_out) array_mul_two_end: - $ => RR :MLOAD(array_mul_two_RR), RETURN \ No newline at end of file + $ => RR :MLOAD(array_mul_two_RR) + :RETURN \ No newline at end of file diff --git a/main/modexp/array_lib/array_square.zkasm b/main/modexp/array_lib/array_square.zkasm index 1aea892d..72932ddc 100644 --- a/main/modexp/array_lib/array_square.zkasm +++ b/main/modexp/array_lib/array_square.zkasm @@ -359,4 +359,5 @@ array_square_trim: C - 1 :MSTORE(array_square_len_out) array_square_end: - $ => RR :MLOAD(array_square_RR), RETURN \ No newline at end of file + $ => RR :MLOAD(array_square_RR) + :RETURN \ No newline at end of file diff --git a/main/modexp/modexp.zkasm b/main/modexp/modexp.zkasm index 74685287..6f5ed75a 100644 --- a/main/modexp/modexp.zkasm +++ b/main/modexp/modexp.zkasm @@ -373,4 +373,5 @@ modexp_rem_from_div3: ; ------------------- modexp_end: - $ => RR :MLOAD(modexp_RR), RETURN \ No newline at end of file + $ => RR :MLOAD(modexp_RR) + :RETURN \ No newline at end of file From ce1d2b1daf8308ee9b1cb58f7437b099953825ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Masip?= Date: Wed, 9 Oct 2024 11:40:12 +0200 Subject: [PATCH 10/12] Library counters done --- main/modexp/array_lib/array_add_AGTB.zkasm | 8 ++++++ main/modexp/array_lib/array_add_short.zkasm | 9 ++++++ main/modexp/array_lib/array_div_long.zkasm | 31 +++++++++++++++++++-- main/modexp/array_lib/array_div_short.zkasm | 26 +++++++++++++++-- main/modexp/array_lib/array_div_two.zkasm | 29 +++++++++++++++---- main/modexp/array_lib/array_mul_long.zkasm | 17 +++++++---- main/modexp/array_lib/array_mul_short.zkasm | 8 ++++++ main/modexp/array_lib/array_mul_two.zkasm | 8 ++++++ main/modexp/array_lib/array_square.zkasm | 31 ++++++++++++++------- 9 files changed, 142 insertions(+), 25 deletions(-) diff --git a/main/modexp/array_lib/array_add_AGTB.zkasm b/main/modexp/array_lib/array_add_AGTB.zkasm index ce7b6e3f..fed61e36 100644 --- a/main/modexp/array_lib/array_add_AGTB.zkasm +++ b/main/modexp/array_lib/array_add_AGTB.zkasm @@ -45,6 +45,14 @@ VAR GLOBAL array_add_AGTB_carry VAR GLOBAL array_add_AGTB_RR +/* + * RESOURCES: + * ----------------------------- + * (worst case) [steps: 9, bin: 1] + (lenB-1)*[steps: 10, bin: 2] + [steps: 3] + (lenA - lenB)*[steps: 6, bin: 1] + [steps: 6] + * total: [steps: 8 + 6*lenA + 4*lenB, bin: lenA + lenB - 2] + * ----------------------------- + */ + array_add_AGTB: %MAX_CNT_BINARY - CNT_BINARY - 1 - 2*%ARRAY_MAX_LEN_MINUS_ONE - 2 :JMPN(outOfCountersBinary) %MAX_CNT_STEPS - STEP - 10 - 11*%ARRAY_MAX_LEN_MINUS_ONE - 2 - 8 - 5*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE - 3 :JMPN(outOfCountersStep) diff --git a/main/modexp/array_lib/array_add_short.zkasm b/main/modexp/array_lib/array_add_short.zkasm index 961a44be..66124c29 100644 --- a/main/modexp/array_lib/array_add_short.zkasm +++ b/main/modexp/array_lib/array_add_short.zkasm @@ -35,6 +35,15 @@ VAR GLOBAL array_add_short_len_out VAR GLOBAL array_add_short_RR + +/* + * RESOURCES: + * ----------------------------- + * (worst case) [steps: 8] + (lenA-1)*[steps: 6, bin: 1] + [steps: 6] + * total: [steps: 8 + 6*lenA, bin: lenA - 1] + * ----------------------------- + */ + array_add_short: %MAX_CNT_BINARY - CNT_BINARY - 1 - %ARRAY_MAX_LEN_MINUS_ONE :JMPN(outOfCountersBinary) %MAX_CNT_STEPS - STEP - 10 - 8*%ARRAY_MAX_LEN_MINUS_ONE - 5 :JMPN(outOfCountersStep) diff --git a/main/modexp/array_lib/array_div_long.zkasm b/main/modexp/array_lib/array_div_long.zkasm index 677b7995..e4297cdd 100644 --- a/main/modexp/array_lib/array_div_long.zkasm +++ b/main/modexp/array_lib/array_div_long.zkasm @@ -68,8 +68,30 @@ VAR GLOBAL array_div_long_len_rem VAR GLOBAL array_div_long_RR +/* + * RESOURCES: + * ------------------------------------------- + * + * Worst Path: A != 0, A > B, len(A) == len(B) and len(R) == len(B): + * [steps: 14, bin: 1] + (len(A)-1)*[steps: 4] + // compare A and B + * + [steps: 15, bin: 1] + (len(Q)-1)*[steps: 4] + len(B)*[steps: 3] + [steps: 1] // get Q and input Q and B to mul + * + [steps: 15 + 14*len(Q) + 7*len(B) + 19*len(Q)*(len(B)-1), bin: 1 + len(Q) + 2*len(Q)*(len(B)-1), arith: len(Q) + len(B) + 19*len(Q)*(len(B)-1)] // multiply Q and B + * + [steps: 14, bin: 1] + (len(R)-1)*[steps: 5] + [steps: 4] + len(Q·B)*[steps: 3] + [steps: 1] // R and Q·B to add + * + [steps: 8 + 6*len(Q·B) + 4*len(B), bin: len(Q·B) + len(B) - 2] // add Q·B and R + * + [steps: 3] + len(A)*[steps: 3] + [steps: 2] // compare A and Q·B + R and finish + * Total: [steps: 64 + 7*len(A) + 23*len(B) + 8*len(Q) + 5*len(R) + 19*len(Q)*len(B), + * bin: 2 + 2*len(B) + 2*len(Q)*len(B), + * arith: len(B) - 18*len(Q) + 19*len(Q)*len(B)] + * ------------------------------------------- + * where: + * R = Remainder of A / B + * Q = Quotient of A / B + * + * Note: For the total count, we have used the fact that len(Q·B) <= len(Q) + len(B) + */ + array_div_long: - ; w.c. is when inA > inB and len(inA) >> len(inB) + ; w.c. until array_mul_long is when inA > inB and len(inA) == len(inB) %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) %MAX_CNT_STEPS - STEP - 24 - 4*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE - 3*%ARRAY_MAX_LEN - 1 :JMPN(outOfCountersStep) ; till array_mul_long @@ -117,8 +139,8 @@ array_div_long_inA_not_zero_two_chunks: $ => B :MLOAD(array_div_long_inA + RR) 1 :LT - ; Now, we must check that the above chunks are all equal, unless there are none - C - 1 => E + ; Now, we must check that the previous chunks are all equal + C - 1 => E ; [steps: 14, bin: 1] array_div_long_check_inAGTinB_loop: E - RR :JMPZ(array_div_long_inAGTinB) $ => A :MLOAD(array_div_long_inA + E) @@ -177,6 +199,7 @@ array_div_long_inALTinB: ; End of edge cases array_div_long_inAGTinB: + ; block: [steps: 15, bin: 1] ; From here, inA > inB ; Strategy: Divide outside and check the result inside @@ -229,6 +252,7 @@ array_div_long_inB_to_mul: array_div_long_mul_quo_inB: :CALL(array_mul_long) ; inputs: [array_mul_long_len_inA: C, array_mul_long_len_inB: D, array_mul_long_inA: array_div_long_quo, array_mul_long_inB: array_div_long_inB] ; outputs: [array_mul_long_len_out, array_mul_long_out] + ; block (R != 0 and len(R) == len(B)): [steps: 14, bin: 1] ; w.c. is when rem is not zero %MAX_CNT_BINARY - CNT_BINARY - 1 - 1 :JMPN(outOfCountersBinary) @@ -279,6 +303,7 @@ array_div_long_compare_rem_first: array_div_long_rem_to_add: ; From here, we have checked that the R < inB + ; Introduce the remaining rem chunks to the addition E - 1 => E :JMPN(array_div_long_add_check) ${receiveRemainderChunk(E)} => A :MSTORE(array_div_long_rem + E) A :MSTORE(array_add_AGTB_inB + E) diff --git a/main/modexp/array_lib/array_div_short.zkasm b/main/modexp/array_lib/array_div_short.zkasm index 48bcc2b4..8df00a8e 100644 --- a/main/modexp/array_lib/array_div_short.zkasm +++ b/main/modexp/array_lib/array_div_short.zkasm @@ -22,9 +22,29 @@ VAR GLOBAL array_div_short_len_quo VAR GLOBAL array_div_short_RR -array_div_short: - ; w.c. is when len(inA) >> len(inB) +/* + * RESOURCES: + * ------------------------------------------- + * + * Worst Path: A != 0, A > B, len(A) > 1: + * [steps: 4] // compare A and B + * + [steps: 11, bin: 1] + (len(Q)-1)*[steps: 4] + [steps: 3] // get Q and input Q and B to mul + * + [steps: 10 + 7*len(Q), bin: 1, arith: len(Q)] // multiply Q and B + * + [steps: 10, bin: 2] + len(Q·B)*[steps: 3] + [steps: 1] // R and Q·B to add + * + [steps: 8 + 6*len(Q·B), bin: len(Q·B) - 1] // add Q·B and R + * + [steps: 3] + len(A)*[steps: 3] + [steps: 2] // compare A and Q·B + R and finish + * Total: [steps: 57 + 3*len(A) + 19*len(Q), + * bin: 4 + len(Q), + * arith: len(Q)] + * ------------------------------------------- + * where: + * R = Remainder of A / B + * Q = Quotient of A / B + * + * Note: For the total count, we have used the fact that len(Q·B) len(Q) + 1 + */ +array_div_short: %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) %MAX_CNT_STEPS - STEP - 20 - 4*%ARRAY_MAX_LEN_MINUS_ONE - 3 :JMPN(outOfCountersStep) ; till array_mul_short @@ -98,6 +118,7 @@ array_div_short_inALTinB: ; End of edge cases array_div_short_inAGTinB: + ; block: [steps: 11, bin: 1] ; From here, inA > inB ; Strategy: Divide outside and check the result inside @@ -139,6 +160,7 @@ array_div_short_inB_to_mul: array_div_short_mul_quo_inB: :CALL(array_mul_short); inputs: [array_mul_short_len_inA: C, array_mul_short_inA: array_div_short_quo, array_mul_short_inB: array_div_short_inB] ; outputs: [array_mul_short_len_out, array_mul_short_out] + ; block (R != 0): [steps: 10, bin: 1] ; w.c. is when rem is not zero %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) diff --git a/main/modexp/array_lib/array_div_two.zkasm b/main/modexp/array_lib/array_div_two.zkasm index 203cb794..0cb3f2e9 100644 --- a/main/modexp/array_lib/array_div_two.zkasm +++ b/main/modexp/array_lib/array_div_two.zkasm @@ -19,9 +19,29 @@ VAR GLOBAL array_div_two_len_quo VAR GLOBAL array_div_two_RR -array_div_two: - ; w.c. is when len(in) >> len(2) +/* + * RESOURCES: + * ------------------------------------------- + * + * Worst Path: A != 0, inA > 2, len(A) > 1: + * [steps: 5] // compare A and 2 + * + [steps: 11, bin: 1] + (len(Q)-1)*[steps: 4] + [steps: 1] // get Q and input Q to mul_two + * + [steps: 4 + 9*len(Q), bin: len(Q) - 1] // multiply Q by 2 + * + [steps: 9, bin: 2] + len(2·Q)*[steps: 3] + [steps: 1] // R and 2·Q to add + * + [steps: 8 + 6*len(2·Q), bin: len(2·Q) - 1] // add 2·Q and R + * + [steps: 3] + len(A)*[steps: 3] + [steps: 2] // compare A and Q·B + R and finish + * Total: [steps: 49 + 3*len(A) + 22*len(Q), + * bin: 2 + 2*len(Q), + * arith: 0] + * ------------------------------------------- + * where: + * R = Remainder of A / B + * Q = Quotient of A / B + * + * Note: For the total count, we have used the fact that len(2·Q) <= len(Q) + 1 + */ +array_div_two: %MAX_CNT_BINARY - CNT_BINARY - 3 :JMPN(outOfCountersBinary) %MAX_CNT_STEPS - STEP - 26 - 4*%ARRAY_MAX_LEN_MINUS_ONE - 1 :JMPN(outOfCountersStep) ; till array_mul_two @@ -81,6 +101,7 @@ array_div_two_inALTinB: ; End of edge cases array_div_two_inAGTinB: + ; block: [steps: 11, bin: 1] ; From here, in > 2 ; Strategy: Divide outside and check the result inside @@ -90,8 +111,7 @@ array_div_two_inAGTinB: ; 1] The received length must satisfy 1 <= len(Q) <= len(in) C - 1 => RR :JMPN(failAssert) ; if len(Q) < 1 ERROR - $ => A :MLOAD(array_div_two_len_in) - A - C :JMPN(failAssert) ; if len(in) < len(Q) ERROR + $ - C :F_MLOAD(array_div_two_len_in), JMPN(failAssert) ; if len(in) < len(Q) ERROR ; 2] To avoid non-determinism, we must ensure that the quotient is trimmed ; i.e., that its last chunk is not 0 @@ -103,7 +123,6 @@ array_div_two_inAGTinB: ; 3] Let's multiply the quotient by 2 C :MSTORE(array_div_two_len_quo) - C => D C - 1 => RR ; save the first non-zero chunk of quo diff --git a/main/modexp/array_lib/array_mul_long.zkasm b/main/modexp/array_lib/array_mul_long.zkasm index c841b14d..1d45557f 100644 --- a/main/modexp/array_lib/array_mul_long.zkasm +++ b/main/modexp/array_lib/array_mul_long.zkasm @@ -46,8 +46,16 @@ VAR GLOBAL array_mul_long_out_chunk_2 VAR GLOBAL array_mul_long_RR +/* + * RESOURCES: + * ----------------------------- + * (worst case) [steps: 12, arith: 1] + (lenB-1)*[steps: 7, arith: 1] + [steps: 3] + lenA*((lenB-1)*[steps: 19, bin: 2, arith: 1] + [steps: 14, bin: 1, arith: 1]) + [steps: 7, bin: 1] + * total: [steps: 15 + 14*lenA + 7*lenB + 19*lenA*(lenB-1), bin: 1 + lenA + 2*lenA*(lenB-1), arith: lenA + lenB + 19*lenA*(lenB-1)] + * ----------------------------- + */ + array_mul_long: - ; big loop costs (len(inA) - 1)*((len(inB) - 1) * [steps: 21, binary: 2, arith: 1] + [steps: 18, binary: 1, arith: 1]) + ; big loop costs (len(inA) - 1)*((len(inB) - 1) * [steps: 21, bin: 2, arith: 1] + [steps: 18, bin: 1, arith: 1]) %MAX_CNT_ARITH - CNT_ARITH - 1 - %ARRAY_MAX_LEN_MINUS_ONE - %ARRAY_MAX_LEN_TIMES_DOUBLED - %ARRAY_MAX_LEN_DOUBLED_MINUS_ONE :JMPN(outOfCountersArith) %MAX_CNT_BINARY - CNT_BINARY - 2*%ARRAY_MAX_LEN_TIMES_DOUBLED - %ARRAY_MAX_LEN_DOUBLED_MINUS_ONE - 1 :JMPN(outOfCountersBinary) @@ -109,7 +117,7 @@ array_mul_long_inA_index_check: 0 => RR :MSTORE(array_mul_long_out_chunk_2) ; reset the second index and the out chunk 2 array_mul_long_loop2inB: - ; costs [steps: 21, binary: 2, arith: 1] + ; costs [steps: 19, bin: 2, arith: 1] ; The result will be stored as D·base + C @@ -143,8 +151,7 @@ array_mul_long_loop2inB: D => B $ => C :ADD, JMPNC(__array_mul_long_no_carry_continue_2) ;----------------- - 1 :MSTORE(array_mul_long_out_chunk_2) - :JMP(__array_mul_long_carry_continue) + 1 :MSTORE(array_mul_long_out_chunk_2), JMP(__array_mul_long_carry_continue) __array_mul_long_no_carry_continue_2: 0 :MSTORE(array_mul_long_out_chunk_2) __array_mul_long_carry_continue: @@ -158,7 +165,7 @@ array_mul_long_loop2inB: $ - RR - 1 :F_MLOAD(array_mul_long_len_inB), JMPZ(array_mul_long_loop2inB_last, array_mul_long_loop2inB) array_mul_long_loop2inB_last: - ; costs [steps: 13, binary: 1, arith: 1] + ; costs [steps: 14, bin: 1, arith: 1] ; The result will be stored as D·base + C diff --git a/main/modexp/array_lib/array_mul_short.zkasm b/main/modexp/array_lib/array_mul_short.zkasm index 5d9399c6..b63ae8cb 100644 --- a/main/modexp/array_lib/array_mul_short.zkasm +++ b/main/modexp/array_lib/array_mul_short.zkasm @@ -30,6 +30,14 @@ VAR GLOBAL array_mul_short_len_out VAR GLOBAL array_mul_short_RR +/* + * RESOURCES: + * ----------------------------- + * (worst case) [steps: 10, arith: 1] + (lenA-1)*[steps: 7, arith: 1] + [steps: 7, bin: 1] + * total: [steps: 10 + 7*lenA, bin: 1, arith: lenA] + * ----------------------------- + */ + array_mul_short: %MAX_CNT_ARITH - CNT_ARITH - 1 - %ARRAY_MAX_LEN_MINUS_ONE :JMPN(outOfCountersArith) %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) diff --git a/main/modexp/array_lib/array_mul_two.zkasm b/main/modexp/array_lib/array_mul_two.zkasm index 4a4f10b4..091a47fd 100644 --- a/main/modexp/array_lib/array_mul_two.zkasm +++ b/main/modexp/array_lib/array_mul_two.zkasm @@ -36,6 +36,14 @@ VAR GLOBAL array_mul_two_carry VAR GLOBAL array_mul_two_RR +/* + * RESOURCES: + * ----------------------------- + * (worst case) [steps: 7, bin: 1] + (lenA-1)*[steps: 9, bin: 2] + [steps: 6] + * total: [steps: 4 + 9*lenA, bin: lenA - 1] + * ----------------------------- + */ + array_mul_two: %MAX_CNT_BINARY - CNT_BINARY - 1 - 2*%ARRAY_MAX_LEN_MINUS_ONE :JMPN(outOfCountersBinary) %MAX_CNT_STEPS - STEP - 9 - 11*%ARRAY_MAX_LEN_MINUS_ONE - 7 :JMPN(outOfCountersStep) diff --git a/main/modexp/array_lib/array_square.zkasm b/main/modexp/array_lib/array_square.zkasm index 72932ddc..45e952ab 100644 --- a/main/modexp/array_lib/array_square.zkasm +++ b/main/modexp/array_lib/array_square.zkasm @@ -42,10 +42,21 @@ VAR GLOBAL array_square_out_chunk_2 VAR GLOBAL array_square_RR +; (len(in)-1)*(len(in)-1) = len(in)² - 2*len(in) + 1 + +/* + * RESOURCES: + * ----------------------------- + * (worst case) [steps: 6] + [steps: 9, bin: 0, arith: 1] + (len(in)-1)*[steps: 35, bin: 6, arith: 1] <--- Init and first row + * + (len(in)-1)*([steps: 7] + [steps: 6, bin: 0, arith: 1] + [steps: 29, bin: 3, arith: 1] + (len(in)-1)*[steps: 51, bin: 9, arith: 1]) <--- Rest of the rows + * [steps: 8, bin: 1] <--- Ending + * total: [steps: -3 - 25*len(in) + 51*len(in)², + * bin: 1 - 9*len(in) + 9*len(in)², + * arith: -1 + len(in) + len(in)²] + * ----------------------------- + */ + array_square: - ; costs: [steps: 6, binary: 0, arith: 0] + [steps: 9, binary: 0, arith: 1] + (len(in) - 1)*[steps: 35, binary: 6, arith: 1] <--- Init and first row - ; + (len(in) - 1)*([steps: 7, binary: 0, arith: 0] + [steps: 6, binary: 0, arith: 1] + [steps: 29, binary: 3, arith: 1] + (len(in) - 1)*[steps: 51, binary: 9, arith: 1]) <--- Rest of the rows - ; [steps: 8, binary: 1, arith: 0] <--- Ending %MAX_CNT_ARITH - CNT_ARITH - 1 - %ARRAY_MAX_LEN_MINUS_ONE - 2*%ARRAY_MAX_LEN_MINUS_ONE - %ARRAY_MAX_LEN_SQ :JMPN(outOfCountersArith) %MAX_CNT_BINARY - CNT_BINARY - 6*%ARRAY_MAX_LEN_MINUS_ONE - 3*%ARRAY_MAX_LEN_MINUS_ONE - 9*%ARRAY_MAX_LEN_SQ - 1 :JMPN(outOfCountersBinary) %MAX_CNT_STEPS - STEP - 15 - 35*%ARRAY_MAX_LEN_MINUS_ONE - 42*%ARRAY_MAX_LEN_MINUS_ONE - 51*%ARRAY_MAX_LEN_SQ - 8 :JMPN(outOfCountersStep) @@ -62,7 +73,7 @@ array_square: ; Begin of branching array_square_loop_index_check: - ; costs [steps: 7, binary: 0, arith: 0] + ; costs [steps: 7, bin: 0, arith: 0] ; out[i + len] = carry $ => A :MLOAD(array_square_carry_chunk_1) @@ -79,7 +90,7 @@ array_square_loop_index_check: ; Begin of first row array_square_first_iteration_first_row: - ; costs [steps: 9, binary: 0, arith: 1] + ; costs [steps: 9, bin: 0, arith: 1] ; The result will be stored as D·base + C @@ -102,7 +113,7 @@ array_square_first_iteration_first_row: B - RR :JMPZ(array_square_loop_index_check) array_square_finish_first_row: - ; costs [steps: 35, binary: 6, arith: 1] + ; costs [steps: 35, bin: 6, arith: 1] ; The result will be stored as D·base + C @@ -172,7 +183,7 @@ array_square_finish_first_row: ; End of first row array_square_ai_times_ai: - ; costs [steps: 6, binary: 0, arith: 1] + ; costs [steps: 6, bin: 0, arith: 1] ; carry = 0 - a[i]·a[i] ; a[i]·a[i], where a[i] ∈ [0,base-1]: This number cannot be GT (base - 2)·base + 1, two chunks @@ -185,7 +196,7 @@ array_square_ai_times_ai: D :MSTORE(array_square_carry_chunk_2) array_square_first_iteration_loopRR2len: - ; costs [steps: 29, binary: 3, arith: 1] + ; costs [steps: 29, bin: 3, arith: 1] ; product = a[i]·a[i] + out[2i] (in the worst case, this is a 3-chunk number) ; The result will be stored as array_square_chunk_3·base² + D·base + C @@ -241,7 +252,7 @@ array_square_first_iteration_loopRR2len: B - RR :JMPZ(array_square_loop_index_check) array_square_loopRR2len: - ; costs [steps: 51, binary: 9, arith: 1] + ; costs [steps: 51, bin: 9, arith: 1] ; product = 2·(a[i]·a[j]) + out[i+j] + carry (in the worst case, this is a 3-chunk number) ; The result will be stored as array_square_chunk_3·base² + D·base + C @@ -342,7 +353,7 @@ array_square_loopRR2len: B - RR :JMPZ(array_square_loop_index_check, array_square_loopRR2len) array_square_prep_trim: - ; costs [steps: 8, binary: 1, arith: 0] + ; costs [steps: 8, bin: 1, arith: 0] $ => C :MLOAD(array_square_len_out) C - 1 => E From 08edf32bcc354760f5c2a3fbc7a1b8d139ed5e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Masip?= Date: Wed, 9 Oct 2024 13:13:39 +0200 Subject: [PATCH 11/12] First version of modexp counters done --- main/modexp/modexp.zkasm | 62 +++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/main/modexp/modexp.zkasm b/main/modexp/modexp.zkasm index 6f5ed75a..323a6fcf 100644 --- a/main/modexp/modexp.zkasm +++ b/main/modexp/modexp.zkasm @@ -36,18 +36,6 @@ ;; return r; ;; }; -;; RESOURCES (assuming a worst case scenario): -;; ------------------------------------------- -;; cost(pre_loop) = 3·cost(isZero) + 2·cost(isOne) + cost(array_div) -;; nIterations = ⌊log₂(E)⌋ + 1 -;; nTimesEIsOdd = HammingWeight(E) (i.e., number of 1s in the binary representation of E) -;; nTimesEIsEven = nIterations - nTimesEIsOdd -;; cost(iteration1) (if E is odd) = cost(isZero) + cost(isOdd) + 2·cost(array_div) + cost(array_mul) + cost(array_div_short) + cost(array_square) -;; cost(iteration2) (if E is even) = cost(isZero) + cost(isOdd) + cost(array_div) + cost(array_div_short) + cost(array_square) -;; ------------ -;; cost(total) = cost(pre_loop) + nTimesEIsOdd·cost(iteration1) + nTimesEIsEven·cost(iteration2) -;; ------------ - VAR GLOBAL modexp_Blen VAR GLOBAL modexp_Elen VAR GLOBAL modexp_Mlen @@ -60,8 +48,56 @@ VAR GLOBAL modexp_outlen VAR GLOBAL modexp_RR -modexp: +; RESOURCES (assuming a worst case scenario): +; ------------------------------------------- +; [steps: 7] + len(B)*[steps: 3] + len(M)*[steps: 3] + [steps: 1] // init and B and M to array_div_long +; [steps: 64 + 7*len(B) + 23*len(M) + 8*len(Q(B,M)) + 5*len(R(B,M)) + 19*len(Q(B,M))*len(M) // array_div_long of B and M +; bin: 2 + 2*len(M) + 2*len(Q(B,M))*len(M), +; arith: len(M) - 18*len(Q(B,M)) + 19*len(Q(B,M))*len(M)] +; [steps: 2] + len(R(B,M))*[steps: 3] // copy R(B,M) to B +; +; for ⌊log₂(E)⌋ iterations: +; [steps: 4, bin: 1] // check E == 0 +; [steps: 3, bin: 1] // check B == 0 +; [steps: 3, bin: 1] // check E parity +; if E is odd, then compute (O·B) % M: +; [steps: 4] + len(O)*[steps: 3] + len(B)*[steps: 3] + [steps: 1] // O and B to array_mul_long +; [steps: 15 + 14*len(O) + 7*len(B) + 19*len(O)*(len(B)-1), // array_mul_long of O and B +; bin: 1 + len(O) + 2*len(O)*(len(B)-1), +; arith: len(O) + len(B) + 19*len(O)*(len(B)-1)] +; [steps: 4] + len(O·B)*[steps: 3] + len(M)*[steps: 3] + [steps: 1] // O·B and M to array_div_long +; [steps: 64 + 7*len(O·B) + 23*len(M) + 8*len(Q(O·B,M)) + 5*len(R(O·B,M)) + 19*len(Q(O·B,M))*len(M), // array_div_long of O·B and M +; bin: 2 + 2*len(M) + 2*len(Q(O·B,M))*len(M), +; arith: len(M) - 18*len(Q(O·B,M)) + 19*len(Q(O·B,M))*len(M)] +; [steps: 3] + len(R(O·B,M))*[steps: 3] // copy R(O·B,M) to O +; [steps: 2] + len(E)*[steps: 3] + [steps: 1] // E to array_div_two +; [steps: 49 + 3*len(E) + 22*len(Q(E,2)), bin: 2 + 2*len(Q(E,2))] // array_div_two of E +; [steps: 3] + len(Q(E,2))*[steps: 3] // Copy Q(E,2) to E +; [steps: 2] + len(B)*[steps: 3] + [steps: 1] // B to array_square +; [steps: -3 - 25*len(B) + 51*len(B)², bin: 1 - 9*len(B) + 9*len(B)², arith: -1 + len(B) + len(B)²] // array_square of B +; [steps: 4] + len(B²)*[steps: 3] + len(M)*[steps: 3] + [steps: 1] // B² and M to array_div_long +; [steps: 64 + 7*len(B²) + 23*len(M) + 8*len(Q(B²,M)) + 5*len(R(B²,M)) + 19*len(Q(B²,M))*len(M), // array_div_long of B² and M +; bin: 2 + 2*len(M) + 2*len(Q(B²,M))*len(M), +; arith: len(M) - 18*len(Q(B²,M)) + 19*len(Q(B²,M))*len(M)] +; [steps: 3] + len(R(B²,M))*[steps: 3] // copy R(B²,M) to B +; +; [steps: 2] // end +; +; ------------------------------------------- +; nIterations = ⌊log₂(E)⌋ +; num_times_E_is_odd = HammingWeight(E) (i.e., number of 1s in the binary representation of E) +; num_times_E_is_even = nIterations - num_times_E_is_odd +; ------------------------------------------- +; cost(w.c): cost(first_part) + ⌊log₂(E)⌋*odd_iteration + cost(last_part) +; · cost(first_part) = [steps: 74 + 10*len(B) + 26*len(M) + 8*len(Q(B,M)) + 8*len(R(B,M)) + 19*len(Q(B,M))*len(M), +; bin: 2 + 2*len(M) + 2*len(Q(B,M))*len(M), +; arith: len(M) - 18*len(Q(B,M)) + 19*len(Q(B,M))*len(M)] +; · cost(odd_iteration) = [steps: 229 - 2*len(O) - 24*len(B) + 51*len(B)² + 10*len(B²) + 6*len(E) + 25*len(Q(E,2)) + 19*len(O)*len(B) + 10*len(O·B) + 52*len(M) + 8*len(Q(O·B,M)) + 8*len(R(O·B,M)) + 19*len(Q(O·B,M))*len(M) + 8*len(Q(B²,M)) + 8*len(R(B²,M)) + 19*len(Q(B²,M))*len(M), +; bin: 11 + 4*len(M) - 9*len(B) + 9*len(B)² - len(O) + 2*len(O)*len(B) + 2*len(Q(O·B,M))*len(M) + 2*len(Q(E,2)) + 2*len(Q(B²,M))*len(M), +; arith: -1 + 2*len(M) - 18*len(O) + 2*len(B) + len(B)² + 19*len(O)*len(B) - 18*len(Q(O·B,M)) + 19*len(Q(O·B,M))*len(M) - 18*len(Q(B²,M)) + 19*len(Q(B²,M))*len(M)] +; · cost(last_part) = [steps: 2] +modexp: %MAX_CNT_STEPS - STEP - 7 - 3*%ARRAY_MAX_LEN - 3*%ARRAY_MAX_LEN - 1 :JMPN(outOfCountersStep) ; init and array div long RR :MSTORE(modexp_RR) From e2d7b11cb93cbb1b9a52e7069988664485c1219c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Masip?= Date: Wed, 9 Oct 2024 16:59:35 +0200 Subject: [PATCH 12/12] Modexp counters done --- main/modexp/array_lib/array_add_AGTB.zkasm | 4 +- main/modexp/array_lib/array_add_short.zkasm | 4 +- main/modexp/array_lib/array_div_long.zkasm | 9 +- main/modexp/array_lib/array_div_short.zkasm | 9 +- main/modexp/array_lib/array_div_two.zkasm | 10 +- main/modexp/array_lib/array_mul_long.zkasm | 8 +- main/modexp/array_lib/array_mul_short.zkasm | 6 +- main/modexp/array_lib/array_mul_two.zkasm | 4 +- main/modexp/array_lib/array_square.zkasm | 6 +- main/modexp/modexp.zkasm | 11 +- test/testArrayArith.zkasm | 23 ++- tools/counters/modexp.js | 164 ++++++++++++++++++++ 12 files changed, 216 insertions(+), 42 deletions(-) create mode 100644 tools/counters/modexp.js diff --git a/main/modexp/array_lib/array_add_AGTB.zkasm b/main/modexp/array_lib/array_add_AGTB.zkasm index fed61e36..7aa74c6e 100644 --- a/main/modexp/array_lib/array_add_AGTB.zkasm +++ b/main/modexp/array_lib/array_add_AGTB.zkasm @@ -54,8 +54,8 @@ VAR GLOBAL array_add_AGTB_RR */ array_add_AGTB: - %MAX_CNT_BINARY - CNT_BINARY - 1 - 2*%ARRAY_MAX_LEN_MINUS_ONE - 2 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 10 - 11*%ARRAY_MAX_LEN_MINUS_ONE - 2 - 8 - 5*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE - 3 :JMPN(outOfCountersStep) + %MAX_CNT_BINARY - CNT_BINARY + 2 - %ARRAY_MAX_LEN_DOUBLED - %ARRAY_MAX_LEN :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 8 - 6*%ARRAY_MAX_LEN_DOUBLED - 4*%ARRAY_MAX_LEN :JMPN(outOfCountersStep) RR :MSTORE(array_add_AGTB_RR) diff --git a/main/modexp/array_lib/array_add_short.zkasm b/main/modexp/array_lib/array_add_short.zkasm index 66124c29..f168317a 100644 --- a/main/modexp/array_lib/array_add_short.zkasm +++ b/main/modexp/array_lib/array_add_short.zkasm @@ -45,8 +45,8 @@ VAR GLOBAL array_add_short_RR */ array_add_short: - %MAX_CNT_BINARY - CNT_BINARY - 1 - %ARRAY_MAX_LEN_MINUS_ONE :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 10 - 8*%ARRAY_MAX_LEN_MINUS_ONE - 5 :JMPN(outOfCountersStep) + %MAX_CNT_BINARY - CNT_BINARY + 1 - %ARRAY_MAX_LEN :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 8 - 6*%ARRAY_MAX_LEN :JMPN(outOfCountersStep) RR :MSTORE(array_add_short_RR) diff --git a/main/modexp/array_lib/array_div_long.zkasm b/main/modexp/array_lib/array_div_long.zkasm index e4297cdd..747decff 100644 --- a/main/modexp/array_lib/array_div_long.zkasm +++ b/main/modexp/array_lib/array_div_long.zkasm @@ -93,8 +93,9 @@ VAR GLOBAL array_div_long_RR array_div_long: ; w.c. until array_mul_long is when inA > inB and len(inA) == len(inB) - %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 24 - 4*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE - 3*%ARRAY_MAX_LEN - 1 :JMPN(outOfCountersStep) ; till array_mul_long + %MAX_CNT_ARITH - CNT_ARITH - %ARRAY_MAX_LEN + 18*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE - 19*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE*%ARRAY_MAX_LEN :JMPN(outOfCountersArith) + %MAX_CNT_BINARY - CNT_BINARY - 2 - 2*%ARRAY_MAX_LEN - 2*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE*%ARRAY_MAX_LEN :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 64 - 7*%ARRAY_MAX_LEN_DOUBLED - 28*%ARRAY_MAX_LEN - 8*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE - 19*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE*%ARRAY_MAX_LEN :JMPN(outOfCountersStep) ; till array_mul_long RR :MSTORE(array_div_long_RR) @@ -255,8 +256,6 @@ array_div_long_mul_quo_inB: ; block (R != 0 and len(R) == len(B)): [steps: 14, bin: 1] ; w.c. is when rem is not zero - %MAX_CNT_BINARY - CNT_BINARY - 1 - 1 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 14 - 5*%ARRAY_MAX_LEN_MINUS_ONE - 2 - 3 - 3*%ARRAY_MAX_LEN_DOUBLED - 1 :JMPN(outOfCountersStep) ; till array_add_AGTB ; Check the remainder $0{receiveLenRemainder()} => D :JMPZ(array_div_long_rem_is_zero) @@ -324,8 +323,6 @@ array_div_long_add_mul_out_rem: :CALL(array_add_AGTB) ; inputs: [array_add_AGTB_len_inA: C, array_add_AGTB_len_inB: D, array_add_AGTB_inA: array_mul_long_out, array_add_AGTB_inB: array_div_long_rem] ; outputs: [array_add_AGTB_len_out, array_add_AGTB_out] - %MAX_CNT_STEPS - STEP - 3 - 3*%ARRAY_MAX_LEN_DOUBLED - 2 :JMPN(outOfCountersStep) - ; The length of q·b + r must be the same as the input of a $ => C :MLOAD(array_add_AGTB_len_out) C :MLOAD(array_div_long_len_inA) diff --git a/main/modexp/array_lib/array_div_short.zkasm b/main/modexp/array_lib/array_div_short.zkasm index 8df00a8e..b22e31b8 100644 --- a/main/modexp/array_lib/array_div_short.zkasm +++ b/main/modexp/array_lib/array_div_short.zkasm @@ -45,8 +45,9 @@ VAR GLOBAL array_div_short_RR */ array_div_short: - %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 20 - 4*%ARRAY_MAX_LEN_MINUS_ONE - 3 :JMPN(outOfCountersStep) ; till array_mul_short + %MAX_CNT_ARITH - CNT_ARITH - %ARRAY_MAX_LEN :JMPN(outOfCountersArith) + %MAX_CNT_BINARY - CNT_BINARY - 4 - %ARRAY_MAX_LEN :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 57 - 22*%ARRAY_MAX_LEN :JMPN(outOfCountersStep) ; till array_mul_short RR :MSTORE(array_div_short_RR) @@ -163,8 +164,6 @@ array_div_short_mul_quo_inB: ; block (R != 0): [steps: 10, bin: 1] ; w.c. is when rem is not zero - %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 10 - 3*%ARRAY_MAX_LEN_MINUS_ONE - 1 :JMPN(outOfCountersStep) ; till array_add_short ; Check the remainder ${receiveRemainderChunk_short()} => A @@ -193,8 +192,6 @@ array_div_short_add_result_rem: :CALL(array_add_short) ; inputs: [array_add_short_len_inA: C, array_add_short_inA: array_mul_short_out, array_add_short_inB: array_div_short_inB] ; outputs: [array_add_short_len_out, array_add_short_out] - %MAX_CNT_STEPS - STEP - 3 - 3*%ARRAY_MAX_LEN - 2 :JMPN(outOfCountersStep) - ; The length of q·b + r must be the same as the input of a $ => C :MLOAD(array_add_short_len_out) C :MLOAD(array_div_short_len_inA) diff --git a/main/modexp/array_lib/array_div_two.zkasm b/main/modexp/array_lib/array_div_two.zkasm index 0cb3f2e9..70b9cbfa 100644 --- a/main/modexp/array_lib/array_div_two.zkasm +++ b/main/modexp/array_lib/array_div_two.zkasm @@ -42,8 +42,8 @@ VAR GLOBAL array_div_two_RR */ array_div_two: - %MAX_CNT_BINARY - CNT_BINARY - 3 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 26 - 4*%ARRAY_MAX_LEN_MINUS_ONE - 1 :JMPN(outOfCountersStep) ; till array_mul_two + %MAX_CNT_BINARY - CNT_BINARY - 2 - 2*%ARRAY_MAX_LEN :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 49 - 25*%ARRAY_MAX_LEN :JMPN(outOfCountersStep) ; till array_mul_two RR :MSTORE(array_div_two_RR) @@ -141,10 +141,6 @@ array_div_two_mul_quo_inB: :CALL(array_mul_two) ; inputs: [array_mul_two_len_in: C, array_mul_two_in: array_div_two_quo] ; outputs: [array_mul_two_len_out, array_mul_two_out] - ; w.c. is when rem is not zero - %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 9 - 3*%ARRAY_MAX_LEN_MINUS_ONE - 1 :JMPN(outOfCountersStep) ; till array_add_short - ; Check the remainder ${receiveRemainderChunk_short()} => A @@ -171,8 +167,6 @@ array_div_two_add_result_rem: :CALL(array_add_short) ; inputs: [array_add_short_len_inA: C, array_add_short_inA: array_mul_two_out, array_add_short_inB: A] ; outputs: [array_add_short_len_out, array_add_short_out] - %MAX_CNT_STEPS - STEP - 3 - 3*%ARRAY_MAX_LEN - 2 :JMPN(outOfCountersStep) - ; The length of q·b + r must be the same as the input of a $ => C :MLOAD(array_add_short_len_out) C :MLOAD(array_div_two_len_in) diff --git a/main/modexp/array_lib/array_mul_long.zkasm b/main/modexp/array_lib/array_mul_long.zkasm index 1d45557f..9b5ea952 100644 --- a/main/modexp/array_lib/array_mul_long.zkasm +++ b/main/modexp/array_lib/array_mul_long.zkasm @@ -55,11 +55,9 @@ VAR GLOBAL array_mul_long_RR */ array_mul_long: - ; big loop costs (len(inA) - 1)*((len(inB) - 1) * [steps: 21, bin: 2, arith: 1] + [steps: 18, bin: 1, arith: 1]) - - %MAX_CNT_ARITH - CNT_ARITH - 1 - %ARRAY_MAX_LEN_MINUS_ONE - %ARRAY_MAX_LEN_TIMES_DOUBLED - %ARRAY_MAX_LEN_DOUBLED_MINUS_ONE :JMPN(outOfCountersArith) - %MAX_CNT_BINARY - CNT_BINARY - 2*%ARRAY_MAX_LEN_TIMES_DOUBLED - %ARRAY_MAX_LEN_DOUBLED_MINUS_ONE - 1 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 12 - 9*%ARRAY_MAX_LEN_MINUS_ONE - 21*%ARRAY_MAX_LEN_TIMES_DOUBLED - 18*%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE - 7 :JMPN(outOfCountersStep) + %MAX_CNT_ARITH - CNT_ARITH - %ARRAY_MAX_LEN_DOUBLED - %ARRAY_MAX_LEN - 19*%ARRAY_MAX_LEN_DOUBLED*%ARRAY_MAX_LEN_MINUS_ONE :JMPN(outOfCountersArith) + %MAX_CNT_BINARY - CNT_BINARY - 1 - %ARRAY_MAX_LEN_DOUBLED - 2*%ARRAY_MAX_LEN_DOUBLED*%ARRAY_MAX_LEN_MINUS_ONE :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 15 - 14*%ARRAY_MAX_LEN_DOUBLED - 7*%ARRAY_MAX_LEN - 19*%ARRAY_MAX_LEN_DOUBLED*%ARRAY_MAX_LEN_MINUS_ONE :JMPN(outOfCountersStep) RR :MSTORE(array_mul_long_RR) diff --git a/main/modexp/array_lib/array_mul_short.zkasm b/main/modexp/array_lib/array_mul_short.zkasm index b63ae8cb..6b85717e 100644 --- a/main/modexp/array_lib/array_mul_short.zkasm +++ b/main/modexp/array_lib/array_mul_short.zkasm @@ -39,9 +39,9 @@ VAR GLOBAL array_mul_short_RR */ array_mul_short: - %MAX_CNT_ARITH - CNT_ARITH - 1 - %ARRAY_MAX_LEN_MINUS_ONE :JMPN(outOfCountersArith) - %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 11 - 8*%ARRAY_MAX_LEN_MINUS_ONE - 7 :JMPN(outOfCountersStep) + %MAX_CNT_ARITH - CNT_ARITH - %ARRAY_MAX_LEN :JMPN(outOfCountersArith) + %MAX_CNT_BINARY - CNT_BINARY - 1 :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 10 - 7*%ARRAY_MAX_LEN :JMPN(outOfCountersStep) RR :MSTORE(array_mul_short_RR) diff --git a/main/modexp/array_lib/array_mul_two.zkasm b/main/modexp/array_lib/array_mul_two.zkasm index 091a47fd..aea0fcb9 100644 --- a/main/modexp/array_lib/array_mul_two.zkasm +++ b/main/modexp/array_lib/array_mul_two.zkasm @@ -45,8 +45,8 @@ VAR GLOBAL array_mul_two_RR */ array_mul_two: - %MAX_CNT_BINARY - CNT_BINARY - 1 - 2*%ARRAY_MAX_LEN_MINUS_ONE :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 9 - 11*%ARRAY_MAX_LEN_MINUS_ONE - 7 :JMPN(outOfCountersStep) + %MAX_CNT_BINARY - CNT_BINARY + 1 - %ARRAY_MAX_LEN :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP - 4 - 9*%ARRAY_MAX_LEN :JMPN(outOfCountersStep) RR :MSTORE(array_mul_two_RR) diff --git a/main/modexp/array_lib/array_square.zkasm b/main/modexp/array_lib/array_square.zkasm index 45e952ab..a01c65ed 100644 --- a/main/modexp/array_lib/array_square.zkasm +++ b/main/modexp/array_lib/array_square.zkasm @@ -57,9 +57,9 @@ VAR GLOBAL array_square_RR */ array_square: - %MAX_CNT_ARITH - CNT_ARITH - 1 - %ARRAY_MAX_LEN_MINUS_ONE - 2*%ARRAY_MAX_LEN_MINUS_ONE - %ARRAY_MAX_LEN_SQ :JMPN(outOfCountersArith) - %MAX_CNT_BINARY - CNT_BINARY - 6*%ARRAY_MAX_LEN_MINUS_ONE - 3*%ARRAY_MAX_LEN_MINUS_ONE - 9*%ARRAY_MAX_LEN_SQ - 1 :JMPN(outOfCountersBinary) - %MAX_CNT_STEPS - STEP - 15 - 35*%ARRAY_MAX_LEN_MINUS_ONE - 42*%ARRAY_MAX_LEN_MINUS_ONE - 51*%ARRAY_MAX_LEN_SQ - 8 :JMPN(outOfCountersStep) + %MAX_CNT_ARITH - CNT_ARITH + 1 - %ARRAY_MAX_LEN - %ARRAY_MAX_LEN_SQ :JMPN(outOfCountersArith) + %MAX_CNT_BINARY - CNT_BINARY - 1 + 9*%ARRAY_MAX_LEN - 9*%ARRAY_MAX_LEN_SQ :JMPN(outOfCountersBinary) + %MAX_CNT_STEPS - STEP + 3 + 25*%ARRAY_MAX_LEN - 51*%ARRAY_MAX_LEN_SQ :JMPN(outOfCountersStep) RR :MSTORE(array_square_RR) diff --git a/main/modexp/modexp.zkasm b/main/modexp/modexp.zkasm index 323a6fcf..b6c9a1cd 100644 --- a/main/modexp/modexp.zkasm +++ b/main/modexp/modexp.zkasm @@ -88,14 +88,17 @@ VAR GLOBAL modexp_RR ; num_times_E_is_odd = HammingWeight(E) (i.e., number of 1s in the binary representation of E) ; num_times_E_is_even = nIterations - num_times_E_is_odd ; ------------------------------------------- -; cost(w.c): cost(first_part) + ⌊log₂(E)⌋*odd_iteration + cost(last_part) ; · cost(first_part) = [steps: 74 + 10*len(B) + 26*len(M) + 8*len(Q(B,M)) + 8*len(R(B,M)) + 19*len(Q(B,M))*len(M), ; bin: 2 + 2*len(M) + 2*len(Q(B,M))*len(M), ; arith: len(M) - 18*len(Q(B,M)) + 19*len(Q(B,M))*len(M)] -; · cost(odd_iteration) = [steps: 229 - 2*len(O) - 24*len(B) + 51*len(B)² + 10*len(B²) + 6*len(E) + 25*len(Q(E,2)) + 19*len(O)*len(B) + 10*len(O·B) + 52*len(M) + 8*len(Q(O·B,M)) + 8*len(R(O·B,M)) + 19*len(Q(O·B,M))*len(M) + 8*len(Q(B²,M)) + 8*len(R(B²,M)) + 19*len(Q(B²,M))*len(M), -; bin: 11 + 4*len(M) - 9*len(B) + 9*len(B)² - len(O) + 2*len(O)*len(B) + 2*len(Q(O·B,M))*len(M) + 2*len(Q(E,2)) + 2*len(Q(B²,M))*len(M), -; arith: -1 + 2*len(M) - 18*len(O) + 2*len(B) + len(B)² + 19*len(O)*len(B) - 18*len(Q(O·B,M)) + 19*len(Q(O·B,M))*len(M) - 18*len(Q(B²,M)) + 19*len(Q(B²,M))*len(M)] +; · cost(odd_iteration) = [steps: 229 + 14*len(B) + 6*len(E) + 68*len(M) + 51*len(B)² + 38*len(B)*len(M) + 25*len(Q(E,2)) + 19*len(Q(B²,M))*len(M) + 8*len(Q(B²,M)) + 8*len(R(B²,M)), +; bin: 11 - 9*len(B) + 3*len(M) + 9*len(B)² + 4*len(B)*len(M) + 2*len(Q(E,2)) + 2*len(Q(B²,M))*len(M), +; arith: -1 - 16*len(B) - 16*len(M) + len(B)² + 38*len(B)*len(M) + 19*len(Q(B²,M))*len(M) - 18*len(Q(B²,M))] ; · cost(last_part) = [steps: 2] +; ------------------------------------------- +; cost(w.c): cost(first_part) + ⌊log₂(E)⌋*odd_iteration + cost(last_part) +; ------------------------------------------- +; Note: For the total count, we have used that O <= M, len(B²) <= 2*len(B), len(O·B) <= len(M·B) <= len(M) + len(B), Q(O·B,M) <= Q(M·B,M) = B and R(O·B,M) < M modexp: %MAX_CNT_STEPS - STEP - 7 - 3*%ARRAY_MAX_LEN - 3*%ARRAY_MAX_LEN - 1 :JMPN(outOfCountersStep) ; init and array div long diff --git a/test/testArrayArith.zkasm b/test/testArrayArith.zkasm index c0b97c54..b197445b 100644 --- a/test/testArrayArith.zkasm +++ b/test/testArrayArith.zkasm @@ -120,7 +120,28 @@ start: 1n :MLOAD(array_add_AGTB_out + E) 5 :MLOAD(array_add_AGTB_len_out) - ; 4] [2**256-2]*%ARRAY_MAX_LEN_DOUBLED + [1]*%ARRAY_MAX_LEN + ; 4] [2**256-2,2**256-2,2**256-1,2**256-1] + [1] + 4 => C + 1 => D + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inA) + 1 => E + %ARRAY_BASE_MINUS_ONE :MSTORE(array_add_AGTB_inA + E) + 2 => E + %ARRAY_BASE_MINUS_TWO :MSTORE(array_add_AGTB_inA + E) + 3 => E + %ARRAY_BASE_MINUS_TWO :MSTORE(array_add_AGTB_inA + E) + 1n :MSTORE(array_add_AGTB_inB) + :CALL(array_add_AGTB) + 0n :MLOAD(array_add_AGTB_out) + 1 => E + 0n :MLOAD(array_add_AGTB_out + E) + 2 => E + 115792089237316195423570985008687907853269984665640564039457584007913129639935n :MLOAD(array_add_AGTB_out + E) + 3 => E + 115792089237316195423570985008687907853269984665640564039457584007913129639934n :MLOAD(array_add_AGTB_out + E) + 4 :MLOAD(array_add_AGTB_len_out) + + ; 5] [2**256-2]*%ARRAY_MAX_LEN_DOUBLED + [1]*%ARRAY_MAX_LEN %ARRAY_MAX_LEN_DOUBLED => C %ARRAY_MAX_LEN => D C - 1 => E diff --git a/tools/counters/modexp.js b/tools/counters/modexp.js new file mode 100644 index 00000000..89a5f17a --- /dev/null +++ b/tools/counters/modexp.js @@ -0,0 +1,164 @@ +const { fea2scalar } = require("@0xpolygonhermez/zkevm-commonjs").smtUtils; + +module.exports = class myHelper { + setup(props) { + for (const name in props) { + this[name] = props[name]; + } + } + + ///////////// MODEXP + + /** + * Saves the initial counters for the modexp instance. + * @param ctx - Context. + * @sets ctx.modExpCounters. + */ + eval_recordModExpCounters(ctx) { + ctx.modExpCounters = {cntArith: ctx.cntArith, cntBinary: ctx.cntBinary, cntStep: BigInt(ctx.step)}; + } + + /** + * Checks whether the expected modExp counters are not undercounting the real ones. + * @param ctx - Context. + */ + eval_checkModExpCounters(ctx) { + const realCounters = { + cntStep: BigInt(ctx.step) - ctx.modExpCounters.cntStep + 1n, + cntBinary: ctx.cntBinary - ctx.modExpCounters.cntBinary, + cntArith: ctx.cntArith - ctx.modExpCounters.cntArith, + }; + + for (const key in realCounters) { + const expected = ctx.emodExpCounters[key]; + const real = realCounters[key]; + if (expected < real) { + throw new Error(`Caution: Counter ${key} is undercounted. Expected ${expected}, got ${real}.`); + } + } + } + + /** + * Computes the expected modExp counters for the given inputs. + * @param ctx - Context. + * @param tag - Tag. + * @sets ctx.ctx.emodExpCounters. + */ + eval_expectedModExpCounters(ctx, tag) { + const addrB = Number(this.evalCommand(ctx, tag.params[0])); + const lenB = Number(this.evalCommand(ctx, tag.params[1])); + const addrE = Number(this.evalCommand(ctx, tag.params[2])); + const lenE = Number(this.evalCommand(ctx, tag.params[3])); + const addrM = Number(this.evalCommand(ctx, tag.params[4])); + const lenM = Number(this.evalCommand(ctx, tag.params[5])); + + let B = 0n; + let E = 0n; + let M = 0n; + for (let i = 0; i < lenB; ++i) { + B += fea2scalar(ctx.Fr, ctx.mem[addrB + i]) * (1n << (256n * BigInt(i))); + } + for (let i = 0; i < lenE; ++i) { + E += fea2scalar(ctx.Fr, ctx.mem[addrE + i]) * (1n << (256n * BigInt(i))); + } + for (let i = 0; i < lenM; ++i) { + M += fea2scalar(ctx.Fr, ctx.mem[addrM + i]) * (1n << (256n * BigInt(i))); + } + + const [Q_B_M, R_B_M] = [B / M, B % M]; + const Bsq = B * B; + const [Q_Bsq_M, R_Bsq_M] = [Bsq / M, Bsq % M]; + + const lenE2 = Math.floor(lenE / 2) || 1; + + let nTimesOdd = 0; + while (E > 0n) { + nTimesOdd += Number(E & 1n); + E >>= 1n; + } + const nTimesEven = lenE * 256 - nTimesOdd; + + let counters = {cntStep: 0, cntBinary: 0, cntArith: 0}; + // I do an overstimation that the number is always odd! + const a = setupAndFirstDivCounters(); + const b = fullLoopCounters(); // halfLoopCounters(); + const c = fullLoopCounters(); + + for (const key in counters) { + counters[key] = a[key] + nTimesEven * b[key] + nTimesOdd * c[key]; + } + + // console.log(JSON.stringify(counters, null, 2)); + + ctx.emodExpCounters = counters; + + function computeLenThisBase(x) { + if (x === 0n) return 1; + + let len = 0; + while (x > 0n) { + x >>= 256n; + len++; + } + return len; + } + + function setupAndFirstDivCounters() { + // [steps: 74 + 10*len(B) + 26*len(M) + 8*len(Q(B,M)) + 8*len(R(B,M)) + 19*len(Q(B,M))*len(M), + // bin: 2 + 2*len(M) + 2*len(Q(B,M))*len(M), + // arith: len(M) - 18*len(Q(B,M)) + 19*len(Q(B,M))*len(M)] + return { + cntStep: + 74 + + 10 * lenB + + 26 * lenM + + 8 * computeLenThisBase(Q_B_M) + + 8 * computeLenThisBase(R_B_M) + + 19 * computeLenThisBase(Q_B_M) * lenM, + cntBinary: + 2 + + 2 * lenM + + 2 * computeLenThisBase(Q_B_M) * lenM, + cntArith: + lenM - + 18 * computeLenThisBase(Q_B_M) + + 19 * computeLenThisBase(Q_B_M) * lenM, + }; + } + + function fullLoopCounters() { + // [steps: 229 + 14*len(B) + 6*len(E) + 68*len(M) + 51*len(B)² + 38*len(B)*len(M) + 25*len(Q(E,2)) + 19*len(Q(B²,M))*len(M) + 8*len(Q(B²,M)) + 8*len(R(B²,M)), + // bin: 11 - 9*len(B) + 3*len(M) + 9*len(B)² + 4*len(B)*len(M) + 2*len(Q(E,2)) + 2*len(Q(B²,M))*len(M), + // arith: -1 - 16*len(B) - 16*len(M) + len(B)² + 38*len(B)*len(M) + 19*len(Q(B²,M))*len(M) - 18*len(Q(B²,M))] + return { + cntStep: + 229 + + 14 * lenB + + 6 * lenE + + 68 * lenM + + 51 * lenB**2 + + 38 * lenB * lenM + + 25 * lenE2 + + 19 * computeLenThisBase(Q_Bsq_M) * lenM + + 8 * computeLenThisBase(Q_Bsq_M) + + 8 * computeLenThisBase(R_Bsq_M), + cntBinary: + 11 - + 9 * lenB + + 3 * lenM + + 9 * lenB**2 + + 4 * lenB * lenM + + 2 * lenE2 + + 2 * computeLenThisBase(Q_Bsq_M) * lenM, + cntArith: + -1 - + 16 * lenB - + 16 * lenM + + lenB**2 + + 38 * lenB * lenM + + 19 * computeLenThisBase(Q_Bsq_M) * lenM - + 18 * computeLenThisBase(Q_Bsq_M), + }; + } + } +} \ No newline at end of file