From 9b4f11e518c6bbf66070a97243e47ab7b6e01580 Mon Sep 17 00:00:00 2001 From: Andrei Maiboroda Date: Tue, 4 Apr 2017 16:18:15 +0200 Subject: [PATCH] Minor improvements & more tests added --- libethcore/Precompiled.cpp | 29 +++-- libethcore/Precompiled.h | 2 +- test/unittests/libethcore/PrecompiledTest.cpp | 115 ++++++++++++++++-- 3 files changed, 125 insertions(+), 21 deletions(-) diff --git a/libethcore/Precompiled.cpp b/libethcore/Precompiled.cpp index 23fe6a0f73b..c9a1c5735e7 100644 --- a/libethcore/Precompiled.cpp +++ b/libethcore/Precompiled.cpp @@ -97,15 +97,18 @@ ETH_REGISTER_PRECOMPILED(identity)(bytesConstRef _in) return {true, _in.toBytes()}; } -template -T parseBigEndianRightPadded(bytesConstRef _in, size_t _begin, size_t _count) +// Parse _count bytes of _in starting with _begin offset as big endian int. +// If there's not enough bytes in _in, consider it infinitely right-padded with zeroes. +bigint parseBigEndianRightPadded(bytesConstRef _in, size_t _begin, size_t _count) { if (_begin > _in.count()) return 0; + // crop _in, not going beyond its size bytesConstRef cropped = _in.cropped(_begin, min(_count, _in.count() - _begin)); - T ret = fromBigEndian(cropped); + bigint ret = fromBigEndian(cropped); + // shift as if we had right-padding zeroes ret <<= 8 * (_count - cropped.count()); return ret; @@ -113,15 +116,15 @@ T parseBigEndianRightPadded(bytesConstRef _in, size_t _begin, size_t _count) ETH_REGISTER_PRECOMPILED(modexp)(bytesConstRef _in) { - size_t const baseLength(parseBigEndianRightPadded(_in, 0, 32)); - size_t const expLength(parseBigEndianRightPadded(_in, 32, 32)); - size_t const modLength(parseBigEndianRightPadded(_in, 64, 32)); + size_t const baseLength(parseBigEndianRightPadded(_in, 0, 32)); + size_t const expLength(parseBigEndianRightPadded(_in, 32, 32)); + size_t const modLength(parseBigEndianRightPadded(_in, 64, 32)); - bigint const base(parseBigEndianRightPadded(_in, 96, baseLength)); - bigint const exp(parseBigEndianRightPadded(_in, 96 + baseLength, expLength)); - bigint const mod(parseBigEndianRightPadded(_in, 96 + baseLength + expLength, modLength)); + bigint const base(parseBigEndianRightPadded(_in, 96, baseLength)); + bigint const exp(parseBigEndianRightPadded(_in, 96 + baseLength, expLength)); + bigint const mod(parseBigEndianRightPadded(_in, 96 + baseLength + expLength, modLength)); - bigint const result = boost::multiprecision::powm(base, exp, mod); + bigint const result = mod != 0 ? boost::multiprecision::powm(base, exp, mod) : bigint{0}; bytes ret(modLength); toBigEndian(result, ret); @@ -131,9 +134,9 @@ ETH_REGISTER_PRECOMPILED(modexp)(bytesConstRef _in) ETH_REGISTER_PRECOMPILED_PRICER(modexp)(bytesConstRef _in) { - u256 const baseLength(parseBigEndianRightPadded(_in, 0, 32)); - u256 const expLength(parseBigEndianRightPadded(_in, 32, 32)); - u256 const modLength(parseBigEndianRightPadded(_in, 64, 32)); + bigint const baseLength(parseBigEndianRightPadded(_in, 0, 32)); + bigint const expLength(parseBigEndianRightPadded(_in, 32, 32)); + bigint const modLength(parseBigEndianRightPadded(_in, 64, 32)); bigint const maxLength = max(modLength, baseLength); diff --git a/libethcore/Precompiled.h b/libethcore/Precompiled.h index ef09d84f50f..df2e34239b0 100644 --- a/libethcore/Precompiled.h +++ b/libethcore/Precompiled.h @@ -53,7 +53,7 @@ class PrecompiledRegistrar /// Register a pricer. In general just use ETH_REGISTER_PRECOMPILED_PRICER. static PrecompiledPricer registerPricer(std::string const& _name, PrecompiledPricer const& _exec) { return (get()->m_pricers[_name] = _exec); } - /// Unregister an executor. Shouldn't generally be necessary. + /// Unregister a pricer. Shouldn't generally be necessary. static void unregisterPricer(std::string const& _name) { get()->m_pricers.erase(_name); } private: diff --git a/test/unittests/libethcore/PrecompiledTest.cpp b/test/unittests/libethcore/PrecompiledTest.cpp index d1abefbf183..61f44cc1d08 100644 --- a/test/unittests/libethcore/PrecompiledTest.cpp +++ b/test/unittests/libethcore/PrecompiledTest.cpp @@ -46,22 +46,23 @@ BOOST_AUTO_TEST_CASE(modexpFermatTheorem) bytes expected = fromHex("0000000000000000000000000000000000000000000000000000000000000001"); BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end()); } -/* -BOOST_AUTO_TEST_CASE(modexpTooLarge) + +BOOST_AUTO_TEST_CASE(modexpZeroBase) { PrecompiledExecutor exec = PrecompiledRegistrar::executor("modexp"); bytes in = fromHex( "0000000000000000000000000000000000000000000000000000000000000000" "0000000000000000000000000000000000000000000000000000000000000020" - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" - "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd"); + "0000000000000000000000000000000000000000000000000000000000000020" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"); auto res = exec(bytesConstRef(in.data(), in.size())); - BOOST_REQUIRE_EQUAL(res.first, false); + BOOST_REQUIRE(res.first); + bytes expected = fromHex("0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end()); } -*/ BOOST_AUTO_TEST_CASE(modexpExtraByteIgnored) { @@ -100,4 +101,104 @@ BOOST_AUTO_TEST_CASE(modexpRightPadding) BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end()); } +BOOST_AUTO_TEST_CASE(modexpMissingValues) +{ + PrecompiledExecutor exec = PrecompiledRegistrar::executor("modexp"); + + bytes in = fromHex( + "0000000000000000000000000000000000000000000000000000000000000001" + "0000000000000000000000000000000000000000000000000000000000000002" + "0000000000000000000000000000000000000000000000000000000000000020" + "03"); + auto res = exec(bytesConstRef(in.data(), in.size())); + + BOOST_REQUIRE(res.first); + bytes expected = fromHex("0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end()); +} + +BOOST_AUTO_TEST_CASE(modexpEmptyValue) +{ + PrecompiledExecutor exec = PrecompiledRegistrar::executor("modexp"); + + bytes in = fromHex( + "0000000000000000000000000000000000000000000000000000000000000001" + "0000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000000020" + "03" + "8000000000000000000000000000000000000000000000000000000000000000"); + auto res = exec(bytesConstRef(in.data(), in.size())); + + BOOST_REQUIRE(res.first); + bytes expected = fromHex("0000000000000000000000000000000000000000000000000000000000000001"); + BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end()); +} + +BOOST_AUTO_TEST_CASE(modexpZeroPowerZero) +{ + PrecompiledExecutor exec = PrecompiledRegistrar::executor("modexp"); + + bytes in = fromHex( + "0000000000000000000000000000000000000000000000000000000000000001" + "0000000000000000000000000000000000000000000000000000000000000001" + "0000000000000000000000000000000000000000000000000000000000000020" + "00" + "00" + "80"); + auto res = exec(bytesConstRef(in.data(), in.size())); + + BOOST_REQUIRE(res.first); + bytes expected = fromHex("0000000000000000000000000000000000000000000000000000000000000001"); + BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end()); +} + +BOOST_AUTO_TEST_CASE(modexpZeroPowerZeroModZero) +{ + PrecompiledExecutor exec = PrecompiledRegistrar::executor("modexp"); + + bytes in = fromHex( + "0000000000000000000000000000000000000000000000000000000000000001" + "0000000000000000000000000000000000000000000000000000000000000001" + "0000000000000000000000000000000000000000000000000000000000000020" + "00" + "00" + "00"); + auto res = exec(bytesConstRef(in.data(), in.size())); + + BOOST_REQUIRE(res.first); + bytes expected = fromHex("0000000000000000000000000000000000000000000000000000000000000000"); + BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end()); +} + +BOOST_AUTO_TEST_CASE(modexpCostFermatTheorem) +{ + PrecompiledPricer cost = PrecompiledRegistrar::pricer("modexp"); + + bytes in = fromHex( + "0000000000000000000000000000000000000000000000000000000000000001" + "0000000000000000000000000000000000000000000000000000000000000020" + "0000000000000000000000000000000000000000000000000000000000000020" + "03" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"); + auto res = cost(bytesConstRef(in.data(), in.size())); + + BOOST_REQUIRE_EQUAL(static_cast(res), 1638); +} + +BOOST_AUTO_TEST_CASE(modexpCostTooLarge) +{ + PrecompiledPricer cost = PrecompiledRegistrar::pricer("modexp"); + + bytes in = fromHex( + "0000000000000000000000000000000000000000000000000000000000000000" + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + "0000000000000000000000000000000000000000000000000000000000000020" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe" + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd"); + auto res = cost(bytesConstRef(in.data(), in.size())); + + BOOST_REQUIRE(res == bigint{"5928554968950589205686834432444820882087423214880796878820228301205152237564672"}); +} + BOOST_AUTO_TEST_SUITE_END()