Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

Commit

Permalink
Minor improvements & more tests added
Browse files Browse the repository at this point in the history
  • Loading branch information
gumb0 committed Apr 4, 2017
1 parent cea171f commit 9b4f11e
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 21 deletions.
29 changes: 16 additions & 13 deletions libethcore/Precompiled.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,31 +97,34 @@ ETH_REGISTER_PRECOMPILED(identity)(bytesConstRef _in)
return {true, _in.toBytes()};
}

template<class T>
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<T>(cropped);
bigint ret = fromBigEndian<bigint>(cropped);
// shift as if we had right-padding zeroes
ret <<= 8 * (_count - cropped.count());

return ret;
}

ETH_REGISTER_PRECOMPILED(modexp)(bytesConstRef _in)
{
size_t const baseLength(parseBigEndianRightPadded<u256>(_in, 0, 32));
size_t const expLength(parseBigEndianRightPadded<u256>(_in, 32, 32));
size_t const modLength(parseBigEndianRightPadded<u256>(_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<bigint>(_in, 96, baseLength));
bigint const exp(parseBigEndianRightPadded<bigint>(_in, 96 + baseLength, expLength));
bigint const mod(parseBigEndianRightPadded<bigint>(_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);
Expand All @@ -131,9 +134,9 @@ ETH_REGISTER_PRECOMPILED(modexp)(bytesConstRef _in)

ETH_REGISTER_PRECOMPILED_PRICER(modexp)(bytesConstRef _in)
{
u256 const baseLength(parseBigEndianRightPadded<u256>(_in, 0, 32));
u256 const expLength(parseBigEndianRightPadded<u256>(_in, 32, 32));
u256 const modLength(parseBigEndianRightPadded<u256>(_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);

Expand Down
2 changes: 1 addition & 1 deletion libethcore/Precompiled.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
115 changes: 108 additions & 7 deletions test/unittests/libethcore/PrecompiledTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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<int>(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()

0 comments on commit 9b4f11e

Please sign in to comment.