diff --git a/counters/countersConstants.zkasm b/counters/countersConstants.zkasm index 7997a17b..b3829b94 100644 --- a/counters/countersConstants.zkasm +++ b/counters/countersConstants.zkasm @@ -233,7 +233,7 @@ CONST %OPCODECOPY_CNT_PADDING_PG = 0 CONST %OPCODECOPY_CNT_POSEIDON_G = 0 ; opEXTCODECOPY - COMPLEX - hardcoded values at test CONST %OPEXTCODECOPY_STEP = 2000 -CONST %OPEXTCODECOPY_CNT_BINARY = 105 +CONST %OPEXTCODECOPY_CNT_BINARY = 103 CONST %OPEXTCODECOPY_CNT_ARITH = 4 CONST %OPEXTCODECOPY_CNT_KECCAK_F = 0 CONST %OPEXTCODECOPY_CNT_MEM_ALIGN = 43 @@ -257,7 +257,7 @@ CONST %OPCREATE2_CNT_PADDING_PG = 0 CONST %OPCREATE2_CNT_POSEIDON_G = 27 ; opCALL - COMPLEX - hardcoded values at test CONST %OPCALL_STEP = 600 -CONST %OPCALL_CNT_BINARY = 28 +CONST %OPCALL_CNT_BINARY = 26 CONST %OPCALL_CNT_ARITH = 3 CONST %OPCALL_CNT_KECCAK_F = 0 CONST %OPCALL_CNT_MEM_ALIGN = 0 @@ -265,7 +265,7 @@ CONST %OPCALL_CNT_PADDING_PG = 0 CONST %OPCALL_CNT_POSEIDON_G = 14 ; opCALLCODE - COMPLEX - hardcoded values at test CONST %OPCALLCODE_STEP = 600 -CONST %OPCALLCODE_CNT_BINARY = 27 +CONST %OPCALLCODE_CNT_BINARY = 25 CONST %OPCALLCODE_CNT_ARITH = 3 CONST %OPCALLCODE_CNT_KECCAK_F = 0 CONST %OPCALLCODE_CNT_MEM_ALIGN = 0 @@ -289,7 +289,7 @@ CONST %OPREVERT_CNT_PADDING_PG = 0 CONST %OPREVERT_CNT_POSEIDON_G = 0 ; opDELEGATECALL - COMPLEX - hardcoded values at test CONST %OPDELEGATECALL_STEP = 600 -CONST %OPDELEGATECALL_CNT_BINARY = 24 +CONST %OPDELEGATECALL_CNT_BINARY = 22 CONST %OPDELEGATECALL_CNT_ARITH = 3 CONST %OPDELEGATECALL_CNT_KECCAK_F = 0 CONST %OPDELEGATECALL_CNT_MEM_ALIGN = 0 @@ -297,7 +297,7 @@ CONST %OPDELEGATECALL_CNT_PADDING_PG = 0 CONST %OPDELEGATECALL_CNT_POSEIDON_G = 6 ; opSTATICCALL - COMPLEX - hardcoded values at test CONST %OPSTATICCALL_STEP = 600 -CONST %OPSTATICCALL_CNT_BINARY = 24 +CONST %OPSTATICCALL_CNT_BINARY = 22 CONST %OPSTATICCALL_CNT_ARITH = 3 CONST %OPSTATICCALL_CNT_KECCAK_F = 0 CONST %OPSTATICCALL_CNT_MEM_ALIGN = 0 diff --git a/main/modexp/array_lib/array_add_AGTB.zkasm b/main/modexp/array_lib/array_add_AGTB.zkasm index 9bf388a5..4c13bc8f 100644 --- a/main/modexp/array_lib/array_add_AGTB.zkasm +++ b/main/modexp/array_lib/array_add_AGTB.zkasm @@ -23,10 +23,10 @@ ; code ; -------------------------- ; first_iteration <-- Compute a[0] + b[0] -; while(inB_index_check) { <-- While 0 < i < len(b) +; while(inB_index_check) { <-- While 1 <= i < len(b) ; loop2inB <-- Compute a[i] + b[i] + carry ; } -; while (inA_index_check) { <-- While 0 < i < len(a) +; while (inA_index_check) { <-- While len(b) <= i < len(a) ; loop2inA <-- Compute a[i] + carry ; } ; 1] check_carry <-- If there is a carry, append it to the result @@ -36,7 +36,7 @@ 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_DOUBLED] ; This cannot be bigger because we use it for division checking +VAR GLOBAL array_add_AGTB_out[%ARRAY_MAX_LEN_DOUBLED] ; This cannot be higher 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 diff --git a/main/modexp/array_lib/array_add_short.zkasm b/main/modexp/array_lib/array_add_short.zkasm index c0d3e552..f4152e1a 100644 --- a/main/modexp/array_lib/array_add_short.zkasm +++ b/main/modexp/array_lib/array_add_short.zkasm @@ -19,7 +19,7 @@ ; code ; -------------------------- ; first_iteration <-- Compute a[0] + b -; while(loop_index_check) { <-- While 0 < i < len(a) +; while(loop_index_check) { <-- While 1 <= i < len(a) ; loop2inA <-- Compute a[i] + carry ; } ; 1] check_carry <-- If there is a carry, append it to the result @@ -29,7 +29,7 @@ VAR GLOBAL array_add_short_inA[%ARRAY_MAX_LEN] VAR GLOBAL array_add_short_inB -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_out[%ARRAY_MAX_LEN] ; This cannot be higher because we use it for division checking VAR GLOBAL array_add_short_len_inA VAR GLOBAL array_add_short_len_out diff --git a/main/modexp/array_lib/array_div_long.zkasm b/main/modexp/array_lib/array_div_long.zkasm index 76e02362..6f2d4640 100644 --- a/main/modexp/array_lib/array_div_long.zkasm +++ b/main/modexp/array_lib/array_div_long.zkasm @@ -1,5 +1,5 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; PRE: The input arrays have been trimmed, len(inB) >= 2 and therefore inB != 0 +;; PRE: The input arrays have been trimmed, len(inB) >= 2 and therefore inB != 0,1. ;; POST: The quotient and remainder are trimmed. ;; ;; array_div_long: @@ -58,7 +58,7 @@ 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_DOUBLED_MINUS_ONE] +VAR GLOBAL array_div_long_quo[%ARRAY_MAX_LEN_DOUBLED_MINUS_ONE] ; Note: This cannot be higher because len(inB) >= 2 VAR GLOBAL array_div_long_rem[%ARRAY_MAX_LEN] VAR GLOBAL array_div_long_len_inA @@ -131,6 +131,7 @@ array_div_long_inA_not_zero_two_chunks: ; where i is the first different chunk from 0 to len(inA) RR :JMPN(array_div_long_check_inALTinB) + ; inA > inB C - RR :JMPN(failAssert) ; if C < RR ERROR @@ -231,7 +232,6 @@ array_div_long_inAGTinB: C :MSTORE(array_div_long_len_quo) $ => D :MLOAD(array_div_long_len_inB) - C - 1 => RR D - 1 => E ; save the first non-zero chunk of quo diff --git a/main/modexp/array_lib/array_div_short.zkasm b/main/modexp/array_lib/array_div_short.zkasm index 3f03a865..2b7437f6 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 and inB != 0. +;; PRE: The input arrays have been trimmed and inB != 0,1. ;; POST: The quotient is trimmed. ;; ;; array_div_short: @@ -55,14 +55,16 @@ array_div_short: C :MSTORE(array_div_short_len_quo) ; Let's cover the edge cases - ; Is C == 1 and inA == 0? + ; 1] Is C == 1 and inA == 0? 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 + + ; Here, len(inA) = len(inB) = 1 + $ => A :MLOAD(array_div_short_inA) 0 => B $ :EQ, JMPC(array_div_short_inA_is_zero) array_div_short_equal_len: - ; Here, C = 1 + ; 2] Check if inA = inB, inA < inB or inA > inB ; 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) @@ -76,9 +78,7 @@ array_div_short_equal_len: RR :JMPN(array_div_short_check_inALTinB) - 1 - RR :JMPN(failAssert) ; if 1 < RR ERROR - - ; Ensure that the chunk is higher + ; Ensure inB < inA $ => A :MLOAD(array_div_short_inB) $ => B :MLOAD(array_div_short_inA) 1 :LT, JMP(array_div_short_inAGTinB) @@ -101,8 +101,7 @@ array_div_short_same_input: 0 :MSTORE(array_div_short_rem), JMP(array_div_short_end) array_div_short_check_inALTinB: - RR + 1 :JMPN(failAssert) ; if RR < -1 ERROR - + ; Ensure inA < inB $ => A :MLOAD(array_div_short_inA) $ => B :MLOAD(array_div_short_inB) 1 :LT @@ -138,7 +137,6 @@ array_div_short_inAGTinB: ; 3] Let's multiply the quotient by inB C :MSTORE(array_div_short_len_quo) - C - 1 => RR ; save the first non-zero chunk of quo A :MSTORE(array_div_short_quo + RR) @@ -200,7 +198,6 @@ array_div_short_check_result_eq_inA1: A :MLOAD(array_div_short_inA + RR) RR - 1 => RR :JMPN(array_div_short_end, array_div_short_check_result_eq_inA1) - ; Path with remainder equal to 0 array_div_short_rem_is_zero: 0 :ASSERT, MSTORE(array_div_short_rem) diff --git a/main/modexp/array_lib/array_div_two.zkasm b/main/modexp/array_lib/array_div_two.zkasm index 98089ba5..4f30349b 100644 --- a/main/modexp/array_lib/array_div_two.zkasm +++ b/main/modexp/array_lib/array_div_two.zkasm @@ -51,14 +51,17 @@ array_div_two: 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 + $ => A :MLOAD(array_div_two_in) + 0 => B + $ :EQ, JMPC(array_div_two_inALTinB) +array_div_two_equal_len: ; 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) @@ -71,9 +74,7 @@ array_div_two: RR :JMPN(array_div_two_check_inALTtwo) - 1 - RR :JMPN(failAssert) ; if 1 < RR ERROR - - ; Ensure that the chunk is higher + ; Ensure 2 < inA 2 => A $ => B :MLOAD(array_div_two_in) 1 :LT, JMP(array_div_two_inAGTinB) @@ -88,14 +89,11 @@ array_div_two_same_input: 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 + ; Ensure in < 2 <-> in == 1 + 1 :MLOAD(array_div_two_in) array_div_two_inALTinB: - ; If in < 2, then the result is 0 + ; If in == 1, 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 @@ -123,7 +121,6 @@ array_div_two_inAGTinB: ; 3] Let's multiply the quotient by 2 C :MSTORE(array_div_two_len_quo) - C - 1 => RR ; save the first non-zero chunk of quo A :MSTORE(array_div_two_quo + RR) @@ -146,13 +143,8 @@ array_div_two_mul_quo_inB: ${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 + ; Check that the remainder is 1 < 2 + 1 :ASSERT A :MSTORE(array_add_short_inB) @@ -178,16 +170,15 @@ array_div_two_check_result_eq_inA1: 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 + ; The length of q·2 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 + ; Check that input == q·2 + 0 C - 1 => RR array_div_two_check_result_eq_inA2: $ => A :MLOAD(array_mul_two_out + RR) diff --git a/main/modexp/array_lib/array_mul_long.zkasm b/main/modexp/array_lib/array_mul_long.zkasm index 96fb2cc3..77f2431d 100644 --- a/main/modexp/array_lib/array_mul_long.zkasm +++ b/main/modexp/array_lib/array_mul_long.zkasm @@ -37,7 +37,7 @@ 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] ; This cannot be bigger because we use it for division checking +VAR GLOBAL array_mul_long_out[%ARRAY_MAX_LEN_DOUBLED] ; This cannot be higher because it is used for division checking (in the w.c.) VAR GLOBAL array_mul_long_len_inA VAR GLOBAL array_mul_long_len_inB VAR GLOBAL array_mul_long_len_out @@ -82,7 +82,7 @@ array_mul_long_first_iteration_first_row: ; out[1] = carry 1 => RR - D => C :MSTORE(array_mul_long_out + RR) + D => C :MSTORE(array_mul_long_out + RR) ; The store is not needed, but it is included for clarity array_mul_long_finish_first_row: ; 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 d323371e..1492ce0e 100644 --- a/main/modexp/array_lib/array_mul_short.zkasm +++ b/main/modexp/array_lib/array_mul_short.zkasm @@ -50,7 +50,7 @@ array_mul_short: array_mul_short_first_iteration: ; The result will be stored as D·base + C - ; 1] a[0] * b, where a[0],b ∈ [0,base-1]: This number cannot be GT (base - 1)·base, two chunks + ; 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 @@ -69,7 +69,7 @@ array_mul_short_loop_index_check: 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 + ; 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} @@ -83,6 +83,7 @@ array_mul_short_loop2inA: ; If the last carry > 0, we need to insert it to the output array_mul_short_check_carry: + ; D = carry, E = last_index_out D => A 0 => B $ :EQ, JMPC(array_mul_short_trim) diff --git a/main/modexp/array_lib/array_mul_two.zkasm b/main/modexp/array_lib/array_mul_two.zkasm index ade68c13..efdbafde 100644 --- a/main/modexp/array_lib/array_mul_two.zkasm +++ b/main/modexp/array_lib/array_mul_two.zkasm @@ -18,7 +18,7 @@ ; code ; -------------------------- ; first_iteration <-- a[0] + a[0] -; while(loop_index_check) { <-- While 0 < i < len(a) +; while(loop_index_check) { <-- While 1 <= i < len(a) ; loop2in <-- Compute a[i] + a[i] + carry ; } ; 1] check_carry <-- If there is a carry, append it to the result @@ -27,7 +27,7 @@ ; -------------------------- 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_out[%ARRAY_MAX_LEN] ; This cannot be higher because we use it for division checking VAR GLOBAL array_mul_two_len_in VAR GLOBAL array_mul_two_len_out diff --git a/main/modexp/array_lib/array_square.zkasm b/main/modexp/array_lib/array_square.zkasm index 4eff5c7f..556e684d 100644 --- a/main/modexp/array_lib/array_square.zkasm +++ b/main/modexp/array_lib/array_square.zkasm @@ -12,6 +12,19 @@ ; Matrix visualization: https://hackmd.io/C9KQPGoaSICStIQQFweBlw?view +; a3 a2 a1 a0 +; * a3 a2 a1 a0 +; ------------------------------------------------------- 0 +; Y 2*a0*a2 2*a0*a1 a0*a0 +; ------------------------------------------------------- 1 +; 2*a1*a3+Z 2*a1*a2 a1*a1 X 0 +; ------------------------------------------------------- 2 +; Z Y 2*a2*a3 a2*a2 X X 0 0 +; ------------------------------------------------------- 3 +; a3*a3 X X X 0 0 0 +; ------------------------------------------------------- 4 +; RESULT + ; code ; -------------------------- ; first_iteration_first_row <-- Compute a[0]·b[0] @@ -75,18 +88,20 @@ array_square: ; Begin of branching array_square_loop_index_check: ; costs [steps: 7] + ; B = len(in) ; out[i + len] = carry $ => A :MLOAD(array_square_carry_chunk_1) RCX + B => E A :MSTORE(array_square_out + E) + ; if the carry has two chunks, store the second one to be used in the next iteration $ => A :MLOAD(array_square_carry_chunk_2) A :MSTORE(array_square_out_chunk_2) ; update indices - RCX + 1 => RCX,RR,A - B - A :JMPZ(array_square_prep_trim, array_square_ai_times_ai) + RCX + 1 => RCX,RR + B - RR :JMPZ(array_square_prep_trim, array_square_first_iteration_loopDiagonal2len) ; End of branching ; Begin of first row @@ -111,42 +126,48 @@ array_square_first_iteration_first_row: ; update the index 1 => RR $ => B :MLOAD(array_square_len_in) - B - RR :JMPZ(array_square_loop_index_check) + B - RR :JMPNZ(array_square_finish_first_row) + + ; if only one chunk, set out[1] = carry + D :MSTORE(array_square_out + 1), JMP(array_square_prep_trim) array_square_finish_first_row: ; costs [steps: 35, bin: 6, arith: 1] + ; PRE: 'carry_chunk_2, 'carry_chunk_1 - ; The result will be stored as D·base + C + ; POST: The result will be stored as chunk_3·base² + D·base + C - ; 1] a[0]·a[j] + ; 1] a[0]·a[j], j >= 1 $ => 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) + 0 => C ; We cannot add anything here because we need to multiply a[0]·a[j] by 2 + $${var _arraySquare_a0aj = A*B} + ${_arraySquare_a0aj >> 256} => D + ${_arraySquare_a0aj} => C :ARITH + D :MSTORE(array_square_aiaj_chunk_2) ; carry(a[0]·a[j]) ; 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 + D => A ; carry(a[0]·a[j]) 1 => B - $ => D :ADD + $ => D :ADD ; carry(a[0]·a[j]) + 1 ;----------------- __array_square_no_carry_continue_1: - $ => A :MLOAD(array_square_aiaj_chunk_2) + ; duplicate the carry of a[0]·a[j] + $ => A :MLOAD(array_square_aiaj_chunk_2) ; carry(a[0]·a[j]) D => B - $ => D :ADD, JMPNC(__array_square_no_carry_continue_2) + $ => D :ADD, JMPNC(__array_square_no_carry_continue_2) ; 2·carry(a[0]·a[j]) or 2·carry(a[0]·a[j]) + 1 ;----------------- 1 :MSTORE(array_square_chunk_3) ;----------------- __array_square_no_carry_continue_2: + ; 2·a[0]·a[j] = chunk_3·base² + D·base + C - ; 3] 2·a[0]·a[j] + carry + ; 3] 2·a[0]·a[j] + carry_chunk_2·B + carry_chunk_1 C => A $ => B :MLOAD(array_square_carry_chunk_1) $ => C :ADD, JMPNC(__array_square_no_carry_continue_3) @@ -155,17 +176,22 @@ array_square_finish_first_row: D => A 1 => B $ => D :ADD, JMPNC(__array_square_no_carry_continue_3) + ; NOTE: It cannot happen that chunk_3 = 1 and 2·a[0]·a[j] + carry_chunk_1 produces carry 1 :MSTORE(array_square_chunk_3) ;----------------- __array_square_no_carry_continue_3: + ; 2·a[0]·a[j] + carry_chunk_1 = chunk_3·base² + D·base + C + ; Now add carry_chunk_2·B D => A $ => B :MLOAD(array_square_carry_chunk_2) $ => D :ADD, JMPNC(__array_square_no_carry_continue_4) ;----------------- + ; NOTE: It cannot happen that chunk_3 = 1 and 2·a[0]·a[j] + carry_chunk_2·B produces carry 1 :MSTORE(array_square_chunk_3) ;----------------- __array_square_no_carry_continue_4: + ; 2·a[0]·a[j] + carry_chunk_2·B + carry_chunk_1 = chunk_3·base² + D·base + C ; carry = product / base D :MSTORE(array_square_carry_chunk_1) @@ -183,48 +209,24 @@ array_square_finish_first_row: 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, 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 - $ => A,B :MLOAD(array_square_in + RR) - 0 => C - $${var _arraySquare_aiai = A*B} - ${_arraySquare_aiai >> 256} => D - ${_arraySquare_aiai} => C :ARITH - C :MSTORE(array_square_carry_chunk_1) - D :MSTORE(array_square_carry_chunk_2) - -array_square_first_iteration_loopRR2len: +; Begin of remaining rows +array_square_first_iteration_loopDiagonal2len: ; 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 + ; product = a[i]·a[i] + out[2i] (in the worst case, this is a 2-chunk number) + ; The result will be stored as D·base + C - ; 1] a[i]·a[i] + ; a[i]·a[i] + out[2i] $ => 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: + $ => C :MLOAD(array_square_out + E) + $${var _arraySquare_aiai = A*B + C} + ${_arraySquare_aiai >> 256} => D + ${_arraySquare_aiai} => C :ARITH + D :MSTORE(array_square_aiaj_chunk_2) - ; The output can have two chunks only if i == len-1, so we must jump the following block of code if i < len-1 + ; When i == len-1, the iteration a[i]·a[i] becomes the last iteration of such row + ; Therefore, we must add the second carry chunk of the last iteration of the previous row (saved on out_chunk_2) RR + 1 => A $ => B :MLOAD(array_square_len_in) B - A :JMPNZ(__array_square_no_carry_continue_6) @@ -252,10 +254,10 @@ array_square_first_iteration_loopRR2len: $ => B :MLOAD(array_square_len_in) B - RR :JMPZ(array_square_loop_index_check) -array_square_loopRR2len: +array_square_loopDiagonal2len: ; 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) + ; product = 2·(a[i]·a[j]) + out[i+j] + carry, j > i (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[j], where a[i],a[j] ∈ [0,base-1]: This number cannot be GT (base - 2)·base + 1, two chunks @@ -279,6 +281,7 @@ array_square_loopRR2len: ;----------------- __array_square_no_carry_continue_7: + ; duplicate the carry of a[i]·a[j] $ => A :MLOAD(array_square_aiaj_chunk_2) D => B $ => D :ADD, JMPNC(__array_square_no_carry_continue_8) @@ -286,6 +289,7 @@ array_square_loopRR2len: 1 :MSTORE(array_square_chunk_3) ;----------------- __array_square_no_carry_continue_8: + ; 2·a[i]·a[j] = chunk_3·base² + D·base + C ; 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 @@ -300,16 +304,18 @@ array_square_loopRR2len: D => A 1 => B $ => D :ADD, JMPNC(__array_square_no_carry_continue_9) + ; NOTE: It cannot happen that chunk_3 = 1 and 2·a[i]·a[j] + out[i+j] produces carry 1 :MSTORE(array_square_chunk_3) ;----------------- __array_square_no_carry_continue_9: + ; 2·a[i]·a[j] + out[i+j] = chunk_3·base² + D·base + C - ; The output can have two chunks only if j == len-1, so we must jump the following block of code if j < len-1 + ; 4] When j == len-1, we must add the second carry chunk of the last iteration of the previous row (saved on out_chunk_2) RR + 1 => A $ => B :MLOAD(array_square_len_in) B - A :JMPNZ(__array_square_no_carry_continue_10) ; Add the second output chunk - $ => A :MLOAD(array_square_out_chunk_2) + $ => A :MLOAD(array_square_out_chunk_2) ; out_chunk_2 ∈ [0,1] D => B $ => D :ADD, JMPNC(__array_square_no_carry_continue_10) ;----------------- @@ -317,7 +323,7 @@ array_square_loopRR2len: ;----------------- __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 + ; 5] product = 2·a[i]·a[j] + out[i+j] + carry_chunk_2·B + carry_chunk_1: This number cannot be GT base² + (base - 2)·base, three chunks C => A $ => B :MLOAD(array_square_carry_chunk_1) $ => C :ADD, JMPNC(__array_square_no_carry_continue_11) @@ -329,7 +335,9 @@ array_square_loopRR2len: 1 :MSTORE(array_square_chunk_3) ;----------------- __array_square_no_carry_continue_11: + ; 2·a[i]·a[j] + out[i+j] + carry_chunk_1 = chunk_3·base² + D·base + C + ; Now add carry_chunk_2·B D => A $ => B :MLOAD(array_square_carry_chunk_2) $ => D :ADD, JMPNC(__array_square_no_carry_continue_12) @@ -337,6 +345,7 @@ array_square_loopRR2len: 1 :MSTORE(array_square_chunk_3) ;----------------- __array_square_no_carry_continue_12: + ; 2·a[i]·a[j] + out[i+j] + carry_chunk_2·B + carry_chunk_1 = chunk_3·base² + D·base + C ; carry = product / base; This number cannot be greater than base + (base - 2) D :MSTORE(array_square_carry_chunk_1) @@ -351,7 +360,8 @@ array_square_loopRR2len: ; update the index RR + 1 => RR $ => B :MLOAD(array_square_len_in) - B - RR :JMPZ(array_square_loop_index_check, array_square_loopRR2len) + B - RR :JMPZ(array_square_loop_index_check, array_square_loopDiagonal2len) +; End of remaining rows array_square_prep_trim: ; costs [steps: 8, bin: 1, arith: 0] diff --git a/main/modexp/modexp.zkasm b/main/modexp/modexp.zkasm index d1414403..0298093a 100644 --- a/main/modexp/modexp.zkasm +++ b/main/modexp/modexp.zkasm @@ -1,5 +1,5 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; PRE: B, E, M have been trimmed. +;; PRE: B, E, M have been trimmed, M != 0,1, B != 0,1 and E != 0. ;; POST: out is trimmed ;; ;; modexp: @@ -18,11 +18,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; function modexp(base: bigint[], exp: bigint[], mod: bigint[]): bigint[] { -;; if (array_is_zero(mod) || array_is_one(mod)) return [0n]; -;; if (array_is_zero(base)) return [0n]; -;; if (array_is_one(base)) return [1n]; -;; if (array_is_zero(e)) return [1n]; -;; ;; let out = [1n]; ;; let base = array_div(base, mod)[1]; ;; while (!array_is_zero(exp)) { @@ -30,12 +25,14 @@ ;; if (isOdd(exp)) { ;; out = array_div(array_mul(out, base),mod)[1]; ;; } -;; exp = array_div_two(exp); +;; exp = array_div_two(exp)[0]; ;; base = array_div(array_square(base),mod)[1]; ;; } ;; return r; ;; }; +;; TODO: Context variables instead of global ones???? + VAR GLOBAL modexp_Blen VAR GLOBAL modexp_Elen VAR GLOBAL modexp_Mlen @@ -237,7 +234,7 @@ modexp_mul_long_out_and_B: $ => C :MLOAD(array_mul_long_len_out) $ => D :MLOAD(modexp_Mlen) C - 1 => RR - D - 1 => E :JMPNZ(modexp_mul_long_out_to_div_long, modexp_mul_long_out_to_div_short) + D - 1 => E :JMPNZ(modexp_mul_long_out_to_div_long, modexp_mul_long_out_to_div_short) ; Note: div_short cannot happen here ; Compute out = (out * B) % M ;-------------------------------- @@ -265,7 +262,7 @@ modexp_div_short_out_and_M1: 1 :MSTORE(modexp_outlen) $ => A :MLOAD(array_div_short_rem) - A :MSTORE(modexp_out), JMP(return_modexp_loop_multiply) + A :MSTORE(modexp_out), JMP(__return_modexp_loop_multiply) ; 3] Mul short out to div long modexp_mul_short_out_to_div_long: @@ -297,7 +294,7 @@ modexp_div_long_out_and_M1: modexp_rem_from_div2: $ => A :MLOAD(array_div_long_rem + RR) A :MSTORE(modexp_out + RR) - RR - 1 => RR :JMPN(return_modexp_loop_multiply, modexp_rem_from_div2) + RR - 1 => RR :JMPN(__return_modexp_loop_multiply, modexp_rem_from_div2) ; ------------------- ; End of branching @@ -324,7 +321,7 @@ modexp_loop: $ => A :MLOAD(modexp_E) 1 => B $ :AND, JMPC(modexp_loop_multiply) ; In the worst case, the exponent is odd in each iteration - return_modexp_loop_multiply: + __return_modexp_loop_multiply: $ => C :MLOAD(modexp_Elen) C - 1 => RR diff --git a/main/modexp/modexp_utils.zkasm b/main/modexp/modexp_utils.zkasm index 39d5b019..fe508c9f 100644 --- a/main/modexp/modexp_utils.zkasm +++ b/main/modexp/modexp_utils.zkasm @@ -45,7 +45,7 @@ modexp_getBaseMloadX: E - C => E E :MSTORE(readXFromCalldataOffset), CALL(readFromCalldataOffset); in: [readXFromCalldataOffset: offset value, readXFromCalldataLength: length value], out: [readXFromCalldataResult: result value] $ => A :MLOAD(readXFromCalldataResult) - 32 - C => D :CALL(SHRarith) + 32 - C => D :CALL(SHRarith) ; in: [A: value, D: #bytes to right shift (A >> D)] out: [A: shifted result] 0 => C modexp_getBaseMstore: @@ -116,7 +116,7 @@ modexp_getExpMloadX: E - C => E E :MSTORE(readXFromCalldataOffset), CALL(readFromCalldataOffset); in: [readXFromCalldataOffset: offset value, readXFromCalldataLength: length value], out: [readXFromCalldataResult: result value] $ => A :MLOAD(readXFromCalldataResult) - 32 - C => D :CALL(SHRarith) + 32 - C => D :CALL(SHRarith) ; in: [A: value, D: #bytes to right shift (A >> D)] out: [A: shifted result] 0 => C modexp_getExpMstore: @@ -187,7 +187,7 @@ modexp_getModMloadX: E - C => E E :MSTORE(readXFromCalldataOffset), CALL(readFromCalldataOffset); in: [readXFromCalldataOffset: offset value, readXFromCalldataLength: length value], out: [readXFromCalldataResult: result value] $ => A :MLOAD(readXFromCalldataResult) - 32 - C => D :CALL(SHRarith) + 32 - C => D :CALL(SHRarith) ; in: [A: value, D: #bytes to right shift (A >> D)] out: [A: shifted result] 0 => C modexp_getModMstore: diff --git a/main/p256verify/dblScalarMulSecp256r1.zkasm b/main/p256verify/dblScalarMulSecp256r1.zkasm index 54c483d9..d606e287 100644 --- a/main/p256verify/dblScalarMulSecp256r1.zkasm +++ b/main/p256verify/dblScalarMulSecp256r1.zkasm @@ -3,11 +3,11 @@ ;; dblScalarMulSecp256r1: ;; in: Points p1 = (p1_x, p1_y), p2 = (p2_x, p2_y) and scalars k1, k2 ;; out: -;; · p3 = (p3_x, p3_y) ∈ E(Fp) +;; · p3 = [k1]·P1 + [k2]·P2 = (p3_x, p3_y) ∈ E(Fp) ;; · Variable p3_is_zero = 0 or 1, to indicate whether p3 is the point at infinity or not ;; ;; PRE: p1 = (p1_x, p1_y), p2 = (p2_x, p2_y) are in E(Fp)\{𝒪} and p1_x,p1_y,p2_x,p2_y are in Fp. -; Moreover, k1,k2 are in Fn and they cannot be both zero. +;; Moreover, k1,k2 are in Fn and they cannot be both zero. ;; POST: The resulting coordinates p3_x,p3_y are in Fp. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -59,9 +59,8 @@ dblScalarMulSecp256r1: ; receive the maximum length (minus one) between the binary representations of k1 and k2 ; Note that 0 <= max(len(k1)-1,len(k2)-1) <= 255 - $0{receiveLen(mem.dblScalarMulSecp256r1_k1, mem.dblScalarMulSecp256r1_k2)} => A,RR - 256 => B - 1 :LT + $0{receiveLen(mem.dblScalarMulSecp256r1_k1, mem.dblScalarMulSecp256r1_k2)} => RR :JMPN(failAssert) + 255 - RR :JMPN(failAssert) ; start the acummulator of k1 and k2 0 => RCX :MSTORE(dblScalarMulSecp256r1_acum_k1) @@ -87,11 +86,11 @@ dblScalarMulSecp256r1: ${B == D} :JMPNZ(dblScalarMulSecp256r1SameInitialPoints) ; [steps: 15, bin: 1, arith: 0] - ; verify path p1_y != p2_y <==> p1_y = -p2_y <==> p1_y + p2_y = 0 + ; verify path p1_y != p2_y <==> p1_y = -p2_y (mod p) <==> p1_y + p2_y = 0 (mod p) <==> p1_y + p2_y ∊ {0,SECP256R1_P} ; Note: In this path we could use a binary, but we use an arith ; because in this path we do not perform point arithmetic - ; y must be distinct from 0, because there are no points with y = 0 + ; y must be distinct from 0, because there are no points with y = 0, then p1_y + p2_y = SECP256R1_P ; check p1_y + p2_y = SECP256R1_P B => A ; A = p1_y @@ -296,13 +295,11 @@ dblScalarMulSecp256r1_x_equals_before_add: 1 :MSTORE(dblScalarMulSecp256r1_p3_zero), JMP(dblScalarMulSecp256r1_double) dblScalarMulSecp256r1_same_point_to_add: - ; must check really are equals, use MLOAD as ASSERT - ; ASSERT(D == dblScalarMulSecp256r1_p3_y) - + ; verify path p3_y == p_y (D) D :MLOAD(dblScalarMulSecp256r1_p3_y) + C => A D => B - ; (A,B) * 2 = (E, op) ${xDblPointEc_secp256r1(A,B)} => E :MSTORE(dblScalarMulSecp256r1_p3_x) ${yDblPointEc_secp256r1(A,B)} :ARITH_SECP256R1_ECADD_SAME, MSTORE(dblScalarMulSecp256r1_p3_y), JMP(dblScalarMulSecp256r1_double) diff --git a/main/p256verify/p256verify.zkasm b/main/p256verify/p256verify.zkasm index 6d0e8b99..46b3867e 100644 --- a/main/p256verify/p256verify.zkasm +++ b/main/p256verify/p256verify.zkasm @@ -14,9 +14,13 @@ ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Note: If hash = 0, then one can forge a valid signature: +; Note1 ZeroHash: If hash = 0, then one can forge a valid signature: ; https://crypto.stackexchange.com/questions/50279/how-should-ecdsa-handle-the-null-hash -; We anyways do not check for this case, as it happens with negligible probability +; We anyways do not check for this case, as it happens with negligible probability. + +; Note2 Malleability: Given a signature (r,s) over a message m, the signature (r,N-s) is also valid for the same message: +; https://github.com/cosmos/cosmos-sdk/issues/9723, https://eips.ethereum.org/EIPS/eip-2 +; This opens the door to replay attacks. This is not checked in this precompiled. ; inputs VAR GLOBAL p256verify_hash @@ -26,6 +30,7 @@ VAR GLOBAL p256verify_x VAR GLOBAL p256verify_y VAR GLOBAL p256verify_x3 +VAR GLOBAL p256verify_y2 VAR GLOBAL p256verify_s_inv VAR GLOBAL p256verify_u1 VAR GLOBAL p256verify_u2 @@ -35,16 +40,17 @@ VAR GLOBAL p256verify_RR INCLUDE "constants.zkasm" ; ERROR CODES (B) -; 0 - no error -; 1 - r is zero -; 2 - r is too big -; 3 - s is zero -; 4 - s is too big -; 5 - x is too big -; 6 - y is too big -; 7 - PK is the point at infinity -; 8 - PK is not in the curve -; 9 - result is the point at infinity +; 0 - no error +; 1 - r is zero +; 2 - r is too big +; 3 - s is zero +; 4 - s is too big +; 5 - x is too big +; 6 - y is too big +; 7 - PK is the point at infinity +; 8 - PK is not in the curve +; 9 - result is the point at infinity +; 10 - signature not verified ; RESOURCES: ; · r is zero: [steps: 13, bin: 1, arith: 0] @@ -76,31 +82,31 @@ p256verify_correctness_checks: ; 1] Check that r in [1,N-1] 0n => A $ => B :MLOAD(p256verify_r) - $ :EQ, JMPC(p256verify_r_is_zero) + $ :EQ, JMPC(p256verify_error_r_is_zero) %SECP256R1_N_MINUS_ONE => A - $ :LT, JMPC(p256verify_r_is_too_big) + $ :LT, JMPC(p256verify_error_r_is_too_big) ; 2] Check that s in [1,N-1] $ => B :MLOAD(p256verify_s) - $ :LT, JMPC(p256verify_s_is_too_big) + $ :LT, JMPC(p256verify_error_s_is_too_big) 0n => A - $ :EQ, JMPC(p256verify_s_is_zero) + $ :EQ, JMPC(p256verify_error_s_is_zero) ; 3] Check that x in [0,P-1] %SECP256R1_P_MINUS_ONE => A $ => B :MLOAD(p256verify_x) - $ :LT, JMPC(p256verify_x_is_too_big) + $ :LT, JMPC(p256verify_error_x_is_too_big) ; 4] Check that y in [0,P-1] $ => B :MLOAD(p256verify_y) - $ :LT, JMPC(p256verify_y_is_too_big) + $ :LT, JMPC(p256verify_error_y_is_too_big) ; 5] Check whether PK = (x,y) is the point at infinity 𝒪 0n => B $ => A :MLOAD(p256verify_x) $ :EQ, JMPNC(p256verify_pk_not_point_at_infinity) $ => A :MLOAD(p256verify_y) - $ :EQ, JMPC(p256verify_pk_point_at_infinity) + $ :EQ, JMPC(p256verify_error_pk_point_at_infinity) ; [steps: 29, bin: 8, arith: 0] p256verify_pk_not_point_at_infinity: @@ -123,14 +129,14 @@ p256verify_pk_not_point_at_infinity: $ => A :MLOAD(p256verify_x3), CALL(addFpSecp256r1) ; [in: A,C, out: C] [steps: 10, bin: 1, arith: 2] ; C = x³ + a·x + b - C :MSTORE(p256verify_x3) + C :MSTORE(p256verify_y2) $ => A :MLOAD(p256verify_y), CALL(squareFpSecp256r1) ; [in: A, out: A] [steps: 11, bin: 1, arith: 2] ; A = y² ; 1.2] Check if LHS == RHS - $ => B :MLOAD(p256verify_x3) - $ :EQ, JMPNC(p256verify_pk_not_in_curve) + $ => B :MLOAD(p256verify_y2) + $ :EQ, JMPNC(p256verify_error_pk_not_in_curve) ; [steps: 100, bin: 15, arith: 12] p256verify_scalars: @@ -163,12 +169,12 @@ p256verify_ecp: $ => A :MLOAD(p256verify_x) A :MSTORE(dblScalarMulSecp256r1_p2_x) $ => A :MLOAD(p256verify_y) - A :MSTORE(dblScalarMulSecp256r1_p2_y), CALL(dblScalarMulSecp256r1) ; [steps: 6459, bin: 1, arith: 513] + A :MSTORE(dblScalarMulSecp256r1_p2_y), CALL(dblScalarMulSecp256r1) ; [in: [k1, p1_x, p1_y, k2, p2_x, p2_y], out: [p3_is_zero, p3_x, p3_y]] [steps: 6459, bin: 1, arith: 513] ; [steps: 7707, bin: 19, arith: 531] p256verify_verification: ; check if result of dblScalarMulSecp256k1 is point at infinity - $ :MLOAD(dblScalarMulSecp256r1_p3_zero), JMPNZ(p256verify_result_point_at_infinity) + $ :MLOAD(dblScalarMulSecp256r1_p3_zero), JMPNZ(p256verify_error_result_point_at_infinity) ; check if the x-coordinate of the result is equal to r ; perform modular reduction is p3_x >= SECP256R1_N @@ -187,7 +193,7 @@ p256verify_assign_a: p256verify_final_check: $ => B :MLOAD(p256verify_r) - $ => A :EQ + $ => A :EQ, JMPNC(p256verify_error_signature_not_verified) ; A = 1 if the signature is valid; 0 otherwise ; program ended with no errors @@ -195,33 +201,36 @@ p256verify_final_check: ; till the end -> [steps: 7718, bin: 22, arith: 531] ; ERRORS -p256verify_r_is_zero: +p256verify_error_r_is_zero: 1 => B :JMP(p256verify_error) -p256verify_r_is_too_big: +p256verify_error_r_is_too_big: 2 => B :JMP(p256verify_error) -p256verify_s_is_zero: +p256verify_error_s_is_zero: 3 => B :JMP(p256verify_error) -p256verify_s_is_too_big: +p256verify_error_s_is_too_big: 4 => B :JMP(p256verify_error) -p256verify_x_is_too_big: +p256verify_error_x_is_too_big: 5 => B :JMP(p256verify_error) -p256verify_y_is_too_big: +p256verify_error_y_is_too_big: 6 => B :JMP(p256verify_error) -p256verify_pk_point_at_infinity: +p256verify_error_pk_point_at_infinity: 7 => B :JMP(p256verify_error) -p256verify_pk_not_in_curve: +p256verify_error_pk_not_in_curve: 8 => B :JMP(p256verify_error) -p256verify_result_point_at_infinity: +p256verify_error_result_point_at_infinity: 9 => B :JMP(p256verify_error) +p256verify_error_signature_not_verified: + 10 => B :JMP(p256verify_end) + p256verify_error: 0 => A diff --git a/main/precompiled/end.zkasm b/main/precompiled/end.zkasm index ed75777b..b7bfa5d1 100644 --- a/main/precompiled/end.zkasm +++ b/main/precompiled/end.zkasm @@ -26,7 +26,8 @@ VAR GLOBAL preGAS preFailModExpLength: $ => SR :MLOAD(initSR), CALL(revertTouched) :CALL(revertBlockInfoTree) - $ => A :MLOAD(originCTX), JMPZ(errorAtFirstContext) + $${eventLog(onError, revert)} + $ => A :MLOAD(originCTX), JMPZ(preFailModExpLengthCTX0) A => CTX ; Add return data context value to origin context ; Clear return data context @@ -39,4 +40,10 @@ preFailModExpLength: 0 :MSTORE(preGAS) $ => SP :MLOAD(lastSP) $ => PC :MLOAD(lastPC) - 0 :MSTORE(SP++), JMP(readCode) \ No newline at end of file + 0 :MSTORE(SP++), JMP(readCode) + +preFailModExpLengthCTX0: + ; return preGAS + $ => A :MLOAD(preGAS) + 0 :MSTORE(preGAS) + A + GAS => GAS :JMP(handleGasFromError) diff --git a/main/precompiled/pre-modexp.zkasm b/main/precompiled/pre-modexp.zkasm index 4a924836..5d141590 100644 --- a/main/precompiled/pre-modexp.zkasm +++ b/main/precompiled/pre-modexp.zkasm @@ -8,7 +8,7 @@ * - stack input: [x1, y1, x2, y2] * - stack output: [x, y] * @note We work with unbounded and unsigned integers represented in (little-endian) chunks of 256 bits. - * @note After a few discussions, we decided to set the maximum input length of the base, modulus and exponent to 32. + * @note After a few discussions, we decided to set the maximum input length of the base, modulus and exponent to 32 chunks (8192 bits). * See [https://github.com/0xPolygonHermez/zkevm-rom-internal/issues/43] for more details. */ INCLUDE "../modexp/constants.zkasm" @@ -72,7 +72,8 @@ funcModexp: ; get exp offset = 96 bytes (Bsize | Esize | Msize) + Bsize $ => A :MLOAD(modexp_Bsize) 96 => B - $ => A :ADD + ; check carry ADD --> outOfGas + $ => A :ADD, JMPC(outOfGas) $ => B :MLOAD(txCalldataLen) ; expLenBits = bit length of first 32 bytes of exp 0 :MSTORE(expLenBits) @@ -95,8 +96,8 @@ setExpBitsContinue: E :MSTORE(readXFromCalldataOffset), CALL(readFromCalldataOffset); in: [readXFromCalldataOffset: offset value, readXFromCalldataLength: length value], out: [readXFromCalldataResult: result value] $ => A :MLOAD(readXFromCalldataResult) ; A = first 32 bytes of exp - 32 - C => D :CALL(SHRarith) - A => B :CALL(getLenBits); A bits length first 32 bytes + 32 - C => D :CALL(SHRarith) ; in: [A: value, D: #bytes to right shift (A >> D)] out: [A: shifted result] + A => B :CALL(getLenBits); in: [B: number] out: [A: bits length] ; A = bit length of first 32 bytes of exp A :JMPZ(setMaxLen) A - 1 :MSTORE(expLenBits) @@ -116,19 +117,19 @@ calculateGas: %MAX_CNT_STEPS - STEP - 120 :JMPN(outOfCountersStep) B :MSTORE(arithA) - 7 :MSTORE(arithB), CALL(addARITH) + 7 :MSTORE(arithB), CALL(addARITH) ; in: [arithA, arithB] out: [arithRes1: arithA + arithB, addArithOverflow] ; check arith overflow $ :MLOAD(addArithOverflow), JMPNZ(outOfGas) $ => B :MLOAD(arithRes1) B :MSTORE(arithA) - 8 :MSTORE(arithB), CALL(divARITH) + 8 :MSTORE(arithB), CALL(divARITH) ; in: [arithA, arithB] out: [arithRes1: arithA/arithB, arithRes2: arithA%arithB] ; B: words = (max_length + 7) / 8 $ => B :MLOAD(arithRes1) %MAX_GAS_WORD_MODEXP => A $ :LT, JMPC(outOfGas) ; A: multiplication_complexity = words**2 B :MSTORE(arithA) - B :MSTORE(arithB), CALL(mulARITH) + B :MSTORE(arithB), CALL(mulARITH) ; in: [arithA, arithB] out: [arithRes1: arithA*arithB, mulArithOverflowValue, mulArithOverflowFlag] $ => A :MLOAD(arithRes1) A :MSTORE(multiplication_complexity), JMPZ(dynamicGas) @@ -138,10 +139,10 @@ calculateGas: $ => B :LT, JMPC(modexp_expLT32) ;elif Esize > 32: iteration_count = (8 * (Esize - 32)) + ((exponent & (2**256 - 1)).bit_length() - 1) A :MSTORE(arithA) - 32 :MSTORE(arithB), CALL(subARITH) + 32 :MSTORE(arithB), CALL(subARITH) ; in: [arithA, arithB] out: [arithRes1: arithA - arithB] $ => A :MLOAD(arithRes1) A :MSTORE(arithA) - 8 :MSTORE(arithB), CALL(mulARITH) + 8 :MSTORE(arithB), CALL(mulARITH) ; in: [arithA, arithB] out: [arithRes1: arithA*arithB, mulArithOverflowValue, mulArithOverflowFlag] ; check arith overflow $ :MLOAD(mulArithOverflowFlag), JMPNZ(outOfGas) ; A = 8 * (Esize - 32) @@ -149,7 +150,7 @@ calculateGas: $ => B :MLOAD(expLenBits) ; iteration_count = (8 * (Esize - 32)) + ((exponent & (2**256 - 1)).bit_length() - 1) A :MSTORE(arithA) - B :MSTORE(arithB), CALL(addARITH) + B :MSTORE(arithB), CALL(addARITH) ; in: [arithA, arithB] out: [arithRes1: arithA + arithB, addArithOverflow] ; check arith overflow $ :MLOAD(addArithOverflow), JMPNZ(outOfGas) $ => E :MLOAD(arithRes1), JMP(finalGas) @@ -175,13 +176,13 @@ dynamicGas: ; E = calculate_iteration_count = max(iteration_count, 1) $ => A :MLOAD(multiplication_complexity) A :MSTORE(arithA) - E :MSTORE(arithB), CALL(mulARITH) + E :MSTORE(arithB), CALL(mulARITH) ; in: [arithA, arithB] out: [arithRes1: arithA*arithB, mulArithOverflowValue, mulArithOverflowFlag] ; check arith overflow $ :MLOAD(mulArithOverflowFlag), JMPNZ(outOfGas) ; A = multiplication_complexity * iteration_count $ => A :MLOAD(arithRes1) A :MSTORE(arithA) - 3 :MSTORE(arithB), CALL(divARITH) + 3 :MSTORE(arithB), CALL(divARITH) ; in: [arithA, arithB] out: [arithRes1: arithA/arithB, arithRes2: arithA%arithB] ; A = multiplication_complexity * iteration_count / 3 $ => A :MLOAD(arithRes1) %TX_GAS_LIMIT => B @@ -195,10 +196,12 @@ lastChecks: ; B = max(200, multiplication_complexity * iteration_count / 3) GAS - B => GAS :JMPN(outOfGas) ; check first modulo size and base size to match ethereum specification + ; https://github.com/0xPolygonHermez/ethereumjs-monorepo/blob/master/packages/evm/src/precompiles/05-modexp.ts#L142 0 => A $ => B :MLOAD(modexp_Msize) - $ :EQ, JMPC(save0outMod0) ; if Msize = 0 --> save0outMod0 + $ :EQ, JMPC(preEndMODEXP) ; if Msize = 0 --> preEndMODEXP ; Msize > 0 from here + ; https://github.com/0xPolygonHermez/ethereumjs-monorepo/blob/master/packages/evm/src/precompiles/05-modexp.ts#L135 $ => B :MLOAD(modexp_Bsize) $ :EQ, JMPC(save0out) ; if Bsize = 0 --> save0out ; Bsize > 0 from here @@ -215,13 +218,13 @@ lastChecks: ; get base value $ => E :MLOAD(modexp_offset) ; This is used in modexp_getBase, modexp_getExp and modexp_getMod $ => C :MLOAD(modexp_Bsize) - :CALL(modexp_getBase) + :CALL(modexp_getBase) ; in [E: offset, C: length (Bsize)] out: [modexp_Blen, modexp_B] ; get exp value $ => C :MLOAD(modexp_Esize) - :CALL(modexp_getExp) + :CALL(modexp_getExp) ; in [E: offset, C: length (Esize)] out: [modexp_Elen, modexp_E] ; get mod value $ => C :MLOAD(modexp_Msize) - :CALL(modexp_getMod) + :CALL(modexp_getMod) ; in [E: offset, C: length (Msize)] out: [modexp_Mlen, modexp_M] 1 => B ; if mod == 0 --> return 0 $ => A :MLOAD(modexp_Mlen), JMPZ(save0out) @@ -252,14 +255,12 @@ save1out: 1 :MSTORE(modexp_out), JMP(finalMODEXP) save0out: + ; return with Msize (check Msize < MAX_SIZE_MODEXP) $ => B :MLOAD(modexp_Msize) %MAX_SIZE_MODEXP => A $ :LT,JMPC(preFailModExpLength) 0 :MSTORE(modexp_out), JMP(finalMODEXP) -save0outMod0: - 0 :MSTORE(modexp_out), JMP(preEndMODEXP) - finalMODEXP: %MAX_CNT_STEPS - STEP - 100 :JMPN(outOfCountersStep) @@ -278,25 +279,26 @@ finalMODEXPreturn: ; memory length === Msize $ => C :MLOAD(modexp_Msize) C :MSTORE(arithA) - 32 :MSTORE(arithB), CALL(divARITH) + 32 :MSTORE(arithB), CALL(divARITH) ; in: [arithA, arithB] out: [arithRes1: arithA/arithB, arithRes2: arithA%arithB] ; 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 :JMPZ(memoryLoop) - + ; if Msize % 32 > 0, copy last bytes, else --> memoryLoop A => C ; A = 0x0000000000000000000000000000000000000000XXXXXXXXXXXXXXXXXXXXXXXX - ; C = lenght X's + ; C = length X's $ => A :MLOAD(modexp_out+E) - 32 - C => D :CALL(SHLarith) + 32 - C => D :CALL(SHLarith) ; in: [A: value, D: #bytes to left shift] out: [A: shifted result (A << D)] + ; A = 0xXXXXXXXXXXXXXXXXXXXXXXXX0000000000000000000000000000000000000000 A :MSTORE(bytesToStore) A :MSTORE(modexp_out+E) - B => E - ; MSTORE X with C = lenght X's + 0 => E + ; MSTORE X with C = length X's :CALL(MSTOREX) ; in: [bytesToStore, E: offset, C: length] out: [E: new offset] ; E == new offset (0 + length X's) E => B @@ -340,21 +342,21 @@ modexpReturn: ; copy retCopyLen from memory (currentCTX) to retCallOffset (originCTX) modexpReturnLoop: C - 32 :JMPN(modexpReturnFinal) - B => CTX :CALL(MLOAD32) + B => CTX :CALL(MLOAD32) ; in: [E: offset] out: [A: value, E: new offset] E => D $ => CTX :MLOAD(originCTX) A :MSTORE(bytesToStore) $ => E :MLOAD(offsetCopyReturn) - :CALL(MSTORE32) + :CALL(MSTORE32) ; in: [bytesToStore, E: offset] out: [E: new offset] E :MSTORE(offsetCopyReturn) D => E C - 32 => C :JMPZ(endMODEXP, modexpReturnLoop) modexpReturnFinal: - B => CTX :CALL(MLOADX) + B => CTX :CALL(MLOADX) ; in: [E: offset, C: length] out: [A: value, E: new offset] $ => CTX :MLOAD(originCTX) A :MSTORE(bytesToStore) - $ => E :MLOAD(offsetCopyReturn),CALL(MSTOREX) + $ => E :MLOAD(offsetCopyReturn),CALL(MSTOREX) ; in: [bytesToStore, E: offset, C: length] out: [E: new offset] :JMP(endMODEXP) preEndMODEXP: diff --git a/main/precompiled/pre-p256verify.zkasm b/main/precompiled/pre-p256verify.zkasm index 92948dbf..ef50c428 100644 --- a/main/precompiled/pre-p256verify.zkasm +++ b/main/precompiled/pre-p256verify.zkasm @@ -36,13 +36,15 @@ funcP256VERIFY: $ => D :MLOAD(readXFromCalldataResult) ; read y [32 bytes] E + 32 => E :MSTORE(readXFromCalldataOffset), CALL(readFromCalldataOffset); in: [readXFromCalldataOffset: offset value, readXFromCalldataLength: length value], out: [readXFromCalldataResult: result value] - $ => E :MLOAD(readXFromCalldataResult), CALL(p256verify) ;in: [A: hash, B: r, C: s, D: x, E: y], out: [A: result, B: result_code] + $ => E :MLOAD(readXFromCalldataResult) + + ; call p256verify + :CALL(p256verify) ;in: [A: hash, B: r, C: s, D: x, E: y], out: [A: result, B: result_code] B :JMPNZ(endP256VERIFYFail) - A :JMPZ(preEndP256VERIFY) ; write result p256verify into memory 0 => E - A :MSTORE(bytesToStore), CALL(MSTORE32); in: [bytesToStore, E: offset] out: [E: new offset] + 1 :MSTORE(bytesToStore), CALL(MSTORE32); in: [bytesToStore, E: offset] out: [E: new offset] ; prepare return data 0 :MSTORE(retDataOffset) diff --git a/main/precompiled/selector.zkasm b/main/precompiled/selector.zkasm index 9f36292b..0365a0e6 100644 --- a/main/precompiled/selector.zkasm +++ b/main/precompiled/selector.zkasm @@ -77,6 +77,5 @@ selectorPrecompiled: A - 8 :JMPN(funcEcMul) A - 9 :JMPN(funcEcPairing) A - 10 :JMPN(revertPrecompiled) ;:JMPN(BLAKE2F) - -selectorPrecompiledP256Verify: - :JMP(funcP256VERIFY) \ No newline at end of file + A - 256 :JMPZ(funcP256VERIFY) + :JMP(callContract) \ No newline at end of file diff --git a/main/process-tx.zkasm b/main/process-tx.zkasm index 761a7292..08c35fac 100644 --- a/main/process-tx.zkasm +++ b/main/process-tx.zkasm @@ -209,9 +209,7 @@ txType: ; Check zero address since zero address is not a precompiled contract 0 => B $ :EQ, JMPC(callContract) - 0x100 => B - $ :EQ, JMPC(selectorPrecompiledP256Verify) - 10 => B + 0x101 => B $ :LT, JMPC(selectorPrecompiled, callContract) ;;;;;;;;;;;;;;;;;; diff --git a/main/touched.zkasm b/main/touched.zkasm index 14bcbfae..14ad2d0e 100644 --- a/main/touched.zkasm +++ b/main/touched.zkasm @@ -23,21 +23,20 @@ revertTouched: isColdAddress: ; checks zk-counters %MAX_CNT_STEPS - STEP - 100 :JMPN(outOfCountersStep) - %MAX_CNT_BINARY - CNT_BINARY - 4 :JMPN(outOfCountersBinary) + %MAX_CNT_BINARY - CNT_BINARY - 2 :JMPN(outOfCountersBinary) %MAX_CNT_POSEIDON_G - CNT_POSEIDON_G - %MAX_CNT_POSEIDON_SLOAD_SSTORE*2 :JMPN(outOfCountersPoseidon) ; store previous registers values temporary B :MSTORE(tmpB) C :MSTORE(tmpC) E :MSTORE(tmpE) - ; if address is a zero address check if it is warm - 0 => B - $ :EQ, JMPC(checkWarmed) ; if address is a precompiled considered as warm address - 10 => B - $ :LT, JMPC(finishColdPrecompiled) - 0x100 => B - $ :EQ, JMPC(finishColdPrecompiled) + 0x101 => B + $ :LT, JMPNC(checkWarmed) + ; if address is a zero address check if it is warm (A <= 256) + A :JMPZ(checkWarmed) + A - 0x100 :JMPZ(finishColdPrecompiled) + A - 10 :JMPN(finishColdPrecompiled) checkWarmed: ; save current state root & load touched root diff --git a/package.json b/package.json index d5481544..f0a1617a 100644 --- a/package.json +++ b/package.json @@ -43,9 +43,9 @@ "yargs": "^17.5.1" }, "devDependencies": { - "@0xpolygonhermez/zkevm-commonjs": "github:0xPolygonHermez/zkevm-commonjs#v9.0.0-rc.2-fork.13", + "@0xpolygonhermez/zkevm-commonjs": "github:0xPolygonHermez/zkevm-commonjs#fix/internal-audit-durian", "@0xpolygonhermez/zkevm-proverjs": "github:0xPolygonHermez/zkevm-proverjs#develop-durian", - "@0xpolygonhermez/zkevm-testvectors": "github:0xPolygonHermez/zkevm-testvectors#v9.0.0-rc.2-fork.13", + "@0xpolygonhermez/zkevm-testvectors": "github:0xPolygonHermez/zkevm-testvectors#fix/internal-audit-durian", "chai": "^4.3.6", "chalk": "^3.0.0", "eslint": "^8.25.0", diff --git a/test/testp256verify.zkasm b/test/testp256verify.zkasm index 2902e285..b6717b3a 100644 --- a/test/testp256verify.zkasm +++ b/test/testp256verify.zkasm @@ -148,6 +148,27 @@ test_p256verify: ; Inputs: A = hash, B = r, C = s, D = x, E = y ; Outputs: A = result, B = result_code + ; zero hash tests: take any public key (x,y) and set the signature (r,y) = (x,x) + 0x0 => A ; hash + %SECP256R1_G_X => B ; r + %SECP256R1_G_X => C ; s + %SECP256R1_G_X => D ; x + %SECP256R1_G_Y => E ; y + :CALL(p256verify) + 1 :ASSERT + B => A + 0 :ASSERT + + 0x0 => A ; hash + 0x2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838n => B ; r + 0x2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838n => C ; s + 0x2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838n => D ; x + 0xc7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513en => E ; y + :CALL(p256verify) + 1 :ASSERT + B => A + 0 :ASSERT + ; Tests from https://github.com/ulerdogan/go-ethereum/blob/ulerdogan-secp256r1/core/vm/testdata/precompiles/p256Verify.json ; 1] wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #1: signature malleability @@ -161,6 +182,17 @@ test_p256verify: B => A 0 :ASSERT + ; same test but with the s = n - s + 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash + 0x2ba3a8be6b94d5ec80a6d9d1190a436effe50d85a1eee859b8cc6af9bd5c2e18n => B ; r + 0xb329f479a2bbd0a5c384ee1493b1f5186a87139cac5df4087c134b49156847dbn => C ; s + 0x2927b10512bae3eddcfe467828128bad2903269919f7086069c8c4df6c732838n => D ; x + 0xc7787964eaac00e5921fb1498a60f4606766b3d9685001558d1a974e7341513en => E ; y + :CALL(p256verify) + 1 :ASSERT + B => A + 0 :ASSERT + ; 2] wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #3: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash 0xd45c5740946b2a147f59262ee6f5bc90bd01ed280528b62b3aed5fc93f06f739n => B ; r @@ -170,7 +202,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 3] wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #5: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -181,7 +213,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 4] wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #8: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -192,7 +224,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 5] wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #9: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -291,7 +323,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 14] wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #18: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -313,7 +345,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 16] wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #20: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -445,7 +477,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 28] wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #32: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -467,7 +499,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 30] wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #34: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -1963,7 +1995,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 166] wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #175: comparison with point at infinity 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -2117,7 +2149,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 180] wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #189: testing point duplication 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -2150,7 +2182,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 183] wycheproof/ecdsa_secp256r1_sha256_p1363_test.json EcdsaP1363Verify SHA-256 #192: pseudorandom signature 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855n => A ; hash @@ -2502,7 +2534,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 215] wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #120: modify last byte of integer 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -2513,7 +2545,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 216] wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #121: modify last byte of integer 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -2524,7 +2556,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 217] wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #124: truncated integer 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -2535,7 +2567,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 218] wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #133: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -2546,7 +2578,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 219] wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #134: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -2557,7 +2589,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 220] wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #137: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -2568,7 +2600,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 221] wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #139: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -2579,7 +2611,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 222] wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #143: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -2590,7 +2622,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 223] wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #177: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -2667,7 +2699,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 230] wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #189: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -4086,7 +4118,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 359] wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #357: testing point duplication 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -4119,7 +4151,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 362] wycheproof/ecdsa_secp256r1_sha256_test.json EcdsaVerify SHA-256 #360: pseudorandom signature 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855n => A ; hash @@ -4471,7 +4503,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 394] wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #120: modify last byte of integer 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -4482,7 +4514,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 395] wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #121: modify last byte of integer 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -4493,7 +4525,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 396] wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #124: truncated integer 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -4504,7 +4536,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 397] wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #133: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -4515,7 +4547,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 398] wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #134: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -4526,7 +4558,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 399] wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #137: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -4537,7 +4569,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 400] wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #139: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -4548,7 +4580,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 401] wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #143: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -4559,7 +4591,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 402] wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #177: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -4636,7 +4668,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 409] wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #189: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -6055,7 +6087,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 538] wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #707: testing point duplication 0x532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25n => A ; hash @@ -6088,7 +6120,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 541] wycheproof/ecdsa_test.json EcdsaVerify SHA-256 #1210: pseudorandom signature 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -6418,7 +6450,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 571] wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #5: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -6429,7 +6461,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 572] wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #8: Modified r or s, e.g. by adding or subtracting the order of the group 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -6440,7 +6472,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 573] wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #9: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -6539,7 +6571,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 582] wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #18: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -6561,7 +6593,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 584] wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #20: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -6693,7 +6725,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 596] wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #32: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -6715,7 +6747,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 598] wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #34: Signature with special case values for r and s 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash @@ -8211,7 +8243,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 734] wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #175: comparison with point at infinity 0x532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25n => A ; hash @@ -8365,7 +8397,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 748] wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #189: testing point duplication 0x532eaabd9574880dbf76b9b8cc00832c20a6ec113d682299550d7a6e0f345e25n => A ; hash @@ -8398,7 +8430,7 @@ test_p256verify: :CALL(p256verify) 0 :ASSERT B => A - 0 :ASSERT + 10 :ASSERT ; 751] wycheproof/ecdsa_webcrypto_test.json EcdsaP1363Verify SHA-256 #269: pseudorandom signature 0xbb5a52f42f9c9261ed4361f59422a1e30036e7c32b270c8807a419feca605023n => A ; hash