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