diff --git a/Builds/VisualStudio2013/Beast.props b/Builds/VisualStudio2013/Beast.props
index 95b35522ca..f1c7c45345 100644
--- a/Builds/VisualStudio2013/Beast.props
+++ b/Builds/VisualStudio2013/Beast.props
@@ -12,6 +12,7 @@
true
false
%(AdditionalIncludeDirectories)
+ /bigobj %(AdditionalOptions)
diff --git a/Builds/VisualStudio2013/beast.vcxproj b/Builds/VisualStudio2013/beast.vcxproj
index 9dbccaa521..ee0ff1d65f 100644
--- a/Builds/VisualStudio2013/beast.vcxproj
+++ b/Builds/VisualStudio2013/beast.vcxproj
@@ -246,6 +246,7 @@
+
@@ -756,6 +757,12 @@
true
true
+
+ true
+ true
+ true
+ true
+
true
@@ -766,6 +773,8 @@
true
true
+ true
+ true
@@ -892,6 +901,8 @@
true
true
+ true
+ true
true
@@ -1301,7 +1312,6 @@
Disabled
WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
- %(AdditionalIncludeDirectories)
false
true
@@ -1316,7 +1326,7 @@
Disabled
WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
- $(ProjectDir);%(AdditionalIncludeDirectories)
+ MultiThreadedDebug
Windows
@@ -1351,6 +1361,7 @@
true
WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
$(ProjectDir);%(AdditionalIncludeDirectories)
+ MultiThreaded
Windows
diff --git a/Builds/VisualStudio2013/beast.vcxproj.filters b/Builds/VisualStudio2013/beast.vcxproj.filters
index eb91f1d7cc..eccb9d4e45 100644
--- a/Builds/VisualStudio2013/beast.vcxproj.filters
+++ b/Builds/VisualStudio2013/beast.vcxproj.filters
@@ -1227,6 +1227,9 @@
beast\unit_test
+
+ beast\utility
+
@@ -1700,6 +1703,9 @@
beast\threads\tests
+
+ beast\utility\tests
+
diff --git a/beast/threads/impl/Stoppable.cpp b/beast/threads/impl/Stoppable.cpp
index 35eb60df6b..7c8eb891e8 100644
--- a/beast/threads/impl/Stoppable.cpp
+++ b/beast/threads/impl/Stoppable.cpp
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
/*
- This file is part of rippled: https://github.com/ripple/rippled
- Copyright (c) 2012, 2013 Ripple Labs Inc.
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2012, Vinnie Falco
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
diff --git a/beast/utility/Utility.cpp b/beast/utility/Utility.cpp
index 9b42c0733c..ef14dce0d9 100644
--- a/beast/utility/Utility.cpp
+++ b/beast/utility/Utility.cpp
@@ -34,3 +34,4 @@
#include "tests/bassert.test.cpp"
#include "tests/empty_base_optimization.test.cpp"
+#include "tests/hardened_hash.test.cpp"
diff --git a/beast/utility/empty_base_optimization.h b/beast/utility/empty_base_optimization.h
index 726d67db61..2989f0987b 100644
--- a/beast/utility/empty_base_optimization.h
+++ b/beast/utility/empty_base_optimization.h
@@ -1,7 +1,8 @@
//------------------------------------------------------------------------------
/*
- This file is part of rippled: https://github.com/ripple/rippled
- Copyright (c) 2012, 2013 Ripple Labs Inc.
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2014, Howard Hinnant ,
+ Vinnie Falco
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
diff --git a/beast/utility/hardened_hash.h b/beast/utility/hardened_hash.h
new file mode 100644
index 0000000000..6e1979609c
--- /dev/null
+++ b/beast/utility/hardened_hash.h
@@ -0,0 +1,168 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef BEAST_UTILITY_HARDENED_HASH_H_INCLUDED
+#define BEAST_UTILITY_HARDENED_HASH_H_INCLUDED
+
+#include "is_call_possible.h"
+
+#include "noexcept.h"
+#include
+#include
+#include
+#include "../cxx14/utility.h" //
+
+// When set to 1, makes the seed per-process instead
+// of per default-constructed instance of hardened_hash
+//
+#ifndef BEAST_NO_HARDENED_HASH_INSTANCE_SEED
+# ifdef __GLIBCXX__
+# define BEAST_NO_HARDENED_HASH_INSTANCE_SEED 1
+# else
+# define BEAST_NO_HARDENED_HASH_INSTANCE_SEED 0
+# endif
+#endif
+
+namespace beast {
+
+namespace detail {
+
+template
+class hardened_hash_base
+{
+public:
+ typedef Result result_type;
+
+private:
+ static
+ result_type
+ next_seed() 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;
+ }
+
+#if BEAST_NO_HARDENED_HASH_INSTANCE_SEED
+protected:
+ result_type
+ seed() const noexcept
+ {
+ static result_type const value (next_seed());
+ return value;
+ }
+
+#else
+protected:
+ hardened_hash_base() noexcept
+ : m_seed (next_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
+};
+
+}
+
+/** A std compatible hash adapter that resists adversarial inputs.
+ For this to work, one of the following must exist:
+
+ * A member function of `T` called `hash_combine` with
+ this signature:
+
+ @code
+
+ void hash_combine (std::size_t&) const noexcept;
+
+ @endcode
+
+ * A free function called `hash_combine`, found via argument
+ dependent lookup, callable with this signature:
+
+ @code
+
+ void hash_combine (std::size_t, T const& t) noexcept;
+
+ @endcode
+*/
+template
+class hardened_hash
+ : public detail::hardened_hash_base
+{
+public:
+ typedef T argument_type;
+ using detail::hardened_hash_base ::result_type;
+
+private:
+ BEAST_DEFINE_IS_CALL_POSSIBLE(has_hash_combine,hash_combine);
+
+ typedef detail::hardened_hash_base base;
+
+ // Called when hash_combine is a member function
+ result_type
+ operator() (argument_type const& key, std::true_type) const noexcept
+ {
+ result_type result (base::seed());
+ key.hash_combine (result);
+ return result;
+ }
+
+ result_type
+ operator() (argument_type const& key, std::false_type) const noexcept
+ {
+ result_type result (base::seed());
+ hash_combine (result, key);
+ return result;
+ }
+
+public:
+ hardened_hash() = default;
+
+ result_type
+ operator() (argument_type const& key) const noexcept
+ {
+ return operator() (key, std::integral_constant ::value>());
+ }
+};
+
+}
+
+#endif
diff --git a/beast/utility/is_call_possible.h b/beast/utility/is_call_possible.h
index c38cfa86f8..099c9fccd1 100644
--- a/beast/utility/is_call_possible.h
+++ b/beast/utility/is_call_possible.h
@@ -29,25 +29,25 @@ namespace beast {
//
namespace is_call_possible_detail
{
- template
+ template
struct add_reference
{
- typedef T& type;
+ typedef Z& type;
};
- template
- struct add_reference
+ template
+ struct add_reference
{
- typedef T& type;
+ typedef Z& type;
};
- template class void_exp_result {};
+ template class void_exp_result {};
- template
- U const& operator,(U const&, void_exp_result);
+ template
+ U const& operator,(U const&, void_exp_result);
- template
- U& operator,(U&, void_exp_result);
+ template
+ U& operator,(U&, void_exp_result);
template
struct clone_constness
@@ -63,10 +63,10 @@ namespace is_call_possible_detail
}
#define BEAST_DEFINE_HAS_MEMBER_FUNCTION(trait_name, member_function_name) \
-template class trait_name; \
+template class trait_name; \
\
-template \
-class trait_name \
+template \
+class trait_name \
{ \
class yes { char m; }; \
class no { yes m[2]; }; \
@@ -74,7 +74,7 @@ class trait_name
{ \
Result member_function_name(); \
}; \
- struct base : public T, public base_mixin { private: base(); }; \
+ struct base : public Z, public base_mixin { private: base(); }; \
template class helper{}; \
template \
static no deduce(U*, helper* = 0); \
@@ -83,8 +83,8 @@ public:
static const bool value = sizeof(yes) == sizeof(deduce(static_cast(0))); \
}; \
\
-template \
-class trait_name \
+template \
+class trait_name \
{ \
class yes { char m; }; \
class no { yes m[2]; }; \
@@ -92,7 +92,7 @@ class trait_name
{ \
Result member_function_name(Arg); \
}; \
- struct base : public T, public base_mixin { private: base(); }; \
+ struct base : public Z, public base_mixin { private: base(); }; \
template class helper{}; \
template \
static no deduce(U*, helper* = 0); \
@@ -101,8 +101,8 @@ public:
static const bool value = sizeof(yes) == sizeof(deduce(static_cast(0))); \
}; \
\
-template \
-class trait_name \
+template \
+class trait_name \
{ \
class yes { char m; }; \
class no { yes m[2]; }; \
@@ -110,7 +110,7 @@ class trait_name
{ \
Result member_function_name(Arg1,Arg2); \
}; \
- struct base : public T, public base_mixin { private: base(); }; \
+ struct base : public Z, public base_mixin { private: base(); }; \
template class helper{}; \
template \
static no deduce(U*, helper* = 0); \
@@ -119,8 +119,8 @@ public:
static const bool value = sizeof(yes) == sizeof(deduce(static_cast(0))); \
}; \
\
-template \
-class trait_name \
+template \
+class trait_name \
{ \
class yes { char m; }; \
class no { yes m[2]; }; \
@@ -128,7 +128,7 @@ class trait_name
{ \
Result member_function_name(Arg1,Arg2,Arg3); \
}; \
- struct base : public T, public base_mixin { private: base(); }; \
+ struct base : public Z, public base_mixin { private: base(); }; \
template class helper{}; \
template \
static no deduce(U*, helper* = 0); \
@@ -137,8 +137,8 @@ public:
static const bool value = sizeof(yes) == sizeof(deduce(static_cast(0))); \
}; \
\
-template \
-class trait_name \
+template \
+class trait_name \
{ \
class yes { char m; }; \
class no { yes m[2]; }; \
@@ -146,7 +146,7 @@ class trait_name
{ \
Result member_function_name(Arg1,Arg2,Arg3,Arg4); \
}; \
- struct base : public T, public base_mixin { private: base(); }; \
+ struct base : public Z, public base_mixin { private: base(); }; \
template class helper{}; \
template \
static no deduce(U*, helper* = 0); \
@@ -165,17 +165,17 @@ template
struct trait_name \
{ \
private: \
- typedef std::remove_reference_t T; \
+ typedef std::remove_reference_t Z; \
class yes {}; \
class no { yes m[2]; }; \
- struct derived : public T \
+ struct derived : public Z \
{ \
- using T::member_function_name; \
+ using Z::member_function_name; \
no member_function_name(...) const; \
private: derived (); \
}; \
\
- typedef typename beast::is_call_possible_detail::clone_constness::type derived_type; \
+ typedef typename beast::is_call_possible_detail::clone_constness::type derived_type; \
\
template \
struct return_value_check \
@@ -183,7 +183,7 @@ private:
static yes deduce(Result); \
static no deduce(...); \
static no deduce(no); \
- static no deduce(beast::is_call_possible_detail::void_exp_result); \
+ static no deduce(beast::is_call_possible_detail::void_exp_result); \
}; \
\
template \
@@ -206,8 +206,8 @@ private:
\
static const bool value = \
sizeof( \
- return_value_check::deduce( \
- (test_me.member_function_name(), beast::is_call_possible_detail::void_exp_result())) \
+ return_value_check::deduce( \
+ (test_me.member_function_name(), beast::is_call_possible_detail::void_exp_result())) \
) == sizeof(yes); \
}; \
\
@@ -219,8 +219,8 @@ private:
\
static const bool value = \
sizeof( \
- return_value_check::deduce( \
- (test_me.member_function_name(arg), beast::is_call_possible_detail::void_exp_result()) \
+ return_value_check::deduce( \
+ (test_me.member_function_name(arg), beast::is_call_possible_detail::void_exp_result()) \
) \
) == sizeof(yes); \
}; \
@@ -234,8 +234,8 @@ private:
\
static const bool value = \
sizeof( \
- return_value_check::deduce( \
- (test_me.member_function_name(arg1,arg2), beast::is_call_possible_detail::void_exp_result()) \
+ return_value_check::deduce( \
+ (test_me.member_function_name(arg1,arg2), beast::is_call_possible_detail::void_exp_result()) \
) \
) == sizeof(yes); \
}; \
@@ -250,8 +250,8 @@ private:
\
static const bool value = \
sizeof( \
- return_value_check::deduce( \
- (test_me.member_function_name(arg1,arg2,arg3), beast::is_call_possible_detail::void_exp_result()) \
+ return_value_check::deduce( \
+ (test_me.member_function_name(arg1,arg2,arg3), beast::is_call_possible_detail::void_exp_result()) \
) \
) == sizeof(yes); \
}; \
@@ -267,15 +267,15 @@ private:
\
static const bool value = \
sizeof( \
- return_value_check::deduce( \
+ return_value_check::deduce( \
(test_me.member_function_name(arg1,arg2,arg3,arg4), \
- beast::is_call_possible_detail::void_exp_result()) \
+ beast::is_call_possible_detail::void_exp_result()) \
) \
) == sizeof(yes); \
}; \
\
public: \
- static const bool value = impl::value, \
+ static const bool value = impl::value, \
IsCallPossibleSignature>::value; \
}
diff --git a/beast/utility/tests/empty_base_optimization.test.cpp b/beast/utility/tests/empty_base_optimization.test.cpp
index 57c57287aa..1a72c2aed0 100644
--- a/beast/utility/tests/empty_base_optimization.test.cpp
+++ b/beast/utility/tests/empty_base_optimization.test.cpp
@@ -1,7 +1,7 @@
-//-------------------- empty_base_optimization.test.cpp ------------------------
+//------------------------------------------------------------------------------
/*
- This file is part of rippled: https://github.com/ripple/rippled
- Copyright (c) 2014 Ripple Labs Inc.
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2014, Howard Hinnant
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
diff --git a/beast/utility/tests/hardened_hash.test.cpp b/beast/utility/tests/hardened_hash.test.cpp
new file mode 100644
index 0000000000..c7dcdedbab
--- /dev/null
+++ b/beast/utility/tests/hardened_hash.test.cpp
@@ -0,0 +1,311 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of Beast: https://github.com/vinniefalco/Beast
+ Copyright 2013, Vinnie Falco
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#if BEAST_INCLUDE_BEASTCONFIG
+#include "../../../BeastConfig.h"
+#endif
+
+#include "../hardened_hash.h"
+#include "../../unit_test/suite.h"
+
+#include "../../crypto/Sha256.h"
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace beast {
+namespace detail {
+
+template
+class test_user_type_member
+{
+private:
+ T t;
+
+public:
+ explicit test_user_type_member (T const& t_ = T())
+ : t (t_)
+ {
+ }
+
+ void
+ hash_combine (std::size_t& seed) const noexcept
+ {
+ boost::hash_combine (seed, t);
+ }
+};
+
+template
+class test_user_type_free
+{
+private:
+ T t;
+
+public:
+ explicit test_user_type_free (T const& t_ = T())
+ : t (t_)
+ {
+ }
+
+ friend
+ void
+ hash_combine (std::size_t& seed,
+ test_user_type_free const& v) noexcept
+ {
+ boost::hash_combine (seed, v.t);
+ }
+};
+
+} // detail
+} // beast
+
+//------------------------------------------------------------------------------
+
+namespace beast {
+
+namespace detail {
+
+template
+using test_hardened_unordered_set =
+ std::unordered_set >;
+
+template
+using test_hardened_unordered_map =
+ std::unordered_map >;
+
+template
+using test_hardened_unordered_multiset =
+ std::unordered_multiset >;
+
+template
+using test_hardened_unordered_multimap =
+ std::unordered_multimap >;
+
+} // beast
+
+template
+class unsigned_integer
+{
+private:
+ static_assert (std::is_integral::value &&
+ std::is_unsigned ::value,
+ "UInt must be an unsigned integral type");
+
+ static_assert (Bits%(8*sizeof(UInt))==0,
+ "Bits must be a multiple of 8*sizeof(UInt)");
+
+ static_assert (Bits >= (8*sizeof(UInt)),
+ "Bits must be at least 8*sizeof(UInt)");
+
+ static std::size_t const size = Bits/(8*sizeof(UInt));
+
+ std::array m_vec;
+
+public:
+ typedef UInt value_type;
+
+ static std::size_t const bits = Bits;
+ static std::size_t const bytes = bits / 8;
+
+ template
+ static
+ unsigned_integer
+ from_number (Int v)
+ {
+ unsigned_integer result;
+ for (std::size_t i (1); i < size; ++i)
+ result.m_vec [i] = 0;
+ result.m_vec[0] = v;
+ return result;
+ }
+
+ void*
+ data() noexcept
+ {
+ return &m_vec[0];
+ }
+
+ void const*
+ data() const noexcept
+ {
+ return &m_vec[0];
+ }
+
+ void
+ hash_combine (std::size_t& seed) const noexcept
+ {
+ for (std::size_t i (0); i < size; ++i)
+ boost::hash_combine (seed, m_vec[i]);
+ }
+
+ friend
+ std::ostream&
+ operator<< (std::ostream& s, unsigned_integer const& v)
+ {
+ for (std::size_t i (0); i < size; ++i)
+ s <<
+ std::hex <<
+ std::setfill ('0') <<
+ std::setw (2*sizeof(UInt)) <<
+ v.m_vec[i]
+ ;
+ return s;
+ }
+};
+
+typedef unsigned_integer <256, std::size_t> sha256_t;
+
+static_assert (sha256_t::bits == 256,
+ "sha256_t must have 256 bits");
+
+} // beast
+
+//------------------------------------------------------------------------------
+
+namespace beast {
+
+class hardened_hash_test
+ : public unit_test::suite
+{
+public:
+ template
+ void
+ check ()
+ {
+ T t{};
+ hardened_hash () (t);
+ pass();
+ }
+
+ template class U>
+ void
+ check_user_type()
+ {
+ check > ();
+ check > ();
+ check > ();
+ check > ();
+ // These cause trouble for boost
+ //check > ();
+ //check > ();
+ check > ();
+ check > ();
+ check > ();
+ check > ();
+ check > ();
+ check > ();
+ check > ();
+ check > ();
+ check > ();
+ check > ();
+ check > ();
+ check > ();
+ }
+
+ template class C >
+ void
+ check_container()
+ {
+ {
+ C > c;
+ }
+
+ pass();
+
+ {
+ C > c;
+ }
+
+ pass();
+ }
+
+ void
+ test_user_types()
+ {
+ testcase ("user types");
+ check_user_type ();
+ check_user_type ();
+ }
+
+ void
+ test_containers()
+ {
+ testcase ("containers");
+ check_container ();
+ check_container ();
+ check_container ();
+ check_container ();
+ }
+
+ void
+ run ()
+ {
+ test_user_types();
+ test_containers();
+ }
+};
+
+class hardened_hash_sha256_test
+ : public unit_test::suite
+{
+public:
+ void
+ testSHA256()
+ {
+ testcase ("sha256");
+
+ log <<
+ "sizeof(std::size_t) == " << sizeof(std::size_t);
+
+ hardened_hash h;
+ for (int i = 0; i < 100; ++i)
+ {
+ sha256_t v (sha256_t::from_number (i));
+ Sha256::digest_type d;
+ Sha256::hash (v.data(), sha256_t::bytes, d);
+ sha256_t d_;
+ memcpy (d_.data(), d.data(), sha256_t::bytes);
+ std::size_t result (h (d_));
+ log <<
+ "i=" << std::setw(2) << i << " " <<
+ "sha256=0x" << d_ << " " <<
+ "hash=0x" <<
+ std::setfill ('0') <<
+ std::setw (2*sizeof(std::size_t)) << result
+ ;
+ pass();
+ }
+ }
+
+ void
+ run ()
+ {
+ testSHA256();
+ }
+};
+
+BEAST_DEFINE_TESTSUITE(hardened_hash,utility,beast);
+BEAST_DEFINE_TESTSUITE_MANUAL(hardened_hash_sha256,utility,beast);
+
+} // beast