rippled
base_uint_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2016 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/Blob.h>
21 #include <ripple/basics/base_uint.h>
22 #include <ripple/basics/hardened_hash.h>
23 #include <ripple/beast/unit_test.h>
24 #include <boost/endian/conversion.hpp>
25 #include <complex>
26 
27 #include <type_traits>
28 
29 namespace ripple {
30 namespace test {
31 
32 // a non-hashing Hasher that just copies the bytes.
33 // Used to test hash_append in base_uint
34 template <std::size_t Bits>
35 struct nonhash
36 {
37  static constexpr auto const endian = boost::endian::order::big;
38  static constexpr std::size_t WIDTH = Bits / 8;
39 
41 
42  nonhash() = default;
43 
44  void
45  operator()(void const* key, std::size_t len) noexcept
46  {
47  assert(len == WIDTH);
48  memcpy(data_.data(), key, len);
49  }
50 
51  explicit operator std::size_t() noexcept
52  {
53  return WIDTH;
54  }
55 };
56 
57 struct base_uint_test : beast::unit_test::suite
58 {
62 
63  void
65  {
66  {
67  static constexpr std::
68  array<std::pair<std::string_view, std::string_view>, 6>
69  test_args{
70  {{"0000000000000000", "0000000000000001"},
71  {"0000000000000000", "ffffffffffffffff"},
72  {"1234567812345678", "2345678923456789"},
73  {"8000000000000000", "8000000000000001"},
74  {"aaaaaaaaaaaaaaa9", "aaaaaaaaaaaaaaaa"},
75  {"fffffffffffffffe", "ffffffffffffffff"}}};
76 
77  for (auto const& arg : test_args)
78  {
79  ripple::base_uint<64> const u{arg.first}, v{arg.second};
80  BEAST_EXPECT(u < v);
81  BEAST_EXPECT(u <= v);
82  BEAST_EXPECT(u != v);
83  BEAST_EXPECT(!(u == v));
84  BEAST_EXPECT(!(u > v));
85  BEAST_EXPECT(!(u >= v));
86  BEAST_EXPECT(!(v < u));
87  BEAST_EXPECT(!(v <= u));
88  BEAST_EXPECT(v != u);
89  BEAST_EXPECT(!(v == u));
90  BEAST_EXPECT(v > u);
91  BEAST_EXPECT(v >= u);
92  BEAST_EXPECT(u == u);
93  BEAST_EXPECT(v == v);
94  }
95  }
96 
97  {
98  static constexpr std::array<
100  6>
101  test_args{{
102  {"000000000000000000000000", "000000000000000000000001"},
103  {"000000000000000000000000", "ffffffffffffffffffffffff"},
104  {"0123456789ab0123456789ab", "123456789abc123456789abc"},
105  {"555555555555555555555555", "55555555555a555555555555"},
106  {"aaaaaaaaaaaaaaa9aaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaa"},
107  {"fffffffffffffffffffffffe", "ffffffffffffffffffffffff"},
108  }};
109 
110  for (auto const& arg : test_args)
111  {
112  ripple::base_uint<96> const u{arg.first}, v{arg.second};
113  BEAST_EXPECT(u < v);
114  BEAST_EXPECT(u <= v);
115  BEAST_EXPECT(u != v);
116  BEAST_EXPECT(!(u == v));
117  BEAST_EXPECT(!(u > v));
118  BEAST_EXPECT(!(u >= v));
119  BEAST_EXPECT(!(v < u));
120  BEAST_EXPECT(!(v <= u));
121  BEAST_EXPECT(v != u);
122  BEAST_EXPECT(!(v == u));
123  BEAST_EXPECT(v > u);
124  BEAST_EXPECT(v >= u);
125  BEAST_EXPECT(u == u);
126  BEAST_EXPECT(v == v);
127  }
128  }
129  }
130 
131  void
132  run() override
133  {
134  testcase("base_uint: general purpose tests");
135 
136  static_assert(
138  static_assert(
140 
141  testComparisons();
142 
143  // used to verify set insertion (hashing required)
145 
146  Blob raw{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
147  BEAST_EXPECT(test96::bytes == raw.size());
148 
149  test96 u{raw};
150  uset.insert(u);
151  BEAST_EXPECT(raw.size() == u.size());
152  BEAST_EXPECT(to_string(u) == "0102030405060708090A0B0C");
153  BEAST_EXPECT(*u.data() == 1);
154  BEAST_EXPECT(u.signum() == 1);
155  BEAST_EXPECT(!!u);
156  BEAST_EXPECT(!u.isZero());
157  BEAST_EXPECT(u.isNonZero());
158  unsigned char t = 0;
159  for (auto& d : u)
160  {
161  BEAST_EXPECT(d == ++t);
162  }
163 
164  // Test hash_append by "hashing" with a no-op hasher (h)
165  // and then extracting the bytes that were written during hashing
166  // back into another base_uint (w) for comparison with the original
167  nonhash<96> h;
168  hash_append(h, u);
170  BEAST_EXPECT(w == u);
171 
172  test96 v{~u};
173  uset.insert(v);
174  BEAST_EXPECT(to_string(v) == "FEFDFCFBFAF9F8F7F6F5F4F3");
175  BEAST_EXPECT(*v.data() == 0xfe);
176  BEAST_EXPECT(v.signum() == 1);
177  BEAST_EXPECT(!!v);
178  BEAST_EXPECT(!v.isZero());
179  BEAST_EXPECT(v.isNonZero());
180  t = 0xff;
181  for (auto& d : v)
182  {
183  BEAST_EXPECT(d == --t);
184  }
185 
186  BEAST_EXPECT(u < v);
187  BEAST_EXPECT(v > u);
188 
189  v = u;
190  BEAST_EXPECT(v == u);
191 
192  test96 z{beast::zero};
193  uset.insert(z);
194  BEAST_EXPECT(to_string(z) == "000000000000000000000000");
195  BEAST_EXPECT(*z.data() == 0);
196  BEAST_EXPECT(*z.begin() == 0);
197  BEAST_EXPECT(*std::prev(z.end(), 1) == 0);
198  BEAST_EXPECT(z.signum() == 0);
199  BEAST_EXPECT(!z);
200  BEAST_EXPECT(z.isZero());
201  BEAST_EXPECT(!z.isNonZero());
202  for (auto& d : z)
203  {
204  BEAST_EXPECT(d == 0);
205  }
206 
207  test96 n{z};
208  n++;
209  BEAST_EXPECT(n == test96(1));
210  n--;
211  BEAST_EXPECT(n == beast::zero);
212  BEAST_EXPECT(n == z);
213  n--;
214  BEAST_EXPECT(to_string(n) == "FFFFFFFFFFFFFFFFFFFFFFFF");
215  n = beast::zero;
216  BEAST_EXPECT(n == z);
217 
218  test96 zp1{z};
219  zp1++;
220  test96 zm1{z};
221  zm1--;
222  test96 x{zm1 ^ zp1};
223  uset.insert(x);
224  BEAST_EXPECTS(to_string(x) == "FFFFFFFFFFFFFFFFFFFFFFFE", to_string(x));
225 
226  BEAST_EXPECT(uset.size() == 4);
227 
228  test96 tmp;
229  BEAST_EXPECT(tmp.parseHex(to_string(u)));
230  BEAST_EXPECT(tmp == u);
231  tmp = z;
232 
233  // fails with extra char
234  BEAST_EXPECT(!tmp.parseHex("A" + to_string(u)));
235  tmp = z;
236 
237  // fails with extra char at end
238  BEAST_EXPECT(!tmp.parseHex(to_string(u) + "A"));
239 
240  // fails with a non-hex character at some point in the string:
241  tmp = z;
242 
243  for (std::size_t i = 0; i != 24; ++i)
244  {
245  std::string x = to_string(z);
246  x[i] = ('G' + (i % 10));
247  BEAST_EXPECT(!tmp.parseHex(x));
248  }
249 
250  // Walking 1s:
251  for (std::size_t i = 0; i != 24; ++i)
252  {
253  std::string s1 = "000000000000000000000000";
254  s1[i] = '1';
255 
256  BEAST_EXPECT(tmp.parseHex(s1));
257  BEAST_EXPECT(to_string(tmp) == s1);
258  }
259 
260  // Walking 0s:
261  for (std::size_t i = 0; i != 24; ++i)
262  {
263  std::string s1 = "111111111111111111111111";
264  s1[i] = '0';
265 
266  BEAST_EXPECT(tmp.parseHex(s1));
267  BEAST_EXPECT(to_string(tmp) == s1);
268  }
269 
270  // Constexpr constructors
271  {
272  static_assert(test96{}.signum() == 0);
273  static_assert(test96("0").signum() == 0);
274  static_assert(test96("000000000000000000000000").signum() == 0);
275  static_assert(test96("000000000000000000000001").signum() == 1);
276  static_assert(test96("800000000000000000000000").signum() == 1);
277 
278 // Everything within the #if should fail during compilation.
279 #if 0
280  // Too few characters
281  static_assert(test96("00000000000000000000000").signum() == 0);
282 
283  // Too many characters
284  static_assert(test96("0000000000000000000000000").signum() == 0);
285 
286  // Non-hex characters
287  static_assert(test96("00000000000000000000000 ").signum() == 1);
288  static_assert(test96("00000000000000000000000/").signum() == 1);
289  static_assert(test96("00000000000000000000000:").signum() == 1);
290  static_assert(test96("00000000000000000000000@").signum() == 1);
291  static_assert(test96("00000000000000000000000G").signum() == 1);
292  static_assert(test96("00000000000000000000000`").signum() == 1);
293  static_assert(test96("00000000000000000000000g").signum() == 1);
294  static_assert(test96("00000000000000000000000~").signum() == 1);
295 #endif // 0
296 
297  // Using the constexpr constructor in a non-constexpr context
298  // with an error in the parsing throws an exception.
299  {
300  // Invalid length for string.
301  bool caught = false;
302  try
303  {
304  // Try to prevent constant evaluation.
305  std::vector<char> str(23, '7');
306  std::string_view sView(str.data(), str.size());
307  [[maybe_unused]] test96 t96(sView);
308  }
309  catch (std::invalid_argument const& e)
310  {
311  BEAST_EXPECT(
312  e.what() ==
313  std::string("invalid length for hex string"));
314  caught = true;
315  }
316  BEAST_EXPECT(caught);
317  }
318  {
319  // Invalid character in string.
320  bool caught = false;
321  try
322  {
323  // Try to prevent constant evaluation.
324  std::vector<char> str(23, '7');
325  str.push_back('G');
326  std::string_view sView(str.data(), str.size());
327  [[maybe_unused]] test96 t96(sView);
328  }
329  catch (std::range_error const& e)
330  {
331  BEAST_EXPECT(
332  e.what() == std::string("invalid hex character"));
333  caught = true;
334  }
335  BEAST_EXPECT(caught);
336  }
337 
338  // Verify that constexpr base_uints interpret a string the same
339  // way parseHex() does.
340  struct StrBaseUint
341  {
342  char const* const str;
343  test96 tst;
344 
345  constexpr StrBaseUint(char const* s) : str(s), tst(s)
346  {
347  }
348  };
349  constexpr StrBaseUint testCases[] = {
350  "000000000000000000000000",
351  "000000000000000000000001",
352  "fedcba9876543210ABCDEF91",
353  "19FEDCBA0123456789abcdef",
354  "800000000000000000000000",
355  "fFfFfFfFfFfFfFfFfFfFfFfF"};
356 
357  for (StrBaseUint const& t : testCases)
358  {
359  test96 t96;
360  BEAST_EXPECT(t96.parseHex(t.str));
361  BEAST_EXPECT(t96 == t.tst);
362  }
363  }
364  }
365 };
366 
367 BEAST_DEFINE_TESTSUITE(base_uint, ripple_basics, ripple);
368 
369 } // namespace test
370 } // namespace ripple
std::string
STL class.
ripple::test::base_uint_test
Definition: base_uint_test.cpp:57
std::string_view
STL class.
std::unordered_set
STL class.
std::pair
ripple::test::nonhash::WIDTH
static constexpr std::size_t WIDTH
Definition: base_uint_test.cpp:38
std::vector< unsigned char >
std::unordered_set::size
T size(T... args)
std::is_assignable
std::vector::push_back
T push_back(T... args)
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:82
ripple::base_uint::bytes
static constexpr std::size_t bytes
Definition: base_uint.h:105
std::array< std::uint8_t, WIDTH >
std::invalid_argument
STL class.
ripple::test::nonhash::endian
static constexpr const auto endian
Definition: base_uint_test.cpp:37
ripple::base_uint::signum
constexpr int signum() const
Definition: base_uint.h:327
ripple::test::base_uint_test::test96
base_uint< 96 > test96
Definition: base_uint_test.cpp:59
ripple::test::nonhash::nonhash
nonhash()=default
std::is_copy_constructible
ripple::test::base_uint_test::testComparisons
void testComparisons()
Definition: base_uint_test.cpp:64
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::nonhash
Definition: base_uint_test.cpp:35
std::array::begin
T begin(T... args)
std::unordered_set::insert
T insert(T... args)
ripple::test::nonhash::operator()
void operator()(void const *key, std::size_t len) noexcept
Definition: base_uint_test.cpp:45
std::is_constructible
complex
std::size_t
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
std::array::end
T end(T... args)
std::is_copy_assignable
ripple::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:496
std::prev
T prev(T... args)
std::range_error
STL class.
ripple::hash_append
void hash_append(Hasher &h, ValidatorBlobInfo const &blobInfo)
Definition: ValidatorList.h:897
ripple::test::nonhash::data_
std::array< std::uint8_t, WIDTH > data_
Definition: base_uint_test.cpp:40
ripple::test::base_uint_test::run
void run() override
Definition: base_uint_test.cpp:132
std::array::data
T data(T... args)
type_traits
std::invalid_argument::what
T what(T... args)
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)