diff --git a/constantine/math/elliptic/ec_scalar_mul_vartime.nim b/constantine/math/elliptic/ec_scalar_mul_vartime.nim index fcc44b4..40fc96f 100644 --- a/constantine/math/elliptic/ec_scalar_mul_vartime.nim +++ b/constantine/math/elliptic/ec_scalar_mul_vartime.nim @@ -361,7 +361,7 @@ func scalarMul_vartime*[scalBits; EC]( const L = scalBits.ceilDiv_vartime(M) + 1 - let usedBits = scalar.limbs.getBits_vartime() + let usedBits = scalar.limbs.getBits_LE_vartime() when scalBits == EC.F.C.getCurveOrderBitwidth() and EC.F.C.hasEndomorphismAcceleration(): diff --git a/constantine/math_arbitrary_precision/arithmetic/bigints_views.nim b/constantine/math_arbitrary_precision/arithmetic/bigints_views.nim index 26ad7c9..9569b3c 100644 --- a/constantine/math_arbitrary_precision/arithmetic/bigints_views.nim +++ b/constantine/math_arbitrary_precision/arithmetic/bigints_views.nim @@ -55,8 +55,8 @@ func powOddMod_vartime*( debug: doAssert bool(M.isOdd()) - let aBits = a.getBits_vartime() - let mBits = M.getBits_vartime() + let aBits = a.getBits_LE_vartime() + let mBits = M.getBits_LE_vartime() let L = wordsRequired(mBits) let m0ninv = M[0].negInvModWord() var rMont = allocStackArray(SecretWord, L) @@ -105,17 +105,17 @@ func powMod_vartime*( # Special cases: early returns # ------------------------------------------------------------------- - let mBits = M.getBits_vartime() + let mBits = M.getBits_LE_vartime() if mBits < 2: # Check if modulus = 0 or 1 r.setZero() return - let eBits = exponent.getBits_vartime() + let eBits = exponent.getBits_BE_vartime() if eBits == 0: # Check if exponent == 0 r.setOne() # a⁰ = 1 and 0⁰ = 1 return - let aBits = a.getBits_vartime() + let aBits = a.getBits_LE_vartime() if aBits < 2: # Check if a == 0 or a == 1 r[0] = a[0] for i in 1 ..< r.len: diff --git a/constantine/math_arbitrary_precision/arithmetic/limbs_mod2k.nim b/constantine/math_arbitrary_precision/arithmetic/limbs_mod2k.nim index 59df47a..76c49b8 100644 --- a/constantine/math_arbitrary_precision/arithmetic/limbs_mod2k.nim +++ b/constantine/math_arbitrary_precision/arithmetic/limbs_mod2k.nim @@ -109,7 +109,7 @@ func powMod2k_vartime*( for i in 0 ..< r.len: r[i] = Zero - let msb = getMSB_vartime(exponent) + let msb = getMSB_BE_vartime(exponent) if msb == -1: # exponent is 0 r[0] = One # x⁰ = 1, even for 0⁰ diff --git a/constantine/math_arbitrary_precision/arithmetic/limbs_views.nim b/constantine/math_arbitrary_precision/arithmetic/limbs_views.nim index f8c8f3a..3442258 100644 --- a/constantine/math_arbitrary_precision/arithmetic/limbs_views.nim +++ b/constantine/math_arbitrary_precision/arithmetic/limbs_views.nim @@ -105,18 +105,40 @@ func ccopyWords*( # Bit operations # ------------------------------------------------------------ -func getMSB_vartime*[T](a: openArray[T]): int = +func getMSB_BE_vartime*(a: openArray[byte]): int = ## Returns the position of the most significant bit ## of `a`. ## Returns -1 if a == 0 + ## + ## Input MUST be ordered from most to least significant byte result = -1 - for i in countdown(a.len-1, 0): - if bool(a[i] != T(0)): - return int(log2_vartime(uint64 a[i])) + 8*sizeof(T)*i + for i in 0 ..< a.len: + if bool a[i] != 0: + return int(log2_vartime(uint32 a[i])) + 8*sizeof(byte)*(a.len-1-i) -func getBits_vartime*[T](a: openArray[T]): int {.inline.} = +func getBits_BE_vartime*(a: openArray[byte]): int {.inline.} = ## Returns the number of bits used by `a` ## Returns 0 for 0 - 1 + getMSB_vartime(a) + ## + ## Input MUST be ordered from least to most significant byte + 1 + getMSB_BE_vartime(a) + +func getMSB_LE_vartime(a: openArray[SecretWord]): int = + ## Returns the position of the most significant bit + ## of `a`. + ## Returns -1 if a == 0 + ## + ## Input MUST be ordered from least to most significant word + result = -1 + for i in countdown(a.len-1, 0): + if bool a[i] != Zero: + return int(log2_vartime(uint64 a[i])) + 8*sizeof(SecretWord)*i + +func getBits_LE_vartime*(a: openArray[SecretWord]): int {.inline.} = + ## Returns the number of bits used by `a` + ## Returns 0 for 0 + ## + ## Input MUST be ordered from least to most significant word + 1 + getMSB_LE_vartime(a) {.pop.} # raises no exceptions diff --git a/tests/math_arbitrary_precision/t_bigints_powmod_vs_gmp.nim b/tests/math_arbitrary_precision/t_bigints_powmod_vs_gmp.nim index feefa64..d0465bc 100644 --- a/tests/math_arbitrary_precision/t_bigints_powmod_vs_gmp.nim +++ b/tests/math_arbitrary_precision/t_bigints_powmod_vs_gmp.nim @@ -97,9 +97,9 @@ proc test(rng: var RngState) = mpz_clear(rr) let - aBits = a.getBits_vartime() - eBits = e.getBits_vartime() - mBits = M.getBits_vartime() + aBits = a.getBits_LE_vartime() + eBits = e.getBits_BE_vartime() + mBits = M.getBits_LE_vartime() rCtt.powMod_vartime(a, e, M, window = 4) diff --git a/tests/t_ethereum_evm_modexp.nim b/tests/t_ethereum_evm_modexp.nim index 0de31ed..4f13481 100644 --- a/tests/t_ethereum_evm_modexp.nim +++ b/tests/t_ethereum_evm_modexp.nim @@ -42,6 +42,37 @@ suite "EVM ModExp precompile (EIP-198)": doAssert status == cttEVM_Success doAssert r[0] == 0, ". Result was " & $r[0] + test "Audit #5-2 - Fuzz failure with even modulus strikes back": + let input = [ + + # Length of base (1) + uint8 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + # Length of exponent (5) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, + + # Length of modulus (1) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + + # Base + 0x3a, + + # Exponent + 0x01, 0x00, 0x00, 0x00, 0x00, + + # Modulus + 0x08 + ] + + var r = newSeq[byte](1) + let status = r.eth_evm_modexp(input) + doAssert status == cttEVM_Success + doAssert r[0] == 0, ". Result was " & $r[0] + test "Audit #8 - off-by-1 buffer overflow - ptr + length exclusive vs openArray(lo, hi) inclusive": let input = [ # Length of base (24)