From b1ef2682d60a842c820963f070b87fa4a8980865 Mon Sep 17 00:00:00 2001 From: Mamy Ratsimbazafy Date: Thu, 1 Jun 2023 23:38:41 +0200 Subject: [PATCH] Modular exponentiation (arbitrary output) and EIP-198 (#242) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 --- benchmarks/bench_fields_template.nim | 2 +- benchmarks/bench_powmod.nim | 205 +++++++++ constantine.nimble | 13 +- constantine/ethereum_evm_precompiles.nim | 175 ++++++-- .../limbs_asm_modular_dbl_prec_x86.nim | 2 +- constantine/math/arithmetic/bigints.nim | 2 +- .../math/arithmetic/bigints_montgomery.nim | 8 +- constantine/math/arithmetic/finite_fields.nim | 8 +- .../finite_fields_double_precision.nim | 2 +- .../arithmetic/finite_fields_square_root.nim | 18 +- constantine/math/arithmetic/limbs.nim | 8 - constantine/math/arithmetic/limbs_exgcd.nim | 26 +- constantine/math/arithmetic/limbs_extmul.nim | 3 +- .../math/arithmetic/limbs_montgomery.nim | 19 +- constantine/math/config/precompute.nim | 13 +- constantine/math/config/type_bigint.nim | 23 - .../math/elliptic/ec_scalar_mul_vartime.nim | 14 +- .../math/extension_fields/exponentiations.nim | 10 +- constantine/math/pairings/pairings_bls12.nim | 2 +- constantine/math/pairings/pairings_bn.nim | 2 +- .../math/pairings/pairings_bw6_761.nim | 4 +- .../math_arbitrary_precision/README.md | 11 + .../arithmetic/bigints_views.nim | 202 +++++++++ .../arithmetic/limbs_division.nim | 140 +----- .../arithmetic/limbs_extmul.nim | 44 ++ .../arithmetic/limbs_fixedprec.nim | 74 +++ .../arithmetic/limbs_mod.nim | 48 ++ .../arithmetic/limbs_mod2k.nim | 194 ++++++++ .../arithmetic/limbs_montgomery.nim | 420 ++++++++++++++++++ .../arithmetic/limbs_multiprec.nim | 163 +++++++ .../arithmetic/limbs_views.nim | 122 +++++ constantine/platforms/abstractions.nim | 64 ++- constantine/platforms/code_generator/ir.nim | 11 +- constantine/platforms/primitives.nim | 7 +- research/kzg/fft_lut.nim | 2 +- .../t_bigints_mod.nim | 19 + .../t_bigints_mod_vs_gmp.nim | 12 +- .../t_bigints_powmod_vs_gmp.nim | 125 ++++++ .../t_fp12_exponentiation.nim | 34 +- .../t_fp_tower_frobenius_template.nim | 12 +- tests/math_fields/t_finite_fields_powinv.nim | 8 +- .../modexp.json | 126 ++++++ .../modexp_eip2565.json | 126 ++++++ tests/t_ethereum_evm_precompiles.nim | 57 +-- 44 files changed, 2260 insertions(+), 320 deletions(-) create mode 100644 benchmarks/bench_powmod.nim create mode 100644 constantine/math_arbitrary_precision/README.md create mode 100644 constantine/math_arbitrary_precision/arithmetic/bigints_views.nim rename constantine/{math => math_arbitrary_precision}/arithmetic/limbs_division.nim (62%) create mode 100644 constantine/math_arbitrary_precision/arithmetic/limbs_extmul.nim create mode 100644 constantine/math_arbitrary_precision/arithmetic/limbs_fixedprec.nim create mode 100644 constantine/math_arbitrary_precision/arithmetic/limbs_mod.nim create mode 100644 constantine/math_arbitrary_precision/arithmetic/limbs_mod2k.nim create mode 100644 constantine/math_arbitrary_precision/arithmetic/limbs_montgomery.nim create mode 100644 constantine/math_arbitrary_precision/arithmetic/limbs_multiprec.nim create mode 100644 constantine/math_arbitrary_precision/arithmetic/limbs_views.nim create mode 100644 tests/math_arbitrary_precision/t_bigints_mod.nim create mode 100644 tests/math_arbitrary_precision/t_bigints_powmod_vs_gmp.nim create mode 100644 tests/protocol_ethereum_evm_precompiles/modexp.json create mode 100644 tests/protocol_ethereum_evm_precompiles/modexp_eip2565.json diff --git a/benchmarks/bench_fields_template.nim b/benchmarks/bench_fields_template.nim index 930d871..40d4e1e 100644 --- a/benchmarks/bench_fields_template.nim +++ b/benchmarks/bench_fields_template.nim @@ -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) diff --git a/benchmarks/bench_powmod.nim b/benchmarks/bench_powmod.nim new file mode 100644 index 0000000..4f2daf4 --- /dev/null +++ b/benchmarks/bench_powmod.nim @@ -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() \ No newline at end of file diff --git a/constantine.nimble b/constantine.nimble index 5278b26..126e810 100644 --- a/constantine.nimble +++ b/constantine.nimble @@ -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 # ------------------------------------------ diff --git a/constantine/ethereum_evm_precompiles.nim b/constantine/ethereum_evm_precompiles.nim index 2af6917..5534ffe 100644 --- a/constantine/ethereum_evm_precompiles.nim +++ b/constantine/ethereum_evm_precompiles.nim @@ -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 \ No newline at end of file diff --git a/constantine/math/arithmetic/assembly/limbs_asm_modular_dbl_prec_x86.nim b/constantine/math/arithmetic/assembly/limbs_asm_modular_dbl_prec_x86.nim index f15eac4..5f3ed40 100644 --- a/constantine/math/arithmetic/assembly/limbs_asm_modular_dbl_prec_x86.nim +++ b/constantine/math/arithmetic/assembly/limbs_asm_modular_dbl_prec_x86.nim @@ -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. diff --git a/constantine/math/arithmetic/bigints.nim b/constantine/math/arithmetic/bigints.nim index 6050c7e..1dfe244 100644 --- a/constantine/math/arithmetic/bigints.nim +++ b/constantine/math/arithmetic/bigints.nim @@ -12,7 +12,7 @@ import ./limbs, ./limbs_extmul, ./limbs_exgcd, - ./limbs_division + ../../math_arbitrary_precision/arithmetic/limbs_division export BigInt diff --git a/constantine/math/arithmetic/bigints_montgomery.nim b/constantine/math/arithmetic/bigints_montgomery.nim index 8ee2024..0eb634c 100644 --- a/constantine/math/arithmetic/bigints_montgomery.nim +++ b/constantine/math/arithmetic/bigints_montgomery.nim @@ -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 diff --git a/constantine/math/arithmetic/finite_fields.nim b/constantine/math/arithmetic/finite_fields.nim index 8f81ea4..7d3d95e 100644 --- a/constantine/math/arithmetic/finite_fields.nim +++ b/constantine/math/arithmetic/finite_fields.nim @@ -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, diff --git a/constantine/math/arithmetic/finite_fields_double_precision.nim b/constantine/math/arithmetic/finite_fields_double_precision.nim index fb688c9..c4c4131 100644 --- a/constantine/math/arithmetic/finite_fields_double_precision.nim +++ b/constantine/math/arithmetic/finite_fields_double_precision.nim @@ -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. diff --git a/constantine/math/arithmetic/finite_fields_square_root.nim b/constantine/math/arithmetic/finite_fields_square_root.nim index d89885c..5dfbc64 100644 --- a/constantine/math/arithmetic/finite_fields_square_root.nim +++ b/constantine/math/arithmetic/finite_fields_square_root.nim @@ -39,7 +39,7 @@ func invsqrt_p3mod4(r: var Fp, a: Fp) = # Algorithm # # - # From Euler's criterion: + # From Euler's criterion: # 𝛘(a) = a^((p-1)/2)) ≡ 1 (mod p) if square # a^((p-1)/2)) * a^-1 ≡ 1/a (mod p) # a^((p-3)/2)) ≡ 1/a (mod p) @@ -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) # ------------------------------------------------------------ @@ -106,26 +106,26 @@ func invsqrt_p5mod8(r: var Fp, a: Fp) = # and α = (β/2a)⁽¹⸍²⁾= (2a)^(((p-1)/4 - 1)/2) = (2a)^((p-5)/8) static: doAssert Fp.C.has_P_5mod8_primeModulus() var alpha{.noInit.}, beta{.noInit.}: Fp - + # α = (2a)^((p-5)/8) alpha.double(a) beta = alpha 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 # β = 2aα² r.square(alpha) beta *= r - + # √a = αa(β − 1), so 1/√a = α(β − 1) r.setOne() beta -= r r.prod(alpha, beta) - + # Specialized routines for addchain-based square roots # ------------------------------------------------------------ @@ -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, @@ -299,9 +299,9 @@ func isSquare*(a: Fp): SecretBool = func sqrt_ratio_if_square*(r: var Fp, u, v: Fp): SecretBool {.inline.} = ## If u/v is a square, compute √(u/v) ## if not, the result is undefined - ## + ## ## r must not alias u or v - ## + ## ## The square root, if it exist is multivalued, ## i.e. both (u/v)² == (-u/v)² ## This procedure returns a deterministic result diff --git a/constantine/math/arithmetic/limbs.nim b/constantine/math/arithmetic/limbs.nim index f5e5435..2aa90f1 100644 --- a/constantine/math/arithmetic/limbs.nim +++ b/constantine/math/arithmetic/limbs.nim @@ -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 # ------------------------------------------------------------ diff --git a/constantine/math/arithmetic/limbs_exgcd.nim b/constantine/math/arithmetic/limbs_exgcd.nim index a6445b7..912e986 100644 --- a/constantine/math/arithmetic/limbs_exgcd.nim +++ b/constantine/math/arithmetic/limbs_exgcd.nim @@ -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) diff --git a/constantine/math/arithmetic/limbs_extmul.nim b/constantine/math/arithmetic/limbs_extmul.nim index e2fa84d..ce5fe77 100644 --- a/constantine/math/arithmetic/limbs_extmul.nim +++ b/constantine/math/arithmetic/limbs_extmul.nim @@ -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 ## diff --git a/constantine/math/arithmetic/limbs_montgomery.nim b/constantine/math/arithmetic/limbs_montgomery.nim index d34bf9a..840c8b3 100644 --- a/constantine/math/arithmetic/limbs_montgomery.nim +++ b/constantine/math/arithmetic/limbs_montgomery.nim @@ -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: diff --git a/constantine/math/config/precompute.nim b/constantine/math/config/precompute.nim index dcd27e4..5759c09 100644 --- a/constantine/math/config/precompute.nim +++ b/constantine/math/config/precompute.nim @@ -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: diff --git a/constantine/math/config/type_bigint.nim b/constantine/math/config/type_bigint.nim index 99ebcd3..5171ba4 100644 --- a/constantine/math/config/type_bigint.nim +++ b/constantine/math/config/type_bigint.nim @@ -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 diff --git a/constantine/math/elliptic/ec_scalar_mul_vartime.nim b/constantine/math/elliptic/ec_scalar_mul_vartime.nim index 585637a..40023ff 100644 --- a/constantine/math/elliptic/ec_scalar_mul_vartime.nim +++ b/constantine/math/elliptic/ec_scalar_mul_vartime.nim @@ -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 diff --git a/constantine/math/extension_fields/exponentiations.nim b/constantine/math/extension_fields/exponentiations.nim index c8b32af..be9dfbc 100644 --- a/constantine/math/extension_fields/exponentiations.nim +++ b/constantine/math/extension_fields/exponentiations.nim @@ -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) diff --git a/constantine/math/pairings/pairings_bls12.nim b/constantine/math/pairings/pairings_bls12.nim index e7745c6..16a13dc 100644 --- a/constantine/math/pairings/pairings_bls12.nim +++ b/constantine/math/pairings/pairings_bls12.nim @@ -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], diff --git a/constantine/math/pairings/pairings_bn.nim b/constantine/math/pairings/pairings_bn.nim index 9c0be5d..9a2df4a 100644 --- a/constantine/math/pairings/pairings_bn.nim +++ b/constantine/math/pairings/pairings_bn.nim @@ -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], diff --git a/constantine/math/pairings/pairings_bw6_761.nim b/constantine/math/pairings/pairings_bw6_761.nim index b63273b..bf88cd9 100644 --- a/constantine/math/pairings/pairings_bw6_761.nim +++ b/constantine/math/pairings/pairings_bw6_761.nim @@ -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 # ---------------------------------------------------------------- diff --git a/constantine/math_arbitrary_precision/README.md b/constantine/math_arbitrary_precision/README.md new file mode 100644 index 0000000..48ec75c --- /dev/null +++ b/constantine/math_arbitrary_precision/README.md @@ -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 diff --git a/constantine/math_arbitrary_precision/arithmetic/bigints_views.nim b/constantine/math_arbitrary_precision/arithmetic/bigints_views.nim new file mode 100644 index 0000000..43661c1 --- /dev/null +++ b/constantine/math_arbitrary_precision/arithmetic/bigints_views.nim @@ -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) diff --git a/constantine/math/arithmetic/limbs_division.nim b/constantine/math_arbitrary_precision/arithmetic/limbs_division.nim similarity index 62% rename from constantine/math/arithmetic/limbs_division.nim rename to constantine/math_arbitrary_precision/arithmetic/limbs_division.nim index 745fa34..04542e2 100644 --- a/constantine/math/arithmetic/limbs_division.nim +++ b/constantine/math_arbitrary_precision/arithmetic/limbs_division.nim @@ -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,14 +120,19 @@ func shlAddMod(a: LimbsViewMut, aLen: int, let R = mBits and (WordBitWidth - 1) # (hi, lo) = a * 2^64 + c - let hi = (a[0] shl (WordBitWidth-R)) or (c shr R) - let lo = c shl (WordBitWidth-R) - let m0 = M[0] shl (WordBitWidth-R) + 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) - var q, r: SecretWord - div2n1n(q, r, hi, lo, m0) # (hi, lo) mod M + var q, r: SecretWord + div2n1n(q, r, hi, lo, m0) # (hi, lo) mod M - a[0] = r shr (WordBitWidth-R) + a[0] = r shr (WordBitWidth-R) else: ## Multiple limbs @@ -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. diff --git a/constantine/math_arbitrary_precision/arithmetic/limbs_extmul.nim b/constantine/math_arbitrary_precision/arithmetic/limbs_extmul.nim new file mode 100644 index 0000000..eb8adab --- /dev/null +++ b/constantine/math_arbitrary_precision/arithmetic/limbs_extmul.nim @@ -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) \ No newline at end of file diff --git a/constantine/math_arbitrary_precision/arithmetic/limbs_fixedprec.nim b/constantine/math_arbitrary_precision/arithmetic/limbs_fixedprec.nim new file mode 100644 index 0000000..8e72e89 --- /dev/null +++ b/constantine/math_arbitrary_precision/arithmetic/limbs_fixedprec.nim @@ -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) \ No newline at end of file diff --git a/constantine/math_arbitrary_precision/arithmetic/limbs_mod.nim b/constantine/math_arbitrary_precision/arithmetic/limbs_mod.nim new file mode 100644 index 0000000..7a98a2f --- /dev/null +++ b/constantine/math_arbitrary_precision/arithmetic/limbs_mod.nim @@ -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) \ No newline at end of file diff --git a/constantine/math_arbitrary_precision/arithmetic/limbs_mod2k.nim b/constantine/math_arbitrary_precision/arithmetic/limbs_mod2k.nim new file mode 100644 index 0000000..303275a --- /dev/null +++ b/constantine/math_arbitrary_precision/arithmetic/limbs_mod2k.nim @@ -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] \ No newline at end of file diff --git a/constantine/math_arbitrary_precision/arithmetic/limbs_montgomery.nim b/constantine/math_arbitrary_precision/arithmetic/limbs_montgomery.nim new file mode 100644 index 0000000..62f5f0a --- /dev/null +++ b/constantine/math_arbitrary_precision/arithmetic/limbs_montgomery.nim @@ -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.} \ No newline at end of file diff --git a/constantine/math_arbitrary_precision/arithmetic/limbs_multiprec.nim b/constantine/math_arbitrary_precision/arithmetic/limbs_multiprec.nim new file mode 100644 index 0000000..b9639c1 --- /dev/null +++ b/constantine/math_arbitrary_precision/arithmetic/limbs_multiprec.nim @@ -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 \ No newline at end of file diff --git a/constantine/math_arbitrary_precision/arithmetic/limbs_views.nim b/constantine/math_arbitrary_precision/arithmetic/limbs_views.nim new file mode 100644 index 0000000..bfe1307 --- /dev/null +++ b/constantine/math_arbitrary_precision/arithmetic/limbs_views.nim @@ -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 diff --git a/constantine/platforms/abstractions.nim b/constantine/platforms/abstractions.nim index da1305b..d94f207 100644 --- a/constantine/platforms/abstractions.nim +++ b/constantine/platforms/abstractions.nim @@ -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 "]" # ############################################################ # diff --git a/constantine/platforms/code_generator/ir.nim b/constantine/platforms/code_generator/ir.nim index ab02553..bc12721 100644 --- a/constantine/platforms/code_generator/ir.nim +++ b/constantine/platforms/code_generator/ir.nim @@ -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) diff --git a/constantine/platforms/primitives.nim b/constantine/platforms/primitives.nim index c7cbc21..891401c 100644 --- a/constantine/platforms/primitives.nim +++ b/constantine/platforms/primitives.nim @@ -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, diff --git a/research/kzg/fft_lut.nim b/research/kzg/fft_lut.nim index f3af753..0a2c2df 100644 --- a/research/kzg/fft_lut.nim +++ b/research/kzg/fft_lut.nim @@ -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]) diff --git a/tests/math_arbitrary_precision/t_bigints_mod.nim b/tests/math_arbitrary_precision/t_bigints_mod.nim new file mode 100644 index 0000000..a7ca91c --- /dev/null +++ b/tests/math_arbitrary_precision/t_bigints_mod.nim @@ -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) \ No newline at end of file diff --git a/tests/math_arbitrary_precision/t_bigints_mod_vs_gmp.nim b/tests/math_arbitrary_precision/t_bigints_mod_vs_gmp.nim index 7250e1c..e332559 100644 --- a/tests/math_arbitrary_precision/t_bigints_mod_vs_gmp.nim +++ b/tests/math_arbitrary_precision/t_bigints_mod_vs_gmp.nim @@ -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)" diff --git a/tests/math_arbitrary_precision/t_bigints_powmod_vs_gmp.nim b/tests/math_arbitrary_precision/t_bigints_powmod_vs_gmp.nim new file mode 100644 index 0000000..ca128a2 --- /dev/null +++ b/tests/math_arbitrary_precision/t_bigints_powmod_vs_gmp.nim @@ -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' \ No newline at end of file diff --git a/tests/math_extension_fields/t_fp12_exponentiation.nim b/tests/math_extension_fields/t_fp12_exponentiation.nim index 405b769..b539f29 100644 --- a/tests/math_extension_fields/t_fp12_exponentiation.nim +++ b/tests/math_extension_fields/t_fp12_exponentiation.nim @@ -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) diff --git a/tests/math_extension_fields/t_fp_tower_frobenius_template.nim b/tests/math_extension_fields/t_fp_tower_frobenius_template.nim index 60024a3..b22e403 100644 --- a/tests/math_extension_fields/t_fp_tower_frobenius_template.nim +++ b/tests/math_extension_fields/t_fp_tower_frobenius_template.nim @@ -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): diff --git a/tests/math_fields/t_finite_fields_powinv.nim b/tests/math_fields/t_finite_fields_powinv.nim index 3726dd8..04c9cba 100644 --- a/tests/math_fields/t_finite_fields_powinv.nim +++ b/tests/math_fields/t_finite_fields_powinv.nim @@ -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" diff --git a/tests/protocol_ethereum_evm_precompiles/modexp.json b/tests/protocol_ethereum_evm_precompiles/modexp.json new file mode 100644 index 0000000..1594377 --- /dev/null +++ b/tests/protocol_ethereum_evm_precompiles/modexp.json @@ -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 + } + ] +} diff --git a/tests/protocol_ethereum_evm_precompiles/modexp_eip2565.json b/tests/protocol_ethereum_evm_precompiles/modexp_eip2565.json new file mode 100644 index 0000000..02e5b14 --- /dev/null +++ b/tests/protocol_ethereum_evm_precompiles/modexp_eip2565.json @@ -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 + } + ] +} diff --git a/tests/t_ethereum_evm_precompiles.nim b/tests/t_ethereum_evm_precompiles.nim index 4d157dc..f090389 100644 --- a/tests/t_ethereum_evm_precompiles.nim +++ b/tests/t_ethereum_evm_precompiles.nim @@ -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,36 +38,39 @@ 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) - echo "Running ", filename +template runPrecompileTests(filename: string, funcname: untyped) = + block: + proc `PrecompileTestrunner _ funcname`() = + let vec = loadVectors(PrecompileTests, filename) + echo "Running ", filename - for test in vec.data: - stdout.write " Testing " & test.Name & " ... " + for test in vec.data: + stdout.write " Testing " & test.Name & " ... " - # Length: 2 hex characters -> 1 byte - var inputbytes = newSeq[byte](test.Input.len div 2) - inputbytes.paddedFromHex(test.Input, bigEndian) + # Length: 2 hex characters -> 1 byte + 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) - let status = funcname(r, inputbytes) - if status != cttEVM_Success: - reset(r) + var r = newSeq[byte](test.Expected.len div 2) - expected.paddedFromHex(test.Expected, bigEndian) + let status = funcname(r, inputbytes) + if status != cttEVM_Success: + reset(r) - doAssert r == expected, "[Test Failure]\n" & - " " & funcname.astToStr & " status: " & $status & "\n" & - " " & "result: " & r.toHex() & "\n" & - " " & "expected: " & expected.toHex() & '\n' + doAssert r == expected, "[Test Failure]\n" & + " " & funcname.astToStr & " status: " & $status & "\n" & + " " & "result: " & r.toHex() & "\n" & + " " & "expected: " & expected.toHex() & '\n' - stdout.write "Success\n" + 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) \ No newline at end of file +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) \ No newline at end of file