diff --git a/src/contract/CMakeLists.txt b/src/contract/CMakeLists.txt index 4e4805c9..6a875ad0 100644 --- a/src/contract/CMakeLists.txt +++ b/src/contract/CMakeLists.txt @@ -57,7 +57,11 @@ set(CONTRACT_SOURCES ${CMAKE_SOURCE_DIR}/src/contract/common.cpp ${CMAKE_SOURCE_DIR}/src/contract/executioncontext.cpp ${CMAKE_SOURCE_DIR}/src/contract/evmcontractexecutor.cpp - ${CMAKE_SOURCE_DIR}/src/contract/precompiles.cpp + ${CMAKE_SOURCE_DIR}/src/contract/precompiles/ecrecover.cpp + ${CMAKE_SOURCE_DIR}/src/contract/precompiles/sha256.cpp + ${CMAKE_SOURCE_DIR}/src/contract/precompiles/ripemd160.cpp + ${CMAKE_SOURCE_DIR}/src/contract/precompiles/blake2f.cpp + ${CMAKE_SOURCE_DIR}/src/contract/precompiles/modexp.cpp ${CMAKE_SOURCE_DIR}/src/contract/precompiledcontractexecutor.cpp ${CMAKE_SOURCE_DIR}/src/contract/templates/ownable.cpp ${CMAKE_SOURCE_DIR}/src/contract/templates/erc20.cpp diff --git a/src/contract/abi.h b/src/contract/abi.h index c038e52a..7319d91a 100644 --- a/src/contract/abi.h +++ b/src/contract/abi.h @@ -247,6 +247,8 @@ namespace ABI { template<> struct TypeName { static std::string get() { return "string"; }}; template<> struct TypeName { static std::string get() { return "bytes32"; }}; + template struct TypeName> { static std::string get() { return "bytes" + std::to_string(N); } }; + /// Enum types are encoded as uint8_t template requires std::is_enum_v struct TypeName { @@ -414,6 +416,17 @@ namespace ABI { return len; } }; + + template struct TypeEncoder> { + static_assert(N <= 32); + + static Bytes encode(const FixedBytes& bytes) { + Bytes result(32); + std::ranges::copy(bytes, result.begin()); + return result; + } + }; + template <> struct TypeEncoder { static Bytes encode(const std::string& str) { View bytes = Utils::create_view_span(str); @@ -818,6 +831,19 @@ namespace ABI { } }; + template struct TypeDecoder> { + static_assert(N <= 32); + + static FixedBytes decode(const View& bytes, uint64_t& index) { + if (index + 32 > bytes.size()) + throw std::length_error("Data too short for bytes"); + + FixedBytes result; + std::ranges::copy(bytes.subspan(index, N), result.begin()); + return result; + } + }; + template <> struct TypeDecoder { static std::string decode(const View& bytes, uint64_t& index) { if (index + 32 > bytes.size()) throw std::length_error("Data too short for string 1"); diff --git a/src/contract/gas.h b/src/contract/gas.h index a98ce3de..cc921296 100644 --- a/src/contract/gas.h +++ b/src/contract/gas.h @@ -1,6 +1,7 @@ #ifndef BDK_MESSAGES_GAS_H #define BDK_MESSAGES_GAS_H +#include "utils/evmcconv.h" #include "outofgas.h" class Gas { diff --git a/src/contract/precompiledcontractexecutor.cpp b/src/contract/precompiledcontractexecutor.cpp index b6630657..5617b331 100644 --- a/src/contract/precompiledcontractexecutor.cpp +++ b/src/contract/precompiledcontractexecutor.cpp @@ -1,26 +1,53 @@ #include "precompiledcontractexecutor.h" -#include "precompiles.h" +#include "precompiles/precompiles.h" #include "bytes/hex.h" +#include +#include constexpr Address RANDOM_GENERATOR_ADDRESS = bytes::hex("0x1000000000000000000000000000100000000001"); -constexpr Address ECRECOVER_ADDRESS = bytes::hex("0x0000000000000000000000000000000000000001"); - -constexpr auto ECRECOVER_CALL_COST = 3'000; Bytes PrecompiledContractExecutor::execute(EncodedStaticCallMessage& msg) { if (msg.to() == RANDOM_GENERATOR_ADDRESS) { return Utils::makeBytes(UintConv::uint256ToBytes(std::invoke(randomGen_))); } - if (msg.to() == ECRECOVER_ADDRESS) { - msg.gas().use(ECRECOVER_CALL_COST); - const auto [hash, v, r, s] = ABI::Decoder::decodeData(msg.input()); - return ABI::Encoder::encodeData(ecrecover(hash, v, r, s)); - } + // assuming isPrecompiled() was already called + switch (msg.to()[19]) { + case 0x01: + return precompiles::ecrecover(msg.input(), msg.gas()); + + case 0x02: + return precompiles::sha256(msg.input(), msg.gas()); + + case 0x03: + return ABI::Encoder::encodeData(Address(precompiles::ripemd160(msg.input(), msg.gas()))); + + case 0x04: { + const uint64_t dynamicGasCost = ((msg.input().size() + 31) / 32) * 3; + msg.gas().use(15 + dynamicGasCost); + return Bytes(msg.input()); + return Bytes(msg.input()); + } + + case 0x05: + return precompiles::modexp(msg.input(), msg.gas()); - throw DynamicException("Precompiled contract not found"); + case 0x09: + return precompiles::blake2f(msg.input(), msg.gas()); + + default: + throw DynamicException("Precompiled contract not found"); + } } bool PrecompiledContractExecutor::isPrecompiled(View
address) const { - return address == RANDOM_GENERATOR_ADDRESS || address == ECRECOVER_ADDRESS; + if (address == RANDOM_GENERATOR_ADDRESS) { + return true; + } + + if (std::ranges::any_of(address | std::views::take(19), [] (Byte b) { return b != 0; })) { + return false; + } + + return address[19] <= 0x05 || address[19] == 0x09; } diff --git a/src/contract/precompiles.h b/src/contract/precompiles.h deleted file mode 100644 index 852694a5..00000000 --- a/src/contract/precompiles.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef BDK_CONTRACT_PRECOMPILES_H -#define BDK_CONTRACT_PRECOMPILES_H - -#include "utils/address.h" -#include "utils/hash.h" - -Address ecrecover(View hash, uint8_t v, View r, View s); - -#endif // BDK_CONTRACT_PRECOMPILES_H diff --git a/src/contract/precompiles/blake2f.cpp b/src/contract/precompiles/blake2f.cpp new file mode 100644 index 00000000..edd375cc --- /dev/null +++ b/src/contract/precompiles/blake2f.cpp @@ -0,0 +1,224 @@ +#include "precompiles.h" +#include +#include + +namespace { + +constexpr uint64_t iv[8] = { + 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1, + 0x510E527FADE682D1, 0x9B05688C2B3E6C1F, 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179 +}; + +constexpr Byte precomputed[10][16] = { + {0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, + {14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, + {11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4}, + {7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8}, + {9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13}, + {2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9}, + {12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11}, + {13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10}, + {6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5}, + {10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0} +}; + +constexpr size_t sizeInBytes(const std::ranges::contiguous_range auto& range) { + return std::ranges::size(range) * sizeof(std::ranges::range_value_t); +} + +} // namespace + +void precompiles::blake2f(std::span h, std::span m, + uint64_t c0, uint64_t c1, bool flag, uint32_t rounds) { + + uint64_t v0 = h[0]; + uint64_t v1 = h[1]; + uint64_t v2 = h[2]; + uint64_t v3 = h[3]; + uint64_t v4 = h[4]; + uint64_t v5 = h[5]; + uint64_t v6 = h[6]; + uint64_t v7 = h[7]; + uint64_t v8 = iv[0]; + uint64_t v9 = iv[1]; + uint64_t v10 = iv[2]; + uint64_t v11 = iv[3]; + uint64_t v12 = iv[4]; + uint64_t v13 = iv[5]; + uint64_t v14 = iv[6]; + uint64_t v15 = iv[7]; + + v12 ^= c0; + v13 ^= c1; + + if (flag) { + v14 ^= 0xFFFFFFFFFFFFFFFF; + } + + for (uint32_t i = 0; i < rounds; i++) { + const auto* s = precomputed[i % 10]; + + v0 += m[s[0]]; + v0 += v4; + v12 ^= v0; + v12 = std::rotr(v12, 32); + v8 += v12; + v4 ^= v8; + v4 = std::rotr(v4, 24); + v1 += m[s[1]]; + v1 += v5; + v13 ^= v1; + v13 = std::rotr(v13, 32); + v9 += v13; + v5 ^= v9; + v5 = std::rotr(v5, 24); + v2 += m[s[2]]; + v2 += v6; + v14 ^= v2; + v14 = std::rotr(v14, 32); + v10 += v14; + v6 ^= v10; + v6 = std::rotr(v6, 24); + v3 += m[s[3]]; + v3 += v7; + v15 ^= v3; + v15 = std::rotr(v15, 32); + v11 += v15; + v7 ^= v11; + v7 = std::rotr(v7, 24); + + v0 += m[s[4]]; + v0 += v4; + v12 ^= v0; + v12 = std::rotr(v12, 16); + v8 += v12; + v4 ^= v8; + v4 = std::rotr(v4, 63); + v1 += m[s[5]]; + v1 += v5; + v13 ^= v1; + v13 = std::rotr(v13, 16); + v9 += v13; + v5 ^= v9; + v5 = std::rotr(v5, 63); + v2 += m[s[6]]; + v2 += v6; + v14 ^= v2; + v14 = std::rotr(v14, 16); + v10 += v14; + v6 ^= v10; + v6 = std::rotr(v6, 63); + v3 += m[s[7]]; + v3 += v7; + v15 ^= v3; + v15 = std::rotr(v15, 16); + v11 += v15; + v7 ^= v11; + v7 = std::rotr(v7, 63); + + v0 += m[s[8]]; + v0 += v5; + v15 ^= v0; + v15 = std::rotr(v15, 32); + v10 += v15; + v5 ^= v10; + v5 = std::rotr(v5, 24); + v1 += m[s[9]]; + v1 += v6; + v12 ^= v1; + v12 = std::rotr(v12, 32); + v11 += v12; + v6 ^= v11; + v6 = std::rotr(v6, 24); + v2 += m[s[10]]; + v2 += v7; + v13 ^= v2; + v13 = std::rotr(v13, 32); + v8 += v13; + v7 ^= v8; + v7 = std::rotr(v7, 24); + v3 += m[s[11]]; + v3 += v4; + v14 ^= v3; + v14 = std::rotr(v14, 32); + v9 += v14; + v4 ^= v9; + v4 = std::rotr(v4, 24); + + v0 += m[s[12]]; + v0 += v5; + v15 ^= v0; + v15 = std::rotr(v15, 16); + v10 += v15; + v5 ^= v10; + v5 = std::rotr(v5, 63); + v1 += m[s[13]]; + v1 += v6; + v12 ^= v1; + v12 = std::rotr(v12, 16); + v11 += v12; + v6 ^= v11; + v6 = std::rotr(v6, 63); + v2 += m[s[14]]; + v2 += v7; + v13 ^= v2; + v13 = std::rotr(v13, 16); + v8 += v13; + v7 ^= v8; + v7 = std::rotr(v7, 63); + v3 += m[s[15]]; + v3 += v4; + v14 ^= v3; + v14 = std::rotr(v14, 16); + v9 += v14; + v4 ^= v9; + v4 = std::rotr(v4, 63); + } + + h[0] ^= v0 ^ v8; + h[1] ^= v1 ^ v9; + h[2] ^= v2 ^ v10; + h[3] ^= v3 ^ v11; + h[4] ^= v4 ^ v12; + h[5] ^= v5 ^ v13; + h[6] ^= v6 ^ v14; + h[7] ^= v7 ^ v15; +} + +Bytes precompiles::blake2f(View input, Gas& gas) { + if (input.size() != 213) { + throw std::invalid_argument("Blake2F requires exacly 213 bytes"); + } + + std::array h; + std::array m; + std::array t; + uint8_t flag; + uint32_t rounds; + + const Byte *in = input.data(); + + std::memcpy(&rounds, in, sizeof(rounds)); + in += sizeof(rounds); + + std::memcpy(&h, in, sizeInBytes(h)); + in += sizeInBytes(h); + + std::memcpy(&m, in, sizeInBytes(m)); + in += sizeInBytes(m); + + std::memcpy(&t, in, sizeInBytes(t)); + in += sizeInBytes(t); + + std::memcpy(&flag, in, sizeof(flag)); + + std::reverse(reinterpret_cast(&rounds), reinterpret_cast(&rounds + 1)); + + gas.use(rounds); + + blake2f(h, m, t[0], t[1], flag, rounds); + + Bytes output(sizeInBytes(h)); + std::memcpy(output.data(), h.data(), output.size()); + return output; +} diff --git a/src/contract/precompiles.cpp b/src/contract/precompiles/ecrecover.cpp similarity index 51% rename from src/contract/precompiles.cpp rename to src/contract/precompiles/ecrecover.cpp index 20b2cf3a..cd3a5667 100644 --- a/src/contract/precompiles.cpp +++ b/src/contract/precompiles/ecrecover.cpp @@ -1,7 +1,16 @@ #include "precompiles.h" +#include "contract/abi.h" #include "utils/signature.h" #include "utils/ecdsa.h" +namespace { + +constexpr auto ECRECOVER_COST = 3'000; + +} // namespace + +namespace precompiles { + Address ecrecover(View hash, uint8_t v, View r, View s) { if (v == 27) { v = 0; @@ -22,3 +31,15 @@ Address ecrecover(View hash, uint8_t v, View r, View s) { return Secp256k1::toAddress(pubkey); } + +Bytes ecrecover(View input, Gas& gas) { + gas.use(ECRECOVER_COST); + try { + const auto [hash, v, r, s] = ABI::Decoder::decodeData(input); + return ABI::Encoder::encodeData(ecrecover(hash, v, r, s)); + } catch (...) { + return ABI::Encoder::encodeData(Address{}); + } +} + +} // namespace precompiles diff --git a/src/contract/precompiles/modexp.cpp b/src/contract/precompiles/modexp.cpp new file mode 100644 index 00000000..e74ee586 --- /dev/null +++ b/src/contract/precompiles/modexp.cpp @@ -0,0 +1,118 @@ +#include "precompiles.h" +#include +#include "contract/abi.h" + +namespace { + +using BigInt = boost::multiprecision::cpp_int; +using boost::multiprecision::import_bits; +using boost::multiprecision::export_bits; + +constexpr int bitLength(auto value) { + int count = 0; + while (value) { + value >>= 1; + ++count; + } + return count; +} + +constexpr uint32_t multiplicationComplexity(uint16_t bSize, uint16_t mSize) { + const uint16_t maxSize = std::max(bSize, mSize); + const uint32_t words = (maxSize / 8) + bool(maxSize % 8); + return words * words; +} + +constexpr uint32_t iterationCount(uint16_t eSize, const BigInt& exp) { + uint32_t count; + + if (eSize <= 32 && exp == 0) { + count = 0; + } else if (eSize <= 32) { + count = bitLength(exp) - 1; + } else { + count = (8 * (eSize - 32)) + (bitLength(exp & ((BigInt(1) << 256) - 1)) - 1); + } + + return std::max(count, uint32_t(1)); +} + +inline uint64_t gasRequired(uint16_t bSize, uint16_t mSize, uint16_t eSize, const BigInt& exp) { + const uint64_t complexity = multiplicationComplexity(bSize, mSize); + const uint64_t count = iterationCount(eSize, exp); + return std::max(uint64_t(200), complexity * count / 3); +} + +std::tuple decodeSizes(View input) { + const auto [baseSize, expSize, modSize] = ABI::Decoder::decodeData(input); + + const uint256_t expectedSize = (32 * 3) + baseSize + expSize + modSize; + + if (input.size() < expectedSize) { + throw std::invalid_argument("not enough bytes given"); + } else if (input.size() > expectedSize) { + throw std::invalid_argument("too much bytes given"); + } + + if (baseSize > std::numeric_limits::max()) { + throw std::invalid_argument("base size is too big"); + } + + if (expSize > std::numeric_limits::max()) { + throw std::invalid_argument("exp size is too big"); + } + + if (modSize > std::numeric_limits::max()) { + throw std::invalid_argument("mod size is too big"); + } + + return std::make_tuple(uint16_t(baseSize), uint16_t(expSize), uint16_t(modSize)); +} + +} // namespace + + +Bytes precompiles::modexp(View input, Gas& gas) { + const auto [baseSize, expSize, modSize] = decodeSizes(input); + + auto in = input.begin() + (32 * 3); + + BigInt base = 0, exp = 0, mod = 0, result = 1; + + if (baseSize > 0) { + import_bits(base, in, in + baseSize); + in += baseSize; + } + + if (expSize > 0) { + import_bits(exp, in, in + expSize); + in += expSize; + } + + if (modSize > 0) { + import_bits(mod, in, in + modSize); + } + + gas.use(gasRequired(baseSize, modSize, expSize, exp)); + + Bytes output; + output.resize(modSize); + + if (mod == 1) { + return output; // means: return 0 + } + + base = base % mod; + + while (exp > 0) { + if (exp & 1 != 0) { + result = (result * base) % mod; + } + + exp >>= 1; + base = (base * base) % mod; + } + + export_bits(result, output.begin(), 8); + return output; +} diff --git a/src/contract/precompiles/precompiles.h b/src/contract/precompiles/precompiles.h new file mode 100644 index 00000000..0ea1be7f --- /dev/null +++ b/src/contract/precompiles/precompiles.h @@ -0,0 +1,29 @@ +#ifndef BDK_PRECOMPILES_H +#define BDK_PRECOMPILES_H + +#include "utils/bytes.h" +#include "utils/view.h" +#include "contract/gas.h" + +namespace precompiles { + +Address ecrecover(View hash, uint8_t v, View r, View s); + +Bytes ecrecover(View input, Gas& gas); + +Bytes sha256(View input, Gas& gas); + +Bytes ripemd160(View input, Gas& gas); + +Bytes modexp(View input, Gas& gas); + +void blake2f(std::span h, std::span m, + uint64_t c0, uint64_t c1, bool flag, uint32_t rounds); + +Bytes blake2f(View input, Gas& gas); + +Bytes modexp(View input, Gas& gas); + +} // namespace precompiles + +#endif // BDK_PRECOMPILES_H diff --git a/src/contract/precompiles/ripemd160.cpp b/src/contract/precompiles/ripemd160.cpp new file mode 100644 index 00000000..b654d6db --- /dev/null +++ b/src/contract/precompiles/ripemd160.cpp @@ -0,0 +1,21 @@ +#include "precompiles.h" +#include "utils/address.h" +#include "ripemd160.hpp" +#include "contract/abi.h" + +namespace { + +constexpr size_t OUTPUT_SIZE = 20; + +constexpr uint64_t gasRequired(size_t size) { + return ((size + 31) / 32) * 120 + 600; +} + +} // namespace + +Bytes precompiles::ripemd160(View input, Gas& gas) { + gas.use(gasRequired(input.size())); + Bytes output(OUTPUT_SIZE); + RIPEMD160::ripemd160(input.data(), input.size(), output.data()); + return output; +} diff --git a/src/contract/precompiles/ripemd160.hpp b/src/contract/precompiles/ripemd160.hpp new file mode 100644 index 00000000..3168fee7 --- /dev/null +++ b/src/contract/precompiles/ripemd160.hpp @@ -0,0 +1,344 @@ +/** + * Copyright (c) 2015 Jonas Schnelli + * Copyright (c) 2013-2014 Tomas Dzetkulic + * Copyright (c) 2013-2014 Pavol Rusnak + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef RIPMD160_HPP +#define RIPMD160_HPP + + +#include +#include + +// ================================================== + +namespace RIPEMD160 { +#define ROL_RIPEMD160(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +#define F_RIPEMD160(x, y, z) ((x) ^ (y) ^ (z)) +#define G_RIPEMD160(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define H_RIPEMD160(x, y, z) (((x) | ~(y)) ^ (z)) +#define IQ_RIPEMD160(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define J_RIPEMD160(x, y, z) ((x) ^ ((y) | ~(z))) + +#define FF(a, b, c, d, e, x, s) \ +{ \ + (a) += F_RIPEMD160((b), (c), (d)) + (x); \ + (a) = ROL_RIPEMD160((a), (s)) + (e); \ + (c) = ROL_RIPEMD160((c), 10); \ +} +#define GG(a, b, c, d, e, x, s) \ +{ \ + (a) += G_RIPEMD160((b), (c), (d)) + (x) + 0x5a827999UL; \ + (a) = ROL_RIPEMD160((a), (s)) + (e); \ + (c) = ROL_RIPEMD160((c), 10); \ +} +#define HH(a, b, c, d, e, x, s) \ +{ \ + (a) += H_RIPEMD160((b), (c), (d)) + (x) + 0x6ed9eba1UL; \ + (a) = ROL_RIPEMD160((a), (s)) + (e); \ + (c) = ROL_RIPEMD160((c), 10); \ +} +#define II(a, b, c, d, e, x, s) \ +{ \ + (a) += IQ_RIPEMD160((b), (c), (d)) + (x) + 0x8f1bbcdcUL; \ + (a) = ROL_RIPEMD160((a), (s)) + (e); \ + (c) = ROL_RIPEMD160((c), 10); \ +} +#define JJ(a, b, c, d, e, x, s) \ +{ \ + (a) += J_RIPEMD160((b), (c), (d)) + (x) + 0xa953fd4eUL; \ + (a) = ROL_RIPEMD160((a), (s)) + (e); \ + (c) = ROL_RIPEMD160((c), 10); \ +} + +#define FFF(a, b, c, d, e, x, s) \ +{ \ + (a) += F_RIPEMD160((b), (c), (d)) + (x); \ + (a) = ROL_RIPEMD160((a), (s)) + (e); \ + (c) = ROL_RIPEMD160((c), 10); \ +} +#define GGG(a, b, c, d, e, x, s) \ +{ \ + (a) += G_RIPEMD160((b), (c), (d)) + (x) + 0x7a6d76e9UL; \ + (a) = ROL_RIPEMD160((a), (s)) + (e); \ + (c) = ROL_RIPEMD160((c), 10); \ +} +#define HHH(a, b, c, d, e, x, s) \ +{ \ + (a) += H_RIPEMD160((b), (c), (d)) + (x) + 0x6d703ef3UL; \ + (a) = ROL_RIPEMD160((a), (s)) + (e); \ + (c) = ROL_RIPEMD160((c), 10); \ +} +#define III(a, b, c, d, e, x, s) \ +{ \ + (a) += IQ_RIPEMD160((b), (c), (d)) + (x) + 0x5c4dd124UL; \ + (a) = ROL_RIPEMD160((a), (s)) + (e); \ + (c) = ROL_RIPEMD160((c), 10); \ +} +#define JJJ(a, b, c, d, e, x, s) \ +{ \ + (a) += J_RIPEMD160((b), (c), (d)) + (x) + 0x50a28be6UL; \ + (a) = ROL_RIPEMD160((a), (s)) + (e); \ + (c) = ROL_RIPEMD160((c), 10); \ +} + static void compress(uint32_t* MDbuf, uint32_t* X) + { + uint32_t aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2], dd = MDbuf[3], ee = MDbuf[4]; + uint32_t aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2], ddd = MDbuf[3], eee = MDbuf[4]; + + /* round 1 */ + FF(aa, bb, cc, dd, ee, X[0], 11); + FF(ee, aa, bb, cc, dd, X[1], 14); + FF(dd, ee, aa, bb, cc, X[2], 15); + FF(cc, dd, ee, aa, bb, X[3], 12); + FF(bb, cc, dd, ee, aa, X[4], 5); + FF(aa, bb, cc, dd, ee, X[5], 8); + FF(ee, aa, bb, cc, dd, X[6], 7); + FF(dd, ee, aa, bb, cc, X[7], 9); + FF(cc, dd, ee, aa, bb, X[8], 11); + FF(bb, cc, dd, ee, aa, X[9], 13); + FF(aa, bb, cc, dd, ee, X[10], 14); + FF(ee, aa, bb, cc, dd, X[11], 15); + FF(dd, ee, aa, bb, cc, X[12], 6); + FF(cc, dd, ee, aa, bb, X[13], 7); + FF(bb, cc, dd, ee, aa, X[14], 9); + FF(aa, bb, cc, dd, ee, X[15], 8); + + /* round 2 */ + GG(ee, aa, bb, cc, dd, X[7], 7); + GG(dd, ee, aa, bb, cc, X[4], 6); + GG(cc, dd, ee, aa, bb, X[13], 8); + GG(bb, cc, dd, ee, aa, X[1], 13); + GG(aa, bb, cc, dd, ee, X[10], 11); + GG(ee, aa, bb, cc, dd, X[6], 9); + GG(dd, ee, aa, bb, cc, X[15], 7); + GG(cc, dd, ee, aa, bb, X[3], 15); + GG(bb, cc, dd, ee, aa, X[12], 7); + GG(aa, bb, cc, dd, ee, X[0], 12); + GG(ee, aa, bb, cc, dd, X[9], 15); + GG(dd, ee, aa, bb, cc, X[5], 9); + GG(cc, dd, ee, aa, bb, X[2], 11); + GG(bb, cc, dd, ee, aa, X[14], 7); + GG(aa, bb, cc, dd, ee, X[11], 13); + GG(ee, aa, bb, cc, dd, X[8], 12); + + /* round 3 */ + HH(dd, ee, aa, bb, cc, X[3], 11); + HH(cc, dd, ee, aa, bb, X[10], 13); + HH(bb, cc, dd, ee, aa, X[14], 6); + HH(aa, bb, cc, dd, ee, X[4], 7); + HH(ee, aa, bb, cc, dd, X[9], 14); + HH(dd, ee, aa, bb, cc, X[15], 9); + HH(cc, dd, ee, aa, bb, X[8], 13); + HH(bb, cc, dd, ee, aa, X[1], 15); + HH(aa, bb, cc, dd, ee, X[2], 14); + HH(ee, aa, bb, cc, dd, X[7], 8); + HH(dd, ee, aa, bb, cc, X[0], 13); + HH(cc, dd, ee, aa, bb, X[6], 6); + HH(bb, cc, dd, ee, aa, X[13], 5); + HH(aa, bb, cc, dd, ee, X[11], 12); + HH(ee, aa, bb, cc, dd, X[5], 7); + HH(dd, ee, aa, bb, cc, X[12], 5); + + /* round 4 */ + II(cc, dd, ee, aa, bb, X[1], 11); + II(bb, cc, dd, ee, aa, X[9], 12); + II(aa, bb, cc, dd, ee, X[11], 14); + II(ee, aa, bb, cc, dd, X[10], 15); + II(dd, ee, aa, bb, cc, X[0], 14); + II(cc, dd, ee, aa, bb, X[8], 15); + II(bb, cc, dd, ee, aa, X[12], 9); + II(aa, bb, cc, dd, ee, X[4], 8); + II(ee, aa, bb, cc, dd, X[13], 9); + II(dd, ee, aa, bb, cc, X[3], 14); + II(cc, dd, ee, aa, bb, X[7], 5); + II(bb, cc, dd, ee, aa, X[15], 6); + II(aa, bb, cc, dd, ee, X[14], 8); + II(ee, aa, bb, cc, dd, X[5], 6); + II(dd, ee, aa, bb, cc, X[6], 5); + II(cc, dd, ee, aa, bb, X[2], 12); + + /* round 5 */ + JJ(bb, cc, dd, ee, aa, X[4], 9); + JJ(aa, bb, cc, dd, ee, X[0], 15); + JJ(ee, aa, bb, cc, dd, X[5], 5); + JJ(dd, ee, aa, bb, cc, X[9], 11); + JJ(cc, dd, ee, aa, bb, X[7], 6); + JJ(bb, cc, dd, ee, aa, X[12], 8); + JJ(aa, bb, cc, dd, ee, X[2], 13); + JJ(ee, aa, bb, cc, dd, X[10], 12); + JJ(dd, ee, aa, bb, cc, X[14], 5); + JJ(cc, dd, ee, aa, bb, X[1], 12); + JJ(bb, cc, dd, ee, aa, X[3], 13); + JJ(aa, bb, cc, dd, ee, X[8], 14); + JJ(ee, aa, bb, cc, dd, X[11], 11); + JJ(dd, ee, aa, bb, cc, X[6], 8); + JJ(cc, dd, ee, aa, bb, X[15], 5); + JJ(bb, cc, dd, ee, aa, X[13], 6); + + /* parallel round 1 */ + JJJ(aaa, bbb, ccc, ddd, eee, X[5], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9); + JJJ(ddd, eee, aaa, bbb, ccc, X[7], 9); + JJJ(ccc, ddd, eee, aaa, bbb, X[0], 11); + JJJ(bbb, ccc, ddd, eee, aaa, X[9], 13); + JJJ(aaa, bbb, ccc, ddd, eee, X[2], 15); + JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15); + JJJ(ddd, eee, aaa, bbb, ccc, X[4], 5); + JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7); + JJJ(bbb, ccc, ddd, eee, aaa, X[6], 7); + JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[8], 11); + JJJ(ddd, eee, aaa, bbb, ccc, X[1], 14); + JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14); + JJJ(bbb, ccc, ddd, eee, aaa, X[3], 12); + JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6); + + /* parallel round 2 */ + III(eee, aaa, bbb, ccc, ddd, X[6], 9); + III(ddd, eee, aaa, bbb, ccc, X[11], 13); + III(ccc, ddd, eee, aaa, bbb, X[3], 15); + III(bbb, ccc, ddd, eee, aaa, X[7], 7); + III(aaa, bbb, ccc, ddd, eee, X[0], 12); + III(eee, aaa, bbb, ccc, ddd, X[13], 8); + III(ddd, eee, aaa, bbb, ccc, X[5], 9); + III(ccc, ddd, eee, aaa, bbb, X[10], 11); + III(bbb, ccc, ddd, eee, aaa, X[14], 7); + III(aaa, bbb, ccc, ddd, eee, X[15], 7); + III(eee, aaa, bbb, ccc, ddd, X[8], 12); + III(ddd, eee, aaa, bbb, ccc, X[12], 7); + III(ccc, ddd, eee, aaa, bbb, X[4], 6); + III(bbb, ccc, ddd, eee, aaa, X[9], 15); + III(aaa, bbb, ccc, ddd, eee, X[1], 13); + III(eee, aaa, bbb, ccc, ddd, X[2], 11); + + /* parallel round 3 */ + HHH(ddd, eee, aaa, bbb, ccc, X[15], 9); + HHH(ccc, ddd, eee, aaa, bbb, X[5], 7); + HHH(bbb, ccc, ddd, eee, aaa, X[1], 15); + HHH(aaa, bbb, ccc, ddd, eee, X[3], 11); + HHH(eee, aaa, bbb, ccc, ddd, X[7], 8); + HHH(ddd, eee, aaa, bbb, ccc, X[14], 6); + HHH(ccc, ddd, eee, aaa, bbb, X[6], 6); + HHH(bbb, ccc, ddd, eee, aaa, X[9], 14); + HHH(aaa, bbb, ccc, ddd, eee, X[11], 12); + HHH(eee, aaa, bbb, ccc, ddd, X[8], 13); + HHH(ddd, eee, aaa, bbb, ccc, X[12], 5); + HHH(ccc, ddd, eee, aaa, bbb, X[2], 14); + HHH(bbb, ccc, ddd, eee, aaa, X[10], 13); + HHH(aaa, bbb, ccc, ddd, eee, X[0], 13); + HHH(eee, aaa, bbb, ccc, ddd, X[4], 7); + HHH(ddd, eee, aaa, bbb, ccc, X[13], 5); + + /* parallel round 4 */ + GGG(ccc, ddd, eee, aaa, bbb, X[8], 15); + GGG(bbb, ccc, ddd, eee, aaa, X[6], 5); + GGG(aaa, bbb, ccc, ddd, eee, X[4], 8); + GGG(eee, aaa, bbb, ccc, ddd, X[1], 11); + GGG(ddd, eee, aaa, bbb, ccc, X[3], 14); + GGG(ccc, ddd, eee, aaa, bbb, X[11], 14); + GGG(bbb, ccc, ddd, eee, aaa, X[15], 6); + GGG(aaa, bbb, ccc, ddd, eee, X[0], 14); + GGG(eee, aaa, bbb, ccc, ddd, X[5], 6); + GGG(ddd, eee, aaa, bbb, ccc, X[12], 9); + GGG(ccc, ddd, eee, aaa, bbb, X[2], 12); + GGG(bbb, ccc, ddd, eee, aaa, X[13], 9); + GGG(aaa, bbb, ccc, ddd, eee, X[9], 12); + GGG(eee, aaa, bbb, ccc, ddd, X[7], 5); + GGG(ddd, eee, aaa, bbb, ccc, X[10], 15); + GGG(ccc, ddd, eee, aaa, bbb, X[14], 8); + + /* parallel round 5 */ + FFF(bbb, ccc, ddd, eee, aaa, X[12], 8); + FFF(aaa, bbb, ccc, ddd, eee, X[15], 5); + FFF(eee, aaa, bbb, ccc, ddd, X[10], 12); + FFF(ddd, eee, aaa, bbb, ccc, X[4], 9); + FFF(ccc, ddd, eee, aaa, bbb, X[1], 12); + FFF(bbb, ccc, ddd, eee, aaa, X[5], 5); + FFF(aaa, bbb, ccc, ddd, eee, X[8], 14); + FFF(eee, aaa, bbb, ccc, ddd, X[7], 6); + FFF(ddd, eee, aaa, bbb, ccc, X[6], 8); + FFF(ccc, ddd, eee, aaa, bbb, X[2], 13); + FFF(bbb, ccc, ddd, eee, aaa, X[13], 6); + FFF(aaa, bbb, ccc, ddd, eee, X[14], 5); + FFF(eee, aaa, bbb, ccc, ddd, X[0], 15); + FFF(ddd, eee, aaa, bbb, ccc, X[3], 13); + FFF(ccc, ddd, eee, aaa, bbb, X[9], 11); + FFF(bbb, ccc, ddd, eee, aaa, X[11], 11); + + /* combine results */ + ddd += cc + MDbuf[1]; + MDbuf[1] = MDbuf[2] + dd + eee; + MDbuf[2] = MDbuf[3] + ee + aaa; + MDbuf[3] = MDbuf[4] + aa + bbb; + MDbuf[4] = MDbuf[0] + bb + ccc; + MDbuf[0] = ddd; + } + + inline void ripemd160(const uint8_t* msg, uint32_t msg_len, uint8_t* hash) + { + uint32_t i; + int j; + uint32_t digest[5] = {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0UL}; + + for (i = 0; i < (msg_len >> 6); ++i) { + uint32_t chunk[16]; + + for (j = 0; j < 16; ++j) { + chunk[j] = static_cast(*(msg++)); + chunk[j] |= static_cast((*(msg++))) << 8; + chunk[j] |= static_cast((*(msg++))) << 16; + chunk[j] |= static_cast((*(msg++))) << 24; + } + + compress(digest, chunk); + } + + // Last chunk + { + uint32_t chunk[16] = {0}; + + for (i = 0; i < (msg_len & 63); ++i) { + chunk[i >> 2] ^= static_cast(*msg++) << ((i & 3) << 3); + } + + chunk[(msg_len >> 2) & 15] ^= static_cast(1) << (8 * (msg_len & 3) + 7); + + if ((msg_len & 63) > 55) { + compress(digest, chunk); + memset(chunk, 0, 64); + } + + chunk[14] = msg_len << 3; + chunk[15] = (msg_len >> 29); + compress(digest, chunk); + } + + for (i = 0; i < 5; ++i) { + *(hash++) = digest[i]; + *(hash++) = digest[i] >> 8; + *(hash++) = digest[i] >> 16; + *(hash++) = digest[i] >> 24; + } + } +} // namespace RIPEMD160 +#endif // RIPMD160_HPP \ No newline at end of file diff --git a/src/contract/precompiles/sha256.cpp b/src/contract/precompiles/sha256.cpp new file mode 100644 index 00000000..d93c4a3c --- /dev/null +++ b/src/contract/precompiles/sha256.cpp @@ -0,0 +1,19 @@ +#include "precompiles.h" +#include + +namespace { + +constexpr size_t OUTPUT_SIZE = 32; + +constexpr uint64_t gasRequired(size_t size) { + return ((size + 31) / 32) * 12 + 60; +} + +} // namespace + +Bytes precompiles::sha256(View input, Gas& gas) { + gas.use(gasRequired(input.size())); + Bytes output(OUTPUT_SIZE); + SHA256(input.data(), input.size(), output.data()); + return output; +} diff --git a/src/utils/fixedbytes.h b/src/utils/fixedbytes.h index 57ba63c6..784cfb79 100644 --- a/src/utils/fixedbytes.h +++ b/src/utils/fixedbytes.h @@ -71,4 +71,68 @@ class FixedBytes : public BytesInterface, N> { using serialize = zpp::bits::members<1>; }; +using Bytes1 = FixedBytes<1>; + +using Bytes2 = FixedBytes<2>; + +using Bytes3 = FixedBytes<3>; + +using Bytes4 = FixedBytes<4>; + +using Bytes5 = FixedBytes<5>; + +using Bytes6 = FixedBytes<6>; + +using Bytes7 = FixedBytes<7>; + +using Bytes8 = FixedBytes<8>; + +using Bytes9 = FixedBytes<9>; + +using Bytes10 = FixedBytes<10>; + +using Bytes11 = FixedBytes<11>; + +using Bytes12 = FixedBytes<12>; + +using Bytes13 = FixedBytes<13>; + +using Bytes14 = FixedBytes<14>; + +using Bytes15 = FixedBytes<15>; + +using Bytes16 = FixedBytes<16>; + +using Bytes17 = FixedBytes<17>; + +using Bytes18 = FixedBytes<18>; + +using Bytes19 = FixedBytes<19>; + +using Bytes20 = FixedBytes<20>; + +using Bytes21 = FixedBytes<21>; + +using Bytes22 = FixedBytes<22>; + +using Bytes23 = FixedBytes<23>; + +using Bytes24 = FixedBytes<24>; + +using Bytes25 = FixedBytes<25>; + +using Bytes26 = FixedBytes<26>; + +using Bytes27 = FixedBytes<27>; + +using Bytes28 = FixedBytes<28>; + +using Bytes29 = FixedBytes<29>; + +using Bytes30 = FixedBytes<30>; + +using Bytes31 = FixedBytes<31>; + +using Bytes32 = FixedBytes<32>; + #endif // BDK_UTILS_FIXEDBYTES_H diff --git a/tests/contract/precompiles.cpp b/tests/contract/precompiles.cpp index 4f07083a..8a2997e2 100644 --- a/tests/contract/precompiles.cpp +++ b/tests/contract/precompiles.cpp @@ -6,24 +6,226 @@ See the LICENSE.txt file in the project root for more information. */ #include "libs/catch2/catch_amalgamated.hpp" -#include "contract/precompiles.h" +#include "contract/precompiles/precompiles.h" #include "bytes/hex.h" #include "../sdktestsuite.hpp" +namespace { +struct PrecompilesTest { + Bytes(*precompile)(View, Gas&); + Bytes input; + Bytes output; + Gas gas; +}; + +const PrecompilesTest testData[] = { + { + .precompile = &precompiles::sha256, + .input = Utils::makeBytes(bytes::hex("0xa8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89")), + .output = Utils::makeBytes(bytes::hex("0xc0b057f584795eff8b06d5e420e71d747587d20de836f501921fd1b5741f1283")), + .gas = Gas(72) + }, + { + .precompile = &precompiles::ripemd160, + .input = Utils::makeBytes(bytes::hex("0x2c0c45d3ecab80fe060e5f1d7057cd2f8de5e557")), + .output = Utils::makeBytes(bytes::hex("0x1f853832265d16cb91fa64938c2f421fac8f6a87")), + .gas = Gas(720) + }, + { + .precompile = &precompiles::ripemd160, + .input = StrConv::stringToBytes("aaaaaaaaa"), + .output = Utils::makeBytes(bytes::hex("d3b9ee61b83094737d0ba58db0e521c11b319aaa")), + .gas = Gas(720) + }, + { + .precompile = &precompiles::ecrecover, + .input = Utils::makeBytes(bytes::hex("0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549")), + .output = Utils::makeBytes(bytes::hex("0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b")), + .gas = Gas(3000) + }, + { + .precompile = &precompiles::ecrecover, + .input = Utils::makeBytes(bytes::hex("0xa8b53bdf3306a35a7103ab5504a0c9b492295564b6202b1942a84ef300107281000000000000000000000000000000000000000000000000000000000000001b307835653165303366353363653138623737326363623030393366663731663366353366356337356237346463623331613835616138623838393262346538621122334455667788991011121314151617181920212223242526272829303132")), + .output = Bytes(32), + .gas = Gas(3000) + }, + { + .precompile = &precompiles::ecrecover, + .input = Utils::makeBytes(bytes::hex("0x18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c100000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549")), + .output = Bytes(32), + .gas = Gas(3000) + }, + { + .precompile = &precompiles::blake2f, + .input = Utils::makeBytes(bytes::hex("0x0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001")), + .output = Utils::makeBytes(bytes::hex("0x08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b")), + .gas = Gas(0) + }, + { + .precompile = &precompiles::blake2f, + .input = Utils::makeBytes(bytes::hex("0x0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001")), + .output = Utils::makeBytes(bytes::hex("0xba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923")), + .gas = Gas(12) + }, + { + .precompile = &precompiles::blake2f, + .input = Utils::makeBytes(bytes::hex("0x0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000")), + .output = Utils::makeBytes(bytes::hex("0x75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735")), + .gas = Gas(12) + }, + { + .precompile = &precompiles::blake2f, + .input = Utils::makeBytes(bytes::hex("0x0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001")), + .output = Utils::makeBytes(bytes::hex("0xb63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421")), + .gas = Gas(1) + }, + { + .precompile = &precompiles::blake2f, + .input = Utils::makeBytes(bytes::hex("0x007A120048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001")), + .output = Utils::makeBytes(bytes::hex("0x6d2ce9e534d50e18ff866ae92d70cceba79bbcd14c63819fe48752c8aca87a4bb7dcc230d22a4047f0486cfcfb50a17b24b2899eb8fca370f22240adb5170189")), + .gas = Gas(8000000) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002003fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f")), + .output = Utils::makeBytes(bytes::hex("0x0100000000000000000000000000000000000000000000000000000000000000")), + .gas = Gas(1360) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f")), + .output = Utils::makeBytes(bytes::hex("0x0000000000000000000000000000000000000000000000000000000000000000")), + .gas = Gas(1360) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb502fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b")), + .output = Utils::makeBytes(bytes::hex("0x60008f1614cc01dcfb6bfb09c625cf90b47d4468db81b5f8b7a39d42f332eab9b2da8f2d95311648a8f243f4bb13cfb3d8f7f2a3c014122ebb3ed41b02783adc")), + .gas = Gas(200) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb503fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b")), + .output = Utils::makeBytes(bytes::hex("0x4834a46ba565db27903b1c720c9d593e84e4cbd6ad2e64b31885d944f68cd801f92225a8961c952ddf2797fa4701b330c85c4b363798100b921a1a22a46a7fec")), + .gas = Gas(200) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb0033ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5010001fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c6b")), + .output = Utils::makeBytes(bytes::hex("0xc36d804180c35d4426b57b50c5bfcca5c01856d104564cd513b461d3c8b8409128a5573e416d0ebe38f5f736766d9dc27143e4da981dfa4d67f7dc474cbee6d2")), + .gas = Gas(341) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5102e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087")), + .output = Utils::makeBytes(bytes::hex("0x981dd99c3b113fae3e3eaa9435c0dc96779a23c12a53d1084b4f67b0b053a27560f627b873e3f16ad78f28c94f14b6392def26e4d8896c5e3c984e50fa0b3aa44f1da78b913187c6128baa9340b1e9c9a0fd02cb78885e72576da4a8f7e5a113e173a7a2889fde9d407bd9f06eb05bc8fc7b4229377a32941a02bf4edcc06d70")), + .gas = Gas(200) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5103e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087")), + .output = Utils::makeBytes(bytes::hex("0xd89ceb68c32da4f6364978d62aaa40d7b09b59ec61eb3c0159c87ec3a91037f7dc6967594e530a69d049b64adfa39c8fa208ea970cfe4b7bcd359d345744405afe1cbf761647e32b3184c7fbe87cee8c6c7ff3b378faba6c68b83b6889cb40f1603ee68c56b4c03d48c595c826c041112dc941878f8c5be828154afd4a16311f")), + .gas = Gas(200) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51010001e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087")), + .output = Utils::makeBytes(bytes::hex("0xad85e8ef13fd1dd46eae44af8b91ad1ccae5b7a1c92944f92a19f21b0b658139e0cabe9c1f679507c2de354bf2c91ebd965d1e633978a830d517d2f6f8dd5fd58065d58559de7e2334a878f8ec6992d9b9e77430d4764e863d77c0f87beede8f2f7f2ab2e7222f85cc9d98b8467f4bb72e87ef2882423ebdb6daf02dddac6db2")), + .gas = Gas(1365) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb02d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d")), + .output = Utils::makeBytes(bytes::hex("0xaffc7507ea6d84751ec6b3f0d7b99dbcc263f33330e450d1b3ff0bc3d0874320bf4edd57debd587306988157958cb3cfd369cc0c9c198706f635c9e0f15d047df5cb44d03e2727f26b083c4ad8485080e1293f171c1ed52aef5993a5815c35108e848c951cf1e334490b4a539a139e57b68f44fee583306f5b85ffa57206b3ee5660458858534e5386b9584af3c7f67806e84c189d695e5eb96e1272d06ec2df5dc5fabc6e94b793718c60c36be0a4d031fc84cd658aa72294b2e16fc240aef70cb9e591248e38bd49c5a554d1afa01f38dab72733092f7555334bbef6c8c430119840492380aa95fa025dcf699f0a39669d812b0c6946b6091e6e235337b6f8")), + .gas = Gas(341) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb03d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d")), + .output = Utils::makeBytes(bytes::hex("0x1b280ecd6a6bf906b806d527c2a831e23b238f89da48449003a88ac3ac7150d6a5e9e6b3be4054c7da11dd1e470ec29a606f5115801b5bf53bc1900271d7c3ff3cd5ed790d1c219a9800437a689f2388ba1a11d68f6a8e5b74e9a3b1fac6ee85fc6afbac599f93c391f5dc82a759e3c6c0ab45ce3f5d25d9b0c1bf94cf701ea6466fc9a478dacc5754e593172b5111eeba88557048bceae401337cd4c1182ad9f700852bc8c99933a193f0b94cf1aedbefc48be3bc93ef5cb276d7c2d5462ac8bb0c8fe8923a1db2afe1c6b90d59c534994a6a633f0ead1d638fdc293486bb634ff2c8ec9e7297c04241a61c37e3ae95b11d53343d4ba2b4cc33d2cfa7eb705e")), + .gas = Gas(341) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb010001d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d")), + .output = Utils::makeBytes(bytes::hex("0x37843d7c67920b5f177372fa56e2a09117df585f81df8b300fba245b1175f488c99476019857198ed459ed8d9799c377330e49f4180c4bf8e8f66240c64f65ede93d601f957b95b83efdee1e1bfde74169ff77002eaf078c71815a9220c80b2e3b3ff22c2f358111d816ebf83c2999026b6de50bfc711ff68705d2f40b753424aefc9f70f08d908b5a20276ad613b4ab4309a3ea72f0c17ea9df6b3367d44fb3acab11c333909e02e81ea2ed404a712d3ea96bba87461720e2d98723e7acd0520ac1a5212dbedcd8dc0c1abf61d4719e319ff4758a774790b8d463cdfe131d1b2dcfee52d002694e98e720cb6ae7ccea353bc503269ba35f0f63bf8d7b672a76")), + .gas = Gas(5461) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8102df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f")), + .output = Utils::makeBytes(bytes::hex("0x8a5aea5f50dcc03dc7a7a272b5aeebc040554dbc1ffe36753c4fc75f7ed5f6c2cc0de3a922bf96c78bf0643a73025ad21f45a4a5cadd717612c511ab2bff1190fe5f1ae05ba9f8fe3624de1de2a817da6072ddcdb933b50216811dbe6a9ca79d3a3c6b3a476b079fd0d05f04fb154e2dd3e5cb83b148a006f2bcbf0042efb2ae7b916ea81b27aac25c3bf9a8b6d35440062ad8eae34a83f3ffa2cc7b40346b62174a4422584f72f95316f6b2bee9ff232ba9739301c97c99a9ded26c45d72676eb856ad6ecc81d36a6de36d7f9dafafee11baa43a4b0d5e4ecffa7b9b7dcefd58c397dd373e6db4acd2b2c02717712e6289bed7c813b670c4a0c6735aa7f3b0f1ce556eae9fcc94b501b2c8781ba50a8c6220e8246371c3c7359fe4ef9da786ca7d98256754ca4e496be0a9174bedbecb384bdf470779186d6a833f068d2838a88d90ef3ad48ff963b67c39cc5a3ee123baf7bf3125f64e77af7f30e105d72c4b9b5b237ed251e4c122c6d8c1405e736299c3afd6db16a28c6a9cfa68241e53de4cd388271fe534a6a9b0dbea6171d170db1b89858468885d08fecbd54c8e471c3e25d48e97ba450b96d0d87e00ac732aaa0d3ce4309c1064bd8a4c0808a97e0143e43a24cfa847635125cd41c13e0574487963e9d725c01375db99c31da67b4cf65eff555f0c0ac416c727ff8d438ad7c42030551d68c2e7adda0abb1ca7c10")), + .gas = Gas(1365) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8103df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f")), + .output = Utils::makeBytes(bytes::hex("0x5a2664252aba2d6e19d9600da582cdd1f09d7a890ac48e6b8da15ae7c6ff1856fc67a841ac2314d283ffa3ca81a0ecf7c27d89ef91a5a893297928f5da0245c99645676b481b7e20a566ee6a4f2481942bee191deec5544600bb2441fd0fb19e2ee7d801ad8911c6b7750affec367a4b29a22942c0f5f4744a4e77a8b654da2a82571037099e9c6d930794efe5cdca73c7b6c0844e386bdca8ea01b3d7807146bb81365e2cdc6475f8c23e0ff84463126189dc9789f72bbce2e3d2d114d728a272f1345122de23df54c922ec7a16e5c2a8f84da8871482bd258c20a7c09bbcd64c7a96a51029bbfe848736a6ba7bf9d931a9b7de0bcaf3635034d4958b20ae9ab3a95a147b0421dd5f7ebff46c971010ebfc4adbbe0ad94d5498c853e7142c450d8c71de4b2f84edbf8acd2e16d00c8115b150b1c30e553dbb82635e781379fe2a56360420ff7e9f70cc64c00aba7e26ed13c7c19622865ae07248daced36416080f35f8cc157a857ed70ea4f347f17d1bee80fa038abd6e39b1ba06b97264388b21364f7c56e192d4b62d9b161405f32ab1e2594e86243e56fcf2cb30d21adef15b9940f91af681da24328c883d892670c6aa47940867a81830a82b82716895db810df1b834640abefb7db2092dd92912cb9a735175bc447be40a503cf22dfe565b4ed7a3293ca0dfd63a507430b323ee248ec82e843b673c97ad730728cebc")), + .gas = Gas(1365) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81010001df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f")), + .output = Utils::makeBytes(bytes::hex("0xbed8b970c4a34849fc6926b08e40e20b21c15ed68d18f228904878d4370b56322d0da5789da0318768a374758e6375bfe4641fca5285ec7171828922160f48f5ca7efbfee4d5148612c38ad683ae4e3c3a053d2b7c098cf2b34f2cb19146eadd53c86b2d7ccf3d83b2c370bfb840913ee3879b1057a6b4e07e110b6bcd5e958bc71a14798c91d518cc70abee264b0d25a4110962a764b364ac0b0dd1ee8abc8426d775ec0f22b7e47b32576afaf1b5a48f64573ed1c5c29f50ab412188d9685307323d990802b81dacc06c6e05a1e901830ba9fcc67688dc29c5e27bde0a6e845ca925f5454b6fb3747edfaa2a5820838fb759eadf57f7cb5cec57fc213ddd8a4298fa079c3c0f472b07fb15aa6a7f0a3780bd296ff6a62e58ef443870b02260bd4fd2bbc98255674b8e1f1f9f8d33c7170b0ebbea4523b695911abbf26e41885344823bd0587115fdd83b721a4e8457a31c9a84b3d3520a07e0e35df7f48e5a9d534d0ec7feef1ff74de6a11e7f93eab95175b6ce22c68d78a642ad642837897ec11349205d8593ac19300207572c38d29ca5dfa03bc14cdbc32153c80e5cc3e739403d34c75915e49beb43094cc6dcafb3665b305ddec9286934ae66ec6b777ca528728c851318eb0f207b39f1caaf96db6eeead6b55ed08f451939314577d42bcc9f97c0b52d0234f88fd07e4c1d7780fdebc025cfffcb572cb27a8c33963")), + .gas = Gas(21845) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf02e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad")), + .output = Utils::makeBytes(bytes::hex("0xd61fe4e3f32ac260915b5b03b78a86d11bfc41d973fce5b0cc59035cf8289a8a2e3878ea15fa46565b0d806e2f85b53873ea20ed653869b688adf83f3ef444535bf91598ff7e80f334fb782539b92f39f55310cc4b35349ab7b278346eda9bc37c0d8acd3557fae38197f412f8d9e57ce6a76b7205c23564cab06e5615be7c6f05c3d05ec690cba91da5e89d55b152ff8dd2157dc5458190025cf94b1ad98f7cbe64e9482faba95e6b33844afc640892872b44a9932096508f4a782a4805323808f23e54b6ff9b841dbfa87db3505ae4f687972c18ea0f0d0af89d36c1c2a5b14560c153c3fee406f5cf15cfd1c0bb45d767426d465f2f14c158495069d0c5955a00150707862ecaae30624ebacdd8ac33e4e6aab3ff90b6ba445a84689386b9e945d01823a65874444316e83767290fcff630d2477f49d5d8ffdd200e08ee1274270f86ed14c687895f6caf5ce528bd970c20d2408a9ba66216324c6a011ac4999098362dbd98a038129a2d40c8da6ab88318aa3046cb660327cc44236d9e5d2163bd0959062195c51ed93d0088b6f92051fc99050ece2538749165976233697ab4b610385366e5ce0b02ad6b61c168ecfbedcdf74278a38de340fd7a5fead8e588e294795f9b011e2e60377a89e25c90e145397cdeabc60fd32444a6b7642a611a83c464d8b8976666351b4865c37b02e6dc21dbcdf5f930341707b618cc0f03c3122646b3385c9df9f2ec730eec9d49e7dfc9153b6e6289da8c4f0ebea9ccc1b751948e3bb7171c9e4d57423b0eeeb79095c030cb52677b3f7e0b45c30f645391f3f9c957afa549c4e0b2465b03c67993cd200b1af01035962edbc4c9e89b31c82ac121987d6529dafdeef67a132dc04b6dc68e77f22862040b75e2ceb9ff16da0fca534e6db7bd12fa7b7f51b6c08c1e23dfcdb7acbd2da0b51c87ffbced065a612e9b1c8bba9b7e2d8d7a2f04fcc4aaf355b60d764879a76b5e16762d5f2f55d585d0c8e82df6940960cddfb72c91dfa71f6b4e1c6ca25dfc39a878e998a663c04fe29d5e83b9586d047b4d7ff70a9f0d44f127e7d741685ca75f11629128d916a0ffef4be586a30c4b70389cc746e84ebf177c01ee8a4511cfbb9d1ecf7f7b33c7dd8177896e10bbc82f838dcd6db7ac67de62bf46b6a640fb580c5d1d2708f3862e3d2b645d0d18e49ef088053e3a220adc0e033c2afcfe61c90e32151152eb3caaf746c5e377d541cafc6cbb0cc0fa48b5caf1728f2e1957f5addfc234f1a9d89e40d49356c9172d0561a695fce6dab1d412321bbf407f63766ffd7b6b3d79bcfa07991c5a9709849c1008689e3b47c50d613980bec239fb64185249d055b30375ccb4354d71fe4d05648fbf6c80634dfc3575f2f24abb714c1e4c95e8896763bf4316e954c7ad19e5780ab7a040ca6fb9271f90a8b22ae738daf6cb")), + .gas = Gas(5461) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf03e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad")), + .output = Utils::makeBytes(bytes::hex("0x5f9c70ec884926a89461056ad20ac4c30155e817f807e4d3f5bb743d789c83386762435c3627773fa77da5144451f2a8aad8adba88e0b669f5377c5e9bad70e45c86fe952b613f015a9953b8a5de5eaee4566acf98d41e327d93a35bd5cef4607d025e58951167957df4ff9b1627649d3943805472e5e293d3efb687cfd1e503faafeb2840a3e3b3f85d016051a58e1c9498aab72e63b748d834b31eb05d85dcde65e27834e266b85c75cc4ec0135135e0601cb93eeeb6e0010c8ceb65c4c319623c5e573a2c8c9fbbf7df68a930beb412d3f4dfd146175484f45d7afaa0d2e60684af9b34730f7c8438465ad3e1d0c3237336722f2aa51095bd5759f4b8ab4dda111b684aa3dac62a761722e7ae43495b7709933512c81c4e3c9133a51f7ce9f2b51fcec064f65779666960b4e45df3900f54311f5613e8012dd1b8efd359eda31a778264c72aa8bb419d862734d769076bce2810011989a45374e5c5d8729fec21427f0bf397eacbb4220f603cf463a4b0c94efd858ffd9768cd60d6ce68d755e0fbad007ce5c2223d70c7018345a102e4ab3c60a13a9e7794303156d4c2063e919f2153c13961fb324c80b240742f47773a7a8e25b3e3fb19b00ce839346c6eb3c732fbc6b888df0b1fe0a3d07b053a2e9402c267b2d62f794d8a2840526e3ade15ce2264496ccd7519571dfde47f7a4bb16292241c20b2be59f3f8fb4f6383f232d838c5a22d8c95b6834d9d2ca493f5a505ebe8899503b0e8f9b19e6e2dd81c1628b80016d02097e0134de51054c4e7674824d4d758760fc52377d2cad145e259aa2ffaf54139e1a66b1e0c1c191e32ac59474c6b526f5b3ba07d3e5ec286eddf531fcd5292869be58c9f22ef91026159f7cf9d05ef66b4299f4da48cc1635bf2243051d342d378a22c83390553e873713c0454ce5f3234397111ac3fe3207b86f0ed9fc025c81903e1748103692074f83824fda6341be4f95ff00b0a9a208c267e12fa01825054cc0513629bf3dbb56dc5b90d4316f87654a8be18227978ea0a8a522760cad620d0d14fd38920fb7321314062914275a5f99f677145a6979b156bd82ecd36f23f8e1273cc2759ecc0b2c69d94dad5211d1bed939dd87ed9e07b91d49713a6e16ade0a98aea789f04994e318e4ff2c8a188cd8d43aeb52c6daa3bc29b4af50ea82a247c5cd67b573b34cbadcc0a376d3bbd530d50367b42705d870f2e27a8197ef46070528bfe408360faa2ebb8bf76e9f388572842bcb119f4d84ee34ae31f5cc594f23705a49197b181fb78ed1ec99499c690f843a4d0cf2e226d118e9372271054fbabdcc5c92ae9fefaef0589cd0e722eaf30c1703ec4289c7fd81beaa8a455ccee5298e31e2080c10c366a6fcf56f7d13582ad0bcad037c612b710fc595b70fbefaaca23623b60c6c39b11beb8e5843b6b3dac60f")), + .gas = Gas(5461) + }, + { + .precompile = &precompiles::modexp, + .input = Utils::makeBytes(bytes::hex("0x000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf010001e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad")), + .output = Utils::makeBytes(bytes::hex("0x5a0eb2bdf0ac1cae8e586689fa16cd4b07dfdedaec8a110ea1fdb059dd5253231b6132987598dfc6e11f86780428982d50cf68f67ae452622c3b336b537ef3298ca645e8f89ee39a26758206a5a3f6409afc709582f95274b57b71fae5c6b74619ae6f089a5393c5b79235d9caf699d23d88fb873f78379690ad8405e34c19f5257d596580c7a6a7206a3712825afe630c76b31cdb4a23e7f0632e10f14f4e282c81a66451a26f8df2a352b5b9f607a7198449d1b926e27036810368e691a74b91c61afa73d9d3b99453e7c8b50fd4f09c039a2f2feb5c419206694c31b92df1d9586140cb3417b38d0c503c7b508cc2ed12e813a1c795e9829eb39ee78eeaf360a169b491a1d4e419574e712402de9d48d54c1ae5e03739b7156615e8267e1fb0a897f067afd11fb33f6e24182d7aaaaa18fe5bc1982f20d6b871e5a398f0f6f718181d31ec225cfa9a0a70124ed9a70031bdf0c1c7829f708b6e17d50419ef361cf77d99c85f44607186c8d683106b8bd38a49b5d0fb503b397a83388c5678dcfcc737499d84512690701ed621a6f0172aecf037184ddf0f2453e4053024018e5ab2e30d6d5363b56e8b41509317c99042f517247474ab3abc848e00a07f69c254f46f2a05cf6ed84e5cc906a518fdcfdf2c61ce731f24c5264f1a25fc04934dc28aec112134dd523f70115074ca34e3807aa4cb925147f3a0ce152d323bd8c675ace446d0fd1ae30c4b57f0eb2c23884bc18f0964c0114796c5b6d080c3d89175665fbf63a6381a6a9da39ad070b645c8bb1779506da14439a9f5b5d481954764ea114fac688930bc68534d403cff4210673b6a6ff7ae416b7cd41404c3d3f282fcd193b86d0f54d0006c2a503b40d5c3930da980565b8f9630e9493a79d1c03e74e5f93ac8e4dc1a901ec5e3b3e57049124c7b72ea345aa359e782285d9e6a5c144a378111dd02c40855ff9c2be9b48425cb0b2fd62dc8678fd151121cf26a65e917d65d8e0dacfae108eb5508b601fb8ffa370be1f9a8b749a2d12eeab81f41079de87e2d777994fa4d28188c579ad327f9957fb7bdecec5c680844dd43cb57cf87aeb763c003e65011f73f8c63442df39a92b946a6bd968a1c1e4d5fa7d88476a68bd8e20e5b70a99259c7d3f85fb1b65cd2e93972e6264e74ebf289b8b6979b9b68a85cd5b360c1987f87235c3c845d62489e33acf85d53fa3561fe3a3aee18924588d9c6eba4edb7a4d106b31173e42929f6f0c48c80ce6a72d54eca7c0fe870068b7a7c89c63cdda593f5b32d3cb4ea8a32c39f00ab449155757172d66763ed9527019d6de6c9f2416aa6203f4d11c9ebee1e1d3845099e55504446448027212616167eb36035726daa7698b075286f5379cd3e93cb3e0cf4f9cb8d017facbb5550ed32d5ec5400ae57e47e2bf78d1eaeff9480cc765ceff39db500")), + .gas = Gas(87381) + } +}; + +} // namespace namespace TPRECOMPILES { -struct EcRecoverCaller { +const Bytes BYTECODE = Utils::makeBytes(bytes::hex("60806040527f5ffa7c26a64500657f3786514cf062ddd52098f30000000000000000000000006000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908360601c021790555034801561005d57600080fd5b5061094e8061006d6000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063128e49e51461005c578063265dc68c1461008c5780632dbe5cfe146100bc578063ad0eb88c146100ec578063b49fd0231461011c575b600080fd5b61007660048036038101906100719190610516565b61014c565b60405161008391906105de565b60405180910390f35b6100a660048036038101906100a1919061066f565b6101d0565b6040516100b39190610717565b60405180910390f35b6100d660048036038101906100d19190610516565b61029f565b6040516100e391906105de565b60405180910390f35b61010660048036038101906101019190610516565b610323565b6040516101139190610741565b60405180910390f35b61013660048036038101906101319190610516565b61037c565b6040516101439190610797565b60405180910390f35b6060600080600973ffffffffffffffffffffffffffffffffffffffff168460405161017791906107ee565b600060405180830381855afa9150503d80600081146101b2576040519150601f19603f3d011682016040523d82523d6000602084013e6101b7565b606091505b5091509150816101c657600080fd5b8092505050919050565b600080600186868686604051600081526020016040526040516101f69493929190610814565b6020604051602081039080840390855afa158015610218573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610293576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161028a906108b6565b60405180910390fd5b80915050949350505050565b6060600080600473ffffffffffffffffffffffffffffffffffffffff16846040516102ca91906107ee565b600060405180830381855afa9150503d8060008114610305576040519150601f19603f3d011682016040523d82523d6000602084013e61030a565b606091505b50915091508161031957600080fd5b8092505050919050565b600060028260405161033591906107ee565b602060405180830381855afa158015610352573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061037591906108eb565b9050919050565b600060038260405161038e91906107ee565b602060405180830381855afa1580156103ab573d6000803e3d6000fd5b5050506040515160601b9050919050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610423826103da565b810181811067ffffffffffffffff82111715610442576104416103eb565b5b80604052505050565b60006104556103bc565b9050610461828261041a565b919050565b600067ffffffffffffffff821115610481576104806103eb565b5b61048a826103da565b9050602081019050919050565b82818337600083830152505050565b60006104b96104b484610466565b61044b565b9050828152602081018484840111156104d5576104d46103d5565b5b6104e0848285610497565b509392505050565b600082601f8301126104fd576104fc6103d0565b5b813561050d8482602086016104a6565b91505092915050565b60006020828403121561052c5761052b6103c6565b5b600082013567ffffffffffffffff81111561054a576105496103cb565b5b610556848285016104e8565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561059957808201518184015260208101905061057e565b60008484015250505050565b60006105b08261055f565b6105ba818561056a565b93506105ca81856020860161057b565b6105d3816103da565b840191505092915050565b600060208201905081810360008301526105f881846105a5565b905092915050565b6000819050919050565b61061381610600565b811461061e57600080fd5b50565b6000813590506106308161060a565b92915050565b600060ff82169050919050565b61064c81610636565b811461065757600080fd5b50565b60008135905061066981610643565b92915050565b60008060008060808587031215610689576106886103c6565b5b600061069787828801610621565b94505060206106a88782880161065a565b93505060406106b987828801610621565b92505060606106ca87828801610621565b91505092959194509250565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610701826106d6565b9050919050565b610711816106f6565b82525050565b600060208201905061072c6000830184610708565b92915050565b61073b81610600565b82525050565b60006020820190506107566000830184610732565b92915050565b60007fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b6107918161075c565b82525050565b60006020820190506107ac6000830184610788565b92915050565b600081905092915050565b60006107c88261055f565b6107d281856107b2565b93506107e281856020860161057b565b80840191505092915050565b60006107fa82846107bd565b915081905092915050565b61080e81610636565b82525050565b60006080820190506108296000830187610732565b6108366020830186610805565b6108436040830185610732565b6108506060830184610732565b95945050505050565b600082825260208201905092915050565b7f696e76616c6964207369676e6174757265000000000000000000000000000000600082015250565b60006108a0601183610859565b91506108ab8261086a565b602082019050919050565b600060208201905081810360008301526108cf81610893565b9050919050565b6000815190506108e58161060a565b92915050565b600060208284031215610901576109006103c6565b5b600061090f848285016108d6565b9150509291505056fea2646970667358221220829fac99ebbdda74b29b407dfc3384eebc38d9bb4e6bf37f309ce516e3791fc364736f6c63430008130033")); + +struct PrecompilesCaller { Address callEcRecover(const Hash&, const uint8_t&, const Hash&, const Hash&) const { return Address{}; } + Hash callSHA256(const Bytes&) const { return Hash{}; } + + Bytes20 callRIPEMD160(const Bytes&) const { return Bytes20{}; } + + Bytes callIdentity(const Bytes&) const { return Bytes{}; } + + Bytes callBlake2(const Bytes&) const { return Bytes{}; } + static void registerContract() { - ContractReflectionInterface::registerContractMethods( + ContractReflectionInterface::registerContractMethods( std::vector{}, - std::make_tuple("callEcRecover", &EcRecoverCaller::callEcRecover, FunctionTypes::View, std::vector{"hash", "v", "r", "s"}) + std::make_tuple("callEcRecover", &PrecompilesCaller::callEcRecover, FunctionTypes::View, std::vector{"hash", "v", "r", "s"}), + std::make_tuple("callSHA256", &PrecompilesCaller::callSHA256, FunctionTypes::View, std::vector{"input"}), + std::make_tuple("callRIPEMD160", &PrecompilesCaller::callRIPEMD160, FunctionTypes::View, std::vector{"input"}), + std::make_tuple("callIdentity", &PrecompilesCaller::callIdentity, FunctionTypes::View, std::vector{"input"}), + std::make_tuple("callBlake2", &PrecompilesCaller::callBlake2, FunctionTypes::View, std::vector{"input"}) ); } }; TEST_CASE("Precompiles", "[contract][precompiles]") { + SECTION("test data") { + for (const auto& test : testData) { + Gas gas = test.gas; + REQUIRE(test.output == std::invoke(test.precompile, test.input, gas)); + REQUIRE(uint256_t(gas) == 0); + } + } + SECTION("valid ecrecover") { const Hash hash = bytes::hex("0x456e9aea5e197a1f1af7a3e85a3212fa4049a3ba34c2289b4c860fc0b0c64ef3"); const uint8_t v = 28; @@ -32,26 +234,65 @@ TEST_CASE("Precompiles", "[contract][precompiles]") { const Address expectedResult = bytes::hex("0x7156526fbd7a3c72969b54f64e42c10fbb768c8a"); - REQUIRE(ecrecover(hash, v, r, s) == expectedResult); + REQUIRE(precompiles::ecrecover(hash, v, r, s) == expectedResult); } - SECTION("contract call for ecrecover") { - const Bytes bytecode = Utils::makeBytes(bytes::hex("0x608060405234801561000f575f80fd5b5061035f8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063265dc68c1461002d575b5f80fd5b61004760048036038101906100429190610194565b61005d565b6040516100549190610237565b60405180910390f35b5f806001868686866040515f8152602001604052604051610081949392919061026e565b6020604051602081039080840390855afa1580156100a1573d5f803e3d5ffd5b5050506020604051035190505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361011b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101129061030b565b60405180910390fd5b80915050949350505050565b5f80fd5b5f819050919050565b61013d8161012b565b8114610147575f80fd5b50565b5f8135905061015881610134565b92915050565b5f60ff82169050919050565b6101738161015e565b811461017d575f80fd5b50565b5f8135905061018e8161016a565b92915050565b5f805f80608085870312156101ac576101ab610127565b5b5f6101b98782880161014a565b94505060206101ca87828801610180565b93505060406101db8782880161014a565b92505060606101ec8782880161014a565b91505092959194509250565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610221826101f8565b9050919050565b61023181610217565b82525050565b5f60208201905061024a5f830184610228565b92915050565b6102598161012b565b82525050565b6102688161015e565b82525050565b5f6080820190506102815f830187610250565b61028e602083018661025f565b61029b6040830185610250565b6102a86060830184610250565b95945050505050565b5f82825260208201905092915050565b7f696e76616c6964207369676e61747572650000000000000000000000000000005f82015250565b5f6102f56011836102b1565b9150610300826102c1565b602082019050919050565b5f6020820190508181035f830152610322816102e9565b905091905056fea26469706673582212200c75aacb55079af649692b63d700a6647842c0bd30bfef639e59862b2acbbed564736f6c63430008140033")); - + SECTION("contract call for all precompiles") { SDKTestSuite sdk = SDKTestSuite::createNewEnvironment("TestEcRecoverCall"); - const Address contract = sdk.deployBytecode(bytecode); + const Address contract = sdk.deployBytecode(BYTECODE); - const Hash hash = bytes::hex("0x456e9aea5e197a1f1af7a3e85a3212fa4049a3ba34c2289b4c860fc0b0c64ef3"); - const uint8_t v = 28; - const Hash r = bytes::hex("0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608"); - const Hash s = bytes::hex("0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada"); + { + const Hash hash = bytes::hex("0x456e9aea5e197a1f1af7a3e85a3212fa4049a3ba34c2289b4c860fc0b0c64ef3"); + const uint8_t v = 28; + const Hash r = bytes::hex("0x9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac8038825608"); + const Hash s = bytes::hex("0x4f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada"); - const Address expectedResult = bytes::hex("0x7156526fbd7a3c72969b54f64e42c10fbb768c8a"); + const Address expectedResult = bytes::hex("0x7156526fbd7a3c72969b54f64e42c10fbb768c8a"); + + Address result = sdk.callViewFunction(contract, &PrecompilesCaller::callEcRecover, hash, v, r, s); + + REQUIRE(result == expectedResult); + } + + { + const Bytes input = Utils::makeBytes(bytes::hex("0xa8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89")); + const Hash output = sdk.callViewFunction(contract, &PrecompilesCaller::callSHA256, input); + const Hash expectedOutput = bytes::hex("0xc0b057f584795eff8b06d5e420e71d747587d20de836f501921fd1b5741f1283"); + + REQUIRE(output == expectedOutput); + } + + { + const Bytes input = Utils::makeBytes(bytes::hex("0x2c0c45d3ecab80fe060e5f1d7057cd2f8de5e557")); + + const Bytes20 output = sdk.callViewFunction(contract, &PrecompilesCaller::callRIPEMD160, input); + const Bytes20 expectedOutput = bytes::hex("0x1f853832265d16cb91fa64938c2f421fac8f6a87"); + + REQUIRE(output == expectedOutput); + + const Bytes strInput = StrConv::stringToBytes("aaaaaaaaa"); + + const Bytes20 strOutput = sdk.callViewFunction(contract, &PrecompilesCaller::callRIPEMD160, strInput); + const Bytes20 expectedStrOutput = bytes::hex("0xd3b9ee61b83094737d0ba58db0e521c11b319aaa"); + + REQUIRE(strOutput == expectedStrOutput); + } + + { + const Bytes input = Utils::makeBytes(bytes::hex("0x1234567890")); + const Bytes output = sdk.callViewFunction(contract, &PrecompilesCaller::callIdentity, input); + + REQUIRE(input == output); + } - Address result = sdk.callViewFunction(contract, &EcRecoverCaller::callEcRecover, hash, v, r, s); + { + const Bytes input = Utils::makeBytes(bytes::hex("0x0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001")); + const Bytes output = sdk.callViewFunction(contract, &PrecompilesCaller::callBlake2, input); + const Bytes expectedOutput = Utils::makeBytes(bytes::hex("0xba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923")); - REQUIRE(result == expectedResult); + REQUIRE(output == expectedOutput); + } } } -} // namespace TABI +} // namespace TPRECOMPILES