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

Commit aaf29c7

Browse files
committed
Minor improvements & more tests added
1 parent cea171f commit aaf29c7

File tree

3 files changed

+141
-21
lines changed

3 files changed

+141
-21
lines changed

libethcore/Precompiled.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,31 +97,34 @@ ETH_REGISTER_PRECOMPILED(identity)(bytesConstRef _in)
9797
return {true, _in.toBytes()};
9898
}
9999

100-
template<class T>
101-
T parseBigEndianRightPadded(bytesConstRef _in, size_t _begin, size_t _count)
100+
// Parse _count bytes of _in starting with _begin offset as big endian int.
101+
// If there's not enough bytes in _in, consider it infinitely right-padded with zeroes.
102+
bigint parseBigEndianRightPadded(bytesConstRef _in, size_t _begin, size_t _count)
102103
{
103104
if (_begin > _in.count())
104105
return 0;
105106

107+
// crop _in, not going beyond its size
106108
bytesConstRef cropped = _in.cropped(_begin, min(_count, _in.count() - _begin));
107109

108-
T ret = fromBigEndian<T>(cropped);
110+
bigint ret = fromBigEndian<bigint>(cropped);
111+
// shift as if we had right-padding zeroes
109112
ret <<= 8 * (_count - cropped.count());
110113

111114
return ret;
112115
}
113116

114117
ETH_REGISTER_PRECOMPILED(modexp)(bytesConstRef _in)
115118
{
116-
size_t const baseLength(parseBigEndianRightPadded<u256>(_in, 0, 32));
117-
size_t const expLength(parseBigEndianRightPadded<u256>(_in, 32, 32));
118-
size_t const modLength(parseBigEndianRightPadded<u256>(_in, 64, 32));
119+
size_t const baseLength(parseBigEndianRightPadded(_in, 0, 32));
120+
size_t const expLength(parseBigEndianRightPadded(_in, 32, 32));
121+
size_t const modLength(parseBigEndianRightPadded(_in, 64, 32));
119122

120-
bigint const base(parseBigEndianRightPadded<bigint>(_in, 96, baseLength));
121-
bigint const exp(parseBigEndianRightPadded<bigint>(_in, 96 + baseLength, expLength));
122-
bigint const mod(parseBigEndianRightPadded<bigint>(_in, 96 + baseLength + expLength, modLength));
123+
bigint const base(parseBigEndianRightPadded(_in, 96, baseLength));
124+
bigint const exp(parseBigEndianRightPadded(_in, 96 + baseLength, expLength));
125+
bigint const mod(parseBigEndianRightPadded(_in, 96 + baseLength + expLength, modLength));
123126

124-
bigint const result = boost::multiprecision::powm(base, exp, mod);
127+
bigint const result = mod != 0 ? boost::multiprecision::powm(base, exp, mod) : bigint{0};
125128

126129
bytes ret(modLength);
127130
toBigEndian(result, ret);
@@ -131,9 +134,9 @@ ETH_REGISTER_PRECOMPILED(modexp)(bytesConstRef _in)
131134

132135
ETH_REGISTER_PRECOMPILED_PRICER(modexp)(bytesConstRef _in)
133136
{
134-
u256 const baseLength(parseBigEndianRightPadded<u256>(_in, 0, 32));
135-
u256 const expLength(parseBigEndianRightPadded<u256>(_in, 32, 32));
136-
u256 const modLength(parseBigEndianRightPadded<u256>(_in, 64, 32));
137+
bigint const baseLength(parseBigEndianRightPadded(_in, 0, 32));
138+
bigint const expLength(parseBigEndianRightPadded(_in, 32, 32));
139+
bigint const modLength(parseBigEndianRightPadded(_in, 64, 32));
137140

138141
bigint const maxLength = max(modLength, baseLength);
139142

libethcore/Precompiled.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class PrecompiledRegistrar
5353

5454
/// Register a pricer. In general just use ETH_REGISTER_PRECOMPILED_PRICER.
5555
static PrecompiledPricer registerPricer(std::string const& _name, PrecompiledPricer const& _exec) { return (get()->m_pricers[_name] = _exec); }
56-
/// Unregister an executor. Shouldn't generally be necessary.
56+
/// Unregister a pricer. Shouldn't generally be necessary.
5757
static void unregisterPricer(std::string const& _name) { get()->m_pricers.erase(_name); }
5858

5959
private:

test/unittests/libethcore/PrecompiledTest.cpp

Lines changed: 124 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,23 @@ BOOST_AUTO_TEST_CASE(modexpFermatTheorem)
4646
bytes expected = fromHex("0000000000000000000000000000000000000000000000000000000000000001");
4747
BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end());
4848
}
49-
/*
50-
BOOST_AUTO_TEST_CASE(modexpTooLarge)
49+
50+
BOOST_AUTO_TEST_CASE(modexpZeroBase)
5151
{
5252
PrecompiledExecutor exec = PrecompiledRegistrar::executor("modexp");
5353

5454
bytes in = fromHex(
5555
"0000000000000000000000000000000000000000000000000000000000000000"
5656
"0000000000000000000000000000000000000000000000000000000000000020"
57-
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
58-
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
59-
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd");
57+
"0000000000000000000000000000000000000000000000000000000000000020"
58+
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e"
59+
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f");
6060
auto res = exec(bytesConstRef(in.data(), in.size()));
6161

62-
BOOST_REQUIRE_EQUAL(res.first, false);
62+
BOOST_REQUIRE(res.first);
63+
bytes expected = fromHex("0000000000000000000000000000000000000000000000000000000000000000");
64+
BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end());
6365
}
64-
*/
6566

6667
BOOST_AUTO_TEST_CASE(modexpExtraByteIgnored)
6768
{
@@ -100,4 +101,120 @@ BOOST_AUTO_TEST_CASE(modexpRightPadding)
100101
BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end());
101102
}
102103

104+
BOOST_AUTO_TEST_CASE(modexpMissingValues)
105+
{
106+
PrecompiledExecutor exec = PrecompiledRegistrar::executor("modexp");
107+
108+
bytes in = fromHex(
109+
"0000000000000000000000000000000000000000000000000000000000000001"
110+
"0000000000000000000000000000000000000000000000000000000000000002"
111+
"0000000000000000000000000000000000000000000000000000000000000020"
112+
"03");
113+
auto res = exec(bytesConstRef(in.data(), in.size()));
114+
115+
BOOST_REQUIRE(res.first);
116+
bytes expected = fromHex("0000000000000000000000000000000000000000000000000000000000000000");
117+
BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end());
118+
}
119+
120+
BOOST_AUTO_TEST_CASE(modexpEmptyValue)
121+
{
122+
PrecompiledExecutor exec = PrecompiledRegistrar::executor("modexp");
123+
124+
bytes in = fromHex(
125+
"0000000000000000000000000000000000000000000000000000000000000001"
126+
"0000000000000000000000000000000000000000000000000000000000000000"
127+
"0000000000000000000000000000000000000000000000000000000000000020"
128+
"03"
129+
"8000000000000000000000000000000000000000000000000000000000000000");
130+
auto res = exec(bytesConstRef(in.data(), in.size()));
131+
132+
BOOST_REQUIRE(res.first);
133+
bytes expected = fromHex("0000000000000000000000000000000000000000000000000000000000000001");
134+
BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end());
135+
}
136+
137+
BOOST_AUTO_TEST_CASE(modexpZeroPowerZero)
138+
{
139+
PrecompiledExecutor exec = PrecompiledRegistrar::executor("modexp");
140+
141+
bytes in = fromHex(
142+
"0000000000000000000000000000000000000000000000000000000000000001"
143+
"0000000000000000000000000000000000000000000000000000000000000001"
144+
"0000000000000000000000000000000000000000000000000000000000000020"
145+
"00"
146+
"00"
147+
"80");
148+
auto res = exec(bytesConstRef(in.data(), in.size()));
149+
150+
BOOST_REQUIRE(res.first);
151+
bytes expected = fromHex("0000000000000000000000000000000000000000000000000000000000000001");
152+
BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end());
153+
}
154+
155+
BOOST_AUTO_TEST_CASE(modexpZeroPowerZeroModZero)
156+
{
157+
PrecompiledExecutor exec = PrecompiledRegistrar::executor("modexp");
158+
159+
bytes in = fromHex(
160+
"0000000000000000000000000000000000000000000000000000000000000001"
161+
"0000000000000000000000000000000000000000000000000000000000000001"
162+
"0000000000000000000000000000000000000000000000000000000000000020"
163+
"00"
164+
"00"
165+
"00");
166+
auto res = exec(bytesConstRef(in.data(), in.size()));
167+
168+
BOOST_REQUIRE(res.first);
169+
bytes expected = fromHex("0000000000000000000000000000000000000000000000000000000000000000");
170+
BOOST_REQUIRE_EQUAL_COLLECTIONS(res.second.begin(), res.second.end(), expected.begin(), expected.end());
171+
}
172+
173+
BOOST_AUTO_TEST_CASE(modexpModLengthZero)
174+
{
175+
PrecompiledExecutor exec = PrecompiledRegistrar::executor("modexp");
176+
177+
bytes in = fromHex(
178+
"0000000000000000000000000000000000000000000000000000000000000001"
179+
"0000000000000000000000000000000000000000000000000000000000000001"
180+
"0000000000000000000000000000000000000000000000000000000000000000"
181+
"01"
182+
"01");
183+
auto res = exec(bytesConstRef(in.data(), in.size()));
184+
185+
BOOST_REQUIRE(res.first);
186+
BOOST_REQUIRE(res.second.empty());
187+
}
188+
189+
BOOST_AUTO_TEST_CASE(modexpCostFermatTheorem)
190+
{
191+
PrecompiledPricer cost = PrecompiledRegistrar::pricer("modexp");
192+
193+
bytes in = fromHex(
194+
"0000000000000000000000000000000000000000000000000000000000000001"
195+
"0000000000000000000000000000000000000000000000000000000000000020"
196+
"0000000000000000000000000000000000000000000000000000000000000020"
197+
"03"
198+
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e"
199+
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f");
200+
auto res = cost(bytesConstRef(in.data(), in.size()));
201+
202+
BOOST_REQUIRE_EQUAL(static_cast<int>(res), 1638);
203+
}
204+
205+
BOOST_AUTO_TEST_CASE(modexpCostTooLarge)
206+
{
207+
PrecompiledPricer cost = PrecompiledRegistrar::pricer("modexp");
208+
209+
bytes in = fromHex(
210+
"0000000000000000000000000000000000000000000000000000000000000000"
211+
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
212+
"0000000000000000000000000000000000000000000000000000000000000020"
213+
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"
214+
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd");
215+
auto res = cost(bytesConstRef(in.data(), in.size()));
216+
217+
BOOST_REQUIRE(res == bigint{"5928554968950589205686834432444820882087423214880796878820228301205152237564672"});
218+
}
219+
103220
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)