Modular exponentiation (arbitrary output) and EIP-198 (#242)

* implement arbitrary precision modular exponentiation (prerequisite EIP-198)

* [modexp] implement exponentiation modulo 2ᵏ

* add inversion (mod 2ᵏ)

* [modexp] High-level wrapper for powmod with odd modulus

* [modexp] faster exponentiation (mod 2ᵏ) for even case and Euler's totient function odd case

* [modexp] implement general fast modular exponentiation

* Fix modular reduction with 64-bit modulus + fuzz powmod vs GMP

* add benchmark

* add EIP-198 support

* fixups following self review

* fix test paths
This commit is contained in:
Mamy Ratsimbazafy 2023-06-01 23:38:41 +02:00 committed by GitHub
parent d996ccd5d8
commit b1ef2682d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 2260 additions and 320 deletions

View File

@ -211,4 +211,4 @@ proc powUnsafeBench*(T: typedesc, iters: int) =
let exponent = rng.random_unsafe(BigInt[T.C.getCurveOrderBitwidth()])
bench("Exp curve order (Leak exponent bits) - " & $exponent.bits & "-bit", T, iters):
var r = x
r.powUnsafeExponent(exponent)
r.pow_vartime(exponent)

205
benchmarks/bench_powmod.nim Normal file
View File

@ -0,0 +1,205 @@
import
../constantine/math/arithmetic,
../constantine/math/io/[io_bigints, io_fields],
../constantine/math/config/curves,
../constantine/platforms/[abstractions, codecs],
../constantine/math_arbitrary_precision/arithmetic/bigints_views,
../helpers/prng_unsafe,
./platforms, ./bench_blueprint
import stint, gmp
from bigints import nil # force qualified import to avoid conflicts on BigInt
# Benchmarks for modular exponentiation implementations:
#
# - Constantine has 2 backends
# - The cryptographic backend uses fixed-sized integer.
# Often the modulus is known at compile-time (specific elliptic curves),
# except for RSA.
#
# This allows reducing precomputation time,
# and unrolling all loops.
# This is significant as incrementing a loop counter messes up carry propagation.
#
# That backend requires the modulus to be prime.
#
# As cryptography only uses primes (which are odd), this is not a limitation.
# However it is not suitable for general-purpose
#
# - The arbitrary-sized integer backend.
# Some protocol like Ethereum modexp (EIP-198) require
# modular exponentiation on arbitrary inputs.
#
# - Stint, GMP, nim-bigints are also benchmarked
# for reference. GMP and nim-bigints require dynamic allocation.
# - For GMP, we reuse buffers to limit allocation to the first benchmark
# - nim-bigints doesn't allow reusing buffers
#
# Stint requires all inputs to be the same size
# so we use 256-bits for all.
#
# To benchmark the cryptographic backend, we use Secp256k1 (the Bitcoin curve).
# Note that Constantine implements it generically,
# due to the special form of the prime (2²⁵⁶ - 2³² - 977),
# even faster algorithms can be used.
# This gives an upper-bound
proc report(op: string, elapsedNs: int64, elapsedCycles: int64, iters: int) =
let ns = elapsedNs div iters
let cycles = elapsedCycles div iters
let throughput = 1e9 / float64(elapsedNs)
when SupportsGetTicks:
echo &"{op:<45} {throughput:>15.3f} ops/s {ns:>16} ns/op {cycles:>12} CPU cycles (approx)"
else:
echo &"{op:<45} {throughput:>15.3f} ops/s {ns:>16} ns/op"
const # https://gmplib.org/manual/Integer-Import-and-Export.html
GMP_WordLittleEndian = -1'i32
GMP_WordNativeEndian = 0'i32
GMP_WordBigEndian = 1'i32
GMP_MostSignificantWordFirst = 1'i32
GMP_LeastSignificantWordFirst = -1'i32
const bits = 256
type BenchDesc = object
# Hex strings
a: string
e: string
M: string
proc genBench(iters: int): seq[BenchDesc] =
for _ in 0 ..< iters:
let a = rng.random_long01Seq(BigInt[bits])
let e = rng.random_long01Seq(BigInt[bits])
let M = rng.random_long01Seq(BigInt[bits])
result.add BenchDesc(
a: a.toHex(),
e: e.toHex(),
M: M.toHex())
template bench(fnCall: untyped, ticks, ns: var int64): untyped =
block:
let startTime = getMonotime()
let startClock = getTicks()
fnCall
let stopClock = getTicks()
let stopTime = getMonotime()
ticks += stopClock - startClock
ns += inNanoseconds(stopTime-startTime)
proc benchAll(desc: seq[BenchDesc]) =
var perfCttArb, perfCttCrypto, perfGmp, perfStint, perfNimBigInt: int64
block: # Constantine Arbitrary-precision
var ticks, nanoseconds: int64
for i in 0 ..< desc.len:
# The implementation is view based and uses unowned-buffers (seq or arrays)
# but for hex parsing simplicity we reuse BigInt buffers
# and we directly access the array behind with .limbs
var r: BigInt[bits]
let a = BigInt[bits].fromHex(desc[i].a)
let M = BigInt[bits].fromHex(desc[i].M)
let e = array[bits div 8, byte].fromHex(desc[i].e)
bench(
r.limbs.powMod_varTime(a.limbs, e, M.limbs, window = 4),
ticks, nanoseconds)
report("Constantine (generic arbitrary-precision)", nanoseconds, ticks, desc.len)
perfCttArb = nanoseconds
block: # Constantine Cryptographic backend
var ticks, nanoseconds: int64
var e = newSeq[byte](bits div 8)
for i in 0 ..< desc.len:
var r: Fp[Secp256k1]
let a = Fp[Secp256k1].fromHex(desc[i].a)
e.paddedFromHex(desc[i].e, bigEndian)
bench(
(r = a; r.pow_varTime(e)),
ticks, nanoseconds)
report("Constantine (crypto fixed 256-bit precision)", nanoseconds, ticks, desc.len)
perfCttCrypto = nanoseconds
block: # GMP
var ticks, nanoseconds: int64
var a, e, M, r: mpz_t
mpz_init(a)
mpz_init(e)
mpz_init(M)
mpz_init(r)
for i in 0 ..< desc.len:
let aCtt = BigInt[bits].fromHex(desc[i].a)
a.mpz_import(aCtt.limbs.len, GMP_LeastSignificantWordFirst, sizeof(SecretWord), GMP_WordNativeEndian, 0, aCtt.limbs[0].unsafeAddr)
let eCtt = BigInt[bits].fromHex(desc[i].e)
e.mpz_import(eCtt.limbs.len, GMP_LeastSignificantWordFirst, sizeof(SecretWord), GMP_WordNativeEndian, 0, eCtt.limbs[0].unsafeAddr)
let mCtt = BigInt[bits].fromHex(desc[i].M)
M.mpz_import(mCtt.limbs.len, GMP_LeastSignificantWordFirst, sizeof(SecretWord), GMP_WordNativeEndian, 0, mCtt.limbs[0].unsafeAddr)
bench(
r.mpz_powm(a, e, M),
ticks, nanoseconds)
report("GMP", nanoseconds, ticks, desc.len)
perfGMP = nanoseconds
mpz_clear(r)
mpz_clear(M)
mpz_clear(e)
mpz_clear(a)
block: # Stint
var ticks, nanoseconds: int64
for i in 0 ..< desc.len:
let a = Stuint[bits].fromHex(desc[i].a)
let e = Stuint[bits].fromHex(desc[i].e)
let M = Stuint[bits].fromHex(desc[i].M)
bench(
(let r = powmod(a, e, M)),
ticks, nanoseconds)
report("Stint", nanoseconds, ticks, desc.len)
perfStint = nanoseconds
block: # Nim bigints
var ticks, nanoseconds: int64
for i in 0 ..< desc.len:
# Drop the 0x prefix
let a = bigints.initBigInt(desc[i].a[2..^1], base = 16)
let e = bigints.initBigInt(desc[i].e[2..^1], base = 16)
let M = bigints.initBigInt(desc[i].M[2..^1], base = 16)
bench(
(let r = bigints.powmod(a, e, M)),
ticks, nanoseconds)
report("nim-bigints", nanoseconds, ticks, desc.len)
perfNimBigInt = nanoseconds
let ratioCrypto = float64(perfCttCrypto) / float64(perfCttArb)
let ratioGMP = float64(perfGMP) / float64(perfCttArb)
let ratioStint = float64(perfStint) / float64(perfCttArb)
let ratioNimBigInt = float64(perfNimBigInt) / float64(perfCttArb)
echo ""
echo &"Perf ratio Constantine generic vs crypto fixed precision: {ratioCrypto:>8.3f}x"
echo &"Perf ratio Constantine generic vs GMP: {ratioGMP:>8.3f}x"
echo &"Perf ratio Constantine generic vs Stint: {ratioStint:>8.3f}x"
echo &"Perf ratio Constantine generic vs nim-bigints: {ratioNimBigInt:>8.3f}x"
when isMainModule:
let benchDesc = genBench(100)
benchDesc.benchAll()

View File

@ -263,10 +263,15 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
("tests/math_bigints/t_io_bigints.nim", false),
# ("tests/math_bigints/t_bigints.nim", false),
# ("tests/math_bigints/t_bigints_multimod.nim", false),
# ("tests/math_bigints/t_bigints_mod_vs_gmp.nim", true),
# ("tests/math_bigints/t_bigints_mul_vs_gmp.nim", true),
# ("tests/math_bigints/t_bigints_mul_high_words_vs_gmp.nim", true),
# Big ints - arbitrary precision
# ----------------------------------------------------------
("tests/math_arbitrary_precision/t_bigints_mod.nim", false),
("tests/math_arbitrary_precision/t_bigints_mod_vs_gmp.nim", true),
("tests/math_arbitrary_precision/t_bigints_powmod_vs_gmp.nim", true),
# Field
# ----------------------------------------------------------
("tests/math_fields/t_io_fields", false),
@ -824,6 +829,12 @@ task test_nvidia, "Run all tests for Nvidia GPUs":
if cmd != "": # Windows doesn't like empty commands
exec cmd
# BigInt benchmark
# ------------------------------------------
task bench_powmod, "Run modular exponentiation benchmark with your CC compiler":
runBench("bench_powmod")
# Finite field 𝔽p
# ------------------------------------------

View File

@ -8,13 +8,14 @@
import
./platforms/abstractions,
./math/config/curves,
./math/config/[curves, precompute],
./math/[arithmetic, extension_fields],
./math/arithmetic/limbs_montgomery,
./math/ec_shortweierstrass,
./math/pairings/[pairings_generic, miller_accumulators],
./math/constants/zoo_subgroups,
./math/io/[io_bigints, io_fields]
./math/io/[io_bigints, io_fields],
./math_arbitrary_precision/arithmetic/bigints_views
# ############################################################
#
@ -28,10 +29,11 @@ import
type
CttEVMStatus* = enum
cttEVM_Success
cttEVM_InvalidInputSize
cttEVM_InvalidOutputSize
cttEVM_IntLargerThanModulus
cttEVM_PointNotOnCurve
cttEVM_PointNotInSubgroup
cttEVM_InvalidInputLength
func parseRawUint(
dst: var Fp[BN254_Snarks],
@ -86,7 +88,7 @@ func fromRawCoords(
return cttEVM_Success
func eth_evm_ecadd*(r: var array[64, byte], inputs: openarray[byte]): CttEVMStatus =
func eth_evm_ecadd*(r: var openArray[byte], inputs: openarray[byte]): CttEVMStatus =
## Elliptic Curve addition on BN254_Snarks
## (also called alt_bn128 in Ethereum specs
## and bn256 in Ethereum tests)
@ -103,6 +105,7 @@ func eth_evm_ecadd*(r: var array[64, byte], inputs: openarray[byte]): CttEVMStat
## If the length is greater than 128 bytes, input is truncated to 128 bytes.
##
## Output
## - Output buffer MUST be of length 64 bytes
## - A G1 point R with coordinates (Px + Qx, Py + Qy)
## - Status code:
## cttEVM_Success
@ -111,6 +114,9 @@ func eth_evm_ecadd*(r: var array[64, byte], inputs: openarray[byte]): CttEVMStat
##
## Spec https://eips.ethereum.org/EIPS/eip-196
if r.len != 64:
return cttEVM_InvalidOutputSize
# Auto-pad with zero
var padded: array[128, byte]
padded.rawCopy(0, inputs, 0, min(inputs.len, 128))
@ -119,14 +125,12 @@ func eth_evm_ecadd*(r: var array[64, byte], inputs: openarray[byte]): CttEVMStat
let statusP = P.fromRawCoords(
x = padded.toOpenArray(0, 31),
y = padded.toOpenArray(32, 63)
)
y = padded.toOpenArray(32, 63))
if statusP != cttEVM_Success:
return statusP
let statusQ = Q.fromRawCoords(
x = padded.toOpenArray(64, 95),
y = padded.toOpenArray(96, 127)
)
y = padded.toOpenArray(96, 127))
if statusQ != cttEVM_Success:
return statusQ
@ -135,13 +139,13 @@ func eth_evm_ecadd*(r: var array[64, byte], inputs: openarray[byte]): CttEVMStat
aff.affine(R)
r.toOpenArray(0, 31).marshal(
aff.x, bigEndian
)
aff.x, bigEndian)
r.toOpenArray(32, 63).marshal(
aff.y, bigEndian
)
aff.y, bigEndian)
func eth_evm_ecmul*(r: var array[64, byte], inputs: openarray[byte]): CttEVMStatus =
return cttEVM_Success
func eth_evm_ecmul*(r: var openArray[byte], inputs: openarray[byte]): CttEVMStatus =
## Elliptic Curve multiplication on BN254_Snarks
## (also called alt_bn128 in Ethereum specs
## and bn256 in Ethereum tests)
@ -158,6 +162,7 @@ func eth_evm_ecmul*(r: var array[64, byte], inputs: openarray[byte]): CttEVMStat
## If the length is greater than 96 bytes, input is truncated to 96 bytes.
##
## Output
## - Output buffer MUST be of length 64 bytes
## - A G1 point R = [s]P
## - Status code:
## cttEVM_Success
@ -166,6 +171,9 @@ func eth_evm_ecmul*(r: var array[64, byte], inputs: openarray[byte]): CttEVMStat
##
## Spec https://eips.ethereum.org/EIPS/eip-196
if r.len != 64:
return cttEVM_InvalidOutputSize
# Auto-pad with zero
var padded: array[128, byte]
padded.rawCopy(0, inputs, 0, min(inputs.len, 128))
@ -174,8 +182,7 @@ func eth_evm_ecmul*(r: var array[64, byte], inputs: openarray[byte]): CttEVMStat
let statusP = P.fromRawCoords(
x = padded.toOpenArray(0, 31),
y = padded.toOpenArray(32, 63)
)
y = padded.toOpenArray(32, 63))
if statusP != cttEVM_Success:
return statusP
@ -205,11 +212,11 @@ func eth_evm_ecmul*(r: var array[64, byte], inputs: openarray[byte]): CttEVMStat
aff.affine(P)
r.toOpenArray(0, 31).marshal(
aff.x, bigEndian
)
aff.x, bigEndian)
r.toOpenArray(32, 63).marshal(
aff.y, bigEndian
)
aff.y, bigEndian)
return cttEVM_Success
func subgroupCheck(P: ECP_ShortW_Aff[Fp2[BN254_Snarks], G2]): bool =
## A point may be on a curve but in case the curve has a cofactor != 1
@ -289,7 +296,7 @@ func fromRawCoords(
return cttEVM_Success
func eth_evm_ecpairing*(
r: var array[32, byte], inputs: openarray[byte]): CttEVMStatus =
r: var openArray[byte], inputs: openarray[byte]): CttEVMStatus =
## Elliptic Curve pairing on BN254_Snarks
## (also called alt_bn128 in Ethereum specs
## and bn256 in Ethereum tests)
@ -300,24 +307,27 @@ func eth_evm_ecpairing*(
## - An array of [(P0, Q0), (P1, Q1), ... (Pk, Qk)] points in (G1, G2)
##
## Output
## - Output buffer MUST be of length 32 bytes
## - 0 or 1 in uint256 BigEndian representation
## - Status code:
## cttEVM_Success
## cttEVM_IntLargerThanModulus
## cttEVM_PointNotOnCurve
## cttEVM_InvalidInputLength
## cttEVM_InvalidInputSize
##
## Spec https://eips.ethereum.org/EIPS/eip-197
if r.len != 32:
return cttEVM_InvalidOutputSize
let N = inputs.len div 192
if inputs.len mod 192 != 0:
return cttEVM_InvalidInputLength
return cttEVM_InvalidInputSize
if N == 0:
# Spec: "Empty input is valid and results in returning one."
zeroMem(r.addr, r.sizeof())
zeroMem(r[0].addr, r.len-1)
r[r.len-1] = byte 1
return
return cttEVM_Success
var P{.noInit.}: ECP_ShortW_Aff[Fp[BN254_Snarks], G1]
var Q{.noInit.}: ECP_ShortW_Aff[Fp2[BN254_Snarks], G2]
@ -331,8 +341,8 @@ func eth_evm_ecpairing*(
let statusP = P.fromRawCoords(
x = inputs.toOpenArray(pos, pos+31),
y = inputs.toOpenArray(pos+32, pos+63)
)
y = inputs.toOpenArray(pos+32, pos+63))
if statusP != cttEVM_Success:
return statusP
@ -342,8 +352,8 @@ func eth_evm_ecpairing*(
x1 = inputs.toOpenArray(pos+64, pos+95),
x0 = inputs.toOpenArray(pos+96, pos+127),
y1 = inputs.toOpenArray(pos+128, pos+159),
y0 = inputs.toOpenArray(pos+160, pos+191)
)
y0 = inputs.toOpenArray(pos+160, pos+191))
if statusQ != cttEVM_Success:
return statusQ
@ -352,13 +362,118 @@ func eth_evm_ecpairing*(
foundInfinity = true
if foundInfinity: # pairing with infinity returns 1, hence no need to compute the following
zeroMem(r[0].addr, r.len-1)
r[r.len-1] = byte 1
return
return cttEVM_Success
var gt {.noinit.}: Fp12[BN254_Snarks]
acc.finish(gt)
gt.finalExp()
zeroMem(r.addr, r.sizeof())
zeroMem(r[0].addr, r.len)
if gt.isOne().bool:
r[r.len-1] = byte 1
return cttEVM_Success
func eth_evm_modexp*(r: var openArray[byte], inputs: openArray[byte]): CttEVMStatus {.noInline, tags:[Alloca, Vartime].} =
## Modular exponentiation
##
## Name: MODEXP
##
## Inputs:
## - `baseLen`: 32 bytes base integer length (in bytes)
## - `exponentLen`: 32 bytes exponent length (in bytes)
## - `modulusLen`: 32 bytes modulus length (in bytes)
## - `base`: base integer (`baseLen` bytes)
## - `exponent`: exponent (`exponentLen` bytes)
## - `modulus`: modulus (`modulusLen` bytes)
##
## Output:
## - baseᵉˣᵖᵒⁿᵉⁿᵗ (mod modulus)
## The result buffer size `r` MUST match the modulusLen
## - status code:
## cttEVM_Success
## cttEVM_InvalidInputSize if the lengths require more than 32-bit or 64-bit addressing (depending on hardware)
## cttEVM_InvalidOutputSize
##
## Spec
## Yellow Paper Appendix E
## EIP-198 - https://github.com/ethereum/EIPs/blob/master/EIPS/eip-198.md
##
## Hardware considerations:
## This procedure stack allocates a table of (16+1)*modulusLen and many stack temporaries.
## Make sure to validate gas costs and reject large inputs to bound stack usage.
# Input parse sizes
# -----------------
let
bL = BigInt[256].unmarshal(inputs.toOpenArray(0, 31), bigEndian)
eL = BigInt[256].unmarshal(inputs.toOpenArray(32, 63), bigEndian)
mL = BigInt[256].unmarshal(inputs.toOpenArray(64, 95), bigEndian)
maxSize = BigInt[256].fromUint(high(uint)) # A CPU can only address up to high(uint)
# Input validation
# -----------------
if bool(bL > maxSize):
return cttEVM_InvalidInputSize
if bool(eL > maxSize):
return cttEVM_InvalidInputSize
if bool(mL > maxSize):
return cttEVM_InvalidInputSize
let
baseLen = cast[int](bL.limbs[0])
exponentLen = cast[int](eL.limbs[0])
modulusLen = cast[int](mL.limbs[0])
if r.len != modulusLen:
return cttEVM_InvalidOutputSize
if baseLen.ceilDiv_vartime(WordBitWidth div 8) > modulusLen.ceilDiv_vartime(WordBitWidth div 8):
return cttEVM_InvalidInputSize
# Special cases
# ----------------------
if modulusLen == 0:
r.setZero()
return cttEVM_Success
if exponentLen == 0:
r.setZero()
r[r.len-1] = byte 1 # 0^0 = 1 and x^0 = 1
return cttEVM_Success
if baseLen == 0:
r.setZero()
return cttEVM_Success
# Input deserialization
# ---------------------
var baseBuf = allocStackArray(SecretWord, baseLen)
var modulusBuf = allocStackArray(SecretWord, modulusLen)
var outputBuf = allocStackArray(SecretWord, modulusLen)
template base(): untyped = baseBuf.toOpenArray(0, baseLen-1)
template modulus(): untyped = modulusBuf.toOpenArray(0, modulusLen-1)
template output(): untyped = outputBuf.toOpenArray(0, modulusLen-1)
# Inclusive stops
let baseStart = 96
let baseStop = baseStart+baseLen-1
let expStart = baseStop+1
let expStop = expStart+exponentLen-1
let modStart = expStop+1
let modStop = modStart+modulusLen-1
base.toOpenArray(0, baseLen-1).unmarshal(inputs.toOpenArray(baseStart, baseStop), WordBitWidth, bigEndian)
modulus.toOpenArray(0, modulusLen-1).unmarshal(inputs.toOpenArray(modStart, modStop), WordBitWidth, bigEndian)
template exponent(): untyped =
inputs.toOpenArray(expStart, expStop)
# Computation
# ---------------------
output.powMod_vartime(base, exponent, modulus, window = 4)
# Output serialization
# ---------------------
r.marshal(output, WordBitWidth, bigEndian)
return cttEVM_Success

View File

@ -21,7 +21,7 @@ import
# A FpDbl is a partially-reduced double-precision element of Fp
# The allowed range is [0, 2ⁿp)
# with n = w*WordBitSize
# with n = w*WordBitWidth
# and w the number of words necessary to represent p on the machine.
# Concretely a 381-bit p needs 6*64 bits limbs (hence 384 bits total)
# and so FpDbl would 768 bits.

View File

@ -12,7 +12,7 @@ import
./limbs,
./limbs_extmul,
./limbs_exgcd,
./limbs_division
../../math_arbitrary_precision/arithmetic/limbs_division
export BigInt

View File

@ -104,7 +104,7 @@ func powMont*[mBits: static int](
var scratchSpace {.noInit.}: array[scratchLen, Limbs[mBits.wordsRequired]]
powMont(a.limbs, exponent, M.limbs, one.limbs, negInvModWord, scratchSpace, spareBits)
func powMontUnsafeExponent*[mBits: static int](
func powMont_vartime*[mBits: static int](
a: var BigInt[mBits], exponent: openarray[byte],
M, one: BigInt[mBits], negInvModWord: BaseType, windowSize: static int,
spareBits: static int
@ -126,7 +126,7 @@ func powMontUnsafeExponent*[mBits: static int](
const scratchLen = if windowSize == 1: 2
else: (1 shl windowSize) + 1
var scratchSpace {.noInit.}: array[scratchLen, Limbs[mBits.wordsRequired]]
powMontUnsafeExponent(a.limbs, exponent, M.limbs, one.limbs, negInvModWord, scratchSpace, spareBits)
powMont_vartime(a.limbs, exponent, M.limbs, one.limbs, negInvModWord, scratchSpace, spareBits)
func powMont*[mBits, eBits: static int](
a: var BigInt[mBits], exponent: BigInt[eBits],
@ -147,7 +147,7 @@ func powMont*[mBits, eBits: static int](
powMont(a, expBE, M, one, negInvModWord, windowSize, spareBits)
func powMontUnsafeExponent*[mBits, eBits: static int](
func powMont_vartime*[mBits, eBits: static int](
a: var BigInt[mBits], exponent: BigInt[eBits],
M, one: BigInt[mBits], negInvModWord: BaseType, windowSize: static int,
spareBits: static int
@ -168,7 +168,7 @@ func powMontUnsafeExponent*[mBits, eBits: static int](
var expBE {.noInit.}: array[ebits.ceilDiv_vartime(8), byte]
expBE.marshal(exponent, bigEndian)
powMontUnsafeExponent(a, expBE, M, one, negInvModWord, windowSize, spareBits)
powMont_vartime(a, expBE, M, one, negInvModWord, windowSize, spareBits)
{.pop.} # inline
{.pop.} # raises no exceptions

View File

@ -372,7 +372,7 @@ func pow*(a: var FF, exponent: openarray[byte]) =
FF.getSpareBits()
)
func powUnsafeExponent*(a: var FF, exponent: BigInt) =
func pow_vartime*(a: var FF, exponent: BigInt) =
## Exponentiation modulo p
## ``a``: a field element to be exponentiated
## ``exponent``: a big integer
@ -384,14 +384,14 @@ func powUnsafeExponent*(a: var FF, exponent: BigInt) =
## - power analysis
## - timing analysis
const windowSize = 5 # TODO: find best window size for each curves
a.mres.powMontUnsafeExponent(
a.mres.powMont_vartime(
exponent,
FF.fieldMod(), FF.getMontyOne(),
FF.getNegInvModWord(), windowSize,
FF.getSpareBits()
)
func powUnsafeExponent*(a: var FF, exponent: openarray[byte]) =
func pow_vartime*(a: var FF, exponent: openarray[byte]) =
## Exponentiation modulo p
## ``a``: a field element to be exponentiated
## ``exponent``: a big integer a big integer in canonical big endian representation
@ -403,7 +403,7 @@ func powUnsafeExponent*(a: var FF, exponent: openarray[byte]) =
## - power analysis
## - timing analysis
const windowSize = 5 # TODO: find best window size for each curves
a.mres.powMontUnsafeExponent(
a.mres.powMont_vartime(
exponent,
FF.fieldMod(), FF.getMontyOne(),
FF.getNegInvModWord(), windowSize,

View File

@ -22,7 +22,7 @@ type FpDbl*[C: static Curve] = object
## Double-precision Fp element
## A FpDbl is a partially-reduced double-precision element of Fp
## The allowed range is [0, 2ⁿp)
## with n = w*WordBitSize
## with n = w*WordBitWidth
## and w the number of words necessary to represent p on the machine.
## Concretely a 381-bit p needs 6*64 bits limbs (hence 384 bits total)
## and so FpDbl would 768 bits.

View File

@ -49,7 +49,7 @@ func invsqrt_p3mod4(r: var Fp, a: Fp) =
r.invsqrt_addchain(a)
else:
r = a
r.powUnsafeExponent(Fp.getPrimeMinus3div4_BE())
r.pow_vartime(Fp.getPrimeMinus3div4_BE())
# Specialized routine for p ≡ 5 (mod 8)
# ------------------------------------------------------------
@ -113,7 +113,7 @@ func invsqrt_p5mod8(r: var Fp, a: Fp) =
when Fp.C.hasSqrtAddchain():
alpha.invsqrt_addchain_pminus5over8(alpha)
else:
alpha.powUnsafeExponent(Fp.getPrimeMinus5div8_BE())
alpha.pow_vartime(Fp.getPrimeMinus5div8_BE())
# Note: if r aliases a, for inverse square root we don't use `a` again
@ -140,7 +140,7 @@ func precompute_tonelli_shanks(a_pre_exp: var Fp, a: Fp) =
a_pre_exp.precompute_tonelli_shanks_addchain(a)
else:
a_pre_exp = a
a_pre_exp.powUnsafeExponent(Fp.C.tonelliShanks(exponent))
a_pre_exp.pow_vartime(Fp.C.tonelliShanks(exponent))
func invsqrt_tonelli_shanks_pre(
invsqrt: var Fp,

View File

@ -160,14 +160,6 @@ func isOne*(a: Limbs): SecretBool =
## Returns true if ``a`` is equal to one
a.eq(One)
func isOdd*(a: Limbs): SecretBool =
## Returns true if a is odd
SecretBool(a[0] and One)
func isEven*(a: Limbs): SecretBool =
## Returns true if a is even
not SecretBool(a[0] and One)
# Bit manipulation
# ------------------------------------------------------------

View File

@ -42,7 +42,7 @@ import
#
# ############################################################
func invModBitwidth(a: BaseType): BaseType =
func invModBitwidth*(a: BaseType): BaseType =
# Modular inverse algorithm:
# Explanation p11 "Dumas iterations" based on Newton-Raphson:
# - Cetin Kaya Koc (2017), https://eprint.iacr.org/2017/411
@ -67,7 +67,7 @@ func invModBitwidth(a: BaseType): BaseType =
for _ in 0 ..< k: # at each iteration we get the inverse mod(2^2k)
result *= 2 - a * result # x' = x(2 - ax)
func invMod2powK(M0: BaseType, k: static BaseType): BaseType =
func invMod2k(M0: BaseType, k: static BaseType): BaseType =
## Compute 1/M mod 2ᵏ
## from M[0]
# Algorithm: Cetin Kaya Koc (2017) p11, https://eprint.iacr.org/2017/411
@ -278,7 +278,7 @@ func matVecMul_shr_k_mod_M[N, E: static int](
d, e: var LimbsUnsaturated[N, E],
k: static int,
M: LimbsUnsaturated[N, E],
invMod2powK: SecretWord
invMod2k: SecretWord
) =
## Compute
##
@ -318,8 +318,8 @@ func matVecMul_shr_k_mod_M[N, E: static int](
me.cadd(q, sign_d)
me.cadd(r, sign_e)
md = md - (SignedSecretWord(invMod2powK * SecretWord(cd.lo) + SecretWord(md)) and Max)
me = me - (SignedSecretWord(invMod2powK * SecretWord(ce.lo) + SecretWord(me)) and Max)
md = md - (SignedSecretWord(invMod2k * SecretWord(cd.lo) + SecretWord(md)) and Max)
me = me - (SignedSecretWord(invMod2k * SecretWord(ce.lo) + SecretWord(me)) and Max)
# First iteration of [u v] [d] [md]
# [q r].[e] + [me].M[0]
@ -399,7 +399,7 @@ func matVecMul_shr_k[N, E: static int](t: TransitionMatrix, f, g: var LimbsUnsat
func invmodImpl[N, E](
a: var LimbsUnsaturated[N, E],
F, M: LimbsUnsaturated[N, E],
invMod2powK: SecretWord,
invMod2k: SecretWord,
k, bits: static int) =
## Modular inversion using Bernstein-Yang algorithm
## r ≡ F.a⁻¹ (mod M)
@ -425,7 +425,7 @@ func invmodImpl[N, E](
# Apply the transition matrix
# [u v] [d]
# [q r]/2ᵏ.[e] mod M
t.matVecMul_shr_k_mod_M(d, e, k, M, invMod2powK)
t.matVecMul_shr_k_mod_M(d, e, k, M, invMod2k)
# [u v] [f]
# [q r]/2ᵏ.[g]
t.matVecMul_shr_k(f, g, k)
@ -450,7 +450,7 @@ func invmod*(
var factor {.noInit.}: LimbsUnsaturated[NumUnsatWords, Excess]
m2.fromPackedRepr(M)
factor.fromPackedRepr(F)
let m0invK = SecretWord invMod2powK(BaseType M[0], k)
let m0invK = SecretWord invMod2k(BaseType M[0], k)
var a2 {.noInit.}: LimbsUnsaturated[NumUnsatWords, Excess]
a2.fromPackedRepr(a)
@ -475,7 +475,7 @@ func invmod*(
# Convert values to unsaturated repr
const m2 = LimbsUnsaturated[NumUnsatWords, Excess].fromPackedRepr(M)
const factor = LimbsUnsaturated[NumUnsatWords, Excess].fromPackedRepr(F)
const m0invK = SecretWord invMod2powK(BaseType M[0], k)
const m0invK = SecretWord invMod2k(BaseType M[0], k)
var a2 {.noInit.}: LimbsUnsaturated[NumUnsatWords, Excess]
a2.fromPackedRepr(a)
@ -805,7 +805,7 @@ func discardUnusedLimb_vartime[N, E: static int](limbsLeft: var int, f, g: var L
func invmodImpl_vartime[N, E: static int](
a: var LimbsUnsaturated[N, E],
F, M: LimbsUnsaturated[N, E],
invMod2powK: SecretWord,
invMod2k: SecretWord,
k, bits: static int) {.tags:[VarTime].} =
## **Variable-time** Modular inversion using Bernstein-Yang algorithm
## r ≡ F.a⁻¹ (mod M)
@ -830,7 +830,7 @@ func invmodImpl_vartime[N, E: static int](
# Apply the transition matrix
# [u v] [d]
# [q r]/2ᵏ.[e] mod M
t.matVecMul_shr_k_mod_M(d, e, k, M, invMod2powK)
t.matVecMul_shr_k_mod_M(d, e, k, M, invMod2k)
# [u v] [f]
# [q r]/2ᵏ.[g]
t.matVecMul_shr_k_partial(f, g, limbsLeft, k)
@ -858,7 +858,7 @@ func invmod_vartime*(
var factor {.noInit.}: LimbsUnsaturated[NumUnsatWords, Excess]
m2.fromPackedRepr(M)
factor.fromPackedRepr(F)
let m0invK = SecretWord invMod2powK(BaseType M[0], k)
let m0invK = SecretWord invMod2k(BaseType M[0], k)
var a2 {.noInit.}: LimbsUnsaturated[NumUnsatWords, Excess]
a2.fromPackedRepr(a)
@ -883,7 +883,7 @@ func invmod_vartime*(
# Convert values to unsaturated repr
const m2 = LimbsUnsaturated[NumUnsatWords, Excess].fromPackedRepr(M)
const factor = LimbsUnsaturated[NumUnsatWords, Excess].fromPackedRepr(F)
const m0invK = SecretWord invMod2powK(BaseType M[0], k)
const m0invK = SecretWord invMod2k(BaseType M[0], k)
var a2 {.noInit.}: LimbsUnsaturated[NumUnsatWords, Excess]
a2.fromPackedRepr(a)

View File

@ -36,6 +36,7 @@ when UseASM_X86_64:
func prod_comba[rLen, aLen, bLen: static int](r: var Limbs[rLen], a: Limbs[aLen], b: Limbs[bLen]) =
## Extended precision multiplication
## `r` must not alias ``a`` or ``b``
# We use Product Scanning / Comba multiplication
var t, u, v = Zero
const stopEx = min(a.len+b.len, r.len)
@ -59,7 +60,7 @@ func prod_comba[rLen, aLen, bLen: static int](r: var Limbs[rLen], a: Limbs[aLen]
for i in aLen+bLen ..< rLen:
r[i] = Zero
func prod*[rLen, aLen, bLen: static int](r: var Limbs[rLen], a: Limbs[aLen], b: Limbs[bLen]) {.inline.} =
func prod*[rLen, aLen, bLen: static int](r{.noalias.}: var Limbs[rLen], a: Limbs[aLen], b: Limbs[bLen]) {.inline.} =
## Multi-precision multiplication
## r <- a*b
##

View File

@ -46,7 +46,7 @@ when UseASM_X86_64:
# to save on code size.
# No exceptions allowed
{.push raises: [].}
{.push raises: [], checks: off.}
# Montgomery Reduction
# ------------------------------------------------------------
@ -570,7 +570,7 @@ func fromMont*(r: var Limbs, a, M: Limbs,
## with W = M.len
## and R = (2^WordBitWidth)^W
##
## Does "a * R^-1 (mod M)"
## Does "a * R^-1 (mod M)" = montMul(a, 1)
##
## This is called a Montgomery Reduction
## The Montgomery Magic Constant is µ = -1/N mod M
@ -730,9 +730,8 @@ func powMont*(
M, one: Limbs,
m0ninv: BaseType,
scratchspace: var openarray[Limbs],
spareBits: static int
) =
## Modular exponentiation r = a^exponent mod M
spareBits: static int) =
## Modular exponentiation a <- a^exponent (mod M)
## in the Montgomery domain
##
## This uses fixed-window optimization if possible
@ -773,8 +772,7 @@ func powMont*(
a, exponent, M, m0ninv,
scratchspace[0], window,
acc, acc_len, e,
spareBits
)
spareBits)
# Window lookup: we set scratchspace[1] to the lookup value.
# If the window length is 1, then it's already set.
@ -791,7 +789,7 @@ func powMont*(
scratchspace[0].mulMont(a, scratchspace[1], M, m0ninv, spareBits)
a.ccopy(scratchspace[0], SecretWord(bits).isNonZero())
func powMontUnsafeExponent*(
func powMont_vartime*(
a: var Limbs,
exponent: openarray[byte],
M, one: Limbs,
@ -799,7 +797,7 @@ func powMontUnsafeExponent*(
scratchspace: var openarray[Limbs],
spareBits: static int
) =
## Modular exponentiation r = a^exponent mod M
## Modular exponentiation a <- a^exponent (mod M)
## in the Montgomery domain
##
## Warning ⚠️ :
@ -821,8 +819,7 @@ func powMontUnsafeExponent*(
a, exponent, M, m0ninv,
scratchspace[0], window,
acc, acc_len, e,
spareBits
)
spareBits)
## Warning ⚠️: Exposes the exponent bits
if bits != 0:

View File

@ -238,6 +238,8 @@ func checkValidModulus(M: BigInt) =
const expectedMsb = M.bits-1 - WordBitWidth * (M.limbs.len - 1)
let msb = log2_vartime(BaseType(M.limbs[M.limbs.len-1]))
# This is important for the constant-time explicit modulo operation
# "reduce" and bigint division.
doAssert msb == expectedMsb, "Internal Error: the modulus must use all declared bits and only those:\n" &
" Modulus '" & M.toHex() & "' is declared with " & $M.bits &
" bits but uses " & $(msb + WordBitWidth * (M.limbs.len - 1)) & " bits."
@ -287,6 +289,12 @@ func invModBitwidth*[T: SomeUnsignedInt](a: T): T =
for _ in 0 ..< k: # at each iteration we get the inverse mod(2^2k)
result *= 2 - a * result # x' = x(2 - ax)
func negInvModWord*[T: SomeUnsignedInt or SecretWord](a: T): T =
let t = invModBitwidth(BaseType a)
{.push hint[ConvFromXtoItselfNotNeeded]: off.}
return T(-SecretWord(t))
{.pop.}
func negInvModWord*(M: BigInt): BaseType =
## Returns the Montgomery domain magic constant for the input modulus:
##
@ -299,10 +307,7 @@ func negInvModWord*(M: BigInt): BaseType =
##
## µ ≡ -1/M[0] (mod 2^64)
checkValidModulus(M)
result = invModBitwidth(BaseType M.limbs[0])
# negate to obtain the negative inverse
result = not(result) + 1
return BaseType M.limbs[0].negInvModWord()
func r_powmod(n: static int, M: BigInt): BigInt =
## Returns the Montgomery domain magic constant for the input modulus:

View File

@ -8,11 +8,6 @@
import ../../platforms/abstractions
func wordsRequired*(bits: int): int {.compileTime.} =
## Compute the number of limbs required
# from the **announced** bit length
bits.ceilDiv_vartime(WordBitWidth)
type
BigInt*[bits: static int] = object
## Fixed-precision big integer
@ -29,24 +24,6 @@ type
debug:
func toHex*(a: SecretWord): string =
const hexChars = "0123456789abcdef"
const L = 2*sizeof(SecretWord)
result = newString(2 + L)
result[0] = '0'
result[1] = 'x'
var a = a
for j in countdown(result.len-1, 0):
result[j] = hexChars.secretLookup(a and SecretWord 0xF)
a = a shr 4
func toString*(a: Limbs): string =
result = "["
result.add " " & toHex(a[0])
for i in 1 ..< a.len:
result.add ", " & toHex(a[i])
result.add "]"
func `$`*(a: BigInt): string =
result = "BigInt["
result.add $BigInt.bits

View File

@ -19,15 +19,9 @@ import
# Support files for testing Elliptic Curve arithmetic
# ------------------------------------------------------------------------------
iterator unpack(scalarByte: byte): bool =
yield bool((scalarByte and 0b10000000) shr 7)
yield bool((scalarByte and 0b01000000) shr 6)
yield bool((scalarByte and 0b00100000) shr 5)
yield bool((scalarByte and 0b00010000) shr 4)
yield bool((scalarByte and 0b00001000) shr 3)
yield bool((scalarByte and 0b00000100) shr 2)
yield bool((scalarByte and 0b00000010) shr 1)
yield bool( scalarByte and 0b00000001)
iterator unpackBE(scalarByte: byte): bool =
for i in countdown(7, 0):
yield bool((scalarByte shr i) and 1)
func scalarMul_doubleAdd_vartime*[EC](P: var EC, scalar: BigInt) {.tags:[VarTime].} =
## **Variable-time** Elliptic Curve Scalar Multiplication
@ -46,7 +40,7 @@ func scalarMul_doubleAdd_vartime*[EC](P: var EC, scalar: BigInt) {.tags:[VarTime
P.setInf()
for scalarByte in scalarCanonical:
for bit in unpack(scalarByte):
for bit in unpackBE(scalarByte):
P.double()
if bit:
P += Paff

View File

@ -101,7 +101,7 @@ func powSquarings[F](
return (k, bits)
func powUnsafeExponent[F](
func pow_vartime[F](
a: var F,
exponent: openArray[byte],
scratchspace: var openArray[F]) =
@ -136,7 +136,7 @@ func powUnsafeExponent[F](
scratchspace[0].prod(a, scratchspace[1])
a = scratchspace[0]
func powUnsafeExponent*[F](
func pow_vartime*[F](
a: var F,
exponent: openArray[byte],
window: static int
@ -159,9 +159,9 @@ func powUnsafeExponent*[F](
const scratchLen = if window == 1: 2
else: (1 shl window) + 1
var scratchSpace {.noInit.}: array[scratchLen, typeof(a)]
a.powUnsafeExponent(exponent, scratchspace)
a.pow_vartime(exponent, scratchspace)
func powUnsafeExponent*[F; bits: static int](
func pow_vartime*[F; bits: static int](
a: var F,
exponent: BigInt[bits],
window: static int
@ -183,4 +183,4 @@ func powUnsafeExponent*[F; bits: static int](
## - timing analysis
var expBE {.noInit.}: array[bits.ceilDiv_vartime(8), byte]
expBE.marshal(exponent, bigEndian)
a.powUnsafeExponent(expBE, window)
a.pow_vartime(expBE, window)

View File

@ -80,7 +80,7 @@ func millerLoopGenericBLS12*[C](
func finalExpGeneric[C: static Curve](f: var Fp12[C]) =
## A generic and slow implementation of final exponentiation
## for sanity checks purposes.
f.powUnsafeExponent(C.pairing(finalexponent), window = 3)
f.pow_vartime(C.pairing(finalexponent), window = 3)
func pairing_bls12_reference*[C](
gt: var Fp12[C],

View File

@ -92,7 +92,7 @@ func millerLoopGenericBN*[C](
func finalExpGeneric[C: static Curve](f: var Fp12[C]) =
## A generic and slow implementation of final exponentiation
## for sanity checks purposes.
f.powUnsafeExponent(C.pairing(finalexponent), window = 3)
f.pow_vartime(C.pairing(finalexponent), window = 3)
func pairing_bn_reference*[C](
gt: var Fp12[C],

View File

@ -63,12 +63,12 @@ func millerLoopBW6_761_naive[C](
func finalExpGeneric[C: static Curve](f: var Fp6[C]) =
## A generic and slow implementation of final exponentiation
## for sanity checks purposes.
f.powUnsafeExponent(C.pairing(finalexponent), window = 3)
f.pow_vartime(C.pairing(finalexponent), window = 3)
func finalExpHard_BW6_761*[C: static Curve](f: var Fp6[C]) =
## A generic and slow implementation of final exponentiation
## for sanity checks purposes.
f.powUnsafeExponent(C.pairing(finalexponent_hard), window = 3)
f.pow_vartime(C.pairing(finalexponent_hard), window = 3)
# Optimized pairing implementation
# ----------------------------------------------------------------

View File

@ -0,0 +1,11 @@
# Arbitrary-precision math backend
While cryptographic protocols allow Constantine to focus on named elliptic curves
and so fixed precision arithmetic, some protocols might need arbitrary-precision.
For example, this can cover can cover:
- Modular exponentiation https://eips.ethereum.org/EIPS/eip-198
- RSA (though in practice RSA2048, RSA3072 and RSA 4096 are likely the only sizes needed)
- primality testing
And arbitrary precision elliptic curves would allow implementing the Lenstra elliptic curve factorization method

View File

@ -0,0 +1,202 @@
# 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
# Internal
../../platforms/[abstractions, allocs],
../../math/config/precompute,
./limbs_views,
./limbs_montgomery,
./limbs_mod2k,
./limbs_multiprec,
./limbs_extmul,
./limbs_division
# No exceptions allowed
{.push raises: [], checks: off.}
# ############################################################
#
# Arbitrary-precision integers
#
# ############################################################
#
# We only implement algorithms that work on views allocated by the caller
# as providing a full-blown arbitrary-precision library is not the goal.
# As the bigint sizes are relatively constrained
# in protocols we implement (4096 bits for RSA, 8192 bit s for the Ethereum EVM),
# this allows us to avoid heap allocations, which simplifies reentrancy and thread-safety.
# TODO: choose between:
# - openArray + countLeadingZeros
# - bits + wordsRequired
# for parameter passing
# This also impacts ergonomics of allocStackArray
#
# Also need to take into account constant-time for RSA
# i.e. countLeadingZeros can only be done on public moduli.
func powOddMod_vartime*(
r: var openArray[SecretWord],
a: openArray[SecretWord],
exponent: openArray[byte],
M: openArray[SecretWord],
window: int) {.noInline, tags:[Alloca, VarTime].} =
## r <- a^exponent (mod M) with M odd
## assumes a < M
##
## At least (2^window + 4) * sizeof(M) stack space will be allocated.
debug:
doAssert bool(M.isOdd())
let aBits = a.getBits_vartime()
let mBits = M.getBits_vartime()
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))
# 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
# TODO: fix https://github.com/mratsim/constantine/issues/241
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)
block:
var oneMontBuf = allocStackArray(SecretWord, L)
template oneMont: untyped = oneMontBuf.toOpenArray(0, L-1)
oneMont.oneMont_vartime(M.toOpenArray(0, L-1))
let scratchLen = L * ((1 shl window) + 1)
var scratchSpace = allocStackArray(SecretWord, scratchLen)
rMont.LimbsViewMut.powMont_vartime(
exponent, M.view(), LimbsViewConst oneMontBuf,
m0ninv, LimbsViewMut scratchSpace, scratchLen, mBits)
r.view().fromMont(LimbsViewConst rMont, M.view(), m0ninv, mBits)
func powMod_vartime*(
r: var openArray[SecretWord],
a: openArray[SecretWord],
exponent: openArray[byte],
M: openArray[SecretWord],
window: int) {.noInline, tags:[Alloca, VarTime].} =
## r <- a^exponent (mod M) with M odd
## assumes a < exponent
##
## At least (2^window + 4) * sizeof(M) stack space will be allocated.
# Special cases: early returns
# -------------------------------------------------------------------
let mBits = M.getBits_vartime()
if mBits < 2: # Check if modulus = 0 or 1
r.setZero()
return
let eBits = exponent.getBits_vartime()
if eBits == 0: # Check if exponent == 0
r.setOne() # a⁰ = 1 and 0⁰ = 1
return
let aBits = a.getBits_vartime()
if aBits < 2: # Check if a == 0 or a == 1
r[0] = a[0]
for i in 1 ..< r.len:
r[i] = Zero
return
# Odd modulus
# -------------------------------------------------------------------
if M.isOdd().bool:
r.powOddMod_vartime(a, exponent, M, window)
return
# Even modulus
# -------------------------------------------------------------------
var i = 0
# Find the first non-zero word from right-to-left. (a != 0)
while i < M.len-1:
if bool(M[i] != Zero):
break
i += 1
let ctz = int(countTrailingZeroBits_vartime(BaseType M[i])) +
WordBitWidth*i
# Even modulus: power of two (mod 2ᵏ)
# -------------------------------------------------------------------
if mBits-ctz == 1: # The modulus is a power of 2
r.powMod2k_vartime(a, exponent, k = uint mBits)
return
# Even modulus: general case
# -------------------------------------------------------------------
#
# We split exponentiation aᵉ (mod M)
# into a₁ = aᵉ (mod q)
# and a₂ = aᵉ (mod 2ᵏ)
# with M = q.2ᵏ
# and we recombine the results using the Chinese Remainder Theorem.
# following
# Montgomery reduction with even modulus
# Çetin Kaya Koç, 1994
# https://cetinkayakoc.net/docs/j34.pdf
let qBits = mBits-ctz
let pBits = 1+ctz
# let qWords = qBits.wordsRequired() # TODO: use minimum size for q
let pWords = pBits.wordsRequired()
var qBuf = allocStackArray(SecretWord, M.len)
var a1Buf = allocStackArray(SecretWord, M.len)
var a2Buf = allocStackArray(SecretWord, pWords)
var yBuf = allocStackArray(SecretWord, pWords)
var qInv2kBuf = allocStackArray(SecretWord, pWords)
template q: untyped = qBuf.toOpenArray(0, M.len-1)
template a1: untyped = a1Buf.toOpenArray(0, M.len-1)
template a2: untyped = a2Buf.toOpenArray(0, pWords-1)
template y: untyped = yBuf.toOpenArray(0, pWords-1)
template qInv2k: untyped = qInv2kBuf.toOpenArray(0, pWords-1)
q.shiftRight_vartime(M, ctz)
a1.powOddMod_vartime(a, exponent, q, window)
a2.powMod2k_vartime(a, exponent, k = uint ctz)
block:
let min = min(pWords, M.len)
for i in 0 ..< min:
qInv2k[i] = q[i]
for i in min ..< pWords:
qInv2k[i] = Zero
qInv2k.invMod2k_vartime(uint ctz)
y.submod2k_vartime(a2, a1, uint ctz)
y.mulmod2k_vartime(y, qInv2k, uint ctz)
var qyBuf = allocStackArray(SecretWord, M.len)
template qy: untyped = qyBuf.toOpenArray(0, M.len-1)
qy.prod(q, y)
discard r.addMP(qy, a1)

View File

@ -6,7 +6,10 @@
# * 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
import
../../platforms/abstractions,
./limbs_views,
./limbs_fixedprec
# No exceptions allowed
{.push raises: [].}
@ -22,107 +25,6 @@ import ../../platforms/abstractions
# we use type-erased procedures, instead of instantiating
# one per number of limbs combination
# Type-erasure
# ------------------------------------------------------------
type
LimbsView = ptr UncheckedArray[SecretWord]
## Type-erased fixed-precision limbs
##
## This type mirrors the Limb type and is used
## for some low-level computation API
## This design
## - avoids code bloat due to generic monomorphization
## otherwise limbs routines would have an instantiation for
## each number of words.
##
## Accesses should be done via BigIntViewConst / BigIntViewConst
## to have the compiler check for mutability
# "Indirection" to enforce pointer types deep immutability
LimbsViewConst = distinct LimbsView
## Immutable view into the limbs of a BigInt
LimbsViewMut = distinct LimbsView
## Mutable view into a BigInt
LimbsViewAny = LimbsViewConst or LimbsViewMut
# Deep Mutability safety
# ------------------------------------------------------------
template view(a: Limbs): LimbsViewConst =
## Returns a borrowed type-erased immutable view to a bigint
LimbsViewConst(cast[LimbsView](a.unsafeAddr))
template view(a: var Limbs): LimbsViewMut =
## Returns a borrowed type-erased mutable view to a mutable bigint
LimbsViewMut(cast[LimbsView](a.addr))
template `[]`*(v: LimbsViewConst, limbIdx: int): SecretWord =
LimbsView(v)[limbIdx]
template `[]`*(v: LimbsViewMut, limbIdx: int): var SecretWord =
LimbsView(v)[limbIdx]
template `[]=`*(v: LimbsViewMut, limbIdx: int, val: SecretWord) =
LimbsView(v)[limbIdx] = val
# Copy
# ------------------------------------------------------------
func copyWords(
a: LimbsViewMut, startA: int,
b: LimbsViewAny, startB: int,
numWords: int
) =
## Copy a slice of B into A. This properly deals
## with overlaps when A and B are slices of the same buffer
if startA > startB:
for i in countdown(numWords-1, 0):
a[startA+i] = b[startB+i]
else:
for i in 0 ..< numWords:
a[startA+i] = b[startB+i]
# Type-erased add-sub
# ------------------------------------------------------------
func cadd(a: LimbsViewMut, b: LimbsViewAny, ctl: SecretBool, len: int): Carry =
## Type-erased conditional addition
## Returns the carry
##
## if ctl is true: a <- a + b
## if ctl is false: a <- a
## The carry is always computed whether ctl is true or false
##
## Time and memory accesses are the same whether a copy occurs or not
result = Carry(0)
var sum: SecretWord
for i in 0 ..< len:
addC(result, sum, a[i], b[i], result)
ctl.ccopy(a[i], sum)
func csub(a: LimbsViewMut, b: LimbsViewAny, ctl: SecretBool, len: int): Borrow =
## Type-erased conditional addition
## Returns the borrow
##
## if ctl is true: a <- a - b
## if ctl is false: a <- a
## The borrow is always computed whether ctl is true or false
##
## Time and memory accesses are the same whether a copy occurs or not
result = Borrow(0)
var diff: SecretWord
for i in 0 ..< len:
subB(result, diff, a[i], b[i], result)
ctl.ccopy(a[i], diff)
# Modular reduction
# ------------------------------------------------------------
func numWordsFromBits(bits: int): int {.inline.} =
const divShiftor = log2_vartime(uint32(WordBitWidth))
result = (bits + WordBitWidth - 1) shr divShiftor
func shlAddMod_estimate(a: LimbsViewMut, aLen: int,
c: SecretWord, M: LimbsViewConst, mBits: int
): tuple[neg, tooBig: SecretBool] =
@ -136,7 +38,7 @@ func shlAddMod_estimate(a: LimbsViewMut, aLen: int,
# Aliases
# ----------------------------------------------------------------------
let MLen = numWordsFromBits(mBits)
let MLen = wordsRequired(mBits)
# Captures aLen and MLen
template `[]`(v: untyped, limbIdxFromEnd: BackwardsIndex): SecretWord {.dirty.}=
@ -190,10 +92,7 @@ func shlAddMod_estimate(a: LimbsViewMut, aLen: int,
subB(borrow, a[i], a[i], qp_lo, Borrow(0))
carry += SecretWord(borrow) # Adjust if borrow
over_p = mux(
a[i] == M[i], over_p,
a[i] > M[i]
)
over_p = mux(a[i] == M[i], over_p, a[i] > M[i])
# Fix quotient, the true quotient is either q-1, q or q+1
#
@ -221,6 +120,11 @@ func shlAddMod(a: LimbsViewMut, aLen: int,
let R = mBits and (WordBitWidth - 1)
# (hi, lo) = a * 2^64 + c
if R == 0:
var q, r: SecretWord
div2n1n(q, r, a[0], c, M[0]) # (hi, lo) mod M
a[0] = r
else:
let hi = (a[0] shl (WordBitWidth-R)) or (c shr R)
let lo = c shl (WordBitWidth-R)
let m0 = M[0] shl (WordBitWidth-R)
@ -236,12 +140,14 @@ func shlAddMod(a: LimbsViewMut, aLen: int,
discard a.cadd(M, ctl = neg, aLen)
discard a.csub(M, ctl = tooBig, aLen)
func reduce(r: LimbsViewMut,
func reduce*(r: LimbsViewMut,
a: LimbsViewAny, aBits: int,
M: LimbsViewConst, mBits: int) =
## Reduce `a` modulo `M` and store the result in `r`
let aLen = numWordsFromBits(aBits)
let mLen = numWordsFromBits(mBits)
##
## The modulus `M` most-significant bit at `mBits` MUST be set.
let aLen = wordsRequired(aBits)
let mLen = wordsRequired(mBits)
let rLen = mLen
if aBits < mBits:
@ -269,6 +175,8 @@ func reduce*[aLen, mLen](r: var Limbs[mLen],
## Reduce `a` modulo `M` and store the result in `r`
##
## This uses constant-time division
##
## The modulus `M` most-significant bit at `mBits` MUST be set.
# This is implemented via type-erased indirection to avoid
# a significant amount of code duplication if instantiated for
# varying bitwidth.

View File

@ -0,0 +1,44 @@
# 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
# Internal
../../platforms/[abstractions, allocs]
func prod_comba(r: var openArray[SecretWord], a, b: openArray[SecretWord]) {.noInline, tags: [Alloca].} =
## Extended precision multiplication
# We use Product Scanning / Comba multiplication
var t, u, v = Zero
let stopEx = min(a.len+b.len, 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(b.len-1, i)
let ia = i - ib
for j in 0 ..< min(a.len - ia, ib+1):
mulAcc(t, u, v, a[ia+j], b[ib-j])
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 prod*(r: var openArray[SecretWord], a, b: openArray[SecretWord]) {.inline.}=
## Extended precision multiplication
r.prod_comba(a, b)

View File

@ -0,0 +1,74 @@
# 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,
./limbs_views
# No exceptions allowed
{.push raises: [].}
# ############################################################
#
# Fixed-precision type-erased arithmetic
#
# ############################################################
#
# This file implements non-performance critical type-erased
# fixed-precision primitives, i.e. it assumes that
# inputs use the same number of limbs.
#
# The goal is to avoid code-size explosion for procedures
# that are not in a hot path and don't benefits from staticFor loops
# like division or modular reduction.
# Comparison
# ------------------------------------------------------------
func lt*(a, b: distinct LimbsViewAny, len: int): SecretBool =
## Returns true if a < b
## Comparison is constant-time
var diff: SecretWord
var borrow: Borrow
for i in 0 ..< len:
subB(borrow, diff, a[i], b[i], borrow)
result = (SecretBool)(borrow)
# Type-erased add-sub
# ------------------------------------------------------------
func cadd*(a: LimbsViewMut, b: LimbsViewAny, ctl: SecretBool, len: int): Carry =
## Type-erased conditional addition
## Returns the carry
##
## if ctl is true: a <- a + b
## if ctl is false: a <- a
## The carry is always computed whether ctl is true or false
##
## Time and memory accesses are the same whether a copy occurs or not
result = Carry(0)
var sum: SecretWord
for i in 0 ..< len:
addC(result, sum, a[i], b[i], result)
ctl.ccopy(a[i], sum)
func csub*(a: LimbsViewMut, b: LimbsViewAny, ctl: SecretBool, len: int): Borrow =
## Type-erased conditional addition
## Returns the borrow
##
## if ctl is true: a <- a - b
## if ctl is false: a <- a
## The borrow is always computed whether ctl is true or false
##
## Time and memory accesses are the same whether a copy occurs or not
result = Borrow(0)
var diff: SecretWord
for i in 0 ..< len:
subB(result, diff, a[i], b[i], result)
ctl.ccopy(a[i], diff)

View File

@ -0,0 +1,48 @@
# 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
# Internal
../../platforms/abstractions,
./limbs_multiprec
# ############################################################
#
# Multi-precision modular arithmetic
#
# ############################################################
func addmod_vartime*(r: var openArray[SecretWord], a, b, M: openArray[SecretWord]) =
## r <- a+b (mod M)
## assumes a and b are in the range [0, M)
debug:
doAssert r.len == M.len
var tBuf = allocStackArray(SecretWord, r.len)
template t: untyped = tBuf.toOpenArray(0, r.len-1)
let overflow = t.addMP(a, b)
if overflow:
# t <- a+b overflowed so it is greater than M.
discard r.subMP(t, M)
return
# Operation didn't overflow in an extra limb but r can still be greater than M
let underflow = r.subMP(t, M)
# r <- t-M
# If there is an underflow t < M, t has the correct result
# if there isn't an underflow, t >= M, r has the correct result
if underflow:
for i in 0 ..< r.len:
r[i] = t[i]
func doublemod_vartime*(r: var openArray[SecretWord], a, M: openArray[SecretWord]) {.inline.} =
## r <- 2a (mod M)
r.addmod_vartime(a, a, M)

View File

@ -0,0 +1,194 @@
# 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
# Internal
../../platforms/abstractions,
../../math/arithmetic/limbs_exgcd,
./limbs_views,
./limbs_extmul,
./limbs_multiprec
# No exceptions allowed
{.push raises: [], checks: off.}
func mod2k_vartime*(a: var openArray[SecretWord], k: uint) =
## a <- a (mod 2ᵏ)
const SlotShift = log2_vartime(WordBitWidth.uint32)
const SelectMask = WordBitWidth - 1
let hiIndex = k.int shr SlotShift
if a.len <= hiIndex:
return
let bitPos = k and SelectMask
if bitPos != 0:
let mask = (One shl bitPos) - One
a[hiIndex] = a[hiIndex] and mask
else:
a[hiIndex] = Zero
for i in hiIndex+1 ..< a.len:
a[i] = Zero
func submod2k_vartime*(r{.noAlias.}: var openArray[SecretWord], a, b: openArray[SecretWord], k: uint) =
## r <- a - b (mod 2ᵏ)
debug:
const SlotShift = log2_vartime(WordBitWidth.uint32)
doAssert r.len >= k.int shr SlotShift, block:
"r.len: " & $r.len & "\n" &
"k: " & $k & "\n" &
"k/WordBitWidth: " & $(k.int shr SlotShift)
# We can compute (mod 2ʷ) with w >= k
# Hence we truncate the substraction to the next multiple of the word size
template trunc(x: openArray[SecretWord]): openArray[SecretWord] =
x.toOpenArray(0, k.int.wordsRequired()-1)
if a.len >= b.len:
let underflow {.used.} = r.subMP(a.trunc(), b.trunc())
else:
let underflow {.used.} = r.subMP(b.trunc(), a.trunc())
r.neg()
r.mod2k_vartime(k)
func mulmod2k_vartime*(r: var openArray[SecretWord], a, b: openArray[SecretWord], k: uint) {.inline.} =
## r <- a*b (mod 2ᵏ)
r.prod(a, b)
r.mod2k_vartime(k)
iterator unpackLE(scalarByte: byte): bool =
for i in 0 ..< 8:
yield bool((scalarByte shr i) and 1)
func powMod2k_vartime*(
r{.noAlias.}: var openArray[SecretWord],
a{.noAlias.}: openArray[SecretWord],
exponent: openArray[byte], k: uint) {.noInline, tags: [Alloca].} =
## r <- a^exponent (mod 2ᵏ)
##
## Requires:
## - r.len > 0
## - r.len <= a.len
## - r.len >= ceilDiv(k, WordBitWidth) = (k+63)/64
## - r and a don't alias
# Fast special cases:
# 1. if a is even, it can be represented as a = 2b
# if exponent e is greater than k, e = k+n
# we have r ≡ aᵉ (mod 2ᵏ) ≡ (2b)ᵏ⁺ⁿ (mod 2ᵏ)
# ≡ 2ᵏ.2ⁿ.bᵏ⁺ⁿ (mod 2ᵏ)
# ≡ 0 (mod 2ᵏ)
# 2. if a is odd, a and 2ᵏ are coprime
# we can apply the Euler's totient theorem (https://en.wikipedia.org/wiki/Euler%27s_theorem
# i.e. aᵠ⁽²^ᵏ⁾ ≡ 1 (mod 2ᵏ)
# with
# - ψ(n), the Euler's totient function, the count of coprimes in [0, n)
# ψ(2ᵏ) = 2ᵏ⁻¹ as half the number (i.e. the odd numbers) are coprimes
# with a power of 2.
# - e' = e (mod ψ(2ᵏ))
# aᵉ (mod 2ᵏ) ≡ aᵉ' (mod 2ᵏ)
#
# The remaining case is when a is even
# and exponent < 2ᵏ⁻¹
#
# We use LSB to MSB square-and-multiply algorithm
# with early stopping when we reach ψ(2ᵏ) if a is odd
for i in 0 ..< r.len:
r[i] = Zero
let msb = getMSB_vartime(exponent)
if msb == -1: # exponent is 0
r[0] = One # x⁰ = 1, even for 0⁰
return
if a.isEven().bool and # if a is even
1+msb >= k.int: # The msb of a n-bit integer is at n-1
return # r ≡ aᵉ (mod 2ᵏ) ≡ (2b)ᵏ⁺ⁿ (mod 2ᵏ) ≡ 2ᵏ.2ⁿ.bᵏ⁺ⁿ (mod 2ᵏ) ≡ 0 (mod 2ᵏ)
var bitsLeft = msb+1
if a.isOdd().bool and # if a is odd
int(k-1) < bitsLeft:
bitsLeft = int(k-1) # Euler's totient acceleration
r[0] = One
var sBuf = allocStackArray(SecretWord, r.len)
template s: untyped = sBuf.toOpenArray(0, r.len-1)
for i in 0 ..< r.len:
# range [r.len, a.len) will be truncated (mod 2ᵏ)
sBuf[i] = a[i]
# TODO: sliding window
for i in countdown(exponent.len-1, 0):
for bit in unpackLE(exponent[i]):
if bit:
r.mulmod2k_vartime(r, s, k)
s.mulmod2k_vartime(s, s, k)
bitsLeft -= 1
if bitsLeft == 0:
return
func invModBitwidth(a: SecretWord): SecretWord {.borrow.}
## Inversion a⁻¹ (mod 2³²) or a⁻¹ (mod 2⁶⁴)
func invMod2k_vartime*(a: var openArray[SecretWord], k: uint) {.noInline, tags: [Alloca].} =
## Inversion a⁻¹ (mod 2ᵏ)
## with 2ᵏ a multi-precision integer.
#
# Algorithm:
# - Dumas iteration based on Newton-Raphson (see litterature in invModBitwidth)
# ax ≡ 1 (mod 2ᵏ) <=> ax(2 - ax) ≡ 1 (mod 2²ᵏ)
# which grows in O(log(log(a)))
# - start with a seed inverse a'⁻¹ (mod 2ⁿ)
# we can start with 2³² or 2⁶⁴
# - Double the number of correct bits at each Dumas iteration
# - once n >= k, reduce mod 2ᵏ
var x = allocStackArray(SecretWord, a.len)
var t = allocStackArray(SecretWord, a.len)
var u = allocStackArray(SecretWord, a.len)
x[0] = a[0].invModBitwidth()
for i in 1 ..< a.len:
x[i] = Zero
var correctWords = 1
while correctWords.uint*WordBitWidth < k:
# x *= 2-ax
let words = 2*correctWords
t.toOpenArray(0, words-1)
.mulmod2k_vartime(
x.toOpenArray(0, correctWords-1),
a.toOpenArray(0, words-1),
words.uint*WordBitWidth)
u.toOpenArray(0, words-1)
.submod2k_vartime(
[SecretWord 2],
t.toOpenArray(0, words-1),
words.uint*WordBitWidth)
x.toOpenArray(0, words-1)
.mulmod2k_vartime(
x.toOpenArray(0, correctWords-1),
u.toOpenArray(0, words-1),
words.uint*WordBitWidth)
correctWords = words
x.toOpenArray(0, a.len-1).mod2k_vartime(k)
for i in 0 ..< a.len:
a[i] = x[i]

View File

@ -0,0 +1,420 @@
# 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
# Internal
../../platforms/[abstractions, allocs, bithacks],
./limbs_views,
./limbs_mod,
./limbs_fixedprec
# No exceptions allowed
{.push raises: [], checks: off.}
# ############################################################
#
# Arbitrary-precision Montgomery Arithmetic
#
# ############################################################
# 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]) =
## Returns 1 in Montgomery domain:
r.r_powmod_vartime(M, 1)
func r2_vartime*(r: var openArray[SecretWord], M: openArray[SecretWord]) =
## 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)
# Montgomery multiplication
# ------------------------------------------
func mulMont_FIPS*(
r: LimbsViewMut,
a, b: distinct LimbsViewAny,
M: LimbsViewConst,
m0ninv: SecretWord,
mBits: int,
skipFinalSub: static bool = false) {.noInline, tags:[Alloca].} =
## Montgomery Multiplication using Finely Integrated Product Scanning (FIPS)
##
## This maps
## - [0, 2p) -> [0, 2p) with skipFinalSub
## - [0, 2p) -> [0, p) without
##
## skipFinalSub skips the final substraction step.
# - Architectural Enhancements for Montgomery
# Multiplication on Embedded RISC Processors
# Johann Großschädl and Guy-Armand Kamendje, 2003
# https://pure.tugraz.at/ws/portalfiles/portal/2887154/ACNS2003_AEM.pdf
#
# - New Speed Records for Montgomery Modular
# Multiplication on 8-bit AVR Microcontrollers
# Zhe Liu and Johann Großschädl, 2013
# https://eprint.iacr.org/2013/882.pdf
let L = wordsRequired(mBits)
var z = LimbsViewMut allocStackArray(SecretWord, L)
z.setZero(L)
var t, u, v = Zero
for i in 0 ..< L:
for j in 0 ..< i:
mulAcc(t, u, v, a[j], b[i-j])
mulAcc(t, u, v, z[j], M[i-j])
mulAcc(t, u, v, a[i], b[0])
z[i] = v * m0ninv
mulAcc(t, u, v, z[i], M[0])
v = u
u = t
t = Zero
for i in L ..< 2*L:
for j in i-L+1 ..< L:
mulAcc(t, u, v, a[j], b[i-j])
mulAcc(t, u, v, z[j], M[i-j])
z[i-L] = v
v = u
u = t
t = Zero
when not skipFinalSub:
discard z.csub(M, v.isNonZero() or not(z.lt(M, L)), L)
r.copyWords(0, z, 0, L)
# Montgomery conversions
# ------------------------------------------
func fromMont*(r: LimbsViewMut, a: LimbsViewAny, M: LimbsViewConst,
m0ninv: SecretWord, mBits: int) {.noInline, tags:[Alloca].} =
## Transform a bigint ``a`` from it's Montgomery N-residue representation (mod N)
## to the regular natural representation (mod N)
##
## with W = M.len
## and R = (2^WordBitWidth)^W
##
## Does "a * R^-1 (mod M)" = montMul(a, 1)
##
## This is called a Montgomery Reduction
## The Montgomery Magic Constant is µ = -1/N mod M
## is used internally and can be precomputed with m0ninv(Curve)
let N = wordsRequired(mBits)
var t = LimbsViewMut allocStackArray(SecretWord, N)
t.copyWords(0, a, 0, N)
for i in 0 ..< N:
let m = t[0] * m0ninv
var C, lo: SecretWord
muladd1(C, lo, m, M[0], t[0])
for j in 1 ..< N:
muladd2(C, t[j-1], m, M[j], C, t[j])
t[N-1] = C
discard t.csub(M, not(t.lt(M, N)), N)
r.copyWords(0, t, 0, N)
func getMont*(r: LimbsViewMut, a: LimbsViewAny, M, r2modM: LimbsViewConst,
m0ninv: SecretWord, mBits: int) {.inline.} =
## Transform a bigint ``a`` from it's natural representation (mod N)
## to a the Montgomery n-residue representation
##
## Montgomery-Multiplication - based
##
## with W = M.len
## and R = (2^WordBitWidth)^W
##
## Does "a * R (mod M)"
##
## `a`: The source BigInt in the natural representation. `a` in [0, N) range
## `M`: The field modulus. M must be odd.
## `r2modM`: 2^WordBitWidth mod `M`. Can be precomputed with `r2mod` function
##
## Important: `r` is overwritten
## The result `r` buffer size MUST be at least the size of `M` buffer
# Reference: https://eprint.iacr.org/2017/1057.pdf
mulMont_FIPS(r, a, r2ModM, M, m0ninv, mBits)
# Montgomery Modular Exponentiation
# ------------------------------------------
# We use fixed-window based exponentiation
# that is constant-time: i.e. the number of multiplications
# does not depend on the number of set bits in the exponents
# those are always done and conditionally copied.
#
# The exponent MUST NOT be private data (until audited otherwise)
# - Power attack on RSA, https://www.di.ens.fr/~fouque/pub/ches06.pdf
# - Flush-and-reload on Sliding window exponentiation: https://tutcris.tut.fi/portal/files/8966761/p1639_pereida_garcia.pdf
# - Sliding right into disaster, https://eprint.iacr.org/2017/627.pdf
# - Fixed window leak: https://www.scirp.org/pdf/JCC_2019102810331929.pdf
# - Constructing sliding-windows leak, https://easychair.org/publications/open/fBNC
#
# For pairing curves, this is the case since exponentiation is only
# used for inversion via the Little Fermat theorem.
# For RSA, some exponentiations uses private exponents.
#
# Note:
# - Implementation closely follows Thomas Pornin's BearSSL
# - Apache Milagro Crypto has an alternative implementation
# that is more straightforward however:
# - the exponent hamming weight is used as loop bounds
# - the baseᵏ is stored at each index of a temp table of size k
# - the baseᵏ to use is indexed by the hamming weight
# of the exponent, leaking this to cache attacks
# - in contrast BearSSL touches the whole table to
# hide the actual selection
template checkPowScratchSpaceLen(bufLen, wordLen: int) =
## Checks that there is a minimum of scratchspace to hold the temporaries
debug:
assert bufLen >= 2*wordLen, "Internal Error: the scratchspace for powmod should be equal or greater than 2"
func getWindowLen(bufLen, wordLen: int): uint =
## Compute the maximum window size that fits in the scratchspace buffer
checkPowScratchSpaceLen(bufLen, wordLen)
result = 5
while ((1 shl result) + 1)*wordLen > bufLen:
dec result
func powMontPrologue(
a: LimbsViewMut, M, one: LimbsViewConst,
m0ninv: SecretWord,
scratchspace: LimbsViewMut,
scratchLen: int,
mBits: int): uint {.tags:[Alloca].} =
## 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(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)
func powMontSquarings(
a: LimbsViewMut,
exponent: openarray[byte],
M: LimbsViewConst,
m0ninv: SecretWord,
mBits: int,
tmp: LimbsViewMut,
window: uint,
acc, acc_len: var uint,
e: var int): tuple[k, bits: uint] {.inline.}=
## Squaring step of exponentiation by squaring
## Get the next k bits in range [1, window)
## Square k times
## Returns the number of squarings done and the corresponding bits
##
## Updates iteration variables and accumulators
# Due to the high number of parameters,
# forcing this inline actually reduces the code size
#
# ⚠️: Extreme care should be used to not leak
# the exponent bits nor its real bitlength
# i.e. if the exponent is zero but encoded in a
# 256-bit integer, only "256" should leak
# as for some application like RSA
# the exponent might be the user secret key.
# Get the next bits
# acc/acc_len must be uint to avoid Nim runtime checks leaking bits
# acc/acc_len must be uint to avoid Nim runtime checks leaking bits
# e is public
var k = window
if acc_len < window:
if e < exponent.len:
acc = (acc shl 8) or exponent[e].uint
inc e
acc_len += 8
else: # Drained all exponent bits
k = acc_len
let bits = (acc shr (acc_len - k)) and ((1'u32 shl k) - 1)
acc_len -= k
# We have k bits and can do k squaring
for i in 0 ..< k:
a.mulMont_FIPS(a, a, M, m0ninv, mBits)
return (k, bits)
func powMont*(
a: LimbsViewMut,
exponent: openarray[byte],
M, one: LimbsViewConst,
m0ninv: SecretWord,
scratchspace: LimbsViewMut,
scratchLen: int,
mBits: int) =
## Modular exponentiation r = a^exponent mod M
## in the Montgomery domain
##
## This uses fixed-window optimization if possible
##
## - On input ``a`` is the base, on ``output`` a = a^exponent (mod M)
## ``a`` is in the Montgomery domain
## - ``exponent`` is the exponent in big-endian canonical format (octet-string)
## Use ``marshal`` for conversion
## - ``M`` is the modulus
## - ``one`` is 1 (mod M) in montgomery representation
## - ``m0ninv`` is the montgomery magic constant "-1/M[0] mod 2^WordBitWidth"
## - ``scratchspace`` with k the window bitsize of size up to 5
## This is a buffer that can hold between 2 and up to 2ᵏ + 1 big-ints
## A window of 1-bit (no window optimization) requires only 2 big-ints
##
## Note that the best window size require benchmarking and is a tradeoff between
## - performance
## - stack usage
## - precomputation
##
## For example BLS12-381 window size of 5 is 30% faster than no window,
## but windows of size 2, 3, 4 bring no performance benefit, only increased stack space.
## A window of size 5 requires (2^5 + 1)*(381 + 7)/8 = 33 * 48 bytes = 1584 bytes
## of scratchspace (on the stack).
let N = wordsRequired(mBits)
let window = powMontPrologue(a, M, one, m0ninv, scratchspace, scratchLen, mBits)
# We process bits with from most to least significant.
# At each loop iteration with have acc_len bits in acc.
# To maintain constant-time the number of iterations
# or the number of operations or memory accesses should be the same
# regardless of acc & acc_len
var
acc, acc_len: uint
e = 0
let s0 = cast[LimbsViewMut](scratchspace[0].addr)
let s1 = cast[LimbsViewConst](scratchspace[1*N].addr)
while acc_len > 0 or e < exponent.len:
let (k, bits) = powMontSquarings(
a, exponent, M, m0ninv, mBits,
s0, window,
acc, acc_len, e)
# Window lookup: we set scratchspace[1] to the lookup value.
# If the window length is 1, then it's already set.
if window > 1:
# otherwise we need a constant-time lookup
# in particular we need the same memory accesses, we can't
# just index the openarray with the bits to avoid cache attacks.
for i in 1 ..< 1 shl k:
let ctl = SecretWord(i) == SecretWord(bits)
scratchspace.ccopyWords(1*N, scratchspace, (1+i)*N, ctl, N)
# Multiply with the looked-up value
# we keep the product only if the exponent bits are not all zeroes
s0.mulMont_FIPS(a, s1, M, m0ninv, mBits)
a.ccopyWords(0, s0, 0, SecretWord(bits).isNonZero(), N)
func powMont_vartime*(
a: LimbsViewMut,
exponent: openArray[byte],
M, one: LimbsViewConst,
m0ninv: SecretWord,
scratchspace: LimbsViewMut,
scratchLen: int,
mBits: int) {.tags:[VarTime, Alloca].} =
## Modular exponentiation a <- a^exponent (mod M)
## in the Montgomery domain
##
## Warning ⚠️ :
## This is an optimization for public exponent
## Otherwise bits of the exponent can be retrieved with:
## - memory access analysis
## - power analysis
## - timing analysis
# TODO: scratchspace[1] is unused when window > 1
let N = wordsRequired(mBits)
let window = powMontPrologue(a, M, one, m0ninv, scratchspace, scratchLen, mBits)
var
acc, acc_len: uint
e = 0
let s0 = cast[LimbsViewMut](scratchspace[0].addr)
let s1 = cast[LimbsViewConst](scratchspace[1*N].addr)
while acc_len > 0 or e < exponent.len:
let (_, bits) = powMontSquarings(
a, exponent, M, m0ninv, mBits,
s0, window,
acc, acc_len, e)
## Warning ⚠️: Exposes the exponent bits
if bits != 0:
if window > 1:
let sBits = cast[LimbsViewConst](scratchspace[int(1+bits)*N].addr)
s0.mulMont_FIPS(a, sBits, M, m0ninv, mBits)
else:
# scratchspace[1] holds the original `a`
s0.mulMont_FIPS(a, s1, M, m0ninv, mBits)
a.copyWords(0, s0, 0, N)
{.pop.}

View File

@ -0,0 +1,163 @@
# 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
# Internal
../../platforms/abstractions
# ############################################################
#
# Multi-precision arithmetic
#
# ############################################################
#
# This file implements multi-precision primitives
# with unbalanced number of limbs.
# Logical Shift Right
# --------------------------------------------------------
func shrSmall(r {.noalias.}: var openArray[SecretWord], a: openArray[SecretWord], k: SomeInteger) =
## Shift right by k.
##
## k MUST be less than the base word size (2^32 or 2^64)
# Note: for speed, loading a[i] and a[i+1]
# instead of a[i-1] and a[i]
# is probably easier to parallelize for the compiler
# (antidependence WAR vs loop-carried dependence RAW)
for i in 0 ..< a.len-1:
r[i] = (a[i] shr k) or (a[i+1] shl (WordBitWidth - k))
if a.len-1 < r.len:
r[a.len-1] = a[a.len-1] shr k
for i in a.len ..< r.len:
r[i] = Zero
func shrLarge(r {.noalias.}: var openArray[SecretWord], a: openArray[SecretWord], w, shift: SomeInteger) =
## Shift right by `w` words + `shift` bits
if w >= a.len:
r.setZero()
return
for i in w ..< a.len-1:
r[i-w] = (a[i] shr shift) or (a[i+1] shl (WordBitWidth - shift))
if a.len-1-w < r.len:
r[a.len-1-w] = a[a.len-1] shr shift
for i in a.len-w ..< r.len:
r[i] = Zero
func shrWords(r {.noalias.}: var openArray[SecretWord], a: openArray[SecretWord], w: SomeInteger) =
## Shift right by w word
for i in 0 ..< a.len-w:
r[i] = a[i+w]
for i in a.len-w ..< r.len:
r[i] = Zero
func shiftRight_vartime*(r {.noalias.}: var openArray[SecretWord], a: openArray[SecretWord], k: SomeInteger) =
## Shift `a` right 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.shrSmall(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.shrWords(a, w)
else:
r.shrLarge(a, w, shift)
# Arithmetic
# --------------------------------------------------------
func neg*(a: var openArray[SecretWord]) =
## Computes the additive inverse -a
## in 2-complement representation
# Algorithm: -a = not(a) + 1
var carry = Carry(0)
addC(carry, a[0], not(a[0]), One, carry)
for i in 1 ..< a.len:
addC(carry, a[i], not(a[i]), Zero, carry)
func addMP*(r {.noAlias.}: var openArray[SecretWord], a, b: openArray[SecretWord]): bool =
## r <- a + b
## and
## returns the carry
##
## Requirements:
## - r.len >= a.len
## - r.len >= b.len
debug:
doAssert r.len >= a.len
doAssert r.len >= b.len
if a.len < b.len:
return r.addMP(b, a)
let minLen = b.len
let maxLen = a.len
var carry = Carry(0)
for i in 0 ..< minLen:
addC(carry, r[i], a[i], b[i], carry)
for i in minLen ..< maxLen:
addC(carry, r[i], a[i], Zero, carry)
if maxLen < r.len:
r[maxLen] = SecretWord(carry)
for i in maxLen+1 ..< r.len:
r[i] = Zero
return false # the rest cannot carry
else:
return bool carry
func subMP*(r {.noAlias.}: var openArray[SecretWord], a, b: openArray[SecretWord]): bool =
## r <- a - b
## and
## returns false if a >= b
## returns true if a < b
## (in that case the 2-complement is stored)
##
## Requirements:
## - r.len >= a.len
## - a.len >= b.len
debug:
doAssert r.len >= a.len
doAssert a.len >= b.len
let minLen = b.len
let maxLen = a.len
var borrow = Borrow(0)
for i in 0 ..< minLen:
subB(borrow, r[i], a[i], b[i], borrow)
for i in minLen ..< maxLen:
subB(borrow, r[i], a[i], Zero, borrow)
result = bool borrow
# if a >= b, no borrow, mask = 0
# if a < b, borrow, we store the 2-complement, mask = -1
let mask = Zero - SecretWord(borrow)
for i in maxLen ..< r.len:
r[i] = mask

View 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.
import ../../platforms/abstractions
# No exceptions allowed
{.push raises: [].}
# Datatype
# ------------------------------------------------------------
# TODO: cleanup openArray vs LimbsView
type
LimbsView* = ptr UncheckedArray[SecretWord]
## Type-erased fixed-precision limbs
##
## This type mirrors the Limb type and is used
## for some low-level computation API
## This design
## - avoids code bloat due to generic monomorphization
## otherwise limbs routines would have an instantiation for
## each number of words.
##
## Accesses should be done via BigIntViewConst / BigIntViewConst
## to have the compiler check for mutability
# "Indirection" to enforce pointer types deep immutability
LimbsViewConst* = distinct LimbsView
## Immutable view into the limbs of a BigInt
LimbsViewMut* = distinct LimbsView
## Mutable view into a BigInt
LimbsViewAny* = LimbsViewConst or LimbsViewMut
# Deep Mutability safety
# ------------------------------------------------------------
template view*(a: Limbs): LimbsViewConst =
## Returns a borrowed type-erased immutable view to a bigint
LimbsViewConst(cast[LimbsView](a.unsafeAddr))
template view*(a: var Limbs): LimbsViewMut =
## Returns a borrowed type-erased mutable view to a mutable bigint
LimbsViewMut(cast[LimbsView](a.addr))
template view*(a: openArray[SecretWord]): LimbsViewConst =
## Returns a borrowed type-erased immutable view to a bigint
LimbsViewConst(cast[LimbsView](a[0].unsafeAddr))
template view*(a: var openArray[SecretWord]): LimbsViewMut =
## Returns a borrowed type-erased mutable view to a mutable bigint
LimbsViewMut(cast[LimbsView](a[0].addr))
template `[]`*(v: LimbsViewConst, limbIdx: int): SecretWord =
LimbsView(v)[limbIdx]
template `[]`*(v: LimbsViewMut, limbIdx: int): var SecretWord =
LimbsView(v)[limbIdx]
template `[]=`*(v: LimbsViewMut, limbIdx: int, val: SecretWord) =
LimbsView(v)[limbIdx] = val
# Init
# ------------------------------------------------------------
func setZero*(p: LimbsViewMut, len: int) {.inline.} =
for i in 0 ..< len:
p[i] = Zero
# Copy
# ------------------------------------------------------------
func copyWords*(
a: LimbsViewMut, startA: int,
b: LimbsViewAny, startB: int,
numWords: int) {.inline.} =
## Copy a slice of B into A. This properly deals
## with overlaps when A and B are slices of the same buffer
if startA > startB:
for i in countdown(numWords-1, 0):
a[startA+i] = b[startB+i]
else:
for i in 0 ..< numWords:
a[startA+i] = b[startB+i]
func ccopyWords*(
a: LimbsViewMut, startA: int,
b: LimbsViewAny, startB: int,
ctl: SecretBool,
numWords: int) {.inline.} =
## Copy a slice of B into A. This properly deals
## with overlaps when A and B are slices of the same buffer
if startA > startB:
for i in countdown(numWords-1, 0):
ctl.ccopy(a[startA+i], b[startB+i])
else:
for i in 0 ..< numWords:
ctl.ccopy(a[startA+i], b[startB+i])
# Bit operations
# ------------------------------------------------------------
func getMSB_vartime*[T](a: openArray[T]): int =
## Returns the position of the most significant bit
## of `a`.
## Returns -1 if a == 0
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
func getBits_vartime*[T](a: openArray[T]): int {.inline.} =
## Returns the number of bits used by `a`
## Returns 0 for 0
1 + getMSB_vartime(a)
{.pop.} # raises no exceptions

View File

@ -17,6 +17,21 @@ import ../../metering/tracer
export primitives, tracer
# ------------------------------------------------------------
const CttASM {.booldefine.} = true
const UseASM_X86_32* = CttASM and X86 and GCC_Compatible
const UseASM_X86_64* = sizeof(pointer)*8 == 64 and UseASM_X86_32
# We use Nim effect system to track vartime subroutines
type VarTime* = object
# ############################################################
#
# Secret Words
#
# ############################################################
when sizeof(int) == 8 and not defined(Ctt32):
type
BaseType* = uint64
@ -52,12 +67,51 @@ const
One* = SecretWord(1)
MaxWord* = SecretWord(high(BaseType))
const CttASM {.booldefine.} = true
const UseASM_X86_32* = CttASM and X86 and GCC_Compatible
const UseASM_X86_64* = WordBitWidth == 64 and UseASM_X86_32
func wordsRequired*(bits: int): int {.inline.} =
## Compute the number of limbs required
## from the **announced** bit length
# We use Nim effect system to track vartime subroutines
type VarTime* = object
# bits.ceilDiv_vartime(WordBitWidth)
# with guarantee to avoid division (especially at compile-time)
const divShiftor = log2_vartime(uint32(WordBitWidth))
result = (bits + WordBitWidth - 1) shr divShiftor
func isOdd*(a: SecretWord): SecretBool {.inline.} =
SecretBool(a and One)
func isOdd*(a: openArray[SecretWord]): SecretBool {.inline.} =
SecretBool(a[0] and One)
func isEven*(a: openArray[SecretWord]): SecretBool {.inline.} =
not a.isOdd
func setZero*(a: var openArray[SecretWord]){.inline.} =
for i in 0 ..< a.len:
a[i] = Zero
func setOne*(a: var openArray[SecretWord]){.inline.} =
a[0] = One
for i in 1 ..< a.len:
a[i] = Zero
debug: # Don't allow printing secret words by default
func toHex*(a: SecretWord): string =
const hexChars = "0123456789abcdef"
const L = 2*sizeof(SecretWord)
result = newString(2 + L)
result[0] = '0'
result[1] = 'x'
var a = a
for j in countdown(result.len-1, 2):
result[j] = hexChars.secretLookup(a and SecretWord 0xF)
a = a shr 4
func toString*(a: openArray[SecretWord]): string =
result = "["
result.add " " & toHex(a[0])
for i in 1 ..< a.len:
result.add ", " & toHex(a[i])
result.add "]"
# ############################################################
#

View File

@ -100,7 +100,7 @@ func byteLen(bits: SomeInteger): SomeInteger {.inline.} =
## Length in bytes to serialize BigNum
(bits + 7) shr 3 # (bits + 8 - 1) div 8
func wordsRequiredForBits(bits, wordBitwidth: SomeInteger): SomeInteger {.inline.} =
func wordsRequired(bits, wordBitwidth: SomeInteger): SomeInteger {.inline.} =
## Compute the number of limbs required
## from the announced bit length
@ -117,7 +117,7 @@ func fromHex[T](a: var BigNum[T], s: string) =
func fromHex[T](BN: type BigNum[T], bits: uint32, s: string): BN =
const wordBitwidth = sizeof(T) * 8
let numWords = wordsRequiredForBits(bits, wordBitwidth)
let numWords = wordsRequired(bits, wordBitwidth)
result.bits = bits
result.limbs.setLen(numWords)
@ -161,10 +161,7 @@ func negInvModWord[T](M: BigNum[T]): T =
##
## µ ≡ -1/M[0] (mod 2^64)
checkValidModulus(M)
result = invModBitwidth(M.limbs[0])
# negate to obtain the negative inverse
result = not(result) + 1
return M.limbs[0].negInvModWord()
# ############################################################
#
@ -209,7 +206,7 @@ proc setFieldConst(fc: var FieldConst, ctx: ContextRef, wordSize: WordSize, modB
of size32: 32'u32
of size64: 64'u32
let numWords = wordsRequiredForBits(modBits, wordBitwidth)
let numWords = wordsRequired(modBits, wordBitwidth)
fc.wordTy = wordTy
fc.fieldTy = array_t(wordTy, numWords)

View File

@ -82,10 +82,15 @@ func ceilDiv_vartime*(a, b: auto): auto {.inline.} =
#
# ############################################################
func setZero*[N](a: var array[N, SomeNumber]){.inline.} =
func setZero*(a: var openArray[SomeNumber]){.inline.} =
for i in 0 ..< a.len:
a[i] = 0
func setOne*(a: var openArray[SomeNumber]){.inline.} =
a[0] = 1
for i in 1 ..< a.len:
a[i] = 0
func rawCopy*(
dst: var openArray[byte],
dStart: SomeInteger,

View File

@ -30,7 +30,7 @@ func buildRootLUT(F: type Fr): array[32, F] =
var i = result.len - 1
exponent.shiftRight(i)
result[i].fromUint(BLS12_381_Fr_primitive_root)
result[i].powUnsafeExponent(exponent)
result[i].pow_vartime(exponent)
while i > 0:
result[i-1].square(result[i])

View File

@ -0,0 +1,19 @@
# From issue #241
import
../../constantine/math/[
arithmetic,
io/io_bigints]
let a = BigInt[64].fromUint(0xa0e5cb56a1c08396'u64)
let M = BigInt[64].fromUint(0xae57180eceb0206f'u64)
var r: BigInt[64]
r.reduce(a, M)
let rU64 = 0xa0e5cb56a1c08396'u64 mod 0xae57180eceb0206f'u64
echo r.toHex()
doAssert rU64 == a.limbs[0].uint64
doAssert bool(a == r)

View File

@ -12,9 +12,8 @@ import
# Third-party
gmp,
# Internal
../../constantine/math/io/io_bigints,
../../constantine/math/arithmetic,
../../constantine/platforms/primitives,
../../constantine/math/[arithmetic, io/io_bigints],
../../constantine/platforms/[primitives, codecs],
# Test utilities
../../helpers/prng_unsafe
@ -26,6 +25,9 @@ const CryptoModSizes = [
# Modulus sizes occuring in crypto
# To be tested more often
# Special-case
64,
# RSA
1024,
2048,
@ -59,7 +61,7 @@ macro testRandomModSizes(numSizes: static int, aBits, mBits, body: untyped): unt
result = newStmtList()
for _ in 0 ..< numSizes:
let aBitsVal = bitSizeRNG.rand(126 .. 8192)
let aBitsVal = bitSizeRNG.rand(62 .. 8192)
let mBitsVal = block:
# Pick from curve modulus if odd
if bool(bitSizeRNG.rand(high(int)) and 1):
@ -95,7 +97,7 @@ proc main() =
mpz_init(m)
mpz_init(r)
testRandomModSizes(12, aBits, mBits):
testRandomModSizes(60, aBits, mBits):
# echo "--------------------------------------------------------------------------------"
echo "Testing: random dividend (" & align($aBits, 4) & "-bit) -- random modulus (" & align($mBits, 4) & "-bit)"

View File

@ -0,0 +1,125 @@
# 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
../../constantine/math_arbitrary_precision/arithmetic/[bigints_views, limbs_views, limbs_division],
../../constantine/platforms/abstractions,
../../helpers/prng_unsafe,
std/[times, strformat],
gmp
# debug
import
../../constantine/platforms/codecs,
../../constantine/math/io/io_bigints
const # https://gmplib.org/manual/Integer-Import-and-Export.html
GMP_WordLittleEndian = -1'i32
GMP_WordNativeEndian = 0'i32
GMP_WordBigEndian = 1'i32
GMP_MostSignificantWordFirst = 1'i32
GMP_LeastSignificantWordFirst = -1'i32
const
moduleName = "t_powmod_vs_gmp"
Iters = 100
var rng: RngState
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
rng.seed(seed)
echo "\n------------------------------------------------------\n"
echo moduleName, " xoshiro512** seed: ", seed
proc fromHex(T: typedesc, hex: string): T =
result.unmarshal(array[sizeof(T), byte].fromHex(hex), WordBitWidth, bigEndian)
proc toHex(a: mpz_t): string =
let size = mpz_sizeinbase(a, 16)
result.setLen(size+2)
result[0] = '0'
result[1] = 'x'
discard mpz_get_str(cast[cstring](result[2].addr), 16, a)
proc test(rng: var RngState) =
let
aLen = rng.random_unsafe(1..100)
eLen = rng.random_unsafe(1..400)
mLen = rng.random_unsafe(1..100)
var
a = newSeq[SecretWord](aLen)
e = newSeq[byte](eLen)
M = newSeq[SecretWord](mLen)
rGMP = newSeq[SecretWord](mLen)
rCtt = newSeq[SecretWord](mLen)
for word in a.mitems():
word = SecretWord rng.next()
for octet in e.mitems():
octet = byte rng.next()
for word in M.mitems():
word = SecretWord rng.next()
var aa, ee, mm, rr: mpz_t
mpz_init(aa)
mpz_init(ee)
mpz_init(mm)
mpz_init(rr)
aa.mpz_import(aLen, GMP_LeastSignificantWordFirst, sizeof(SecretWord), GMP_WordNativeEndian, 0, a[0].addr)
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)
mpz_clear(rr)
let
aBits = a.getBits_vartime()
eBits = e.getBits_vartime()
mBits = M.getBits_vartime()
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" &
&" 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"
for _ in 0 ..< Iters:
rng.test()
stdout.write'.'
stdout.write'\n'

View File

@ -57,15 +57,15 @@ proc test_sameBaseProduct(C: static Curve, gen: RandomGen) =
b.div2()
var xa = x
xa.powUnsafeExponent(a, window = 3)
xa.pow_vartime(a, window = 3)
var xb = x
xb.powUnsafeExponent(b, window = 3)
xb.pow_vartime(b, window = 3)
var xapb = x
var apb: BigInt[128]
discard apb.sum(a, b)
xapb.powUnsafeExponent(apb, window = 3)
xapb.pow_vartime(apb, window = 3)
xa *= xb
doAssert: bool(xa == xapb)
@ -82,10 +82,10 @@ proc test_powpow(C: static Curve, gen: RandomGen) =
var y = x
x.powUnsafeExponent(a, window = 3)
x.powUnsafeExponent(b, window = 3)
x.pow_vartime(a, window = 3)
x.pow_vartime(b, window = 3)
y.powUnsafeExponent(ab, window = 3)
y.pow_vartime(ab, window = 3)
doAssert: bool(x == y)
proc test_powprod(C: static Curve, gen: RandomGen) =
@ -98,10 +98,10 @@ proc test_powprod(C: static Curve, gen: RandomGen) =
var xy{.noInit.}: Fp12[C]
xy.prod(x, y)
xy.powUnsafeExponent(a, window=3)
xy.pow_vartime(a, window=3)
x.powUnsafeExponent(a, window=3)
y.powUnsafeExponent(a, window=3)
x.pow_vartime(a, window=3)
y.pow_vartime(a, window=3)
x *= y
@ -112,7 +112,7 @@ proc test_pow0(C: static Curve, gen: RandomGen) =
var x = rng.random_elem(Fp12[C], gen)
var a: BigInt[128] # 0-init
x.powUnsafeExponent(a, window=3)
x.pow_vartime(a, window=3)
doAssert: bool x.isOne()
proc test_0pow0(C: static Curve, gen: RandomGen) =
@ -120,7 +120,7 @@ proc test_0pow0(C: static Curve, gen: RandomGen) =
var x: Fp12[C] # 0-init
var a: BigInt[128] # 0-init
x.powUnsafeExponent(a, window=3)
x.pow_vartime(a, window=3)
doAssert: bool x.isOne()
proc test_powinv(C: static Curve, gen: RandomGen) =
@ -137,10 +137,10 @@ proc test_powinv(C: static Curve, gen: RandomGen) =
cswap(a, b, a < b)
var xa = x
xa.powUnsafeExponent(a, window = 3)
xa.pow_vartime(a, window = 3)
var xb = x
xb.powUnsafeExponent(b, window = 3)
xb.pow_vartime(b, window = 3)
xb.inv()
xa *= xb
@ -148,7 +148,7 @@ proc test_powinv(C: static Curve, gen: RandomGen) =
var xamb = x
var amb: BigInt[128]
discard amb.diff(a, b)
xamb.powUnsafeExponent(amb, window = 3)
xamb.pow_vartime(amb, window = 3)
doAssert: bool(xa == xamb)
@ -160,10 +160,10 @@ proc test_invpow(C: static Curve, gen: RandomGen) =
var a = rng.random_elem(BigInt[128], gen)
var xa = x
xa.powUnsafeExponent(a, window = 3)
xa.pow_vartime(a, window = 3)
var ya = y
ya.powUnsafeExponent(a, window = 3)
ya.pow_vartime(a, window = 3)
ya.inv()
xa *= ya
@ -171,7 +171,7 @@ proc test_invpow(C: static Curve, gen: RandomGen) =
var invy = y
invy.inv()
xqya *= invy
xqya.powUnsafeExponent(a, window = 3)
xqya.pow_vartime(a, window = 3)
doAssert: bool(xa == xqya)

View File

@ -74,7 +74,7 @@ proc runFrobeniusTowerTests*[N](
var a = rng.random_elem(Field, gen)
var fa {.noInit.}: typeof(a)
fa.frobenius_map(a, k = 1)
a.powUnsafeExponent(Field.fieldMod(), window = 3)
a.pow_vartime(Field.fieldMod(), window = 3)
check: bool(a == fa)
staticFor(curve, TestCurves):
@ -90,8 +90,8 @@ proc runFrobeniusTowerTests*[N](
var fa {.noInit.}: typeof(a)
fa.frobenius_map(a, k = 2)
a.powUnsafeExponent(Field.fieldMod(), window = 3)
a.powUnsafeExponent(Field.fieldMod(), window = 3)
a.pow_vartime(Field.fieldMod(), window = 3)
a.pow_vartime(Field.fieldMod(), window = 3)
check:
bool(a == fa)
@ -109,9 +109,9 @@ proc runFrobeniusTowerTests*[N](
var fa {.noInit.}: typeof(a)
fa.frobenius_map(a, k = 3)
a.powUnsafeExponent(Field.fieldMod(), window = 3)
a.powUnsafeExponent(Field.fieldMod(), window = 3)
a.powUnsafeExponent(Field.fieldMod(), window = 3)
a.pow_vartime(Field.fieldMod(), window = 3)
a.pow_vartime(Field.fieldMod(), window = 3)
a.pow_vartime(Field.fieldMod(), window = 3)
check: bool(a == fa)
staticFor(curve, TestCurves):

View File

@ -151,7 +151,7 @@ proc main() =
let expected = "0x0636759a0f3034fa47174b2c0334902f11e9915b7bd89c6a2b3082b109abbc9837da17201f6d8286fe6203caa1b9d4c8"
x.powUnsafeExponent(exponent)
x.pow_vartime(exponent)
let computed = x.toHex()
check:
@ -338,7 +338,7 @@ proc main_anti_regression =
# # square of "0x406e5e74ee09c84fa0c59f2db3ac814a4937e2f57ecd3c0af4265e04598d643c5b772a6549a2d9b825445c34b8ba100fe8d912e61cfda43d"
# a.fromHex("0x1e6511b2bfabd7d32d8df7492c66df29ade7fdb21bb0d8f6cacfccb05e45a812a27cd087e1bbb2d202ee29f75a021a6a68d990a2a5e73410")
# a.powUnsafeExponent(FKM12_447.getPrimeMinus1div2_BE())
# a.pow_vartime(FKM12_447.getPrimeMinus1div2_BE())
# check: bool a.isOne()
test "#42 - a^(p-3)/4 (inverse square root)":
@ -357,7 +357,7 @@ proc main_anti_regression =
discard pm3div4.sub SecretWord(3)
pm3div4.shiftRight(2)
a.powUnsafeExponent(pm3div4)
a.pow_vartime(pm3div4)
var expected: Fp[BLS12_381]
expected.fromHex"ec6fc6cd4d8a3afe1114d5288759b40a87b6b2f001c8c41693f13132be04de21ca22ea38bded36f3748e06d7b4c348c"
@ -380,7 +380,7 @@ proc main_anti_regression =
discard pm3div4.sub SecretWord(3)
pm3div4.shiftRight(2)
a.powUnsafeExponent(pm3div4)
a.pow_vartime(pm3div4)
var expected: Fp[BLS12_381]
expected.fromHex"16bf380e9b6d01aa6961c4fcee02a00cb827b52d0eb2b541ea8b598d32100d0bd7dc9a600852b49f0379e63ba9c5d35e"

View File

@ -0,0 +1,126 @@
{
"func": "modexp",
"fork": "byzantium",
"data":
[
{
"Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002003fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
"Expected": "0000000000000000000000000000000000000000000000000000000000000001",
"Name": "eip_example1",
"Gas": 13056,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
"Expected": "0000000000000000000000000000000000000000000000000000000000000000",
"Name": "eip_example2",
"Gas": 13056,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb502fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b",
"Expected": "60008f1614cc01dcfb6bfb09c625cf90b47d4468db81b5f8b7a39d42f332eab9b2da8f2d95311648a8f243f4bb13cfb3d8f7f2a3c014122ebb3ed41b02783adc",
"Name": "nagydani-1-square",
"Gas": 204,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb503fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b",
"Expected": "4834a46ba565db27903b1c720c9d593e84e4cbd6ad2e64b31885d944f68cd801f92225a8961c952ddf2797fa4701b330c85c4b363798100b921a1a22a46a7fec",
"Name": "nagydani-1-qube",
"Gas": 204,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5010001fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b",
"Expected": "c36d804180c35d4426b57b50c5bfcca5c01856d104564cd513b461d3c8b8409128a5573e416d0ebe38f5f736766d9dc27143e4da981dfa4d67f7dc474cbee6d2",
"Name": "nagydani-1-pow0x10001",
"Gas": 3276,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5102e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087",
"Expected": "981dd99c3b113fae3e3eaa9435c0dc96779a23c12a53d1084b4f67b0b053a27560f627b873e3f16ad78f28c94f14b6392def26e4d8896c5e3c984e50fa0b3aa44f1da78b913187c6128baa9340b1e9c9a0fd02cb78885e72576da4a8f7e5a113e173a7a2889fde9d407bd9f06eb05bc8fc7b4229377a32941a02bf4edcc06d70",
"Name": "nagydani-2-square",
"Gas": 665,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5103e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087",
"Expected": "d89ceb68c32da4f6364978d62aaa40d7b09b59ec61eb3c0159c87ec3a91037f7dc6967594e530a69d049b64adfa39c8fa208ea970cfe4b7bcd359d345744405afe1cbf761647e32b3184c7fbe87cee8c6c7ff3b378faba6c68b83b6889cb40f1603ee68c56b4c03d48c595c826c041112dc941878f8c5be828154afd4a16311f",
"Name": "nagydani-2-qube",
"Gas": 665,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51010001e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087",
"Expected": "ad85e8ef13fd1dd46eae44af8b91ad1ccae5b7a1c92944f92a19f21b0b658139e0cabe9c1f679507c2de354bf2c91ebd965d1e633978a830d517d2f6f8dd5fd58065d58559de7e2334a878f8ec6992d9b9e77430d4764e863d77c0f87beede8f2f7f2ab2e7222f85cc9d98b8467f4bb72e87ef2882423ebdb6daf02dddac6db2",
"Name": "nagydani-2-pow0x10001",
"Gas": 10649,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb02d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d",
"Expected": "affc7507ea6d84751ec6b3f0d7b99dbcc263f33330e450d1b3ff0bc3d0874320bf4edd57debd587306988157958cb3cfd369cc0c9c198706f635c9e0f15d047df5cb44d03e2727f26b083c4ad8485080e1293f171c1ed52aef5993a5815c35108e848c951cf1e334490b4a539a139e57b68f44fee583306f5b85ffa57206b3ee5660458858534e5386b9584af3c7f67806e84c189d695e5eb96e1272d06ec2df5dc5fabc6e94b793718c60c36be0a4d031fc84cd658aa72294b2e16fc240aef70cb9e591248e38bd49c5a554d1afa01f38dab72733092f7555334bbef6c8c430119840492380aa95fa025dcf699f0a39669d812b0c6946b6091e6e235337b6f8",
"Name": "nagydani-3-square",
"Gas": 1894,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb03d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d",
"Expected": "1b280ecd6a6bf906b806d527c2a831e23b238f89da48449003a88ac3ac7150d6a5e9e6b3be4054c7da11dd1e470ec29a606f5115801b5bf53bc1900271d7c3ff3cd5ed790d1c219a9800437a689f2388ba1a11d68f6a8e5b74e9a3b1fac6ee85fc6afbac599f93c391f5dc82a759e3c6c0ab45ce3f5d25d9b0c1bf94cf701ea6466fc9a478dacc5754e593172b5111eeba88557048bceae401337cd4c1182ad9f700852bc8c99933a193f0b94cf1aedbefc48be3bc93ef5cb276d7c2d5462ac8bb0c8fe8923a1db2afe1c6b90d59c534994a6a633f0ead1d638fdc293486bb634ff2c8ec9e7297c04241a61c37e3ae95b11d53343d4ba2b4cc33d2cfa7eb705e",
"Name": "nagydani-3-qube",
"Gas": 1894,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb010001d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d",
"Expected": "37843d7c67920b5f177372fa56e2a09117df585f81df8b300fba245b1175f488c99476019857198ed459ed8d9799c377330e49f4180c4bf8e8f66240c64f65ede93d601f957b95b83efdee1e1bfde74169ff77002eaf078c71815a9220c80b2e3b3ff22c2f358111d816ebf83c2999026b6de50bfc711ff68705d2f40b753424aefc9f70f08d908b5a20276ad613b4ab4309a3ea72f0c17ea9df6b3367d44fb3acab11c333909e02e81ea2ed404a712d3ea96bba87461720e2d98723e7acd0520ac1a5212dbedcd8dc0c1abf61d4719e319ff4758a774790b8d463cdfe131d1b2dcfee52d002694e98e720cb6ae7ccea353bc503269ba35f0f63bf8d7b672a76",
"Name": "nagydani-3-pow0x10001",
"Gas": 30310,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8102df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f",
"Expected": "8a5aea5f50dcc03dc7a7a272b5aeebc040554dbc1ffe36753c4fc75f7ed5f6c2cc0de3a922bf96c78bf0643a73025ad21f45a4a5cadd717612c511ab2bff1190fe5f1ae05ba9f8fe3624de1de2a817da6072ddcdb933b50216811dbe6a9ca79d3a3c6b3a476b079fd0d05f04fb154e2dd3e5cb83b148a006f2bcbf0042efb2ae7b916ea81b27aac25c3bf9a8b6d35440062ad8eae34a83f3ffa2cc7b40346b62174a4422584f72f95316f6b2bee9ff232ba9739301c97c99a9ded26c45d72676eb856ad6ecc81d36a6de36d7f9dafafee11baa43a4b0d5e4ecffa7b9b7dcefd58c397dd373e6db4acd2b2c02717712e6289bed7c813b670c4a0c6735aa7f3b0f1ce556eae9fcc94b501b2c8781ba50a8c6220e8246371c3c7359fe4ef9da786ca7d98256754ca4e496be0a9174bedbecb384bdf470779186d6a833f068d2838a88d90ef3ad48ff963b67c39cc5a3ee123baf7bf3125f64e77af7f30e105d72c4b9b5b237ed251e4c122c6d8c1405e736299c3afd6db16a28c6a9cfa68241e53de4cd388271fe534a6a9b0dbea6171d170db1b89858468885d08fecbd54c8e471c3e25d48e97ba450b96d0d87e00ac732aaa0d3ce4309c1064bd8a4c0808a97e0143e43a24cfa847635125cd41c13e0574487963e9d725c01375db99c31da67b4cf65eff555f0c0ac416c727ff8d438ad7c42030551d68c2e7adda0abb1ca7c10",
"Name": "nagydani-4-square",
"Gas": 5580,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8103df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f",
"Expected": "5a2664252aba2d6e19d9600da582cdd1f09d7a890ac48e6b8da15ae7c6ff1856fc67a841ac2314d283ffa3ca81a0ecf7c27d89ef91a5a893297928f5da0245c99645676b481b7e20a566ee6a4f2481942bee191deec5544600bb2441fd0fb19e2ee7d801ad8911c6b7750affec367a4b29a22942c0f5f4744a4e77a8b654da2a82571037099e9c6d930794efe5cdca73c7b6c0844e386bdca8ea01b3d7807146bb81365e2cdc6475f8c23e0ff84463126189dc9789f72bbce2e3d2d114d728a272f1345122de23df54c922ec7a16e5c2a8f84da8871482bd258c20a7c09bbcd64c7a96a51029bbfe848736a6ba7bf9d931a9b7de0bcaf3635034d4958b20ae9ab3a95a147b0421dd5f7ebff46c971010ebfc4adbbe0ad94d5498c853e7142c450d8c71de4b2f84edbf8acd2e16d00c8115b150b1c30e553dbb82635e781379fe2a56360420ff7e9f70cc64c00aba7e26ed13c7c19622865ae07248daced36416080f35f8cc157a857ed70ea4f347f17d1bee80fa038abd6e39b1ba06b97264388b21364f7c56e192d4b62d9b161405f32ab1e2594e86243e56fcf2cb30d21adef15b9940f91af681da24328c883d892670c6aa47940867a81830a82b82716895db810df1b834640abefb7db2092dd92912cb9a735175bc447be40a503cf22dfe565b4ed7a3293ca0dfd63a507430b323ee248ec82e843b673c97ad730728cebc",
"Name": "nagydani-4-qube",
"Gas": 5580,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81010001df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f",
"Expected": "bed8b970c4a34849fc6926b08e40e20b21c15ed68d18f228904878d4370b56322d0da5789da0318768a374758e6375bfe4641fca5285ec7171828922160f48f5ca7efbfee4d5148612c38ad683ae4e3c3a053d2b7c098cf2b34f2cb19146eadd53c86b2d7ccf3d83b2c370bfb840913ee3879b1057a6b4e07e110b6bcd5e958bc71a14798c91d518cc70abee264b0d25a4110962a764b364ac0b0dd1ee8abc8426d775ec0f22b7e47b32576afaf1b5a48f64573ed1c5c29f50ab412188d9685307323d990802b81dacc06c6e05a1e901830ba9fcc67688dc29c5e27bde0a6e845ca925f5454b6fb3747edfaa2a5820838fb759eadf57f7cb5cec57fc213ddd8a4298fa079c3c0f472b07fb15aa6a7f0a3780bd296ff6a62e58ef443870b02260bd4fd2bbc98255674b8e1f1f9f8d33c7170b0ebbea4523b695911abbf26e41885344823bd0587115fdd83b721a4e8457a31c9a84b3d3520a07e0e35df7f48e5a9d534d0ec7feef1ff74de6a11e7f93eab95175b6ce22c68d78a642ad642837897ec11349205d8593ac19300207572c38d29ca5dfa03bc14cdbc32153c80e5cc3e739403d34c75915e49beb43094cc6dcafb3665b305ddec9286934ae66ec6b777ca528728c851318eb0f207b39f1caaf96db6eeead6b55ed08f451939314577d42bcc9f97c0b52d0234f88fd07e4c1d7780fdebc025cfffcb572cb27a8c33963",
"Name": "nagydani-4-pow0x10001",
"Gas": 89292,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf02e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad",
"Expected": "d61fe4e3f32ac260915b5b03b78a86d11bfc41d973fce5b0cc59035cf8289a8a2e3878ea15fa46565b0d806e2f85b53873ea20ed653869b688adf83f3ef444535bf91598ff7e80f334fb782539b92f39f55310cc4b35349ab7b278346eda9bc37c0d8acd3557fae38197f412f8d9e57ce6a76b7205c23564cab06e5615be7c6f05c3d05ec690cba91da5e89d55b152ff8dd2157dc5458190025cf94b1ad98f7cbe64e9482faba95e6b33844afc640892872b44a9932096508f4a782a4805323808f23e54b6ff9b841dbfa87db3505ae4f687972c18ea0f0d0af89d36c1c2a5b14560c153c3fee406f5cf15cfd1c0bb45d767426d465f2f14c158495069d0c5955a00150707862ecaae30624ebacdd8ac33e4e6aab3ff90b6ba445a84689386b9e945d01823a65874444316e83767290fcff630d2477f49d5d8ffdd200e08ee1274270f86ed14c687895f6caf5ce528bd970c20d2408a9ba66216324c6a011ac4999098362dbd98a038129a2d40c8da6ab88318aa3046cb660327cc44236d9e5d2163bd0959062195c51ed93d0088b6f92051fc99050ece2538749165976233697ab4b610385366e5ce0b02ad6b61c168ecfbedcdf74278a38de340fd7a5fead8e588e294795f9b011e2e60377a89e25c90e145397cdeabc60fd32444a6b7642a611a83c464d8b8976666351b4865c37b02e6dc21dbcdf5f930341707b618cc0f03c3122646b3385c9df9f2ec730eec9d49e7dfc9153b6e6289da8c4f0ebea9ccc1b751948e3bb7171c9e4d57423b0eeeb79095c030cb52677b3f7e0b45c30f645391f3f9c957afa549c4e0b2465b03c67993cd200b1af01035962edbc4c9e89b31c82ac121987d6529dafdeef67a132dc04b6dc68e77f22862040b75e2ceb9ff16da0fca534e6db7bd12fa7b7f51b6c08c1e23dfcdb7acbd2da0b51c87ffbced065a612e9b1c8bba9b7e2d8d7a2f04fcc4aaf355b60d764879a76b5e16762d5f2f55d585d0c8e82df6940960cddfb72c91dfa71f6b4e1c6ca25dfc39a878e998a663c04fe29d5e83b9586d047b4d7ff70a9f0d44f127e7d741685ca75f11629128d916a0ffef4be586a30c4b70389cc746e84ebf177c01ee8a4511cfbb9d1ecf7f7b33c7dd8177896e10bbc82f838dcd6db7ac67de62bf46b6a640fb580c5d1d2708f3862e3d2b645d0d18e49ef088053e3a220adc0e033c2afcfe61c90e32151152eb3caaf746c5e377d541cafc6cbb0cc0fa48b5caf1728f2e1957f5addfc234f1a9d89e40d49356c9172d0561a695fce6dab1d412321bbf407f63766ffd7b6b3d79bcfa07991c5a9709849c1008689e3b47c50d613980bec239fb64185249d055b30375ccb4354d71fe4d05648fbf6c80634dfc3575f2f24abb714c1e4c95e8896763bf4316e954c7ad19e5780ab7a040ca6fb9271f90a8b22ae738daf6cb",
"Name": "nagydani-5-square",
"Gas": 17868,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf03e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad",
"Expected": "5f9c70ec884926a89461056ad20ac4c30155e817f807e4d3f5bb743d789c83386762435c3627773fa77da5144451f2a8aad8adba88e0b669f5377c5e9bad70e45c86fe952b613f015a9953b8a5de5eaee4566acf98d41e327d93a35bd5cef4607d025e58951167957df4ff9b1627649d3943805472e5e293d3efb687cfd1e503faafeb2840a3e3b3f85d016051a58e1c9498aab72e63b748d834b31eb05d85dcde65e27834e266b85c75cc4ec0135135e0601cb93eeeb6e0010c8ceb65c4c319623c5e573a2c8c9fbbf7df68a930beb412d3f4dfd146175484f45d7afaa0d2e60684af9b34730f7c8438465ad3e1d0c3237336722f2aa51095bd5759f4b8ab4dda111b684aa3dac62a761722e7ae43495b7709933512c81c4e3c9133a51f7ce9f2b51fcec064f65779666960b4e45df3900f54311f5613e8012dd1b8efd359eda31a778264c72aa8bb419d862734d769076bce2810011989a45374e5c5d8729fec21427f0bf397eacbb4220f603cf463a4b0c94efd858ffd9768cd60d6ce68d755e0fbad007ce5c2223d70c7018345a102e4ab3c60a13a9e7794303156d4c2063e919f2153c13961fb324c80b240742f47773a7a8e25b3e3fb19b00ce839346c6eb3c732fbc6b888df0b1fe0a3d07b053a2e9402c267b2d62f794d8a2840526e3ade15ce2264496ccd7519571dfde47f7a4bb16292241c20b2be59f3f8fb4f6383f232d838c5a22d8c95b6834d9d2ca493f5a505ebe8899503b0e8f9b19e6e2dd81c1628b80016d02097e0134de51054c4e7674824d4d758760fc52377d2cad145e259aa2ffaf54139e1a66b1e0c1c191e32ac59474c6b526f5b3ba07d3e5ec286eddf531fcd5292869be58c9f22ef91026159f7cf9d05ef66b4299f4da48cc1635bf2243051d342d378a22c83390553e873713c0454ce5f3234397111ac3fe3207b86f0ed9fc025c81903e1748103692074f83824fda6341be4f95ff00b0a9a208c267e12fa01825054cc0513629bf3dbb56dc5b90d4316f87654a8be18227978ea0a8a522760cad620d0d14fd38920fb7321314062914275a5f99f677145a6979b156bd82ecd36f23f8e1273cc2759ecc0b2c69d94dad5211d1bed939dd87ed9e07b91d49713a6e16ade0a98aea789f04994e318e4ff2c8a188cd8d43aeb52c6daa3bc29b4af50ea82a247c5cd67b573b34cbadcc0a376d3bbd530d50367b42705d870f2e27a8197ef46070528bfe408360faa2ebb8bf76e9f388572842bcb119f4d84ee34ae31f5cc594f23705a49197b181fb78ed1ec99499c690f843a4d0cf2e226d118e9372271054fbabdcc5c92ae9fefaef0589cd0e722eaf30c1703ec4289c7fd81beaa8a455ccee5298e31e2080c10c366a6fcf56f7d13582ad0bcad037c612b710fc595b70fbefaaca23623b60c6c39b11beb8e5843b6b3dac60f",
"Name": "nagydani-5-qube",
"Gas": 17868,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf010001e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad",
"Expected": "5a0eb2bdf0ac1cae8e586689fa16cd4b07dfdedaec8a110ea1fdb059dd5253231b6132987598dfc6e11f86780428982d50cf68f67ae452622c3b336b537ef3298ca645e8f89ee39a26758206a5a3f6409afc709582f95274b57b71fae5c6b74619ae6f089a5393c5b79235d9caf699d23d88fb873f78379690ad8405e34c19f5257d596580c7a6a7206a3712825afe630c76b31cdb4a23e7f0632e10f14f4e282c81a66451a26f8df2a352b5b9f607a7198449d1b926e27036810368e691a74b91c61afa73d9d3b99453e7c8b50fd4f09c039a2f2feb5c419206694c31b92df1d9586140cb3417b38d0c503c7b508cc2ed12e813a1c795e9829eb39ee78eeaf360a169b491a1d4e419574e712402de9d48d54c1ae5e03739b7156615e8267e1fb0a897f067afd11fb33f6e24182d7aaaaa18fe5bc1982f20d6b871e5a398f0f6f718181d31ec225cfa9a0a70124ed9a70031bdf0c1c7829f708b6e17d50419ef361cf77d99c85f44607186c8d683106b8bd38a49b5d0fb503b397a83388c5678dcfcc737499d84512690701ed621a6f0172aecf037184ddf0f2453e4053024018e5ab2e30d6d5363b56e8b41509317c99042f517247474ab3abc848e00a07f69c254f46f2a05cf6ed84e5cc906a518fdcfdf2c61ce731f24c5264f1a25fc04934dc28aec112134dd523f70115074ca34e3807aa4cb925147f3a0ce152d323bd8c675ace446d0fd1ae30c4b57f0eb2c23884bc18f0964c0114796c5b6d080c3d89175665fbf63a6381a6a9da39ad070b645c8bb1779506da14439a9f5b5d481954764ea114fac688930bc68534d403cff4210673b6a6ff7ae416b7cd41404c3d3f282fcd193b86d0f54d0006c2a503b40d5c3930da980565b8f9630e9493a79d1c03e74e5f93ac8e4dc1a901ec5e3b3e57049124c7b72ea345aa359e782285d9e6a5c144a378111dd02c40855ff9c2be9b48425cb0b2fd62dc8678fd151121cf26a65e917d65d8e0dacfae108eb5508b601fb8ffa370be1f9a8b749a2d12eeab81f41079de87e2d777994fa4d28188c579ad327f9957fb7bdecec5c680844dd43cb57cf87aeb763c003e65011f73f8c63442df39a92b946a6bd968a1c1e4d5fa7d88476a68bd8e20e5b70a99259c7d3f85fb1b65cd2e93972e6264e74ebf289b8b6979b9b68a85cd5b360c1987f87235c3c845d62489e33acf85d53fa3561fe3a3aee18924588d9c6eba4edb7a4d106b31173e42929f6f0c48c80ce6a72d54eca7c0fe870068b7a7c89c63cdda593f5b32d3cb4ea8a32c39f00ab449155757172d66763ed9527019d6de6c9f2416aa6203f4d11c9ebee1e1d3845099e55504446448027212616167eb36035726daa7698b075286f5379cd3e93cb3e0cf4f9cb8d017facbb5550ed32d5ec5400ae57e47e2bf78d1eaeff9480cc765ceff39db500",
"Name": "nagydani-5-pow0x10001",
"Gas": 285900,
"NoBenchmark": false
}
]
}

View File

@ -0,0 +1,126 @@
{
"func": "modexp",
"fork": "berlin",
"data":
[
{
"Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002003fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
"Expected": "0000000000000000000000000000000000000000000000000000000000000001",
"Name": "eip_example1",
"Gas": 1360,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
"Expected": "0000000000000000000000000000000000000000000000000000000000000000",
"Name": "eip_example2",
"Gas": 1360,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb502fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b",
"Expected": "60008f1614cc01dcfb6bfb09c625cf90b47d4468db81b5f8b7a39d42f332eab9b2da8f2d95311648a8f243f4bb13cfb3d8f7f2a3c014122ebb3ed41b02783adc",
"Name": "nagydani-1-square",
"Gas": 200,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb503fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b",
"Expected": "4834a46ba565db27903b1c720c9d593e84e4cbd6ad2e64b31885d944f68cd801f92225a8961c952ddf2797fa4701b330c85c4b363798100b921a1a22a46a7fec",
"Name": "nagydani-1-qube",
"Gas": 200,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5010001fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b",
"Expected": "c36d804180c35d4426b57b50c5bfcca5c01856d104564cd513b461d3c8b8409128a5573e416d0ebe38f5f736766d9dc27143e4da981dfa4d67f7dc474cbee6d2",
"Name": "nagydani-1-pow0x10001",
"Gas": 341,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5102e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087",
"Expected": "981dd99c3b113fae3e3eaa9435c0dc96779a23c12a53d1084b4f67b0b053a27560f627b873e3f16ad78f28c94f14b6392def26e4d8896c5e3c984e50fa0b3aa44f1da78b913187c6128baa9340b1e9c9a0fd02cb78885e72576da4a8f7e5a113e173a7a2889fde9d407bd9f06eb05bc8fc7b4229377a32941a02bf4edcc06d70",
"Name": "nagydani-2-square",
"Gas": 200,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5103e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087",
"Expected": "d89ceb68c32da4f6364978d62aaa40d7b09b59ec61eb3c0159c87ec3a91037f7dc6967594e530a69d049b64adfa39c8fa208ea970cfe4b7bcd359d345744405afe1cbf761647e32b3184c7fbe87cee8c6c7ff3b378faba6c68b83b6889cb40f1603ee68c56b4c03d48c595c826c041112dc941878f8c5be828154afd4a16311f",
"Name": "nagydani-2-qube",
"Gas": 200,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51010001e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087",
"Expected": "ad85e8ef13fd1dd46eae44af8b91ad1ccae5b7a1c92944f92a19f21b0b658139e0cabe9c1f679507c2de354bf2c91ebd965d1e633978a830d517d2f6f8dd5fd58065d58559de7e2334a878f8ec6992d9b9e77430d4764e863d77c0f87beede8f2f7f2ab2e7222f85cc9d98b8467f4bb72e87ef2882423ebdb6daf02dddac6db2",
"Name": "nagydani-2-pow0x10001",
"Gas": 1365,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb02d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d",
"Expected": "affc7507ea6d84751ec6b3f0d7b99dbcc263f33330e450d1b3ff0bc3d0874320bf4edd57debd587306988157958cb3cfd369cc0c9c198706f635c9e0f15d047df5cb44d03e2727f26b083c4ad8485080e1293f171c1ed52aef5993a5815c35108e848c951cf1e334490b4a539a139e57b68f44fee583306f5b85ffa57206b3ee5660458858534e5386b9584af3c7f67806e84c189d695e5eb96e1272d06ec2df5dc5fabc6e94b793718c60c36be0a4d031fc84cd658aa72294b2e16fc240aef70cb9e591248e38bd49c5a554d1afa01f38dab72733092f7555334bbef6c8c430119840492380aa95fa025dcf699f0a39669d812b0c6946b6091e6e235337b6f8",
"Name": "nagydani-3-square",
"Gas": 341,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb03d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d",
"Expected": "1b280ecd6a6bf906b806d527c2a831e23b238f89da48449003a88ac3ac7150d6a5e9e6b3be4054c7da11dd1e470ec29a606f5115801b5bf53bc1900271d7c3ff3cd5ed790d1c219a9800437a689f2388ba1a11d68f6a8e5b74e9a3b1fac6ee85fc6afbac599f93c391f5dc82a759e3c6c0ab45ce3f5d25d9b0c1bf94cf701ea6466fc9a478dacc5754e593172b5111eeba88557048bceae401337cd4c1182ad9f700852bc8c99933a193f0b94cf1aedbefc48be3bc93ef5cb276d7c2d5462ac8bb0c8fe8923a1db2afe1c6b90d59c534994a6a633f0ead1d638fdc293486bb634ff2c8ec9e7297c04241a61c37e3ae95b11d53343d4ba2b4cc33d2cfa7eb705e",
"Name": "nagydani-3-qube",
"Gas": 341,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb010001d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d",
"Expected": "37843d7c67920b5f177372fa56e2a09117df585f81df8b300fba245b1175f488c99476019857198ed459ed8d9799c377330e49f4180c4bf8e8f66240c64f65ede93d601f957b95b83efdee1e1bfde74169ff77002eaf078c71815a9220c80b2e3b3ff22c2f358111d816ebf83c2999026b6de50bfc711ff68705d2f40b753424aefc9f70f08d908b5a20276ad613b4ab4309a3ea72f0c17ea9df6b3367d44fb3acab11c333909e02e81ea2ed404a712d3ea96bba87461720e2d98723e7acd0520ac1a5212dbedcd8dc0c1abf61d4719e319ff4758a774790b8d463cdfe131d1b2dcfee52d002694e98e720cb6ae7ccea353bc503269ba35f0f63bf8d7b672a76",
"Name": "nagydani-3-pow0x10001",
"Gas": 5461,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8102df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f",
"Expected": "8a5aea5f50dcc03dc7a7a272b5aeebc040554dbc1ffe36753c4fc75f7ed5f6c2cc0de3a922bf96c78bf0643a73025ad21f45a4a5cadd717612c511ab2bff1190fe5f1ae05ba9f8fe3624de1de2a817da6072ddcdb933b50216811dbe6a9ca79d3a3c6b3a476b079fd0d05f04fb154e2dd3e5cb83b148a006f2bcbf0042efb2ae7b916ea81b27aac25c3bf9a8b6d35440062ad8eae34a83f3ffa2cc7b40346b62174a4422584f72f95316f6b2bee9ff232ba9739301c97c99a9ded26c45d72676eb856ad6ecc81d36a6de36d7f9dafafee11baa43a4b0d5e4ecffa7b9b7dcefd58c397dd373e6db4acd2b2c02717712e6289bed7c813b670c4a0c6735aa7f3b0f1ce556eae9fcc94b501b2c8781ba50a8c6220e8246371c3c7359fe4ef9da786ca7d98256754ca4e496be0a9174bedbecb384bdf470779186d6a833f068d2838a88d90ef3ad48ff963b67c39cc5a3ee123baf7bf3125f64e77af7f30e105d72c4b9b5b237ed251e4c122c6d8c1405e736299c3afd6db16a28c6a9cfa68241e53de4cd388271fe534a6a9b0dbea6171d170db1b89858468885d08fecbd54c8e471c3e25d48e97ba450b96d0d87e00ac732aaa0d3ce4309c1064bd8a4c0808a97e0143e43a24cfa847635125cd41c13e0574487963e9d725c01375db99c31da67b4cf65eff555f0c0ac416c727ff8d438ad7c42030551d68c2e7adda0abb1ca7c10",
"Name": "nagydani-4-square",
"Gas": 1365,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8103df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f",
"Expected": "5a2664252aba2d6e19d9600da582cdd1f09d7a890ac48e6b8da15ae7c6ff1856fc67a841ac2314d283ffa3ca81a0ecf7c27d89ef91a5a893297928f5da0245c99645676b481b7e20a566ee6a4f2481942bee191deec5544600bb2441fd0fb19e2ee7d801ad8911c6b7750affec367a4b29a22942c0f5f4744a4e77a8b654da2a82571037099e9c6d930794efe5cdca73c7b6c0844e386bdca8ea01b3d7807146bb81365e2cdc6475f8c23e0ff84463126189dc9789f72bbce2e3d2d114d728a272f1345122de23df54c922ec7a16e5c2a8f84da8871482bd258c20a7c09bbcd64c7a96a51029bbfe848736a6ba7bf9d931a9b7de0bcaf3635034d4958b20ae9ab3a95a147b0421dd5f7ebff46c971010ebfc4adbbe0ad94d5498c853e7142c450d8c71de4b2f84edbf8acd2e16d00c8115b150b1c30e553dbb82635e781379fe2a56360420ff7e9f70cc64c00aba7e26ed13c7c19622865ae07248daced36416080f35f8cc157a857ed70ea4f347f17d1bee80fa038abd6e39b1ba06b97264388b21364f7c56e192d4b62d9b161405f32ab1e2594e86243e56fcf2cb30d21adef15b9940f91af681da24328c883d892670c6aa47940867a81830a82b82716895db810df1b834640abefb7db2092dd92912cb9a735175bc447be40a503cf22dfe565b4ed7a3293ca0dfd63a507430b323ee248ec82e843b673c97ad730728cebc",
"Name": "nagydani-4-qube",
"Gas": 1365,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81010001df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f",
"Expected": "bed8b970c4a34849fc6926b08e40e20b21c15ed68d18f228904878d4370b56322d0da5789da0318768a374758e6375bfe4641fca5285ec7171828922160f48f5ca7efbfee4d5148612c38ad683ae4e3c3a053d2b7c098cf2b34f2cb19146eadd53c86b2d7ccf3d83b2c370bfb840913ee3879b1057a6b4e07e110b6bcd5e958bc71a14798c91d518cc70abee264b0d25a4110962a764b364ac0b0dd1ee8abc8426d775ec0f22b7e47b32576afaf1b5a48f64573ed1c5c29f50ab412188d9685307323d990802b81dacc06c6e05a1e901830ba9fcc67688dc29c5e27bde0a6e845ca925f5454b6fb3747edfaa2a5820838fb759eadf57f7cb5cec57fc213ddd8a4298fa079c3c0f472b07fb15aa6a7f0a3780bd296ff6a62e58ef443870b02260bd4fd2bbc98255674b8e1f1f9f8d33c7170b0ebbea4523b695911abbf26e41885344823bd0587115fdd83b721a4e8457a31c9a84b3d3520a07e0e35df7f48e5a9d534d0ec7feef1ff74de6a11e7f93eab95175b6ce22c68d78a642ad642837897ec11349205d8593ac19300207572c38d29ca5dfa03bc14cdbc32153c80e5cc3e739403d34c75915e49beb43094cc6dcafb3665b305ddec9286934ae66ec6b777ca528728c851318eb0f207b39f1caaf96db6eeead6b55ed08f451939314577d42bcc9f97c0b52d0234f88fd07e4c1d7780fdebc025cfffcb572cb27a8c33963",
"Name": "nagydani-4-pow0x10001",
"Gas": 21845,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf02e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad",
"Expected": "d61fe4e3f32ac260915b5b03b78a86d11bfc41d973fce5b0cc59035cf8289a8a2e3878ea15fa46565b0d806e2f85b53873ea20ed653869b688adf83f3ef444535bf91598ff7e80f334fb782539b92f39f55310cc4b35349ab7b278346eda9bc37c0d8acd3557fae38197f412f8d9e57ce6a76b7205c23564cab06e5615be7c6f05c3d05ec690cba91da5e89d55b152ff8dd2157dc5458190025cf94b1ad98f7cbe64e9482faba95e6b33844afc640892872b44a9932096508f4a782a4805323808f23e54b6ff9b841dbfa87db3505ae4f687972c18ea0f0d0af89d36c1c2a5b14560c153c3fee406f5cf15cfd1c0bb45d767426d465f2f14c158495069d0c5955a00150707862ecaae30624ebacdd8ac33e4e6aab3ff90b6ba445a84689386b9e945d01823a65874444316e83767290fcff630d2477f49d5d8ffdd200e08ee1274270f86ed14c687895f6caf5ce528bd970c20d2408a9ba66216324c6a011ac4999098362dbd98a038129a2d40c8da6ab88318aa3046cb660327cc44236d9e5d2163bd0959062195c51ed93d0088b6f92051fc99050ece2538749165976233697ab4b610385366e5ce0b02ad6b61c168ecfbedcdf74278a38de340fd7a5fead8e588e294795f9b011e2e60377a89e25c90e145397cdeabc60fd32444a6b7642a611a83c464d8b8976666351b4865c37b02e6dc21dbcdf5f930341707b618cc0f03c3122646b3385c9df9f2ec730eec9d49e7dfc9153b6e6289da8c4f0ebea9ccc1b751948e3bb7171c9e4d57423b0eeeb79095c030cb52677b3f7e0b45c30f645391f3f9c957afa549c4e0b2465b03c67993cd200b1af01035962edbc4c9e89b31c82ac121987d6529dafdeef67a132dc04b6dc68e77f22862040b75e2ceb9ff16da0fca534e6db7bd12fa7b7f51b6c08c1e23dfcdb7acbd2da0b51c87ffbced065a612e9b1c8bba9b7e2d8d7a2f04fcc4aaf355b60d764879a76b5e16762d5f2f55d585d0c8e82df6940960cddfb72c91dfa71f6b4e1c6ca25dfc39a878e998a663c04fe29d5e83b9586d047b4d7ff70a9f0d44f127e7d741685ca75f11629128d916a0ffef4be586a30c4b70389cc746e84ebf177c01ee8a4511cfbb9d1ecf7f7b33c7dd8177896e10bbc82f838dcd6db7ac67de62bf46b6a640fb580c5d1d2708f3862e3d2b645d0d18e49ef088053e3a220adc0e033c2afcfe61c90e32151152eb3caaf746c5e377d541cafc6cbb0cc0fa48b5caf1728f2e1957f5addfc234f1a9d89e40d49356c9172d0561a695fce6dab1d412321bbf407f63766ffd7b6b3d79bcfa07991c5a9709849c1008689e3b47c50d613980bec239fb64185249d055b30375ccb4354d71fe4d05648fbf6c80634dfc3575f2f24abb714c1e4c95e8896763bf4316e954c7ad19e5780ab7a040ca6fb9271f90a8b22ae738daf6cb",
"Name": "nagydani-5-square",
"Gas": 5461,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf03e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad",
"Expected": "5f9c70ec884926a89461056ad20ac4c30155e817f807e4d3f5bb743d789c83386762435c3627773fa77da5144451f2a8aad8adba88e0b669f5377c5e9bad70e45c86fe952b613f015a9953b8a5de5eaee4566acf98d41e327d93a35bd5cef4607d025e58951167957df4ff9b1627649d3943805472e5e293d3efb687cfd1e503faafeb2840a3e3b3f85d016051a58e1c9498aab72e63b748d834b31eb05d85dcde65e27834e266b85c75cc4ec0135135e0601cb93eeeb6e0010c8ceb65c4c319623c5e573a2c8c9fbbf7df68a930beb412d3f4dfd146175484f45d7afaa0d2e60684af9b34730f7c8438465ad3e1d0c3237336722f2aa51095bd5759f4b8ab4dda111b684aa3dac62a761722e7ae43495b7709933512c81c4e3c9133a51f7ce9f2b51fcec064f65779666960b4e45df3900f54311f5613e8012dd1b8efd359eda31a778264c72aa8bb419d862734d769076bce2810011989a45374e5c5d8729fec21427f0bf397eacbb4220f603cf463a4b0c94efd858ffd9768cd60d6ce68d755e0fbad007ce5c2223d70c7018345a102e4ab3c60a13a9e7794303156d4c2063e919f2153c13961fb324c80b240742f47773a7a8e25b3e3fb19b00ce839346c6eb3c732fbc6b888df0b1fe0a3d07b053a2e9402c267b2d62f794d8a2840526e3ade15ce2264496ccd7519571dfde47f7a4bb16292241c20b2be59f3f8fb4f6383f232d838c5a22d8c95b6834d9d2ca493f5a505ebe8899503b0e8f9b19e6e2dd81c1628b80016d02097e0134de51054c4e7674824d4d758760fc52377d2cad145e259aa2ffaf54139e1a66b1e0c1c191e32ac59474c6b526f5b3ba07d3e5ec286eddf531fcd5292869be58c9f22ef91026159f7cf9d05ef66b4299f4da48cc1635bf2243051d342d378a22c83390553e873713c0454ce5f3234397111ac3fe3207b86f0ed9fc025c81903e1748103692074f83824fda6341be4f95ff00b0a9a208c267e12fa01825054cc0513629bf3dbb56dc5b90d4316f87654a8be18227978ea0a8a522760cad620d0d14fd38920fb7321314062914275a5f99f677145a6979b156bd82ecd36f23f8e1273cc2759ecc0b2c69d94dad5211d1bed939dd87ed9e07b91d49713a6e16ade0a98aea789f04994e318e4ff2c8a188cd8d43aeb52c6daa3bc29b4af50ea82a247c5cd67b573b34cbadcc0a376d3bbd530d50367b42705d870f2e27a8197ef46070528bfe408360faa2ebb8bf76e9f388572842bcb119f4d84ee34ae31f5cc594f23705a49197b181fb78ed1ec99499c690f843a4d0cf2e226d118e9372271054fbabdcc5c92ae9fefaef0589cd0e722eaf30c1703ec4289c7fd81beaa8a455ccee5298e31e2080c10c366a6fcf56f7d13582ad0bcad037c612b710fc595b70fbefaaca23623b60c6c39b11beb8e5843b6b3dac60f",
"Name": "nagydani-5-qube",
"Gas": 5461,
"NoBenchmark": false
},
{
"Input": "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf010001e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad",
"Expected": "5a0eb2bdf0ac1cae8e586689fa16cd4b07dfdedaec8a110ea1fdb059dd5253231b6132987598dfc6e11f86780428982d50cf68f67ae452622c3b336b537ef3298ca645e8f89ee39a26758206a5a3f6409afc709582f95274b57b71fae5c6b74619ae6f089a5393c5b79235d9caf699d23d88fb873f78379690ad8405e34c19f5257d596580c7a6a7206a3712825afe630c76b31cdb4a23e7f0632e10f14f4e282c81a66451a26f8df2a352b5b9f607a7198449d1b926e27036810368e691a74b91c61afa73d9d3b99453e7c8b50fd4f09c039a2f2feb5c419206694c31b92df1d9586140cb3417b38d0c503c7b508cc2ed12e813a1c795e9829eb39ee78eeaf360a169b491a1d4e419574e712402de9d48d54c1ae5e03739b7156615e8267e1fb0a897f067afd11fb33f6e24182d7aaaaa18fe5bc1982f20d6b871e5a398f0f6f718181d31ec225cfa9a0a70124ed9a70031bdf0c1c7829f708b6e17d50419ef361cf77d99c85f44607186c8d683106b8bd38a49b5d0fb503b397a83388c5678dcfcc737499d84512690701ed621a6f0172aecf037184ddf0f2453e4053024018e5ab2e30d6d5363b56e8b41509317c99042f517247474ab3abc848e00a07f69c254f46f2a05cf6ed84e5cc906a518fdcfdf2c61ce731f24c5264f1a25fc04934dc28aec112134dd523f70115074ca34e3807aa4cb925147f3a0ce152d323bd8c675ace446d0fd1ae30c4b57f0eb2c23884bc18f0964c0114796c5b6d080c3d89175665fbf63a6381a6a9da39ad070b645c8bb1779506da14439a9f5b5d481954764ea114fac688930bc68534d403cff4210673b6a6ff7ae416b7cd41404c3d3f282fcd193b86d0f54d0006c2a503b40d5c3930da980565b8f9630e9493a79d1c03e74e5f93ac8e4dc1a901ec5e3b3e57049124c7b72ea345aa359e782285d9e6a5c144a378111dd02c40855ff9c2be9b48425cb0b2fd62dc8678fd151121cf26a65e917d65d8e0dacfae108eb5508b601fb8ffa370be1f9a8b749a2d12eeab81f41079de87e2d777994fa4d28188c579ad327f9957fb7bdecec5c680844dd43cb57cf87aeb763c003e65011f73f8c63442df39a92b946a6bd968a1c1e4d5fa7d88476a68bd8e20e5b70a99259c7d3f85fb1b65cd2e93972e6264e74ebf289b8b6979b9b68a85cd5b360c1987f87235c3c845d62489e33acf85d53fa3561fe3a3aee18924588d9c6eba4edb7a4d106b31173e42929f6f0c48c80ce6a72d54eca7c0fe870068b7a7c89c63cdda593f5b32d3cb4ea8a32c39f00ab449155757172d66763ed9527019d6de6c9f2416aa6203f4d11c9ebee1e1d3845099e55504446448027212616167eb36035726daa7698b075286f5379cd3e93cb3e0cf4f9cb8d017facbb5550ed32d5ec5400ae57e47e2bf78d1eaeff9480cc765ceff39db500",
"Name": "nagydani-5-pow0x10001",
"Gas": 87381,
"NoBenchmark": false
}
]
}

View File

@ -16,14 +16,14 @@ import
../constantine/ethereum_evm_precompiles
type
BN256Tests = object
PrecompileTests = object
`func`: string
fork: string
data: seq[BN256Test]
data: seq[PrecompileTest]
HexString = string
BN256Test = object
PrecompileTest = object
Input: HexString
Expected: HexString
Name: string
@ -38,9 +38,10 @@ proc loadVectors(TestType: typedesc, filename: string): TestType =
let content = readFile(TestVectorsDir/filename)
result = content.fromJson(TestType)
template runBN256Tests(filename: string, funcname: untyped, osize: static int) =
proc `bn256testrunner _ funcname`() =
let vec = loadVectors(BN256Tests, filename)
template runPrecompileTests(filename: string, funcname: untyped) =
block:
proc `PrecompileTestrunner _ funcname`() =
let vec = loadVectors(PrecompileTests, filename)
echo "Running ", filename
for test in vec.data:
@ -50,15 +51,15 @@ template runBN256Tests(filename: string, funcname: untyped, osize: static int) =
var inputbytes = newSeq[byte](test.Input.len div 2)
inputbytes.paddedFromHex(test.Input, bigEndian)
var r: array[osize, byte]
var expected: array[osize, byte]
var expected = newSeq[byte](test.Expected.len div 2)
expected.paddedFromHex(test.Expected, bigEndian)
var r = newSeq[byte](test.Expected.len div 2)
let status = funcname(r, inputbytes)
if status != cttEVM_Success:
reset(r)
expected.paddedFromHex(test.Expected, bigEndian)
doAssert r == expected, "[Test Failure]\n" &
" " & funcname.astToStr & " status: " & $status & "\n" &
" " & "result: " & r.toHex() & "\n" &
@ -66,8 +67,10 @@ template runBN256Tests(filename: string, funcname: untyped, osize: static int) =
stdout.write "Success\n"
`bn256testrunner _ funcname`()
`PrecompileTestrunner _ funcname`()
runBN256Tests("bn256Add.json", eth_evm_ecadd, 64)
runBN256Tests("bn256mul.json", eth_evm_ecmul, 64)
runBN256Tests("pairing.json", eth_evm_ecpairing, 32)
runPrecompileTests("bn256Add.json", eth_evm_ecadd)
runPrecompileTests("bn256mul.json", eth_evm_ecmul)
runPrecompileTests("pairing.json", eth_evm_ecpairing)
runPrecompileTests("modexp.json", eth_evm_modexp)
runPrecompileTests("modexp_eip2565.json", eth_evm_modexp)