diff --git a/src/ripple/basics/base_uint.h b/src/ripple/basics/base_uint.h index 2a2b94c3a..cfa686765 100644 --- a/src/ripple/basics/base_uint.h +++ b/src/ripple/basics/base_uint.h @@ -91,7 +91,7 @@ public: const_iterator cend() const { return data()+bytes; } /** Value hashing function. - The seed prevents crafted inputs from causing degenarate parent containers. + The seed prevents crafted inputs from causing degenerate parent containers. */ using hasher = hardened_hash <>; diff --git a/src/test/basics/base_uint_test.cpp b/src/test/basics/base_uint_test.cpp index f95889771..8da8dc25c 100644 --- a/src/test/basics/base_uint_test.cpp +++ b/src/test/basics/base_uint_test.cpp @@ -19,29 +19,49 @@ #include #include +#include #include -#include +#include namespace ripple { namespace test { +// a non-hashing Hasher that just copies the bytes. +// Used to test hash_append in base_uint +template +struct nonhash +{ + static constexpr std::size_t WIDTH = Bits / 8; + std::array data_; + static beast::endian const endian = beast::endian::big; + + nonhash() = default; + + void + operator() (void const* key, std::size_t len) noexcept + { + assert(len == WIDTH); + memcpy(data_.data(), key, len); + } + + explicit + operator std::size_t() noexcept { return WIDTH; } +}; + struct base_uint_test : beast::unit_test::suite { using test96 = base_uint<96>; - template - void checkHash(bt const& t, std::string const& hash) - { - auto h = sha512Half(t); - BEAST_EXPECT(to_string(h) == hash); - } - void run() { - Blob raw{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; + // used to verify set insertion (hashing required) + std::unordered_set> uset; + + Blob raw { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; BEAST_EXPECT(test96::bytes == raw.size()); - test96 u(raw); + test96 u { raw }; + uset.insert(u); BEAST_EXPECT(raw.size() == u.size()); BEAST_EXPECT(to_string(u) == "0102030405060708090A0B0C"); BEAST_EXPECT(*u.data() == 1); @@ -54,9 +74,17 @@ struct base_uint_test : beast::unit_test::suite { BEAST_EXPECT(d == ++t); } - checkHash(u, "25996DBE31A04FF03E4E63C9C647AC6D459475E2845529238F3D08F4A37EBC54"); - test96 v(~u); + // Test hash_append by "hashing" with a no-op hasher (h) + // and then extracting the bytes that were written during hashing + // back into another base_uint (w) for comparison with the original + nonhash<96> h; + hash_append(h, u); + test96 w {std::vector(h.data_.begin(), h.data_.end())}; + BEAST_EXPECT(w == u); + + test96 v { ~u }; + uset.insert(v); BEAST_EXPECT(to_string(v) == "FEFDFCFBFAF9F8F7F6F5F4F3"); BEAST_EXPECT(*v.data() == 0xfe); BEAST_EXPECT(v.signum() == 1); @@ -68,7 +96,6 @@ struct base_uint_test : beast::unit_test::suite { BEAST_EXPECT(d == --t); } - checkHash(v, "019A8C0B8307FD822A1346546200328DB40B4565793FD4799B83D780BDB634CE"); BEAST_EXPECT(compare(u, v) < 0); BEAST_EXPECT(compare(v, u) > 0); @@ -76,7 +103,8 @@ struct base_uint_test : beast::unit_test::suite v = u; BEAST_EXPECT(v == u); - test96 z(beast::zero); + test96 z { beast::zero }; + uset.insert(z); BEAST_EXPECT(to_string(z) == "000000000000000000000000"); BEAST_EXPECT(*z.data() == 0); BEAST_EXPECT(*z.begin() == 0); @@ -89,9 +117,8 @@ struct base_uint_test : beast::unit_test::suite { BEAST_EXPECT(d == 0); } - checkHash(z, "666A9A1A7542E895A9F447D1C3E0FFD679BBF6346E0C43F5C7A733C46F5E56C2"); - test96 n(z); + test96 n { z }; n++; BEAST_EXPECT(n == test96(1)); n--; @@ -102,9 +129,69 @@ struct base_uint_test : beast::unit_test::suite n = beast::zero; BEAST_EXPECT(n == z); - auto hash = sha512Half(u, v, z, n); - BEAST_EXPECT(to_string(hash) == - "55CAB39C72F2572057114B4732210605AA22C6E89243FBB5F9943130D813F902"); + test96 zp1 { z }; + zp1++; + test96 zm1 { z }; + zm1--; + test96 x { zm1 ^ zp1 }; + uset.insert(x); + BEAST_EXPECTS(to_string(x) == "FFFFFFFFFFFFFFFFFFFFFFFE", to_string(x)); + + BEAST_EXPECT(uset.size() == 4); + + // SetHex tests... + test96 fromHex; + BEAST_EXPECT(fromHex.SetHexExact(to_string(u))); + BEAST_EXPECT(fromHex == u); + fromHex = z; + + // fails with extra char + BEAST_EXPECT(! fromHex.SetHexExact("A" + to_string(u))); + fromHex = z; + + // fails with extra char at end + BEAST_EXPECT(! fromHex.SetHexExact(to_string(u) + "A")); + // NOTE: the value fromHex is actually correctly parsed + // in this case, but that is an implementation detail and + // not guaranteed, thus we don't check the value here. + fromHex = z; + + BEAST_EXPECT(fromHex.SetHex(to_string(u))); + BEAST_EXPECT(fromHex == u); + fromHex = z; + + // leading space/0x allowed if not strict + BEAST_EXPECT(fromHex.SetHex(" 0x" + to_string(u))); + BEAST_EXPECT(fromHex == u); + fromHex = z; + + // other leading chars also allowed (ignored) + BEAST_EXPECT(fromHex.SetHex("FEFEFE" + to_string(u))); + BEAST_EXPECT(fromHex == u); + fromHex = z; + + // invalid hex chars should fail (0 replaced with Z here) + BEAST_EXPECT(! fromHex.SetHex( + boost::algorithm::replace_all_copy(to_string(u), "0", "Z"))); + fromHex = z; + + BEAST_EXPECT(fromHex.SetHex(to_string(u), true)); + BEAST_EXPECT(fromHex == u); + fromHex = z; + + // strict mode fails with leading chars + BEAST_EXPECT(! fromHex.SetHex(" 0x" + to_string(u), true)); + fromHex = z; + + // SetHex ignores extra leading hexits, so the parsed value + // is still correct for the following case (strict or non-strict) + BEAST_EXPECT(fromHex.SetHex("DEAD" + to_string(u), true )); + BEAST_EXPECT(fromHex == u); + fromHex = z; + + BEAST_EXPECT(fromHex.SetHex("DEAD" + to_string(u), false )); + BEAST_EXPECT(fromHex == u); + fromHex = z; } };