diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj
index c5163f5a2..ef2ce8165 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj
+++ b/Builds/VisualStudio2013/RippleD.vcxproj
@@ -294,6 +294,9 @@
+
+ True
+
True
diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters
index 0282167f6..ee3d75c74 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters
@@ -849,6 +849,9 @@
beast\container
+
+ beast\container\impl
+
beast\container\impl
diff --git a/src/beast/beast/container/Container.unity.cpp b/src/beast/beast/container/Container.unity.cpp
index 994129dff..d631d45ea 100644
--- a/src/beast/beast/container/Container.unity.cpp
+++ b/src/beast/beast/container/Container.unity.cpp
@@ -22,6 +22,7 @@
#endif
#include
+#include
#include
#include
diff --git a/src/beast/beast/container/hardened_hash.h b/src/beast/beast/container/hardened_hash.h
index 2c632d06a..612fb3c9f 100644
--- a/src/beast/beast/container/hardened_hash.h
+++ b/src/beast/beast/container/hardened_hash.h
@@ -21,16 +21,17 @@
#define BEAST_CONTAINER_HARDENED_HASH_H_INCLUDED
#include
-
+#include //
+#include //
#include
+#include
+
#include
#include
#include
#include
-#include //
#include
#include
-#include //
// When set to 1, makes the seed per-process instead
// of per default-constructed instance of hardened_hash
@@ -44,78 +45,86 @@
#endif
namespace beast {
-namespace detail {
-template
-class hardened_hash_base
+using seed_pair = std::pair;
+
+template
+seed_pair
+get_seed_pair() noexcept
{
-public:
- typedef Result result_type;
+ struct state_t
+ {
+ std::mutex mutex;
+ std::random_device rng;
+ std::mt19937_64 gen {rng()};
+ std::uniform_int_distribution dist;
-private:
+ state_t() : gen(rng()) {}
+ // state_t(state_t const&) = delete;
+ // state_t& operator=(state_t const&) = delete;
+ };
+ static static_initializer state;
+ std::lock_guard lock (state->mutex);
+ return {state->dist(state->gen), state->dist(state->gen)};
+}
+
+template
+class basic_hardened_hash;
+
+/**
+ * Seed functor once per process
+*/
+template
+class basic_hardened_hash
+{
static
+ seed_pair const&
+ init_seed_pair()
+ {
+ static static_initializer const
+ p(get_seed_pair<>());
+ return *p;
+ }
+
+public:
+ using result_type = typename HashAlgorithm::result_type;
+
+ template
result_type
- next_seed() noexcept
+ operator()(T const& t) const noexcept
{
- static std::mutex mutex;
- static std::random_device rng;
- static std::mt19937_64 gen (rng());
- std::lock_guard lock (mutex);
- std::uniform_int_distribution dist;
- result_type value;
- for(;;)
- {
- value = dist (gen);
- // VFALCO Do we care if 0 is picked?
- if (value != 0)
- break;
- }
- return value;
+ std::uint64_t seed0;
+ std::uint64_t seed1;
+ std::tie(seed0, seed1) = init_seed_pair();
+ HashAlgorithm h(seed0, seed1);
+ hash_append(h, t);
+ return static_cast(h);
}
-
-#if BEAST_NO_HARDENED_HASH_INSTANCE_SEED
-protected:
- hardened_hash_base() noexcept = default;
-
- hardened_hash_base(result_type) noexcept
- {
- }
-
- result_type
- seed() const noexcept
- {
- static result_type const value (next_seed());
- return value;
- }
-
-#else
-protected:
- hardened_hash_base() noexcept
- : m_seed (next_seed())
- {
- }
-
- hardened_hash_base(result_type seed) noexcept
- : m_seed (seed)
- {
- }
-
- result_type
- seed() const noexcept
- {
- return m_seed;
- }
-
-private:
- // VFALCO Should seed be per process or per hash function?
- result_type m_seed;
-
-#endif
};
-//------------------------------------------------------------------------------
+/**
+ * Seed functor once per construction
+*/
+template
+class basic_hardened_hash
+{
+ seed_pair m_seeds;
+public:
+ using result_type = typename HashAlgorithm::result_type;
-} // detail
+ basic_hardened_hash()
+ : m_seeds(get_seed_pair<>())
+ {}
+
+ template
+ result_type
+ operator()(T const& t) const noexcept
+ {
+ HashAlgorithm h(m_seeds.first, m_seeds.second);
+ hash_append(h, t);
+ return static_cast(h);
+ }
+};
//------------------------------------------------------------------------------
@@ -140,31 +149,18 @@ private:
}
@endcode
+
+ Do not use any version of Murmur or CityHash for the Hasher
+ template parameter (the hashing algorithm). For details
+ see https://131002.net/siphash/#at
*/
-template
-class hardened_hash
- : public detail::hardened_hash_base
-{
- typedef detail::hardened_hash_base base;
-public:
- typedef T argument_type;
- using detail::hardened_hash_base ::result_type;
-
-public:
- hardened_hash() = default;
- explicit hardened_hash(result_type seed)
- : base (seed)
- {
- }
-
- result_type
- operator() (argument_type const& key) const noexcept
- {
- Hasher h {base::seed()};
- hash_append (h, key);
- return static_cast (h);
- }
-};
+#if BEAST_NO_HARDENED_HASH_INSTANCE_SEED
+template
+ using hardened_hash = basic_hardened_hash;
+#else
+template
+ using hardened_hash = basic_hardened_hash;
+#endif
} // beast
diff --git a/src/beast/beast/container/hash_append.h b/src/beast/beast/container/hash_append.h
index fa5a73454..b8d195154 100644
--- a/src/beast/beast/container/hash_append.h
+++ b/src/beast/beast/container/hash_append.h
@@ -656,16 +656,38 @@ hash_append (Hasher& h, T0 const& t0, T1 const& t1, T const& ...t) noexcept
hash_append (h, t1, t...);
}
-namespace detail
+// See http://www.isthe.com/chongo/tech/comp/fnv/
+class fnv1a
{
+ std::uint64_t state_ = 14695981039346656037ULL;
+public:
-class spooky_wrapper
+ using result_type = std::size_t;
+
+ void
+ append (void const* key, std::size_t len) noexcept
+ {
+ unsigned char const* p = static_cast(key);
+ unsigned char const* const e = p + len;
+ for (; p < e; ++p)
+ state_ = (state_ ^ *p) * 1099511628211ULL;
+ }
+
+ explicit
+ operator std::size_t() noexcept
+ {
+ return static_cast(state_);
+ }
+};
+
+// See http://burtleburtle.net/bob/hash/spooky.html
+class spooky
{
SpookyHash state_;
public:
using result_type = std::size_t;
- spooky_wrapper (std::size_t seed1 = 1, std::size_t seed2 = 2) noexcept
+ spooky (std::size_t seed1 = 1, std::size_t seed2 = 2) noexcept
{
state_.Init (seed1, seed2);
}
@@ -685,9 +707,30 @@ public:
}
};
-} // detail
+// See https://131002.net/siphash/
+class siphash
+{
+ std::uint64_t v0_ = 0x736f6d6570736575ULL;
+ std::uint64_t v1_ = 0x646f72616e646f6dULL;
+ std::uint64_t v2_ = 0x6c7967656e657261ULL;
+ std::uint64_t v3_ = 0x7465646279746573ULL;
+ unsigned char buf_[8];
+ unsigned bufsize_ = 0;
+ unsigned total_length_ = 0;
+public:
+ using result_type = std::size_t;
-template
+ siphash() = default;
+ explicit siphash(std::uint64_t k0, std::uint64_t k1 = 0) noexcept;
+
+ void
+ append (void const* key, std::size_t len) noexcept;
+
+ explicit
+ operator std::size_t() noexcept;
+};
+
+template
struct uhash
{
using result_type = typename Hasher::result_type;
@@ -702,6 +745,7 @@ struct uhash
}
};
+
} // beast
#endif
diff --git a/src/beast/beast/container/impl/siphash.cpp b/src/beast/beast/container/impl/siphash.cpp
new file mode 100644
index 000000000..ef5181b4d
--- /dev/null
+++ b/src/beast/beast/container/impl/siphash.cpp
@@ -0,0 +1,166 @@
+//------------------------------- siphash.h ------------------------------------
+//
+// This software is in the public domain. The only restriction on its use is
+// that no one can remove it from the public domain by claiming ownership of it,
+// including the original authors.
+//
+// There is no warranty of correctness on the software contained herein. Use
+// at your own risk.
+//
+// Derived from:
+//
+// SipHash reference C implementation
+//
+// Written in 2012 by Jean-Philippe Aumasson
+// Daniel J. Bernstein
+//
+// To the extent possible under law, the author(s) have dedicated all copyright
+// and related and neighboring rights to this software to the public domain
+// worldwide. This software is distributed without any warranty.
+//
+// You should have received a copy of the CC0 Public Domain Dedication along
+// with this software. If not, see
+// .
+//
+//------------------------------------------------------------------------------
+
+#include
+#include
+#include
+#include
+
+// namespace acme is used to demonstrate example code. It is not proposed.
+
+namespace beast
+{
+
+namespace
+{
+
+typedef std::uint64_t u64;
+typedef std::uint32_t u32;
+typedef std::uint8_t u8;
+
+inline
+u64
+rotl(u64 x, u64 b)
+{
+ return (x << b) | (x >> (64 - b));
+}
+
+inline
+u64
+u8to64_le(const u8* p)
+{
+#if BEAST_LITTLE_ENDIAN
+ return *static_cast(static_cast(p));
+#else
+ return static_cast(p[7]) << 56 | static_cast(p[6]) << 48 |
+ static_cast(p[5]) << 40 | static_cast(p[4]) << 32 |
+ static_cast(p[3]) << 24 | static_cast(p[2]) << 16 |
+ static_cast(p[1]) << 8 | static_cast(p[0]);
+#endif
+}
+
+inline
+void
+sipround(u64& v0, u64& v1, u64& v2, u64& v3)
+{
+ v0 += v1;
+ v1 = rotl(v1, 13);
+ v1 ^= v0;
+ v0 = rotl(v0, 32);
+ v2 += v3;
+ v3 = rotl(v3, 16);
+ v3 ^= v2;
+ v0 += v3;
+ v3 = rotl(v3, 21);
+ v3 ^= v0;
+ v2 += v1;
+ v1 = rotl(v1, 17);
+ v1 ^= v2;
+ v2 = rotl(v2, 32);
+}
+
+} // unnamed
+
+siphash::siphash(std::uint64_t k0, std::uint64_t k1) noexcept
+{
+ v3_ ^= k1;
+ v2_ ^= k0;
+ v1_ ^= k1;
+ v0_ ^= k0;
+}
+
+void
+siphash::append (void const* key, std::size_t inlen) noexcept
+{
+ u8 const* in = static_cast(key);
+ total_length_ += inlen;
+ if (bufsize_ + inlen < 8)
+ {
+ std::copy(in, in+inlen, buf_ + bufsize_);
+ bufsize_ += inlen;
+ return;
+ }
+ if (bufsize_ > 0)
+ {
+ auto t = 8 - bufsize_;
+ std::copy(in, in+t, buf_ + bufsize_);
+ u64 m = u8to64_le( buf_ );
+ v3_ ^= m;
+ sipround(v0_, v1_, v2_, v3_);
+ sipround(v0_, v1_, v2_, v3_);
+ v0_ ^= m;
+ in += t;
+ inlen -= t;
+ }
+ bufsize_ = inlen & 7;
+ u8 const* const end = in + (inlen - bufsize_);
+ for ( ; in != end; in += 8 )
+ {
+ u64 m = u8to64_le( in );
+ v3_ ^= m;
+ sipround(v0_, v1_, v2_, v3_);
+ sipround(v0_, v1_, v2_, v3_);
+ v0_ ^= m;
+ }
+ std::copy(end, end + bufsize_, buf_);
+}
+
+siphash::operator std::size_t() noexcept
+{
+ std::size_t b = static_cast(total_length_) << 56;
+ switch(bufsize_)
+ {
+ case 7:
+ b |= static_cast(buf_[6]) << 48;
+ case 6:
+ b |= static_cast(buf_[5]) << 40;
+ case 5:
+ b |= static_cast(buf_[4]) << 32;
+ case 4:
+ b |= static_cast(buf_[3]) << 24;
+ case 3:
+ b |= static_cast(buf_[2]) << 16;
+ case 2:
+ b |= static_cast(buf_[1]) << 8;
+ case 1:
+ b |= static_cast(buf_[0]);
+ case 0:
+ break;
+ }
+ v3_ ^= b;
+ sipround(v0_, v1_, v2_, v3_);
+ sipround(v0_, v1_, v2_, v3_);
+ v0_ ^= b;
+ v2_ ^= 0xff;
+ sipround(v0_, v1_, v2_, v3_);
+ sipround(v0_, v1_, v2_, v3_);
+ sipround(v0_, v1_, v2_, v3_);
+ sipround(v0_, v1_, v2_, v3_);
+ b = v0_ ^ v1_ ^ v2_ ^ v3_;
+ return b;
+}
+
+} // beast
diff --git a/src/beast/beast/container/tests/hardened_hash.test.cpp b/src/beast/beast/container/tests/hardened_hash.test.cpp
index f60f18bed..a90aaa1ee 100644
--- a/src/beast/beast/container/tests/hardened_hash.test.cpp
+++ b/src/beast/beast/container/tests/hardened_hash.test.cpp
@@ -90,19 +90,19 @@ namespace detail {
template
using test_hardened_unordered_set =
- std::unordered_set >;
+ std::unordered_set >;
template
using test_hardened_unordered_map =
- std::unordered_map >;
+ std::unordered_map >;
template
using test_hardened_unordered_multiset =
- std::unordered_multiset >;
+ std::unordered_multiset >;
template
using test_hardened_unordered_multimap =
- std::unordered_multimap >;
+ std::unordered_multimap >;
} // beast
@@ -196,7 +196,7 @@ public:
check ()
{
T t{};
- hardened_hash () (t);
+ hardened_hash <>() (t);
pass();
}
@@ -280,7 +280,7 @@ public:
log <<
"sizeof(std::size_t) == " << sizeof(std::size_t);
- hardened_hash h;
+ hardened_hash <> h;
for (int i = 0; i < 100; ++i)
{
sha256_t v (sha256_t::from_number (i));
diff --git a/src/beast/beast/crypto/UnsignedInteger.h b/src/beast/beast/crypto/UnsignedInteger.h
index 99346be6b..de2adbfd4 100644
--- a/src/beast/beast/crypto/UnsignedInteger.h
+++ b/src/beast/beast/crypto/UnsignedInteger.h
@@ -65,7 +65,7 @@ public:
attackers from exploiting crafted inputs to produce degenerate
containers.
*/
- typedef hardened_hash hasher;
+ typedef hardened_hash <> hasher;
/** Determins if two UnsignedInteger objects are equal. */
class equal
diff --git a/src/beast/beast/utility/static_initializer.h b/src/beast/beast/utility/static_initializer.h
index 2033dd39c..237af40b4 100644
--- a/src/beast/beast/utility/static_initializer.h
+++ b/src/beast/beast/utility/static_initializer.h
@@ -83,17 +83,35 @@ public:
T&
get() noexcept;
+ T const&
+ get() const noexcept
+ {
+ return const_cast(*this).get();
+ }
+
T&
operator*() noexcept
{
return get();
}
+ T const&
+ operator*() const noexcept
+ {
+ return get();
+ }
+
T*
operator->() noexcept
{
return &get();
}
+
+ T const*
+ operator->() const noexcept
+ {
+ return &get();
+ }
};
//------------------------------------------------------------------------------
@@ -187,17 +205,35 @@ public:
return *instance_;
}
+ T const&
+ get() const noexcept
+ {
+ return const_cast(*this).get();
+ }
+
T&
operator*() noexcept
{
return get();
}
+ T const&
+ operator*() const noexcept
+ {
+ return get();
+ }
+
T*
operator->() noexcept
{
return &get();
}
+
+ T const*
+ operator->() const noexcept
+ {
+ return &get();
+ }
};
template