mirror of
https://github.com/logos-storage/constantine.git
synced 2026-01-02 13:13:07 +00:00
EVM modexp: solve DOS vectors (#286)
* stash prep for Barret Reduction * benches lost in rebase * fix vartime reduction * some improvement and fixes on reduce_vartime * Fuse reductions when converting to Montgomery + use window=1 in powMont for small exponents. ~2.7x to 3.3x accel * modexp: Introduce a no-reduction path for small base+exponent compared to modulus. Fix DOS * optim for padded exponents * remove commented out code [skip ci] * Missing noInline for allocStackArray
This commit is contained in:
parent
34baa74bc0
commit
4ccd8aaab8
@ -14,6 +14,7 @@ import
|
||||
# Internal
|
||||
../constantine/math/io/io_bigints,
|
||||
../constantine/math/arithmetic,
|
||||
../constantine/math_arbitrary_precision/arithmetic/limbs_divmod_vartime,
|
||||
../constantine/platforms/abstractions,
|
||||
../constantine/serialization/codecs,
|
||||
# Test utilities
|
||||
@ -124,6 +125,13 @@ proc main() =
|
||||
let stopCTTMod = getMonoTime()
|
||||
echo "Constantine - ", aBits, " mod ", bBits, " -> ", bBits, " mod: ", float(inNanoseconds((stopCTTmod-startCTTmod)))/float(NumIters), " ns"
|
||||
|
||||
let startCTTvartimeMod = getMonoTime()
|
||||
var q {.noInit.}: BigInt[bBits]
|
||||
for _ in 0 ..< NumIters:
|
||||
discard divRem_vartime(q.limbs, rTestMod.limbs, aTest.limbs, bTest.limbs)
|
||||
let stopCTTvartimeMod = getMonoTime()
|
||||
echo "Constantine - ", aBits, " mod ", bBits, " (vartime) -> ", bBits, " mod: ", float(inNanoseconds((stopCTTvartimeMod-startCTTvartimeMod)))/float(NumIters), " ns"
|
||||
|
||||
echo "----"
|
||||
# Modular reduction - double-size
|
||||
|
||||
@ -139,7 +147,12 @@ proc main() =
|
||||
let stopCTTMod2 = getMonoTime()
|
||||
echo "Constantine - ", rBits, " mod ", bBits, " -> ", bBits, " mod: ", float(inNanoseconds((stopCTTmod2-startCTTmod2)))/float(NumIters), " ns"
|
||||
|
||||
# Constantine
|
||||
let startCTTvartimeMod2 = getMonoTime()
|
||||
var q2 {.noInit.}: BigInt[bBits]
|
||||
for _ in 0 ..< NumIters:
|
||||
discard divRem_vartime(q2.limbs, rTestMod.limbs, rTest.limbs, bTest.limbs)
|
||||
let stopCTTvartimeMod2 = getMonoTime()
|
||||
echo "Constantine - ", rBits, " mod ", bBits, " (vartime) -> ", bBits, " mod: ", float(inNanoseconds((stopCTTvartimeMod2-startCTTvartimeMod2)))/float(NumIters), " ns"
|
||||
|
||||
echo ""
|
||||
|
||||
|
||||
@ -56,9 +56,8 @@ func prod_comba[rLen, aLen, bLen: static int](r: var Limbs[rLen], a: Limbs[aLen]
|
||||
u = t
|
||||
t = Zero
|
||||
|
||||
if aLen+bLen < rLen:
|
||||
for i in aLen+bLen ..< rLen:
|
||||
r[i] = Zero
|
||||
for i in aLen+bLen ..< rLen:
|
||||
r[i] = Zero
|
||||
|
||||
func prod*[rLen, aLen, bLen: static int](r{.noalias.}: var Limbs[rLen], a: Limbs[aLen], b: Limbs[bLen]) {.inline.} =
|
||||
## Multi-precision multiplication
|
||||
@ -156,9 +155,8 @@ func square_Comba[rLen, aLen](
|
||||
u = t
|
||||
t = Zero
|
||||
|
||||
if aLen*2 < rLen:
|
||||
for i in aLen*2 ..< rLen:
|
||||
r[i] = Zero
|
||||
for i in aLen*2 ..< rLen:
|
||||
r[i] = Zero
|
||||
|
||||
func square_operandScan[rLen, aLen](
|
||||
r: var Limbs[rLen],
|
||||
|
||||
@ -15,7 +15,7 @@ import
|
||||
./limbs_mod2k,
|
||||
./limbs_multiprec,
|
||||
./limbs_extmul,
|
||||
./limbs_divmod
|
||||
./limbs_divmod_vartime
|
||||
|
||||
# No exceptions allowed
|
||||
{.push raises: [], checks: off.}
|
||||
@ -41,7 +41,34 @@ import
|
||||
# Also need to take into account constant-time for RSA
|
||||
# i.e. countLeadingZeros can only be done on public moduli.
|
||||
|
||||
func powOddMod_vartime*(
|
||||
iterator unpackBE(scalarByte: byte): bool =
|
||||
for i in countdown(7, 0):
|
||||
yield bool((scalarByte shr i) and 1)
|
||||
|
||||
func pow_vartime(
|
||||
r: var openArray[SecretWord],
|
||||
a: openArray[SecretWord],
|
||||
exponent: openArray[byte]) {.tags:[VarTime, Alloca], meter.} =
|
||||
## r <- a^exponent
|
||||
|
||||
r.setOne()
|
||||
var isOne = true
|
||||
|
||||
for e in exponent:
|
||||
for bit in unpackBE(e):
|
||||
if not isOne:
|
||||
r.square_vartime(r)
|
||||
if bit:
|
||||
if isOne:
|
||||
for i in 0 ..< a.len:
|
||||
r[i] = a[i]
|
||||
for i in a.len ..< r.len:
|
||||
r[i] = Zero
|
||||
isOne = false
|
||||
else:
|
||||
r.prod_vartime(r, a)
|
||||
|
||||
func powOddMod_vartime(
|
||||
r: var openArray[SecretWord],
|
||||
a: openArray[SecretWord],
|
||||
exponent: openArray[byte],
|
||||
@ -55,33 +82,20 @@ func powOddMod_vartime*(
|
||||
debug:
|
||||
doAssert bool(M.isOdd())
|
||||
|
||||
let aBits = a.getBits_LE_vartime()
|
||||
let mBits = M.getBits_LE_vartime()
|
||||
let eBits = exponent.getBits_BE_vartime()
|
||||
|
||||
if eBits == 1:
|
||||
r.view().reduce(a.view(), aBits, M.view(), mBits)
|
||||
discard r.reduce_vartime(a, M)
|
||||
return
|
||||
|
||||
let L = wordsRequired(mBits)
|
||||
let m0ninv = M[0].negInvModWord()
|
||||
var rMont = allocStackArray(SecretWord, L)
|
||||
|
||||
block:
|
||||
var r2Buf = allocStackArray(SecretWord, L)
|
||||
template r2: untyped = r2Buf.toOpenArray(0, L-1)
|
||||
r2.r2_vartime(M.toOpenArray(0, L-1))
|
||||
var aMont_buf = allocStackArray(SecretWord, L)
|
||||
template aMont: untyped = aMont_buf.toOpenArray(0, L-1)
|
||||
|
||||
# Conversion to Montgomery can auto-reduced by up to M*R
|
||||
# if we use redc2xMont (a/R) and montgomery multiplication by R³
|
||||
# For now, we call explicit reduction as it can handle all sizes.
|
||||
# TODO: explicit reduction uses constant-time division which is **very** expensive
|
||||
if a.len != M.len:
|
||||
let t = allocStackArray(SecretWord, L)
|
||||
t.LimbsViewMut.reduce(a.view(), aBits, M.view(), mBits)
|
||||
rMont.LimbsViewMut.getMont(LimbsViewConst t, M.view(), LimbsViewConst r2.view(), m0ninv, mBits)
|
||||
else:
|
||||
rMont.LimbsViewMut.getMont(a.view(), M.view(), LimbsViewConst r2.view(), m0ninv, mBits)
|
||||
aMont.getMont_vartime(a, M)
|
||||
|
||||
block:
|
||||
var oneMontBuf = allocStackArray(SecretWord, L)
|
||||
@ -91,12 +105,11 @@ func powOddMod_vartime*(
|
||||
let scratchLen = L * ((1 shl window) + 1)
|
||||
var scratchSpace = allocStackArray(SecretWord, scratchLen)
|
||||
|
||||
rMont.LimbsViewMut.powMont_vartime(
|
||||
aMont_buf.LimbsViewMut.powMont_vartime(
|
||||
exponent, M.view(), LimbsViewConst oneMontBuf,
|
||||
m0ninv, LimbsViewMut scratchSpace, scratchLen, mBits)
|
||||
|
||||
r.view().fromMont(LimbsViewConst rMont, M.view(), m0ninv, mBits)
|
||||
|
||||
r.view().fromMont(LimbsViewConst aMont_buf, M.view(), m0ninv, mBits)
|
||||
|
||||
func powMod_vartime*(
|
||||
r: var openArray[SecretWord],
|
||||
@ -128,6 +141,14 @@ func powMod_vartime*(
|
||||
r[i] = Zero
|
||||
return
|
||||
|
||||
# No modular reduction needed
|
||||
# -------------------------------------------------------------------
|
||||
if eBits < WordBitWidth and
|
||||
aBits.uint shr (WordBitWidth - eBits) == 0 and # handle overflow of uint128 [0, aBits] << eBits
|
||||
aBits.uint shl eBits < mBits.uint:
|
||||
r.pow_vartime(a, exponent)
|
||||
return
|
||||
|
||||
# Odd modulus
|
||||
# -------------------------------------------------------------------
|
||||
if M.isOdd().bool:
|
||||
@ -197,5 +218,5 @@ func powMod_vartime*(
|
||||
|
||||
var qyBuf = allocStackArray(SecretWord, M.len)
|
||||
template qy: untyped = qyBuf.toOpenArray(0, M.len-1)
|
||||
qy.prod(q, y)
|
||||
qy.prod_vartime(q, y)
|
||||
discard r.addMP(qy, a1)
|
||||
|
||||
@ -12,7 +12,7 @@ import
|
||||
./limbs_fixedprec
|
||||
|
||||
# No exceptions allowed
|
||||
{.push raises: [].}
|
||||
{.push raises: [], checks: off.}
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
@ -63,7 +63,7 @@ func shlAddMod_estimate(a: LimbsViewMut, aLen: int,
|
||||
a1 = (a[^1] shl (WordBitWidth-R)) or (a[^2] shr R)
|
||||
m0 = (M[^1] shl (WordBitWidth-R)) or (M[^2] shr R)
|
||||
|
||||
# m0 has its high bit set. (a0, a1)/p0 fits in a limb.
|
||||
# m0 has its high bit set. (a0, a1)/m0 fits in a limb.
|
||||
# Get a quotient q, at most we will be 2 iterations off
|
||||
# from the true quotient
|
||||
var q, r: SecretWord
|
||||
@ -78,29 +78,29 @@ func shlAddMod_estimate(a: LimbsViewMut, aLen: int,
|
||||
|
||||
# Now substract a*2^64 - q*p
|
||||
var carry = Zero
|
||||
var over_p = CtTrue # Track if quotient greater than the modulus
|
||||
var overM = CtTrue # Track if quotient greater than the modulus
|
||||
|
||||
for i in 0 ..< MLen:
|
||||
var qp_lo: SecretWord
|
||||
var qm_lo: SecretWord
|
||||
|
||||
block: # q*p
|
||||
# q * p + carry (doubleword) carry from previous limb
|
||||
muladd1(carry, qp_lo, q, M[i], carry)
|
||||
block: # q*m
|
||||
# q * m + carry (doubleword) carry from previous limb
|
||||
muladd1(carry, qm_lo, q, M[i], carry)
|
||||
|
||||
block: # a*2^64 - q*p
|
||||
var borrow: Borrow
|
||||
subB(borrow, a[i], a[i], qp_lo, Borrow(0))
|
||||
subB(borrow, a[i], a[i], qm_lo, Borrow(0))
|
||||
carry += SecretWord(borrow) # Adjust if borrow
|
||||
|
||||
over_p = mux(a[i] == M[i], over_p, a[i] > M[i])
|
||||
overM = mux(a[i] == M[i], overM, a[i] > M[i])
|
||||
|
||||
# Fix quotient, the true quotient is either q-1, q or q+1
|
||||
#
|
||||
# if carry < q or carry == q and over_p we must do "a -= p"
|
||||
# if carry > hi (negative result) we must do "a += p"
|
||||
# if carry < q or carry == q and over_p we must do "a -= m"
|
||||
# if carry > hi (negative result) we must do "a += m"
|
||||
|
||||
result.neg = carry > hi
|
||||
result.tooBig = not(result.neg) and (over_p or (carry < hi))
|
||||
result.tooBig = not(result.neg) and (overM or (carry < hi))
|
||||
|
||||
func shlAddMod(a: LimbsViewMut, aLen: int,
|
||||
c: SecretWord, M: LimbsViewConst, mBits: int) =
|
||||
|
||||
@ -0,0 +1,228 @@
|
||||
# Constantine
|
||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
||||
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../../platforms/abstractions,
|
||||
../../platforms/intrinsics/extended_precision_vartime,
|
||||
./limbs_views
|
||||
|
||||
# No exceptions allowed
|
||||
{.push raises: [], checks: off.}
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Division and Modular Reduction
|
||||
# (variable-time)
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
func shlAddMod_multiprec_vartime(
|
||||
a: var openArray[SecretWord], c: SecretWord,
|
||||
M: openArray[SecretWord], mBits: int): SecretWord {.meter.} =
|
||||
## Fused modular left-shift + add
|
||||
## Computes: a <- a shl 2ʷ + c (mod M)
|
||||
## Returns: (a shl 2ʷ + c) / M
|
||||
##
|
||||
## with w the base word width, usually 32 on 32-bit platforms and 64 on 64-bit platforms
|
||||
##
|
||||
## The modulus `M` most-significant bit at `mBits` MUST be set.
|
||||
##
|
||||
## Specialized for M being a multi-precision integer.
|
||||
# Assuming 64-bit words
|
||||
let hi = a[^1] # Save the high word to detect carries
|
||||
let R = mBits and (WordBitWidth - 1) # R = mBits mod 64
|
||||
|
||||
var a0, a1, m0: SecretWord
|
||||
if R == 0: # If the number of mBits is a multiple of 64
|
||||
a0 = a[^1] #
|
||||
copyWords(a.view(), 1, # we can just shift words
|
||||
a.view(), 0, a.len-1) #
|
||||
a[0] = c # and replace the first one by c
|
||||
a1 = a[^1]
|
||||
m0 = M[^1]
|
||||
else: # Else: need to deal with partial word shifts at the edge.
|
||||
let clz = WordBitWidth-R
|
||||
a0 = (a[^1] shl clz) or (a[^2] shr R)
|
||||
copyWords(a.view(), 1,
|
||||
a.view(), 0, a.len-1)
|
||||
a[0] = c
|
||||
a1 = (a[^1] shl clz) or (a[^2] shr R)
|
||||
m0 = (M[^1] shl clz) or (M[^2] shr R)
|
||||
|
||||
# m0 has its high bit set. (a0, a1)/m0 fits in a limb.
|
||||
# Get a quotient q, at most we will be 2 iterations off
|
||||
# from the true quotient
|
||||
var q: SecretWord # Estimate quotient
|
||||
if bool(a0 == m0): # if a_hi == divisor
|
||||
q = MaxWord # quotient = MaxWord (0b1111...1111)
|
||||
elif bool(a0.isZero()) and
|
||||
bool(a1 < m0): # elif q == 0, true quotient = 0
|
||||
q = Zero
|
||||
return q
|
||||
else:
|
||||
var r: SecretWord
|
||||
div2n1n_vartime(q, r, a0, a1, m0) # else instead of being of by 0, 1 or 2
|
||||
q -= One # we return q-1 to be off by -1, 0 or 1
|
||||
|
||||
# Now substract a*2^64 - q*m
|
||||
var carry = Zero
|
||||
var overM = true # Track if quotient greater than the modulus
|
||||
|
||||
for i in 0 ..< M.len:
|
||||
var qm_lo: SecretWord
|
||||
block: # q*m
|
||||
# q * m + carry (doubleword) carry from previous limb
|
||||
muladd1(carry, qm_lo, q, M[i], carry)
|
||||
|
||||
block: # a*2^64 - q*m
|
||||
var borrow: Borrow
|
||||
subB(borrow, a[i], a[i], qm_lo, Borrow(0))
|
||||
carry += SecretWord(borrow) # Adjust if borrow
|
||||
|
||||
if bool(a[i] != M[i]):
|
||||
overM = bool(a[i] > M[i])
|
||||
|
||||
# Fix quotient, the true quotient is either q-1, q or q+1
|
||||
#
|
||||
# if carry < q or carry == q and overM we must do "a -= M"
|
||||
# if carry > hi (negative result) we must do "a += M"
|
||||
if bool(carry > hi):
|
||||
var c = Carry(0)
|
||||
for i in 0 ..< a.len:
|
||||
addC(c, a[i], a[i], M[i], c)
|
||||
q -= One
|
||||
elif overM or bool(carry < hi):
|
||||
var b = Borrow(0)
|
||||
for i in 0 ..< a.len:
|
||||
subB(b, a[i], a[i], M[i], b)
|
||||
q += One
|
||||
|
||||
return q
|
||||
|
||||
func shortDiv_vartime*(remainder: var SecretWord, n_hi, n_lo, d: SecretWord, normFactor: int): SecretWord =
|
||||
# We normalize d with clz so that the MSB is set
|
||||
# And normalize (n_hi * 2^64 + n_lo) by normFactor as well to maintain the result
|
||||
# This ensures that (n_hi, n_hi)/d fits in a limb.
|
||||
if normFactor == 0:
|
||||
div2n1n_vartime(result, remainder, n_hi, n_lo, d)
|
||||
else:
|
||||
let clz = WordBitWidth-normFactor
|
||||
let hi = (n_hi shl clz) or (n_lo shr normFactor)
|
||||
let lo = n_lo shl clz
|
||||
let d = d shl clz
|
||||
|
||||
div2n1n_vartime(result, remainder, hi, lo, d)
|
||||
remainder = remainder shr clz
|
||||
|
||||
func shlAddMod_vartime(a: var openArray[SecretWord], c: SecretWord,
|
||||
M: openArray[SecretWord], mBits: int): SecretWord {.meter.} =
|
||||
## Fused modular left-shift + add
|
||||
## Computes: a <- a shl 2ʷ + c (mod M)
|
||||
## Returns: (a shl 2ʷ + c) / M
|
||||
##
|
||||
## with w the base word width, usually 32 on 32-bit platforms and 64 on 64-bit platforms
|
||||
##
|
||||
## The modulus `M` most-significant bit at `mBits` MUST be set.
|
||||
if mBits <= WordBitWidth:
|
||||
# If M fits in a single limb
|
||||
|
||||
# We normalize M with clz so that the MSB is set
|
||||
# And normalize (a * 2^64 + c) by R as well to maintain the result
|
||||
# This ensures that (a0, a1)/m0 fits in a limb.
|
||||
let R = mBits and (WordBitWidth - 1)
|
||||
|
||||
# (hi, lo) = a * 2^64 + c
|
||||
return shortDiv_vartime(remainder = a[0], n_hi = a[0], n_lo = c, d = M[0], normFactor = R)
|
||||
else:
|
||||
return shlAddMod_multiprec_vartime(a, c, M, mBits)
|
||||
|
||||
func divRem_vartime*(
|
||||
q, r: var openArray[SecretWord],
|
||||
a, b: openArray[SecretWord]): bool {.meter.} =
|
||||
# q = a div b
|
||||
# r = a mod b
|
||||
#
|
||||
# Requirements:
|
||||
# b != 0
|
||||
# q.len > a.len - b.len
|
||||
# r.len >= b.len
|
||||
|
||||
let aBits = getBits_LE_vartime(a)
|
||||
let bBits = getBits_LE_vartime(b)
|
||||
let aLen = wordsRequired(aBits)
|
||||
let bLen = wordsRequired(bBits)
|
||||
let rLen = bLen
|
||||
|
||||
let aOffset = a.len - b.len
|
||||
|
||||
# Note: don't confuse a.len and aLen (actually used words)
|
||||
|
||||
if unlikely(bool(r.len < bLen)):
|
||||
# remainder buffer cannot store up to modulus size
|
||||
return false
|
||||
|
||||
if unlikely(bool(q.len < aOffset+1)):
|
||||
# quotient buffer cannot store up to quotient size
|
||||
return false
|
||||
|
||||
if unlikely(bBits == 0):
|
||||
# Divide by zero
|
||||
return false
|
||||
|
||||
if aBits < bBits:
|
||||
# if a uses less bits than b,
|
||||
# a < b, so q = 0 and r = a
|
||||
copyWords(r.view(), 0, a.view(), 0, aLen)
|
||||
for i in aLen ..< r.len:
|
||||
r[i] = Zero
|
||||
for i in 0 ..< q.len:
|
||||
q[i] = Zero
|
||||
else:
|
||||
# The length of a is at least the divisor
|
||||
# We can copy bLen-1 words
|
||||
# and modular shift-left-add the rest
|
||||
|
||||
copyWords(r.view(), 0, a.view(), aOffset+1, b.len-1)
|
||||
r[rLen-1] = Zero
|
||||
# Now shift-left the copied words while adding the new word mod b
|
||||
|
||||
for i in countdown(aOffset, 0):
|
||||
q[i] = shlAddMod_vartime(
|
||||
r.toOpenArray(0, rLen-1),
|
||||
a[i],
|
||||
b.toOpenArray(0, bLen-1),
|
||||
bBits)
|
||||
|
||||
# Clean up extra words
|
||||
for i in aOffset+1 ..< q.len:
|
||||
q[i] = Zero
|
||||
for i in rLen ..< r.len:
|
||||
r[i] = Zero
|
||||
|
||||
return true
|
||||
|
||||
func reduce_vartime*(r: var openArray[SecretWord],
|
||||
a, b: openArray[SecretWord]): bool {.noInline, meter.} =
|
||||
let aOffset = max(a.len - b.len, 0)
|
||||
var qBuf = allocStackArray(SecretWord, aOffset+1)
|
||||
template q: untyped = qBuf.toOpenArray(0, aOffset)
|
||||
result = divRem_vartime(q, r, a, b)
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Barrett Reduction
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
# - https://en.wikipedia.org/wiki/Barrett_reduction
|
||||
# - Handbook of Applied Cryptography
|
||||
# Alfred J. Menezes, Paul C. van Oorschot and Scott A. Vanstone
|
||||
# https://cacr.uwaterloo.ca/hac/about/chap14.pdf
|
||||
# - Modern Computer Arithmetic
|
||||
# Richard P. Brent and Paul Zimmermann
|
||||
# https://members.loria.fr/PZimmermann/mca/mca-cup-0.5.9.pdf
|
||||
@ -8,7 +8,8 @@
|
||||
|
||||
import
|
||||
# Internal
|
||||
../../platforms/[abstractions, allocs]
|
||||
../../platforms/[abstractions, allocs],
|
||||
./limbs_views
|
||||
|
||||
func prod_comba(r: var openArray[SecretWord], a, b: openArray[SecretWord]) {.noInline, tags: [Alloca].} =
|
||||
## Extended precision multiplication
|
||||
@ -41,4 +42,63 @@ func prod_comba(r: var openArray[SecretWord], a, b: openArray[SecretWord]) {.noI
|
||||
|
||||
func prod*(r: var openArray[SecretWord], a, b: openArray[SecretWord]) {.inline, meter.}=
|
||||
## Extended precision multiplication
|
||||
r.prod_comba(a, b)
|
||||
r.prod_comba(a, b)
|
||||
|
||||
func prod_vartime*(r: var openArray[SecretWord], a, b: openArray[SecretWord]) {.inline, meter.}=
|
||||
## Extended precision multiplication (vartime)
|
||||
|
||||
let aBits = a.getBits_LE_vartime()
|
||||
let bBits = b.getBits_LE_vartime()
|
||||
|
||||
let aWords = wordsRequired(aBits)
|
||||
let bWords = wordsRequired(bBits)
|
||||
|
||||
r.prod_comba(
|
||||
a.toOpenArray(0, aWords-1),
|
||||
b.toOpenArray(0, bWords-1))
|
||||
|
||||
func square_comba(r: var openArray[SecretWord], a: openArray[SecretWord]) {.noInline, tags: [Alloca].} =
|
||||
## Extended precision squaring
|
||||
# We use Product Scanning / Comba multiplication
|
||||
var t, u, v = Zero
|
||||
let stopEx = min(a.len * 2, r.len)
|
||||
|
||||
let tmp = allocStackArray(SecretWord, stopEx)
|
||||
|
||||
for i in 0 ..< stopEx:
|
||||
# Invariant for product scanning:
|
||||
# if we multiply accumulate by a[k1] * b[k2]
|
||||
# we have k1+k2 == i
|
||||
let ib = min(a.len-1, i)
|
||||
let ia = i - ib
|
||||
for j in 0 ..< min(a.len - ia, ib+1):
|
||||
let k1 = ia+j
|
||||
let k2 = ib-j
|
||||
if k1 < k2:
|
||||
mulDoubleAcc(t, u, v, a[k1], a[k2])
|
||||
elif k1 == k2:
|
||||
mulAcc(t, u, v, a[k1], a[k2])
|
||||
else:
|
||||
discard
|
||||
|
||||
tmp[i] = v
|
||||
if i < stopEx-1:
|
||||
v = u
|
||||
u = t
|
||||
t = Zero
|
||||
|
||||
for i in 0 ..< stopEx:
|
||||
r[i] = tmp[i]
|
||||
|
||||
for i in stopEx ..< r.len:
|
||||
r[i] = Zero
|
||||
|
||||
func square*(r: var openArray[SecretWord], a: openArray[SecretWord]) {.inline, meter.}=
|
||||
## Extended precision squaring
|
||||
r.square_comba(a)
|
||||
|
||||
func square_vartime*(r: var openArray[SecretWord], a: openArray[SecretWord]) {.inline, meter.}=
|
||||
## Extended precision squaring (vartime)
|
||||
let aBits = a.getBits_LE_vartime()
|
||||
let aWords = wordsRequired(aBits)
|
||||
r.square_comba(a.toOpenArray(0, aWords-1))
|
||||
@ -65,7 +65,12 @@ func submod2k_vartime*(r{.noAlias.}: var openArray[SecretWord], a, b: openArray[
|
||||
|
||||
func mulmod2k_vartime*(r: var openArray[SecretWord], a, b: openArray[SecretWord], k: uint) {.inline, meter.} =
|
||||
## r <- a*b (mod 2ᵏ)
|
||||
r.prod(a, b)
|
||||
r.prod_vartime(a, b)
|
||||
r.mod2k_vartime(k)
|
||||
|
||||
func sqrmod2k_vartime*(r: var openArray[SecretWord], a: openArray[SecretWord], k: uint) {.inline, meter.} =
|
||||
## r <- a² (mod 2ᵏ)
|
||||
r.square_vartime(a)
|
||||
r.mod2k_vartime(k)
|
||||
|
||||
iterator unpackLE(scalarByte: byte): bool =
|
||||
@ -153,11 +158,11 @@ func powMod2k_vartime*(
|
||||
sBuf[i] = Zero
|
||||
|
||||
# TODO: sliding/fixed window exponentiation
|
||||
for i in countdown(exponent.len-1, 0):
|
||||
for i in countdown(exponent.len-1, 0): # Little-endian exponentiation
|
||||
for bit in unpackLE(exponent[i]):
|
||||
if bit:
|
||||
r.mulmod2k_vartime(r, s, k)
|
||||
s.mulmod2k_vartime(s, s, k)
|
||||
s.sqrmod2k_vartime(s, k)
|
||||
bitsLeft -= 1
|
||||
if bitsLeft == 0:
|
||||
return
|
||||
|
||||
@ -10,9 +10,9 @@ import
|
||||
# Internal
|
||||
../../platforms/[abstractions, allocs, bithacks],
|
||||
./limbs_views,
|
||||
./limbs_mod,
|
||||
./limbs_multiprec,
|
||||
./limbs_fixedprec,
|
||||
./limbs_divmod
|
||||
./limbs_divmod_vartime
|
||||
|
||||
# No exceptions allowed
|
||||
{.push raises: [], checks: off.}
|
||||
@ -26,77 +26,13 @@ import
|
||||
# Montgomery magic constants
|
||||
# ------------------------------------------
|
||||
|
||||
func r_powmod_vartime(r: var openArray[SecretWord], M: openArray[SecretWord], n: static int) =
|
||||
## Returns the Montgomery domain magic constant for the input modulus:
|
||||
##
|
||||
## R ≡ R (mod M) with R = (2^WordBitWidth)^numWords
|
||||
## or
|
||||
## R² ≡ R² (mod M) with R = (2^WordBitWidth)^numWords
|
||||
##
|
||||
## Assuming a field modulus of size 256-bit with 63-bit words, we require 5 words
|
||||
## R² ≡ ((2^63)^5)^2 (mod M) = 2^630 (mod M)
|
||||
|
||||
# Algorithm
|
||||
# Bos and Montgomery, Montgomery Arithmetic from a Software Perspective
|
||||
# https://eprint.iacr.org/2017/1057.pdf
|
||||
#
|
||||
# For R = r^n = 2^wn and 2^(wn − 1) ≤ N < 2^wn
|
||||
# r^n = 2^63 in on 64-bit and w the number of words
|
||||
#
|
||||
# 1. C0 = 2^(wn - 1), the power of two immediately less than N
|
||||
# 2. for i in 1 ... wn+1
|
||||
# Ci = C(i-1) + C(i-1) (mod M)
|
||||
#
|
||||
# Thus: C(wn+1) ≡ 2^(wn+1) C0 ≡ 2^(wn + 1) 2^(wn - 1) ≡ 2^(2wn) ≡ (2^wn)^2 ≡ R² (mod M)
|
||||
|
||||
debug:
|
||||
doAssert bool(M[0] and One)
|
||||
doAssert BaseType(M[M.len-1]) != 0
|
||||
doAssert r.len == M.len
|
||||
|
||||
let
|
||||
w = M.len
|
||||
msb = int log2_vartime(BaseType M[M.len-1])
|
||||
start = (w-1)*WordBitWidth + msb
|
||||
stop = n*WordBitWidth*w
|
||||
|
||||
for i in 0 ..< r.len-1:
|
||||
r[i] = Zero
|
||||
r[r.len-1] = SecretWord(BaseType(1) shl msb) # C0 = 2^(wn-1), the power of 2 immediatly less than the modulus
|
||||
|
||||
for i in start ..< stop:
|
||||
r.doublemod_vartime(r, M)
|
||||
|
||||
func oneMont_vartime*(r: var openArray[SecretWord], M: openArray[SecretWord]) {.meter.} =
|
||||
func oneMont_vartime*(r: var openArray[SecretWord], M: openArray[SecretWord]) {.noInline, meter.} =
|
||||
## Returns 1 in Montgomery domain:
|
||||
|
||||
# r.r_powmod_vartime(M, 1)
|
||||
|
||||
let mBits = getBits_LE_vartime(M)
|
||||
|
||||
let t = allocStackArray(SecretWord, M.len + 1)
|
||||
zeroMem(t, M.len*sizeof(SecretWord))
|
||||
t[M.len] = One
|
||||
|
||||
r.view().reduce(LimbsViewMut t, M.len*WordBitWidth+1, M.view(), mBits)
|
||||
|
||||
func r2_vartime*(r: var openArray[SecretWord], M: openArray[SecretWord]) {.meter.} =
|
||||
## Returns the Montgomery domain magic constant for the input modulus:
|
||||
##
|
||||
## R² ≡ R² (mod M) with R = (2^WordBitWidth)^numWords
|
||||
##
|
||||
## Assuming a field modulus of size 256-bit with 63-bit words, we require 5 words
|
||||
## R² ≡ ((2^63)^5)^2 (mod M) = 2^630 (mod M)
|
||||
|
||||
# r.r_powmod_vartime(M, 2)
|
||||
|
||||
let mBits = getBits_LE_vartime(M)
|
||||
|
||||
let t = allocStackArray(SecretWord, 2*M.len + 1)
|
||||
zeroMem(t, 2*M.len*sizeof(SecretWord))
|
||||
t[2*M.len] = One
|
||||
|
||||
r.view().reduce(LimbsViewMut t, 2*M.len*WordBitWidth+1, M.view(), mBits)
|
||||
discard r.reduce_vartime(t.toOpenArray(0, M.len), M)
|
||||
|
||||
|
||||
# Montgomery multiplication
|
||||
@ -206,6 +142,21 @@ func getMont*(r: LimbsViewMut, a: LimbsViewAny, M, r2modM: LimbsViewConst,
|
||||
# Reference: https://eprint.iacr.org/2017/1057.pdf
|
||||
mulMont_FIPS(r, a, r2ModM, M, m0ninv, mBits)
|
||||
|
||||
func getMont_vartime*(r: var openArray[SecretWord], a, M: openArray[SecretWord]) {.noInline, meter.} =
|
||||
## Transform a bigint ``a`` from it's natural representation (mod N)
|
||||
## to a the Montgomery n-residue representation
|
||||
##
|
||||
## Shift + reduction based
|
||||
let aBits = a.getBits_LE_vartime()
|
||||
let mBits = M.getBits_LE_vartime()
|
||||
let L = wordsRequired(mBits)
|
||||
let aR_len = wordsRequired(aBits) + L
|
||||
|
||||
var aR_buf = allocStackArray(SecretWord, aR_len)
|
||||
template aR: untyped = aR_Buf.toOpenArray(0, aR_len - 1)
|
||||
|
||||
aR.shiftLeft_vartime(a, WordBitWidth * L)
|
||||
discard r.reduce_vartime(aR, M)
|
||||
|
||||
# Montgomery Modular Exponentiation
|
||||
# ------------------------------------------
|
||||
@ -248,6 +199,30 @@ func getWindowLen(bufLen, wordLen: int): uint =
|
||||
while ((1 shl result) + 1)*wordLen > bufLen:
|
||||
dec result
|
||||
|
||||
func precomputeWindow(
|
||||
a: LimbsViewMut,
|
||||
M, one: LimbsViewConst,
|
||||
m0ninv: SecretWord,
|
||||
scratchspace: LimbsViewMut,
|
||||
wordLen: int,
|
||||
mBits: int,
|
||||
windowLen: uint) =
|
||||
# Precompute window content, special case for window = 1
|
||||
# (i.e scratchspace has only space for 2 temporaries)
|
||||
# The content scratchspace[2+k] is set at aᵏ
|
||||
# with scratchspace[0] untouched
|
||||
if windowLen == 1:
|
||||
scratchspace.copyWords(1*wordLen, a, 0, wordLen)
|
||||
else:
|
||||
scratchspace.copyWords(2*wordLen, a, 0, wordLen)
|
||||
for k in 2 ..< 1 shl windowLen:
|
||||
let sk1 = cast[LimbsViewMut](scratchspace[(k+1)*wordLen].addr)
|
||||
let sk = cast[LimbsViewConst](scratchspace[k*wordLen].addr)
|
||||
sk1.mulMont_FIPS(sk, a, M, m0ninv, mBits)
|
||||
|
||||
# Set a to one
|
||||
a.copyWords(0, one, 0, wordLen)
|
||||
|
||||
func powMontPrologue(
|
||||
a: LimbsViewMut, M, one: LimbsViewConst,
|
||||
m0ninv: SecretWord,
|
||||
@ -262,17 +237,11 @@ func powMontPrologue(
|
||||
# with scratchspace[0] untouched
|
||||
let wordLen = wordsRequired(mBits)
|
||||
result = scratchLen.getWindowLen(wordLen)
|
||||
if result == 1:
|
||||
scratchspace.copyWords(1*wordLen, a, 0, wordLen)
|
||||
else:
|
||||
scratchspace.copyWords(2*wordLen, a, 0, wordLen)
|
||||
for k in 2 ..< 1 shl result:
|
||||
let sk1 = cast[LimbsViewMut](scratchspace[(k+1)*wordLen].addr)
|
||||
let sk = cast[LimbsViewConst](scratchspace[k*wordLen].addr)
|
||||
sk1.mulMont_FIPS(sk, a, M, m0ninv, mBits)
|
||||
|
||||
# Set a to one
|
||||
a.copyWords(0, one, 0, wordLen)
|
||||
precomputeWindow(
|
||||
a, M, one,
|
||||
m0ninv, scratchSpace,
|
||||
wordLen, mBits,
|
||||
result)
|
||||
|
||||
func powMontSquarings(
|
||||
a: LimbsViewMut,
|
||||
@ -392,6 +361,38 @@ func powMont*(
|
||||
s0.mulMont_FIPS(a, s1, M, m0ninv, mBits)
|
||||
a.ccopyWords(0, s0, 0, SecretWord(bits).isNonZero(), N)
|
||||
|
||||
# Montgomery Modular Exponentiation (vartime)
|
||||
# -------------------------------------------
|
||||
|
||||
func getWindowLen_vartime(bufLen, expLen, wordLen: int): uint =
|
||||
## Compute the maximum window size that fits in the scratchspace buffer
|
||||
if expLen == 1:
|
||||
return 1
|
||||
else:
|
||||
return getWindowLen(bufLen, wordLen)
|
||||
|
||||
func powMontPrologue_vartime(
|
||||
a: LimbsViewMut,
|
||||
expLen: int,
|
||||
M, one: LimbsViewConst,
|
||||
m0ninv: SecretWord,
|
||||
scratchspace: LimbsViewMut,
|
||||
scratchLen: int,
|
||||
mBits: int): uint {.tags:[Alloca], meter.} =
|
||||
## Setup the scratchspace
|
||||
## Returns the fixed-window size for exponentiation with window optimization.
|
||||
# Precompute window content, special case for window = 1
|
||||
# (i.e scratchspace has only space for 2 temporaries)
|
||||
# The content scratchspace[2+k] is set at aᵏ
|
||||
# with scratchspace[0] untouched
|
||||
let wordLen = wordsRequired(mBits)
|
||||
result = scratchLen.getWindowLen_vartime(expLen, wordLen)
|
||||
precomputeWindow(
|
||||
a, M, one,
|
||||
m0ninv, scratchSpace,
|
||||
wordLen, mBits,
|
||||
result)
|
||||
|
||||
func powMont_vartime*(
|
||||
a: LimbsViewMut,
|
||||
exponent: openArray[byte],
|
||||
@ -412,7 +413,10 @@ func powMont_vartime*(
|
||||
|
||||
# TODO: scratchspace[1] is unused when window > 1
|
||||
let N = wordsRequired(mBits)
|
||||
let window = powMontPrologue(a, M, one, m0ninv, scratchspace, scratchLen, mBits)
|
||||
let eBits = exponent.getBits_BE_vartime()
|
||||
let eBytes = bytesRequired(eBits)
|
||||
|
||||
let window = powMontPrologue_vartime(a, eBytes, M, one, m0ninv, scratchspace, scratchLen, mBits)
|
||||
|
||||
var
|
||||
acc, acc_len: uint
|
||||
@ -421,9 +425,11 @@ func powMont_vartime*(
|
||||
let s0 = cast[LimbsViewMut](scratchspace[0].addr)
|
||||
let s1 = cast[LimbsViewConst](scratchspace[1*N].addr)
|
||||
|
||||
while acc_len > 0 or e < exponent.len:
|
||||
while acc_len > 0 or e < eBytes:
|
||||
let (_, bits) = powMontSquarings(
|
||||
a, exponent, M, m0ninv, mBits,
|
||||
a,
|
||||
exponent.toOpenArray(exponent.len - eBytes, exponent.len-1), # BigEndian slicing
|
||||
M, m0ninv, mBits,
|
||||
s0, window,
|
||||
acc, acc_len, e)
|
||||
|
||||
|
||||
@ -54,6 +54,9 @@ func shrLarge(r {.noalias.}: var openArray[SecretWord], a: openArray[SecretWord]
|
||||
|
||||
func shrWords(r {.noalias.}: var openArray[SecretWord], a: openArray[SecretWord], w: SomeInteger) =
|
||||
## Shift right by w word
|
||||
if w >= a.len:
|
||||
r.setZero()
|
||||
return
|
||||
|
||||
for i in 0 ..< a.len-w:
|
||||
r[i] = a[i+w]
|
||||
@ -84,6 +87,68 @@ func shiftRight_vartime*(r {.noalias.}: var openArray[SecretWord], a: openArray[
|
||||
else:
|
||||
r.shrLarge(a, w, shift)
|
||||
|
||||
func shlSmall(r: var openArray[SecretWord], a: openArray[SecretWord], k: SomeInteger) =
|
||||
## Compute the `shift left` operation of x and k
|
||||
##
|
||||
## k MUST be less than the base word size (2^32 or 2^64)
|
||||
r[0] = a[0] shl k
|
||||
for i in 1 ..< a.len:
|
||||
r[i] = (a[i] shl k) or (a[i-1] shr (WordBitWidth - k))
|
||||
|
||||
for i in a.len ..< r.len:
|
||||
r[i] = Zero
|
||||
|
||||
func shlLarge(r: var openArray[SecretWord], a: openArray[SecretWord], w, shift: SomeInteger) =
|
||||
## Shift left by `w` words + `shift` bits
|
||||
## Assumes `r` is 0 initialized
|
||||
if w >= a.len:
|
||||
return
|
||||
|
||||
r[w] = a[0] shl shift
|
||||
for i in 1+w ..< r.len:
|
||||
r[i] = (a[i-w] shl shift) or (a[i-w-1] shr (WordBitWidth - shift))
|
||||
|
||||
for i in a.len-w ..< r.len:
|
||||
r[i] = Zero
|
||||
|
||||
func shlWords(r: var openArray[SecretWord], a: openArray[SecretWord], w: SomeInteger) =
|
||||
## Shift left by w word
|
||||
if w >= r.len:
|
||||
r.setZero()
|
||||
return
|
||||
|
||||
for i in 0 ..< w:
|
||||
r[i] = Zero
|
||||
|
||||
for i in w ..< a.len+w:
|
||||
r[i] = a[i-w]
|
||||
|
||||
for i in a.len+w ..< r.len:
|
||||
r[i] = Zero
|
||||
|
||||
func shiftLeft_vartime*(r: var openArray[SecretWord], a: openArray[SecretWord], k: SomeInteger) {.meter.} =
|
||||
## Shift `a` left by k bits and store in `r`
|
||||
if k == 0:
|
||||
let min = min(a.len, r.len)
|
||||
for i in 0 ..< min:
|
||||
r[i] = a[i]
|
||||
for i in min ..< r.len:
|
||||
r[i] = Zero
|
||||
return
|
||||
|
||||
if k < WordBitWidth:
|
||||
r.shlSmall(a, k)
|
||||
return
|
||||
|
||||
# w = k div WordBitWidth, shift = k mod WordBitWidth
|
||||
let w = k shr static(log2_vartime(uint32(WordBitWidth)))
|
||||
let shift = k and (WordBitWidth - 1)
|
||||
|
||||
if shift == 0:
|
||||
r.shlWords(a, w)
|
||||
else:
|
||||
r.shlLarge(a, w, shift)
|
||||
|
||||
# Arithmetic
|
||||
# --------------------------------------------------------
|
||||
|
||||
|
||||
@ -67,6 +67,16 @@ const
|
||||
One* = SecretWord(1)
|
||||
MaxWord* = SecretWord(high(BaseType))
|
||||
|
||||
func bytesRequired*(bits: int): int {.inline.} =
|
||||
## Compute the number of limbs required
|
||||
## from the **announced** bit length
|
||||
|
||||
# bits.ceilDiv_vartime(WordBitWidth)
|
||||
# with guarantee to avoid division (especially at compile-time)
|
||||
const bitsInByte = 8
|
||||
const divShiftor = log2_vartime(uint32 bitsInByte)
|
||||
result = (bits + bitsInByte - 1) shr divShiftor
|
||||
|
||||
func wordsRequired*(bits: int): int {.inline.} =
|
||||
## Compute the number of limbs required
|
||||
## from the **announced** bit length
|
||||
|
||||
122
constantine/platforms/intrinsics/extended_precision_vartime.nim
Normal file
122
constantine/platforms/intrinsics/extended_precision_vartime.nim
Normal file
@ -0,0 +1,122 @@
|
||||
# Constantine
|
||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
||||
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
# Variable-time extended-precision
|
||||
# compiler intrinsics
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
import ../abstractions
|
||||
|
||||
func div2n1n_nim_vartime[T: SomeUnsignedInt](q, r: var T, n_hi, n_lo, d: T) {.tags:[VarTime].}=
|
||||
## Division uint128 by uint64
|
||||
## Warning ⚠️ :
|
||||
## - if n_hi == d, quotient does not fit in an uint64 and will throw SIGFPE
|
||||
## - if n_hi > d result is undefined
|
||||
|
||||
# doAssert leadingZeros(d) == 0, "Divisor was not normalized"
|
||||
|
||||
const
|
||||
size = sizeof(q) * 8
|
||||
halfSize = size div 2
|
||||
halfMask = (1.T shl halfSize) - 1.T
|
||||
|
||||
func halfQR(n_hi, n_lo, d, d_hi, d_lo: T): tuple[q, r: T] {.nimcall.} =
|
||||
|
||||
var (q, r) = (n_hi div d_hi, n_hi mod d_hi)
|
||||
let m = q * d_lo
|
||||
r = (r shl halfSize) or n_lo
|
||||
|
||||
# Fix the reminder, we're at most 2 iterations off
|
||||
if r < m:
|
||||
dec q
|
||||
r += d
|
||||
if r >= d and r < m:
|
||||
dec q
|
||||
r += d
|
||||
r -= m
|
||||
(q, r)
|
||||
|
||||
let
|
||||
d_hi = d shr halfSize
|
||||
d_lo = d and halfMask
|
||||
n_lohi = n_lo shr halfSize
|
||||
n_lolo = n_lo and halfMask
|
||||
|
||||
# First half of the quotient
|
||||
let (q1, r1) = halfQR(n_hi, n_lohi, d, d_hi, d_lo)
|
||||
|
||||
# Second half
|
||||
let (q2, r2) = halfQR(r1, n_lolo, d, d_hi, d_lo)
|
||||
|
||||
q = (q1 shl halfSize) or q2
|
||||
r = r2
|
||||
|
||||
when sizeof(int) == 8 and defined(vcc):
|
||||
func udiv128_vartime(highDividend, lowDividend, divisor: uint64, remainder: var uint64): uint64 {.importc:"_udiv128", header: "<intrin.h>", nodecl, tags:[VarTime].}
|
||||
## Division 128 by 64, Microsoft only, 64-bit only,
|
||||
## returns quotient as return value remainder as var parameter
|
||||
## Warning ⚠️ :
|
||||
## - if n_hi == d, quotient does not fit in an uint64 and will throw SIGFPE
|
||||
## - if n_hi > d result is undefined
|
||||
|
||||
func div2n1n_128_vartime(q, r: var uint64, n_hi, n_lo, d: uint64) {.inline.}=
|
||||
## Division uint128 by uint64
|
||||
## Warning ⚠️ :
|
||||
## - if n_hi == d, quotient does not fit in an uint64 and will throw SIGFPE
|
||||
## - if n_hi > d result is undefined
|
||||
q = udiv128_vartime(n_hi, n_lo, d, r)
|
||||
|
||||
elif sizeof(int) == 8 and GCC_Compatible:
|
||||
type
|
||||
uint128{.importc: "unsigned __int128".} = object
|
||||
|
||||
const
|
||||
newerNim = (NimMajor, NimMinor) > (1, 6)
|
||||
noExplicitPtrDeref = defined(cpp) or newerNim
|
||||
|
||||
func div2n1n_128_vartime(q, r: var uint64, n_hi, n_lo, d: uint64) {.inline, tags:[VarTime].}=
|
||||
## Division uint128 by uint64
|
||||
## Warning ⚠️ :
|
||||
## - if n_hi == d, quotient does not fit in an uint64 and will throw SIGFPE on some platforms
|
||||
## - if n_hi > d result is undefined
|
||||
var dblPrec {.noinit.}: uint128
|
||||
{.emit:[dblPrec, " = (unsigned __int128)", n_hi," << 64 | (unsigned __int128)",n_lo,";"].}
|
||||
|
||||
# Don't forget to dereference the var param in C mode
|
||||
when noExplicitPtrDeref:
|
||||
{.emit:[q, " = (NU64)(", dblPrec," / ", d, ");"].}
|
||||
{.emit:[r, " = (NU64)(", dblPrec," % ", d, ");"].}
|
||||
else:
|
||||
{.emit:["*",q, " = (NU64)(", dblPrec," / ", d, ");"].}
|
||||
{.emit:["*",r, " = (NU64)(", dblPrec," % ", d, ");"].}
|
||||
|
||||
|
||||
func div2n1n_vartime*(q, r: var SecretWord, n_hi, n_lo, d: SecretWord) {.inline.} =
|
||||
## Division uint128 by uint64
|
||||
## Warning ⚠️ :
|
||||
## - if n_hi == d, quotient does not fit in an uint64 and will throw SIGFPE
|
||||
## - if n_hi > d result is undefined
|
||||
##
|
||||
## To avoid issues, n_hi, n_lo, d should be normalized.
|
||||
## i.e. shifted (== multiplied by the same power of 2)
|
||||
## so that the most significant bit in d is set.
|
||||
when sizeof(int) == 4:
|
||||
let dividend = (uint64(n_hi) shl 32) or uint64(n_lo)
|
||||
let divisor = uint64(d)
|
||||
q = uint32(dividend div divisor)
|
||||
r = uint32(dividend mod divisor)
|
||||
when nimvm:
|
||||
div2n1n_nim_vartime(BaseType q, BaseType r, BaseType n_hi, BaseType n_lo, BaseType d)
|
||||
else:
|
||||
when declared(div2n1n_128_vartime):
|
||||
div2n1n_128_vartime(BaseType q, BaseType r, BaseType n_hi, BaseType n_lo, BaseType d)
|
||||
else:
|
||||
div2n1n_nim_vartime(BaseType q, BaseType r, BaseType n_hi, BaseType n_lo, BaseType d)
|
||||
@ -3,17 +3,20 @@
|
||||
import
|
||||
../../constantine/math/[
|
||||
arithmetic,
|
||||
io/io_bigints]
|
||||
io/io_bigints],
|
||||
../../constantine/math_arbitrary_precision/arithmetic/limbs_divmod_vartime
|
||||
|
||||
let a = BigInt[64].fromUint(0xa0e5cb56a1c08396'u64)
|
||||
let M = BigInt[64].fromUint(0xae57180eceb0206f'u64)
|
||||
|
||||
var r: BigInt[64]
|
||||
var r, r2: BigInt[64]
|
||||
|
||||
r.reduce(a, M)
|
||||
doAssert r2.limbs.reduce_vartime(a.limbs, M.limbs)
|
||||
|
||||
let rU64 = 0xa0e5cb56a1c08396'u64 mod 0xae57180eceb0206f'u64
|
||||
echo r.toHex()
|
||||
# echo r.toHex()
|
||||
|
||||
doAssert rU64 == a.limbs[0].uint64
|
||||
doAssert bool(a == r)
|
||||
doAssert bool(a == r)
|
||||
echo "SUCCESS: t_bigints_mod.nim"
|
||||
@ -15,6 +15,7 @@ import
|
||||
../../constantine/math/[arithmetic, io/io_bigints],
|
||||
../../constantine/platforms/primitives,
|
||||
../../constantine/serialization/codecs,
|
||||
../../constantine/math_arbitrary_precision/arithmetic/limbs_divmod_vartime,
|
||||
# Test utilities
|
||||
../../helpers/prng_unsafe
|
||||
|
||||
@ -126,8 +127,9 @@ proc main() =
|
||||
# Modulus
|
||||
mpz_mod(r, a, m)
|
||||
|
||||
var rTest: BigInt[mBits]
|
||||
var rTest, rTest_vartime: BigInt[mBits]
|
||||
rTest.reduce(aTest, mTest)
|
||||
doAssert rTest_vartime.limbs.reduce_vartime(aTest.limbs, mTest.limbs)
|
||||
|
||||
#########################################################
|
||||
# Check
|
||||
@ -139,8 +141,9 @@ proc main() =
|
||||
var rGMP: array[mLen, byte]
|
||||
discard mpz_export(rGMP[0].addr, rW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, r)
|
||||
|
||||
var rConstantine: array[mLen, byte]
|
||||
var rConstantine, rCttVartime: array[mLen, byte]
|
||||
marshal(rConstantine, rTest, bigEndian)
|
||||
marshal(rCttVartime, rTest_vartime, bigEndian)
|
||||
|
||||
# echo "rGMP: ", rGMP.toHex()
|
||||
# echo "rConstantine: ", rConstantine.toHex()
|
||||
@ -158,4 +161,20 @@ proc main() =
|
||||
" Constantine: " & rConstantine.toHex() & "\n" &
|
||||
"(Note that GMP aligns bytes left while constantine aligns bytes right)"
|
||||
|
||||
doAssert rGMP.toOpenArray(0, rW-1) == rCttVartime.toOpenArray(mLen-rW, mLen-1), block:
|
||||
# Reexport as bigEndian for debugging
|
||||
discard mpz_export(aBuf[0].addr, aW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, a)
|
||||
discard mpz_export(mBuf[0].addr, mW.addr, GMP_MostSignificantWordFirst, 1, GMP_WordNativeEndian, 0, m)
|
||||
"\nModulus with operands\n" &
|
||||
" a (" & align($aBits, 4) & "-bit): " & aBuf.toHex & "\n" &
|
||||
" m (" & align($mBits, 4) & "-bit): " & mBuf.toHex & "\n" &
|
||||
"failed:" & "\n" &
|
||||
" GMP: " & rGMP.toHex() & "\n" &
|
||||
" Constantine: " & rCttVartime.toHex() & "\n" &
|
||||
"(Note that GMP aligns bytes left while constantine aligns bytes right)"
|
||||
|
||||
mpz_clear(a)
|
||||
mpz_clear(m)
|
||||
mpz_clear(r)
|
||||
|
||||
main()
|
||||
|
||||
@ -7,8 +7,9 @@
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../../constantine/math_arbitrary_precision/arithmetic/[bigints_views, limbs_views, limbs_divmod],
|
||||
../../constantine/math_arbitrary_precision/arithmetic/[bigints_views, limbs_views],
|
||||
../../constantine/platforms/abstractions,
|
||||
../../constantine/serialization/codecs,
|
||||
../../helpers/prng_unsafe,
|
||||
|
||||
std/[times, strformat],
|
||||
@ -74,23 +75,11 @@ proc test(rng: var RngState) =
|
||||
ee.mpz_import(eLen, GMP_MostSignificantWordFirst, sizeof(byte), GMP_WordNativeEndian, 0, e[0].addr)
|
||||
mm.mpz_import(mLen, GMP_LeastSignificantWordFirst, sizeof(SecretWord), GMP_WordNativeEndian, 0, M[0].addr)
|
||||
|
||||
debug:
|
||||
echo "----------------------------------------------"
|
||||
echo " a (Ctt): ", a.toString()
|
||||
echo " a (GMP): ", aa.toHex()
|
||||
echo " e (Ctt): ", e.toHex()
|
||||
echo " e (GMP): ", ee.toHex()
|
||||
echo " M (Ctt): ", M.toString()
|
||||
echo " M (GMP): ", mm.toHex()
|
||||
|
||||
rr.mpz_powm(aa, ee, mm)
|
||||
|
||||
var rWritten: csize
|
||||
discard rGMP[0].addr.mpz_export(rWritten.addr, GMP_LeastSignificantWordFirst, sizeof(SecretWord), GMP_WordNativeEndian, 0, rr)
|
||||
|
||||
debug:
|
||||
echo " r (GMP): ", rr.toHex()
|
||||
|
||||
mpz_clear(aa)
|
||||
mpz_clear(ee)
|
||||
mpz_clear(mm)
|
||||
@ -103,15 +92,18 @@ proc test(rng: var RngState) =
|
||||
|
||||
rCtt.powMod_vartime(a, e, M, window = 4)
|
||||
|
||||
debug:
|
||||
echo " r (GMP): " & rGMP.toString()
|
||||
echo " r (Ctt): " & rCtt.toString()
|
||||
|
||||
doAssert (seq[BaseType])(rGMP) == (seq[BaseType])(rCtt), block:
|
||||
"Failure with sizes:\n" &
|
||||
"\nModular exponentiation failure:\n" &
|
||||
&" a.len (word): {a.len:>3}, a.bits: {aBits:>4}\n" &
|
||||
&" e.len (byte): {e.len:>3}, e.bits: {eBits:>4}\n" &
|
||||
&" M.len (word): {M.len:>3}, M.bits: {mBits:>4}\n"
|
||||
&" M.len (word): {M.len:>3}, M.bits: {mBits:>4}\n" &
|
||||
" ------------------------------------------------\n" &
|
||||
&" a: {aa.toHex()}\n" &
|
||||
&" e: {ee.toHex()}\n" &
|
||||
&" M: {mm.toHex()}\n" &
|
||||
" ------------------------------------------------\n" &
|
||||
&" r (GMP): {rGMP.toString()}\n" &
|
||||
&" r (Ctt): {rCtt.toString()}\n"
|
||||
|
||||
|
||||
for _ in 0 ..< Iters:
|
||||
|
||||
@ -0,0 +1 @@
|
||||
-d:CTT_DEBUG
|
||||
@ -206,4 +206,423 @@ suite "EVM ModExp precompile (EIP-198)":
|
||||
0xa0]
|
||||
var r = newSeq[byte](1)
|
||||
let status = r.eth_evm_modexp(input)
|
||||
doAssert status == cttEVM_Success
|
||||
|
||||
test "Audit #6 - DOS Vector 1":
|
||||
let input = [
|
||||
# Length of base (32)
|
||||
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, 0x20,
|
||||
|
||||
# Length of exponent (32)
|
||||
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, 0x20,
|
||||
|
||||
# Length of modulus (32)
|
||||
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, 0x20,
|
||||
|
||||
# Base (96064778440517843452771003943013638877275214272712651271554889917016327417616)
|
||||
0xd4, 0x62, 0xbc, 0xde, 0x8f, 0x57, 0xb0, 0x4a, 0x3f, 0xe1, 0x16, 0xc8, 0x12, 0x8c, 0x44, 0x34,
|
||||
0xcf, 0x10, 0x25, 0x2e, 0x48, 0xa3, 0xcc, 0x0d, 0x28, 0xdf, 0x2b, 0xac, 0x4a, 0x8d, 0x6f, 0x10,
|
||||
|
||||
# Exponent (96064778440517843452771003943013638877275214272712651271554889917016327417616)
|
||||
0xd4, 0x62, 0xbc, 0xde, 0x8f, 0x57, 0xb0, 0x4a, 0x3f, 0xe1, 0x16, 0xc8, 0x12, 0x8c, 0x44, 0x34,
|
||||
0xcf, 0x10, 0x25, 0x2e, 0x48, 0xa3, 0xcc, 0x0d, 0x28, 0xdf, 0x2b, 0xac, 0x4a, 0x8d, 0x6f, 0x10,
|
||||
|
||||
# Modulus (57896044618658097711785492504343953926634992332820282019728792003956564819968)
|
||||
0x80, 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,
|
||||
]
|
||||
|
||||
var r = newSeq[byte](32)
|
||||
let status = r.eth_evm_modexp(input)
|
||||
doAssert status == cttEVM_Success
|
||||
doAssert r == @[byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
|
||||
test "Audit #6 - DOS Vector 2":
|
||||
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 (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,
|
||||
|
||||
# Length of modulus (121)
|
||||
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, 0x79,
|
||||
|
||||
# Base
|
||||
0x33,
|
||||
|
||||
# Exponent
|
||||
0x01,
|
||||
|
||||
# Modulus
|
||||
0x04, 0xea, 0xbb, 0x12, 0x55, 0x88, 0xd7, 0x3c, 0xad, 0x22, 0xea, 0x2b, 0x4a, 0x77, 0x6e, 0x9d,
|
||||
0x4d, 0xfc, 0x13, 0xa8, 0x1b, 0xf9, 0x0c, 0x0d, 0x37, 0xe8, 0x4e, 0x8b, 0xeb, 0xb2, 0xa5, 0x48,
|
||||
0x8b, 0x2c, 0x87, 0x6d, 0x13, 0x51, 0x75, 0xeb, 0x97, 0xc6, 0x13, 0xd9, 0x06, 0xce, 0x8b, 0x53,
|
||||
0xd0, 0x02, 0x68, 0xb8, 0xd6, 0x12, 0xab, 0x8b, 0x15, 0x0c, 0xef, 0x0a, 0xd0, 0x3b, 0x73, 0xd2,
|
||||
0xdb, 0x9d, 0x2a, 0xa5, 0x23, 0x70, 0xdc, 0x26, 0x55, 0x80, 0xca, 0xf2, 0xc0, 0x18, 0xe3, 0xe3,
|
||||
0x1b, 0xad, 0xd5, 0x22, 0xdd, 0x10, 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, 0x1c, 0x05, 0x71, 0x52, 0x7c, 0x3a, 0xb0, 0x77,
|
||||
]
|
||||
|
||||
var r = newSeq[byte](121)
|
||||
let status = r.eth_evm_modexp(input)
|
||||
doAssert status == cttEVM_Success
|
||||
doAssert r == @[byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51]
|
||||
|
||||
test "Audit #6 - DOS Vector 2.a - shortcuttable with even modulus":
|
||||
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 (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,
|
||||
|
||||
# Length of modulus (121)
|
||||
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, 0x79,
|
||||
|
||||
# Base
|
||||
0x33,
|
||||
|
||||
# Exponent
|
||||
0x01,
|
||||
|
||||
# Modulus
|
||||
0x04, 0xea, 0xbb, 0x12, 0x55, 0x88, 0xd7, 0x3c, 0xad, 0x22, 0xea, 0x2b, 0x4a, 0x77, 0x6e, 0x9d,
|
||||
0x4d, 0xfc, 0x13, 0xa8, 0x1b, 0xf9, 0x0c, 0x0d, 0x37, 0xe8, 0x4e, 0x8b, 0xeb, 0xb2, 0xa5, 0x48,
|
||||
0x8b, 0x2c, 0x87, 0x6d, 0x13, 0x51, 0x75, 0xeb, 0x97, 0xc6, 0x13, 0xd9, 0x06, 0xce, 0x8b, 0x53,
|
||||
0xd0, 0x02, 0x68, 0xb8, 0xd6, 0x12, 0xab, 0x8b, 0x15, 0x0c, 0xef, 0x0a, 0xd0, 0x3b, 0x73, 0xd2,
|
||||
0xdb, 0x9d, 0x2a, 0xa5, 0x23, 0x70, 0xdc, 0x26, 0x55, 0x80, 0xca, 0xf2, 0xc0, 0x18, 0xe3, 0xe3,
|
||||
0x1b, 0xad, 0xd5, 0x22, 0xdd, 0x10, 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, 0x1c, 0x05, 0x71, 0x52, 0x7c, 0x3a, 0xb0, 0x76,
|
||||
]
|
||||
|
||||
var r = newSeq[byte](121)
|
||||
let status = r.eth_evm_modexp(input)
|
||||
doAssert status == cttEVM_Success
|
||||
doAssert r == @[byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51]
|
||||
|
||||
test "Audit #6 - DOS Vector 2.b - odd modulus with no shortcut":
|
||||
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 (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,
|
||||
|
||||
# Length of modulus (121)
|
||||
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, 0x79,
|
||||
|
||||
# Base
|
||||
0x33,
|
||||
|
||||
# Exponent
|
||||
0x10,
|
||||
|
||||
# Modulus
|
||||
0x04, 0xea, 0xbb, 0x12, 0x55, 0x88, 0xd7, 0x3c, 0xad, 0x22, 0xea, 0x2b, 0x4a, 0x77, 0x6e, 0x9d,
|
||||
0x4d, 0xfc, 0x13, 0xa8, 0x1b, 0xf9, 0x0c, 0x0d, 0x37, 0xe8, 0x4e, 0x8b, 0xeb, 0xb2, 0xa5, 0x48,
|
||||
0x8b, 0x2c, 0x87, 0x6d, 0x13, 0x51, 0x75, 0xeb, 0x97, 0xc6, 0x13, 0xd9, 0x06, 0xce, 0x8b, 0x53,
|
||||
0xd0, 0x02, 0x68, 0xb8, 0xd6, 0x12, 0xab, 0x8b, 0x15, 0x0c, 0xef, 0x0a, 0xd0, 0x3b, 0x73, 0xd2,
|
||||
0xdb, 0x9d, 0x2a, 0xa5, 0x23, 0x70, 0xdc, 0x26, 0x55, 0x80, 0xca, 0xf2, 0xc0, 0x18, 0xe3, 0xe3,
|
||||
0x1b, 0xad, 0xd5, 0x22, 0xdd, 0x10, 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, 0x1c, 0x05, 0x71, 0x52, 0x7c, 0x3a, 0xb0, 0x77,
|
||||
]
|
||||
|
||||
var r = newSeq[byte](121)
|
||||
let status = r.eth_evm_modexp(input)
|
||||
doAssert status == cttEVM_Success
|
||||
doAssert r == @[byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 196, 178, 252, 11, 73, 111, 4, 209, 77, 144, 65]
|
||||
|
||||
test "Audit #6 - DOS Vector 2.c - odd modulus with no shortcut":
|
||||
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 (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,
|
||||
|
||||
# Length of modulus (121)
|
||||
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, 0x79,
|
||||
|
||||
# Base
|
||||
0x33,
|
||||
|
||||
# Exponent
|
||||
0x07,
|
||||
|
||||
# Modulus
|
||||
0x04, 0xea, 0xbb, 0x12, 0x55, 0x88, 0xd7, 0x3c, 0xad, 0x22, 0xea, 0x2b, 0x4a, 0x77, 0x6e, 0x9d,
|
||||
0x4d, 0xfc, 0x13, 0xa8, 0x1b, 0xf9, 0x0c, 0x0d, 0x37, 0xe8, 0x4e, 0x8b, 0xeb, 0xb2, 0xa5, 0x48,
|
||||
0x8b, 0x2c, 0x87, 0x6d, 0x13, 0x51, 0x75, 0xeb, 0x97, 0xc6, 0x13, 0xd9, 0x06, 0xce, 0x8b, 0x53,
|
||||
0xd0, 0x02, 0x68, 0xb8, 0xd6, 0x12, 0xab, 0x8b, 0x15, 0x0c, 0xef, 0x0a, 0xd0, 0x3b, 0x73, 0xd2,
|
||||
0xdb, 0x9d, 0x2a, 0xa5, 0x23, 0x70, 0xdc, 0x26, 0x55, 0x80, 0xca, 0xf2, 0xc0, 0x18, 0xe3, 0xe3,
|
||||
0x1b, 0xad, 0xd5, 0x22, 0xdd, 0x10, 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, 0x1c, 0x05, 0x71, 0x52, 0x7c, 0x3a, 0xb0, 0x77,
|
||||
]
|
||||
|
||||
var r = newSeq[byte](121)
|
||||
let status = r.eth_evm_modexp(input)
|
||||
doAssert status == cttEVM_Success
|
||||
doAssert r == @[byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 241, 216, 60, 91]
|
||||
|
||||
test "Audit #6 - DOS Vector 2.d - power-of-2 modulus with no shortcut":
|
||||
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 (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,
|
||||
|
||||
# Length of modulus (121)
|
||||
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, 0x79,
|
||||
|
||||
# Base
|
||||
0x33,
|
||||
|
||||
# Exponent
|
||||
0x07,
|
||||
|
||||
# Modulus
|
||||
0x04, 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,
|
||||
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, 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, 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,
|
||||
]
|
||||
|
||||
var r = newSeq[byte](121)
|
||||
let status = r.eth_evm_modexp(input)
|
||||
doAssert status == cttEVM_Success
|
||||
doAssert r == @[byte 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 241, 216, 60, 91]
|
||||
|
||||
test "Audit #5 - Modified padded exponent":
|
||||
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 (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, 0x03,
|
||||
|
||||
# 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
|
||||
0x06,
|
||||
|
||||
# Exponent
|
||||
0x00, 0x00, 0x02,
|
||||
|
||||
# Modulus
|
||||
0x04
|
||||
]
|
||||
|
||||
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 #5-2 - Modified padded exponent":
|
||||
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, 0x0A,
|
||||
|
||||
# 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
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 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 #5-3 - Modified padded exponent":
|
||||
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 (2)
|
||||
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, 0x03,
|
||||
|
||||
# Length of modulus (9)
|
||||
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, 0x09,
|
||||
|
||||
# Base
|
||||
0x02,
|
||||
|
||||
# Exponent
|
||||
0x00, 0x02, 0x65,
|
||||
|
||||
# Modulus
|
||||
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x98
|
||||
]
|
||||
|
||||
var r = newSeq[byte](9)
|
||||
let status = r.eth_evm_modexp(input)
|
||||
doAssert status == cttEVM_Success
|
||||
doAssert r == @[byte 0, 0, 1, 45, 106, 227, 225, 162, 136], ". Result was " & $r
|
||||
|
||||
test "Audit #5-4 - Modified padded exponent":
|
||||
var input = [
|
||||
# Length of base
|
||||
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, 0x0c,
|
||||
|
||||
# Length of exponent
|
||||
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, 0x09,
|
||||
|
||||
# Length of modulus
|
||||
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, 0x2b,
|
||||
|
||||
# Base
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
|
||||
|
||||
# Exponent
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
|
||||
|
||||
# Modulus
|
||||
0x17, 0xc6, 0xab, 0xaa, 0x3f, 0x00, 0xe5, 0xc0, 0x5b, 0x75, 0x74, 0xcb,
|
||||
0xcf, 0x2a, 0x44, 0xd4, 0x3a, 0xca, 0x4a, 0xc0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
]
|
||||
var r = newSeq[byte](0x2b)
|
||||
let status = eth_evm_modexp(r, input)
|
||||
doAssert status == cttEVM_Success
|
||||
doAssert r == @[byte 10, 141, 74, 46, 2, 18, 2, 37, 247, 220, 246, 65, 109, 246, 7, 144, 85, 202, 194, 191, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], ". Result was " & $r
|
||||
|
||||
test "Audit #8 - Modified padded exponent":
|
||||
let input = [
|
||||
# Length of base (24)
|
||||
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, 0x18,
|
||||
|
||||
# Length of exponent (36)
|
||||
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, 0x25,
|
||||
|
||||
# Length of modulus (56)
|
||||
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, 0x38,
|
||||
|
||||
# Base
|
||||
0x07, 0x19, 0x2b, 0x95, 0xff, 0xc8, 0xda, 0x78, 0x63, 0x10, 0x11, 0xed, 0x6b, 0x24, 0xcd, 0xd5,
|
||||
0x73, 0xf9, 0x77, 0xa1, 0x1e, 0x79, 0x48, 0x11,
|
||||
|
||||
# Exponent
|
||||
0x00,
|
||||
0x03, 0x67, 0x68, 0x54, 0xfe, 0x24, 0x14, 0x1c, 0xb9, 0x8f, 0xe6, 0xd4, 0xb2, 0x0d, 0x02, 0xb4,
|
||||
0x51, 0x6f, 0xf7, 0x02, 0x35, 0x0e, 0xdd, 0xb0, 0x82, 0x67, 0x79, 0xc8, 0x13, 0xf0, 0xdf, 0x45,
|
||||
0xbe, 0x81, 0x12, 0xf4,
|
||||
|
||||
# Modulus
|
||||
0x1a, 0xbf, 0x81, 0x1f, 0x86, 0xe1, 0x02, 0x78, 0x66, 0xe4, 0x23, 0x65, 0x49, 0x0f, 0x8d, 0x6e,
|
||||
0xc2, 0x23, 0x94, 0x18, 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, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
]
|
||||
|
||||
var r = newSeq[byte](56)
|
||||
let status = r.eth_evm_modexp(input)
|
||||
doAssert status == cttEVM_Success
|
||||
|
||||
test "Audit #18 - Modified padded exponent":
|
||||
let input = [
|
||||
# Base length
|
||||
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, 0x08,
|
||||
# Exponent length
|
||||
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, 0xab, 0xa8, 0xff,
|
||||
# Modulus length
|
||||
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,
|
||||
|
||||
0xc1, 0x00, 0x00, 0x00, 0x51, 0x00, 0x9b, 0x9b,
|
||||
|
||||
0x00, 0x00,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x00, 0x50, 0x50, 0x50,
|
||||
0x50, 0x50, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0xbc, 0x9b, 0xa0, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b,
|
||||
0x9b, 0x9b, 0x9b, 0x9b, 0x00, 0x50, 0x50, 0x50,
|
||||
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
|
||||
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
|
||||
0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00, 0x00,
|
||||
|
||||
0xa0]
|
||||
var r = newSeq[byte](1)
|
||||
let status = r.eth_evm_modexp(input)
|
||||
doAssert status == cttEVM_Success
|
||||
Loading…
x
Reference in New Issue
Block a user