Skip to content

Commit

Permalink
fix fuzz 5 reloaded: modexp - endianness issue for exponent MSB (#266)
Browse files Browse the repository at this point in the history
* fix fuzz 5 reloaded: endianness issue for exponent MSB

* refactoring typo in test vs gmp
  • Loading branch information
mratsim authored Sep 6, 2023
1 parent b645d68 commit 1ad8499
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 15 deletions.
2 changes: 1 addition & 1 deletion constantine/math/elliptic/ec_scalar_mul_vartime.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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⁰
Expand Down
32 changes: 27 additions & 5 deletions constantine/math_arbitrary_precision/arithmetic/limbs_views.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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 0 ..< a.len:
if bool a[i] != 0:
return int(log2_vartime(uint32 a[i])) + 8*sizeof(byte)*(a.len-1-i)

func getBits_BE_vartime*(a: openArray[byte]): int {.inline.} =
## Returns the number of bits used by `a`
## Returns 0 for 0
##
## 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] != T(0)):
return int(log2_vartime(uint64 a[i])) + 8*sizeof(T)*i
if bool a[i] != Zero:
return int(log2_vartime(uint64 a[i])) + 8*sizeof(SecretWord)*i

func getBits_vartime*[T](a: openArray[T]): int {.inline.} =
func getBits_LE_vartime*(a: openArray[SecretWord]): 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 word
1 + getMSB_LE_vartime(a)

{.pop.} # raises no exceptions
6 changes: 3 additions & 3 deletions tests/math_arbitrary_precision/t_bigints_powmod_vs_gmp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
31 changes: 31 additions & 0 deletions tests/t_ethereum_evm_modexp.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 1ad8499

Please sign in to comment.