diff --git a/test/state/precompiles.cpp b/test/state/precompiles.cpp index 638af9afd..a995e8cb5 100644 --- a/test/state/precompiles.cpp +++ b/test/state/precompiles.cpp @@ -317,19 +317,61 @@ ExecutionResult expmod_execute( const uint8_t* input, size_t input_size, uint8_t* output, size_t output_size) noexcept { static constexpr auto LEN_SIZE = sizeof(intx::uint256); + static constexpr auto HEADER_SIZE = 3 * LEN_SIZE; + static constexpr auto LEN32_OFF = LEN_SIZE - sizeof(uint32_t); // The output size equal to the modulus size. + const auto mod_len = output_size; + // Handle short incomplete input up front. The answer is 0 of the length of the modulus. - if (output_size == 0 || input_size <= 3 * LEN_SIZE) [[unlikely]] + if (input_size <= HEADER_SIZE) [[unlikely]] + { + std::fill_n(output, output_size, 0); + return {EVMC_SUCCESS, output_size}; + } + + const auto base_len = intx::be::unsafe::load(&input[LEN32_OFF]); + const auto exp_len = intx::be::unsafe::load(&input[LEN_SIZE + LEN32_OFF]); + assert(intx::be::unsafe::load(&input[2 * LEN_SIZE + LEN32_OFF]) == mod_len); + + const bytes_view payload{input + HEADER_SIZE, input_size - HEADER_SIZE}; + const size_t mod_off = base_len + exp_len; // Cannot overflow if gas cost computed before. + const auto mod_explicit = payload.substr(std::min(mod_off, payload.size()), mod_len); + + // Handle the mod being zero early. + // This serves two purposes: + // - bigint libraries don't like zero modulus because division by 0 is not well-defined, + // - having non-zero modulus guarantees that base and exp aren't out-of-bounds. + if (mod_explicit.find_first_not_of(uint8_t{0}) == bytes_view::npos) [[unlikely]] { + // The modulus is zero, so the result is zero. std::fill_n(output, output_size, 0); return {EVMC_SUCCESS, output_size}; } + const auto mod_requires_padding = mod_explicit.size() != mod_len; + if (mod_requires_padding) [[unlikely]] + { + // The modulus is the last argument and some of its bytes may be missing and be implicitly + // zero. In this case, copy the explicit modulus bytes to the output buffer and pad the rest + // with zeroes. The output buffer is guaranteed to have exactly the modulus size. + const auto [_, output_p] = std::ranges::copy(mod_explicit, output); + std::fill(output_p, output + output_size, 0); + } + + const auto base = payload.substr(0, base_len); + const auto exp = payload.substr(base_len, exp_len); + const auto mod = mod_requires_padding ? bytes_view{output, mod_len} : mod_explicit; + #ifdef EVMONE_PRECOMPILES_SILKPRE + (void)base; + (void)exp; + (void)mod; + // For Silkpre use the raw input for compatibility. return silkpre_expmod_execute(input, input_size, output, output_size); #else - return expmod_stub(input, input_size, output, output_size); + expmod_stub(base, exp, mod, output); + return {EVMC_SUCCESS, mod.size()}; #endif } diff --git a/test/state/precompiles_stubs.cpp b/test/state/precompiles_stubs.cpp index 4fe832758..188f972ef 100644 --- a/test/state/precompiles_stubs.cpp +++ b/test/state/precompiles_stubs.cpp @@ -3,371 +3,121 @@ // SPDX-License-Identifier: Apache-2.0 #include "precompiles_stubs.hpp" -#include "../utils/utils.hpp" -#include "hash_utils.hpp" #include +#include #include -#include namespace evmone::state { -using test::operator""_hex; - namespace { -struct HashedInputStubs : std::unordered_map +/// Returns the expmod result for the known inputs or empty bytes if not found. +/// +/// Missing inputs collected with: +/// bin/evmone-statetest test_dirs >/dev/null 2> >(sort | uniq | tee stub.txt) +/// +/// Results computed with: +/// ```python +/// def e(s): +/// b, x, m = s.split(",") +/// b = int(b, 16) if b != "0x" else 0 +/// x = int(x, 16) if x != "0x" else 0 +/// m = int(m, 16) if m != "0x" else 0 +/// r = 0 +/// if m != 0: +/// r = pow(b, x, m) +/// print(f'{{"{s}","{r:02x}"}},') +/// ``` +bytes expmod_lookup_result(bytes_view base, bytes_view exp, bytes_view mod) { - using unordered_map::unordered_map; + static const std::unordered_map stubs{ + // clang-format off + {"0x02,0x01,0x02","00"}, + {"0x02,0x01,0x03","02"}, + {"0x02,0x02,0x02","00"}, + {"0x02,0x02,0x05","04"}, + {"0x02,0x03,0x06","02"}, + {"0x03,0x05,0x64","2b"}, + {"0x03,0x1c93,0x61", "5f"}, + {"0x03,0x2700,0x9c00","6801"}, + {"0x03,0x7114,0x2d3b","1b"}, + {"0x03,0xffff,0x8000000000000000000000000000000000000000000000000000000000000000","3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab"}, + {"0x03,0x4000000000000000000000000000000000000000000000000000000000000000,0x010000000000000000000000000000000000000000000000000000000000000000","01"}, + {"0x03,0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e,0xffffffffffffffffffffffffffffffffffffffffff2f00000000000000000000","162ead82cadefaeaf6e9283248fdf2f2845f6396f6f17c4d5a39f820b6f6b5f9"}, + {"0x03,0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e,0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f","01"}, + {"0x09,0x0e7f,0x90f7","8615"}, + {"0x09,0x90f7,0x90f7","1c3b"}, + {"0x09,0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff97,0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff97","09"}, + {"0x31,0x0961,0x0961","00"}, + {"0xba,0xee,0xd000","9000"}, + {"0xba,0xee,0xd00000","100000"}, + {"0xba,0xee,0xd00100","789700"}, + {"0x1001,0x0100,0x10","01"}, + {"0x1bd0,0x90f7,0x61","50"}, + {"0x9100,0x578b,0x55f0","3e80"}, + {"0x9100,0x90f7,0x61","5f"}, + {"0x9100,0x90f7,0x90f7","1c3b"}, + {"0x9c00,0x01,0xd7a1","9c00"}, + {"0xd796,0xd796,0xa7d5","866a"}, + {"0x02534f82b1,0x013f20d9c7d18d62cd95674d2e,0x013f20d9c7d18d62cd95674d2f","01"}, + {"0xd935b43e42,0x204fcbfb734a6e27735e8e90,0x204fcc1fd2727bb040f9eecb","01"}, + {"0x0846813a8d2d,0x451387340fa0,0x597c6545ae63","01"}, + {"0x010000000000000000000000000000000000000000000000000000000000000000,0x01,0x304d37f120d696c834550e63d9bb9c14b4f9165c9ede434e4644e3998d6db881","0e7de84a5bcf0e16fa56b80cbf55f39877229030e5a8af78a0a78e003cdb657b"}, + {"0x304d37f120d696c834550e63d9bb9c14b4f9165c9ede434e4644e3998d6db876,0x304d37f120d696c834550e63d9bb9c14b4f9165c9ede434e4644e3998d6db876,0xfffffffffffffffffffffffffffffffffffffff5","cd433bbd1fa6457602a79d957ee85a37e2496d0a"}, + {"0x035ee4e488f45e64d2f07becd54646357381d32f30b74c299a8c25d5202c04938e,0xf6c4764a04f10fc908b78c4486886000,0xf6d290251a79681a83b950c7e5c37351","01"}, + {"0x0785e45de3d6be050ba3c4d33ff0bb2d,0x010ace3b1dfe9c49f4c7a8075102fa19a86c,0x010ace3b1dfe9c49f4c7a8075102fa19a86d","01"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0,0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff97,0x61","3e"}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0,0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff97,0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff97","09"}, + // clang-format on + }; + + /// Combine the arguments into a key. It can be copy-pasted to python's pow(). + const auto key = "0x" + evmc::hex({base.data(), base.size()}) + // + ",0x" + evmc::hex({exp.data(), exp.size()}) + // + ",0x" + evmc::hex({mod.data(), mod.size()}); // - ExecutionResult lookup(bytes_view input, uint8_t* output, size_t max_output_size) const + const auto it = stubs.find(key); + if (it == stubs.end()) { - if (const auto it = find(keccak256(input)); it != end()) - { - if (it->second.size() > max_output_size) - return {EVMC_INTERNAL_ERROR, 0}; // invalid stub entry. - std::ranges::copy(it->second, output); - return {EVMC_SUCCESS, it->second.size()}; - } - return {EVMC_PRECOMPILE_FAILURE, 0}; // not found, treat as a failure. + std::cerr << "expmod: no result for " << key << "\n"; + return {}; } -}; + return evmc::from_hex(it->second).value(); +} } // namespace -ExecutionResult expmod_stub( - const uint8_t* input, size_t input_size, uint8_t* output, size_t max_output_size) noexcept + +void expmod_stub(bytes_view base, bytes_view exp, bytes_view mod, uint8_t* output) noexcept { - static const HashedInputStubs stubs{ - {0x010d1c26efabac677596f64e2e4f8894606e3636370a8665756ebc184e745aba_bytes32, - "000000000001"_hex}, - {0x033274602281965ae0382e28ea7584792e3d846b4ead2f1529e0d61a63afa9b9_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x034d54cdad5956fb28f9060287fad9073c1e87fb7c6d1709e00f362c9052aff7_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x03c85b4c0caf8657ff29b05743c33f9ffbb8df604c46cc86caa2f051e6a065a8_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x067b3e4d57e1fe2d23c71a95cdd86c8019a649e466d5fcf8e22cce66ceea36fc_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x08774b45b9263bbdd4f040b01c444d167f20686daf1d9dc0be2703ac5b79898f_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x0ea4f1fe8ab439ed65bf736c2d1e75244a52fec0e96cefadf09ea5d170956d52_bytes32, - "0e7de84a5bcf0e16fa56b80cbf55f39877229030e5a8af78a0a78e003cdb657b"_hex}, - {0x0f38b3a063df12614121ae2d0cd202213a5fa95e3536e0f82c3bbffb311f9152_bytes32, "02"_hex}, - {0x0ff064739dbad34456d55c4dafd7d33b7e0e7c63b18a1252ef9fd8bc88867234_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009"_hex}, - {0x10eab4762daae8abab287dd86a83326a78f5bbb8641f38a6792819576c94e35a_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x12292042f822da16c3db8dc1fc978be48218e0fb997cfff35857e16abba41300_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x12993abd44b4858730eb18a794ee686dc20b54cfee0e75a1f2e345cf9568ecc1_bytes32, "01"_hex}, - {0x12fc00c16a89e602782828a84667390d4a14bf74c1fd16dab784c7ebae45de06_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x130508100dd1f8b1c72b7eb16f82ee3b8a6f3bcbc8461c9f02c06f14ead89d75_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x1403e9d046887460408ff2c1956a064def64c4bb221b7bdff146b097b3a282c5_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x1669beee2b904266bc5a6eef210d6869ccea5c9a25e173d940428ccfbd6310c4_bytes32, "0000"_hex}, - {0x180fd71813c81062f2cdf852bc03fb8e8b8b98d21436001e255dc7141cb299d7_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x18c5b4c6cf9fccb97b1cf7f966b2ca8e951365e13eaf63ec93d3fd4ad87fadb5_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x18ca0a599a7bcdfd7e487cafca8ab1dfb6ef18074841fc3da95b73479eee3270_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x1a949941ca6b99c817a4e16cefe478308222535d19f1437ae2fdd892cb8ac789_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x1d885466c9ed74249248ad01d298eb4f509d9102a849d767f893da1e78799a9d_bytes32, "0002"_hex}, - {0x1e2d85db0c7c63bcc2054bf2d3caaf5d61920c77bb16f10572e6115458b0c352_bytes32, "00"_hex}, - {0x1e6d8ff8f706b4b423086b9c725a43e4aa6ce504b790612fb0e6f738cafa5b00_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x1ea137b55c9c2a68d4dd701fc31c5a11a2fcb3f9cc4c2fe6b2bf968d250ece35_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x1fe8359bcf1145edd7e23e4c32df953ea82d5db7a0d840ebe1d436f73bf93c5d_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x216ff577ab4b6adc22902060367bba5d514a67cb53b6171bc62569e58ce1a8ce_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x21879cfde84f139c4c53262a49dff3c774b0e2949fce670e2f471e54f1ffbc23_bytes32, "00"_hex}, - {0x21915510d6f6b58738bc790d97df3881396743ef975eb2a4d7dd0cd4bc10bc4b_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x244fa8474b97c1fc5589e3372062373bc939e2c2c8d51733cb62dd1af06d93ae_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x251828ea0fa55eeff4920c784f29d02b3d462893b0a53b35da407951f670d4c3_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x251f23d45faa62fd4edee6c7ca9d0e522dd618b21ca79c0ececcf6b4ab1d418e_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x2559c03f8499faccfb5d86c5a9c6857b9882045939b54fcab26046debc586400_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x25612858eb4e5086b12e02d2fbb70b8b64bb55022fdd629ec789f2c84607688f_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x26d4791888c6a5a6dad93c613727e1025a5e629993ace97b6f60a168ba5b643b_bytes32, "3e"_hex}, - {0x274f35379f9c71d56060a980068aa27bbb6b0163485b566c98f23208d9afebe8_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x27611fee3bcae57830f4acede0e4ddc28d6b80307e4e3c24518ff8427870b1a2_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x2815ce44f31ea08706a5b434ba9241be790bb99a9a14f2abc58f44e4c7ed5258_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x2aa26dd05f29718306030f45826699e7cfa5cee2d7e693743f08ca1890c70471_bytes32, "00"_hex}, - {0x2bbbf3147d86f35e028afe730dbe8a309c343a5af574d686b4de6f0299f44b62_bytes32, "00"_hex}, - {0x2e2b0152d440cb2300acb1a66f126dc6a55d48429cd4d1c65a6b08b1d70faa1a_bytes32, "00"_hex}, - {0x2e7668b70ebbbf0427b7206105b43be56ed44866084aef806b455c4302bb09ed_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x2ebcffbe9bfd10639c61895d63dc4adbea44b1ef949f81ec56b684a553ac3325_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x2fa614a47cc9c85b69679204e1ef9ac927b19471ded492b8ece1e8e67262fb51_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x31d7d7f3d30e2f6915813b0eae348106f9c36033685f734d666df55950721e09_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009"_hex}, - {0x35de80ebb4a020482ef20b08e76ccf3047a069603f0f298ca69d20d652e8d84b_bytes32, - "00000000000000000000000001"_hex}, - {0x39d0581989c293b89482bfa1e116cec4009a18aa00b89c5242b7fe5c3766ed7e_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x39e4706fe515d7364d5d89bca544e81f9ef187062620ac4e97b4c64e9dba668a_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x3b41faafc90d54978545a2f7f0a0fbc5710b148872dd6e1d6c2ec4c94fee3617_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x3b73107bd69d6198ed057833aac40d0dcdc99e568c5e4f2ff154688bbab5fb26_bytes32, - "000000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x3bf09109c39d56015c8905aa26907c8f8c509e4a54ff4efee2f896a8b1176042_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x3cc1cc331ba2e9897c734d97dfb178fecedbc4cc90c706eee0c6059c94b36297_bytes32, "0000"_hex}, - {0x3d8f5d715374acba3f92a425b8bad30eae5f2f534a63c4cea5ad4401fe46ad75_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x4084709b90b82b198ec95c387a53f65e5492611a56a9bf34a46d7c5fa02907dd_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x418b0655db32fa5820ed237053dfe34869c9a1c39460ed8d58e6e87e5164f8ec_bytes32, - "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x4262e4bfbfbc25391172acaa697e2b36c9aa60be165a81de92f9a6be0ed447ca_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x42c4e39cf1e2224199b3895508025d4cf89fc21154dd0ba0c9f86ebbe81667a1_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x42d09d5551133d4982c7c496aa710fdeb46c2974fa2ee405bd0cf2d8687f5eb4_bytes32, "0000"_hex}, - {0x469eae86b1701336b3d583df4527d639b1cccca716608b728563a0eeeeeb55ba_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x4798efaf9795653086f314b2a745a3c677befc3a143f8e71f6961410234d4aa7_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x48cbcce9cddcfc87a9dfb28f8c07a498c6cae91c3577410009e009de8ae15426_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x48d102df204080cb58f6131e8de27892647da0958ab111e3b7604279fe7638d9_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x49daba1e38b9fdb769584f02a5cf0d5ccc52e1dcc5f1683c384e308cbda1aefb_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x4a4e7e22f228bbfeef1e2e652aeb39630a3fea4545ce98694e34b3a13cbf4d9c_bytes32, - "162ead82cadefaeaf6e9283248fdf2f2845f6396f6f17c4d5a39f820b6f6b5f9"_hex}, - {0x4b1c0353029df7c0e24c97c1caa608b2447a736abd6ec92c6a6ad19c74af6764_bytes32, - "0000000000000000000000000000000000000000000000000000000000001c3b"_hex}, - {0x4c1451f2f475e314e13ab026083f0e75042da3757331579bcc2acf982eb93e47_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x4d26511722a244d920d5b388b5008248c71b7232df5e2dad0c68731ecea7baca_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x4e895772ea04e2bebc4494c0f61d649af0ec15eb35e3d6fb23ccd43cec8fc477_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x4e9bc8aacd818468cd54729198300a542eaa7ed24d172b0fa62eaca18c80320f_bytes32, "0000"_hex}, - {0x560aefbbe4dc7910322f1a57808798dd21e6f20b6804497d76feb28109d9e4b4_bytes32, "00"_hex}, - {0x56cd39d56e15e186eb742169736637742fe0129e3816caa42199e1d11444a087_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x57f24ba6197dd6bca4b92b2b069547c4d9715cb715b118fd06b6c506f3fe9a6f_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x58dca178acf545c5f569bf230c25f4b299df65d50427e5599c062de84ae8e117_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x59083a31c083633493c1f0fff98188fc553195939b97664ddf4f1f7372fdb9ed_bytes32, "00"_hex}, - {0x5913b435dbacbaf8a060c4901cb61a7aeea4f64e04bed5194a9cda0e3f7407b9_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x5ad3326c83fc81b119a19e072abec9b015d3230407d61fddeac53d8d622665d2_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x5d8c10bff855aeafad14cc8945d96363078f03b05fdd68cc8bf7db0f345f344d_bytes32, "0000"_hex}, - {0x5daa348868b1c7f027498f63593dc226890161a6e9fc6a458299fb2d954354d2_bytes32, - "0000000000000000000000000000000000000000000000000000000000003e80"_hex}, - {0x5ec71d7c8e69482d0e0118734635e881ff05f5a87604da2302f19e3ade457b42_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x5ef61126f34e679f7b6d859b4f20cb716481fe3e7003d0bcfb017694f6d28649_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x65a35fae82f3775f4e1b92c56cd68718784dd29d132d62722e7bda3853a3d837_bytes32, "04"_hex}, - {0x66b7f8ac5bd4017cc1ae82dc7a1a5334bcb127a1f64ebe4f1a7595196da10a58_bytes32, "0000"_hex}, - {0x67f7c6a923a7558c8cb23e8475dda653460be6ee507466645d79d5fa6dd5c63f_bytes32, "01"_hex}, - {0x68ad0981c9f951bdbcad78d21e35e5ec7918595b341c8b3dd81d5f50eca06b78_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x6b1061285efade3c0b2593286bb08db69ae28df9e1d6714041b063e362ba1988_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x6beafa77883efd2c221ea4cb29831d1fe10a2190379312217dbe57909ac356b0_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x6d835e80050760971242c410fa7ddaf8b268d3669e2db343fd61343cd87d80f4_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x6de36875921c76ab5434e64791cc62395d65f49eb21f9ddaa82aa8756b44ed3d_bytes32, - "000000000000000000000000000000000000000000000000000000000000866a"_hex}, - {0x6edab1ef76af731a34f9a306bfdeeaefe48aa8f4826c329e1fdd702652e17927_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x6f64f08deaeee1f2aa90289b4aaafc4d76bf5d79a6f0aee01cce6f914d6523af_bytes32, - "0000000000000000000000000000000000000000000000000000000000009c00"_hex}, - {0x7030a0dcea1e544f2f20cab453564c3f7343ea3c7949e30b35c9b562d2a6f532_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x72937ea411f48b90764786c97d4229d192cc6b1426fabdc86b59298816af97bc_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x73291d37d5bdc108723a04c171d113d6c323c46000569d0eaa319e295497a911_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x75137d2ac452fa56c54f3a84b6a5032cf7e9979578b76da3d8893684ffc3c0c7_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x75e5c2f08ba7f4f5196eeee2fa5d4585c1a7d13d94c8dd01d8db7c6664bf5dc0_bytes32, "0000"_hex}, - {0x7687fd0273528d2f1aa49723afefa95a867eaa5a6a898a75d8d1c1774f244cdb_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x77d6ede055e1bf3669db1b8e965fcced0a76864f364f6135e6cabe1037fe4809_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x7870eaca19c10f38ad151dabd337cbc8e2df484ac4801b07b0d80348b645931e_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x7bf0fbb8f1754a19c5efdf2dbdc4288c2d8728852734b30dc057d53beb59e5de_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x7d24c042d652db2f2d9e2e5d1eae97d19b44109420f11b6eadb6b90cb1ba50ea_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x7f2686134db3a520c34fdf758eba9a0d4f9c8945a3f06d1f4d7eb68b433be142_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x80de6c463032565ad835285aac5101f9748b93dde6ad45bb1136190bb8f5c253_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x8187355fc5e82694be920349dee28c7d4ec2a7bc15a85db4db530b13f34b4050_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x8191431cab44389a73030b5819d7af3bcdb3cb49e618810032cb1fd4e746bb41_bytes32, "0000"_hex}, - {0x8257bcfd8eb8eb906d8f3a0f3cb71577e6267f1a4af7f3fc611dc19dd96192bc_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x8507835cf8ffeccb9e5a2ef45b957ae5f463861884bcd279214fa36b2965619b_bytes32, - "0000000000000000000000000000000000000000000000000000000000001c3b"_hex}, - {0x86d444d512bd04db648bc23e024132fbc2186aa73cda0bf0741114132324124b_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x87b97726f9d1d6e04d170320fc2d8b16a971ecaa1048ac38dabab51369bd4543_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x880480a0dbe4cddcdb5cea5a9d483524b2f6c4e7b492bfe236b8d15649d0673d_bytes32, "00"_hex}, - {0x88451def3af9b5d137d0082f973d90facb971643f4eabf3c201a634861facef4_bytes32, - "000000000000000000000000000000000000000000000000000000000000001b"_hex}, - {0x8a068cd204782a5859890b4201f784e3ade964c45f373bc4e20f2f0c60c927f6_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x8ad16be55060aff4f690974f6b8c74de388599e798c8ff48261897a95729fb9f_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x8b4d99f7357e3cf1c7ad74cfce0c1bab1ab69920595b7bb2c20ed919aa03f77c_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x8bf994b1ef100d61c6b3857392be820ae7855cc194cfffa90d3b43d0a28b13b5_bytes32, - "3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab"_hex}, - {0x8d69df480ceb95c657631fe973f8777f032a807fe36e698458813ae8ac5276e4_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x90ac1c964e1edcf937f9332f953f971919ef44a105ec663be0eb6707ef52de9b_bytes32, "0002"_hex}, - {0x91bbd8d35060a647704e6e8410263135b9df075665d0286495fba2ad2129d178_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x93d390c50ad9871ea4b3ec9de9c3f10646951691931e069e03c0de0675bc6b05_bytes32, "00"_hex}, - {0x96cf34086b42afae29477ebe8d6eeba6fef1da1690e0ea32d8c4947466324569_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x993d6040be7987f83bb56811395b7d76d577bd885b943d2755b44fda0b44cf50_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x996f9283a0477c8eaddbd50c4a9927c80b0281d3193538469f79ae95f8ec2f5e_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0x9ab09ec74fdfe6a0f390d51b70f6b31a9b99287080d91395864c689ec8ef96e1_bytes32, - "0000000000000000000000000000000000000000000000000000000000000050"_hex}, - {0x9c3a806764dc757a3c4f3e4ab27f2d645f13684a5d0f65b3e527fd144464d052_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0x9ce2281a0a9ead36edc758647abc060766f200a5210d5b97a9b7d1752578c3ee_bytes32, - "0000000000000000000000000000000000000000000000000000000000008615"_hex}, - {0x9e24cd89db1e412aa85e71e9ea955e00a1c22d66716bbd19fc92df1a122a71bf_bytes32, "01"_hex}, - {0x9e6a8ff68b83a4a01c2c344f507ab1c738cf5df1f6f846d47fea6f5d397b06e4_bytes32, - "000000000000000000000000000000000001"_hex}, - {0xa05b578a2942544883921581b74d7bc5f44de59ae5d1a3cc21626658b5d9cf41_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xa4ddac19e1b86ed2a29ecc5ca2e2d840923f30380f5c2a732b746427b97c7970_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xa923d0e400cbbe1e0915c5a699cb8a51578ae87755f1aae7929289166ff23f33_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xab76f1d5488b8542336a386818cf99412b7aa17c589d244c29f9ae9cb3901815_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xada673786089f911b5dc7c5fc3405c206e6e7564e4dd4466b563d03e659e94a2_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xb07a3d24561ccfb56dd51bed4d640a0f00d5d86fe953d986846be0930c35157d_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xb0e9dd0b5749795680b0cc0db0167b85f1d2417acf9b44869d17a876a4f422ba_bytes32, "02"_hex}, - {0xb2f231521511b65fba5f194f65a93426b16df90c4ca4bbf0b51e2c3b02d59b2b_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xb303e361c4edd99c9e86513e769056c2faf0359ed8ec911ab473f14d5e8bfe95_bytes32, "0001"_hex}, - {0xb50e0123a517ebb42db0e4d926c86a515d5cc55cbe6cebe6b6a99ecd3a0dcd90_bytes32, "01"_hex}, - {0xb5a34ff06af3b01441b6ee4ffac60feee6f0b63ed6be80a21c8aaf8b9e7f0b4d_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xb7c17933a8cb769998187b25ea82c3ac8dffcf3d1976a60b023b9d06c0cd9a4f_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xb97681ddced4ee8f4efffc5b58044de3100b2dc7c1f7f6b72161200f10b0604c_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xb9d52ce810f7c808324c717f1a5b612512a24a3227d311f508edec3c931344ad_bytes32, - "000000000000000000000000000000000000000000000000000000000000005f"_hex}, - {0xbafcbd8a4bbc5837e3a637e432c4ee0a48e30a6b760efaaed699aed606b0c768_bytes32, - "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xbc2ae76808e3de30404a4dd4221f3289cf20a272161d4f8c0c58c2e736706256_bytes32, - "3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab"_hex}, - {0xbc8a5df0db3fc6a076ea676a8dd5f6689777de551a235d75f77a520bd243208d_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xbd59618a09cdeb7538ce8cf97820ae2ab18102ac903c34c7de6d72c63c3d0f08_bytes32, "00"_hex}, - {0xbe17aa6916c3d516ea45c2b8fc312f6bffc47f14325b7a9005786f878e1bb3ba_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xbf528ce5e535e2cf241dc944b153d5925ab2cdd488c386e326716b6a8ecf751a_bytes32, "0000"_hex}, - {0xc1ec6ef309c736331efc3000afc186d2021944309ee6b20a4bf3bc735b7aea75_bytes32, - "0000000000000000000000000000000000000000000000000000000000006801"_hex}, - {0xc3e4a3530ca51ae69ee63be92701c84c6ebd820e1f89ca15548c94dbb851101e_bytes32, - "00000000000000000000000000000001"_hex}, - {0xc4527e59efc328e49b6926353042b1758cc422461230653e83a433634155adcd_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xca29ae8887f56b58494b8404be63728fb620247345837253ee264b09b9c1057a_bytes32, "01"_hex}, - {0xcba5ff6688618456c8228b8c2bfb4ed254ad8620b99ef3ed8fbcb5bc66feb478_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xcd223a9e187147d1712bdeed93889e2edad86091108b10bb97790428717dee31_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xce9b2bf13532af4013c467e57479a71625bf1a7c8190393f29ffe8d3f3275aae_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xd09419104ce1c64b6a06bcf063e98c2c91ad9e1beaf98b21c9d4734b4a3c9956_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xd6c0c03ec1f713b63be3d39b4fa8ef082b3407adc29baf74669fd2a574c638ac_bytes32, "01"_hex}, - {0xd837f9dcf93155fe558c02c7a660edc0cd238a8b8f95ee6b68e4a5c6a41fc70a_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xdb5d4994d6dae845a6fd76e91ade4d3a35f270d86673ccc32405042c3c3d37ba_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xdbc6ddf9220c7ccfc94057fd3d25b712a0d7f51c3ff44e291458f2daf4ef2ec4_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xdf244f503af99f62276115256c481d3cf0786d477553cf0bb25df1579dbc9ee3_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xdfab0a2d13154e415f4f999b6570efd185de14a2cf07a14eb543feef7542a5fa_bytes32, - "000000000000000000000001"_hex}, - {0xe0aed3305cfbf6b99096f7ea895c0f2d721dea396d08c75c892152e757668eb8_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xe1223738398f40c909a2f63d7f617ea86f1c6b8bd82786ec6e3ff0a8729ee803_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xe1d19f16b8648afb5fd13c5bd437554c9d1bd61855b47cf4069d6068f27f90c5_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xe6f0c93cd48787b5c65c1df991ab038e7fd1512ae6fa680ca79051348e4bd2c5_bytes32, "2b"_hex}, - {0xe7e08425a2da0d12f7d6cdefc8722e15f577c8b7908924ef5a6f09dc8a8df381_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xe9321ede4409baf4d20ce11283a0267a934062cd546b6fb0097d755686ff0194_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xe99b55f3b486798837a08b10ad2cd917ab907b7c3d62ab7cc31f0d9aeb19c043_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xebd3e19945cff9b7462359bb882a8005d9d1d69d9f82db099f29508447ec7b59_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xece1937784110ebc937ef343c108c6385a8b13b3e8d0617d30bb6bd95701f270_bytes32, "01"_hex}, - {0xf0001b79c0ca5c8fa824f187c3e987fd066688f64c1763648df46d59bfcd7a32_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xf109ca1998eda403604fe597551159daf3bf1c60b6a9f28b02c66fea4594fa33_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xf206ef1f61673596e4abc05dca7be9148dbd34841d85584e8c41d75ecdf5a936_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xf344c28b47c6de556d35ec1e82c6ec3d06f1951d36aa1cd7351d4255e7f04a9c_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xf3f136516fd855c4cd4bd193c2bc38fab112196b023eb22510da3c6cc276eb72_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xf6183b77357ae6ff58dc23d48b3f1d9e76098e6f884751ed03a261a0e7bab231_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xf77262efc56997fdcd4a91cc1449b01f93ebca8c758efcc1c85027e69cc6618b_bytes32, - "cd433bbd1fa6457602a79d957ee85a37e2496d0a"_hex}, - {0xf9adfd03d4d3cf7e9245f9677b882459f0f0ea492b36ebbe34fe965bf3b4e05c_bytes32, - "000000000000000000000000000000000000000000000000000000000000002b"_hex}, - {0xfa22beaea48d8a5e37b2f00efdc83600d4a9d1e1ff5a08cea987db6e6d168833_bytes32, - "0000000000000000000000000000000000000000000000000000000000000001"_hex}, - {0xfaccb2379850753cd96f3a4f37dd3f431863cab480cd1f808f696b0cafab5da4_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xfb859356d00b38d191345159ca428ce6b47c7c03000e91d93ba541f2db07ee75_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xfc08a758057657032bc36068292a2e3dfa490f21697d4e5841ce2bcbf50b12ba_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xfc94ce88596dbda4103ce1ee25fe0f05e0d8e1a57a2d8660d45800ef89ea2f64_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - {0xfe0d647b508fe5dbc76db4136a295fcc960ec1990c7639bb8ddcd06c1761e9e5_bytes32, - "0000000000000000000000000000000000000000000000000000000000000000"_hex}, - }; - return stubs.lookup({input, input_size}, output, max_output_size); + // Keep the output size before the mod normalization. + const auto output_size = mod.size(); + + // Normalize arguments by removing leading zeros. + base = base.substr(std::min(base.find_first_not_of(uint8_t{0}), base.size())); + exp = exp.substr(std::min(exp.find_first_not_of(uint8_t{0}), exp.size())); + mod = mod.substr(std::min(mod.find_first_not_of(uint8_t{0}), mod.size())); + assert(!mod.empty()); // mod must not be 0. + + // Figure out the result by handling trivial cases + // or finally looking it up in the predefined set of results. + const auto result = [&]() -> bytes { + // For mod == 1 the result is 0. + if (mod.size() == 1 && mod[0] == 1) + return bytes{}; + + // For exp == 0 and mod > 1 the result is 1. + if (exp.empty()) + return bytes{1}; + + // For base <= 1, exp != 0, mod > 1 the result is base. + if (base.empty() || (base.size() == 1 && base[0] == 1)) + return bytes{base}; + + return expmod_lookup_result(base, exp, mod); + }(); + + // Set the result in the output buffer. + const auto output_p = std::fill_n(output, output_size - result.size(), 0); + std::ranges::copy(result, output_p); } } // namespace evmone::state diff --git a/test/state/precompiles_stubs.hpp b/test/state/precompiles_stubs.hpp index 5920f6360..461c31e5d 100644 --- a/test/state/precompiles_stubs.hpp +++ b/test/state/precompiles_stubs.hpp @@ -7,6 +7,9 @@ namespace evmone::state { -ExecutionResult expmod_stub( - const uint8_t* input, size_t input_size, uint8_t* output, size_t max_output_size) noexcept; +using evmc::bytes; +using evmc::bytes_view; + +/// Executes the expmod precompile for trivial and pre-defined inputs. +void expmod_stub(bytes_view base, bytes_view exp, bytes_view mod, uint8_t* output) noexcept; } // namespace evmone::state diff --git a/test/unittests/precompiles_expmod_test.cpp b/test/unittests/precompiles_expmod_test.cpp index 8122a0e8f..252e69b1c 100644 --- a/test/unittests/precompiles_expmod_test.cpp +++ b/test/unittests/precompiles_expmod_test.cpp @@ -8,52 +8,51 @@ #include #include -struct TestCase +TEST(expmod, test_vectors) { - std::string base; - std::string exp; - std::string mod; - std::string expected_result; -}; - -/// Test vectors for expmod precompile. -/// TODO: Currently limited to what expmod_stub can handle, but more can be added along the proper -/// implementation, e.g. {"03", "1c93", "61", "5f"}. -static const std::vector test_cases{ - {"", "", "", ""}, - {"", "", "00", "00"}, - {"02", "01", "03", "02"}, + struct TestCase { - "03", - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - "0000000000000000000000000000000000000000000000000000000000000001", - }, -}; + std::string_view base_hex; + std::string_view exp_hex; + std::string_view mod_hex; + std::string_view expected_result_hex; + }; -TEST(expmod, test_vectors) -{ - for (const auto& [base, exp, mod, expected_result] : test_cases) + /// Test vectors for expmod precompile. + const std::vector test_cases{ + {"", "", "", ""}, + {"", "", "00", "00"}, + {"02", "01", "03", "02"}, + {"03", "1c93", "61", "5f"}, + { + "03", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", + "0000000000000000000000000000000000000000000000000000000000000001", + }, + }; + + for (const auto& [base_hex, exp_hex, mod_hex, expected_result_hex] : test_cases) { - const auto base_bytes = *evmc::from_hex(base); - const auto exp_bytes = *evmc::from_hex(exp); - const auto mod_bytes = *evmc::from_hex(mod); - const auto expected_result_bytes = *evmc::from_hex(expected_result); + const auto base = *evmc::from_hex(base_hex); + const auto exp = *evmc::from_hex(exp_hex); + const auto mod = *evmc::from_hex(mod_hex); + const auto expected_result = *evmc::from_hex(expected_result_hex); evmc::bytes input(3 * 32, 0); - input[31] = static_cast(base_bytes.size()); - input[32 + 31] = static_cast(exp_bytes.size()); - input[64 + 31] = static_cast(mod_bytes.size()); - input += base_bytes; - input += exp_bytes; - input += mod_bytes; + input[31] = static_cast(base.size()); + input[32 + 31] = static_cast(exp.size()); + input[64 + 31] = static_cast(mod.size()); + input += base; + input += exp; + input += mod; - evmc::bytes result(expected_result_bytes.size(), 0xfe); - const auto r = + evmc::bytes result(expected_result.size(), 0xfe); + const auto [status, output_size] = evmone::state::expmod_execute(input.data(), input.size(), result.data(), result.size()); - EXPECT_EQ(r.status_code, EVMC_SUCCESS); - EXPECT_EQ(r.output_size, expected_result_bytes.size()); - EXPECT_EQ(hex(result), expected_result); + EXPECT_EQ(status, EVMC_SUCCESS); + EXPECT_EQ(output_size, expected_result.size()); + EXPECT_EQ(hex(result), expected_result_hex); } } @@ -87,3 +86,43 @@ TEST(expmod, analysis_oog) EXPECT_GT(gas_cost, GAS_LIMIT); } } + +TEST(expmod, incomplete_inputs) +{ + struct TestCase + { + std::string_view input_hex; + std::string_view expected_result_hex; + }; + + // Tests for expmod with raw and incomplete inputs (requires padding input with zero bytes). + static constexpr auto GAS_LIMIT = 100'000'000; + const std::vector inputs{ + // clang-format off + {"", ""}, + {"0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000001", "00"}, + {"0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000001 ba ee", "00"}, + {"0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000002 ba ee d0", "9000"}, + {"0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000003 ba ee d000", "100000"}, + {"0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000003 ba ee d001", "789700"}, + {"0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000003 ba ee 00d0", "009000"}, + {"0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000003 ba ee 0000", "000000"}, + {"0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000003 ba ee 000000 fe", "000000"}, + {"0000000000000000000000000000000000000000000000000000000000000010 0000000000000000000000000000000000000000000000000000000000000010 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000001", "00"}, + {"000000000000000000000000000000000000000000000000000000000000ffff 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000001 80", "00"}, + // clang-format on + }; + + for (const auto& [input_hex, expected_result_hex] : inputs) + { + const auto input = evmc::from_spaced_hex(input_hex).value(); + const auto [gas_cost, max_output_size] = evmone::state::expmod_analyze(input, EVMC_PRAGUE); + EXPECT_LT(gas_cost, GAS_LIMIT); + auto output = std::make_unique_for_overwrite(max_output_size); + const auto [status, output_size] = evmone::state::expmod_execute( + input.data(), input.size(), output.get(), max_output_size); + EXPECT_EQ(status, EVMC_SUCCESS); + const auto result_hex = evmc::hex({output.get(), output_size}); + EXPECT_EQ(result_hex, expected_result_hex); + } +}