Add hardened_hash to basics/:

xxhasher is the default hash function for hardened_hash.
This commit is contained in:
Vinnie Falco
2015-01-16 14:11:54 -08:00
parent 6ab1ecd836
commit 53a16f354f
15 changed files with 520 additions and 23 deletions

View File

@@ -2146,6 +2146,8 @@
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\DecayingSample.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\hardened_hash.h">
</ClInclude>
<ClCompile Include="..\..\src\ripple\basics\impl\BasicConfig.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
@@ -2223,6 +2225,9 @@
<ClCompile Include="..\..\src\ripple\basics\tests\CheckLibraryVersions.test.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\basics\tests\hardened_hash_test.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\ripple\basics\tests\KeyCache.test.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>

View File

@@ -3126,6 +3126,9 @@
<ClInclude Include="..\..\src\ripple\basics\DecayingSample.h">
<Filter>ripple\basics</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\basics\hardened_hash.h">
<Filter>ripple\basics</Filter>
</ClInclude>
<ClCompile Include="..\..\src\ripple\basics\impl\BasicConfig.cpp">
<Filter>ripple\basics\impl</Filter>
</ClCompile>
@@ -3219,6 +3222,9 @@
<ClCompile Include="..\..\src\ripple\basics\tests\CheckLibraryVersions.test.cpp">
<Filter>ripple\basics\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\basics\tests\hardened_hash_test.cpp">
<Filter>ripple\basics\tests</Filter>
</ClCompile>
<ClCompile Include="..\..\src\ripple\basics\tests\KeyCache.test.cpp">
<Filter>ripple\basics\tests</Filter>
</ClCompile>

View File

@@ -21,6 +21,7 @@
#define RIPPLE_RIPPLELINECACHE_H
#include <ripple/app/paths/RippleState.h>
#include <ripple/basics/hardened_hash.h>
#include <cstddef>
#include <memory>
#include <vector>
@@ -59,7 +60,7 @@ private:
AccountKey (Account const& account)
: account_ (account)
, hash_value_ (beast::hardened_hash<>{}(account))
, hash_value_ (hardened_hash<>{}(account))
{
}

View File

@@ -20,11 +20,11 @@
#ifndef RIPPLE_BASICS_KEYCACHE_H_INCLUDED
#define RIPPLE_BASICS_KEYCACHE_H_INCLUDED
#include <ripple/basics/hardened_hash.h>
#include <ripple/basics/UnorderedContainers.h>
#include <beast/chrono/abstract_clock.h>
#include <beast/chrono/chrono_io.h>
#include <beast/Insight.h>
#include <beast/hash/hardened_hash.h>
#include <mutex>
namespace ripple {
@@ -38,7 +38,7 @@ namespace ripple {
// VFALCO TODO Figure out how to pass through the allocator
template <
class Key,
class Hash = beast::hardened_hash <>,
class Hash = hardened_hash <>,
class KeyEqual = std::equal_to <Key>,
//class Allocator = std::allocator <std::pair <Key const, Entry>>,
class Mutex = std::mutex

View File

@@ -20,11 +20,11 @@
#ifndef RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
#define RIPPLE_BASICS_TAGGEDCACHE_H_INCLUDED
#include <ripple/basics/hardened_hash.h>
#include <ripple/basics/UnorderedContainers.h>
#include <beast/chrono/abstract_clock.h>
#include <beast/chrono/chrono_io.h>
#include <beast/Insight.h>
#include <beast/hash/hardened_hash.h>
#include <functional>
#include <mutex>
#include <vector>
@@ -50,7 +50,7 @@ struct TaggedCacheLog;
template <
class Key,
class T,
class Hash = beast::hardened_hash <>,
class Hash = hardened_hash <>,
class KeyEqual = std::equal_to <Key>,
//class Allocator = std::allocator <std::pair <Key const, Entry>>,
class Mutex = std::recursive_mutex

View File

@@ -20,7 +20,7 @@
#ifndef RIPPLE_BASICS_UNORDERED_CONTAINERS_H_INCLUDED
#define RIPPLE_BASICS_UNORDERED_CONTAINERS_H_INCLUDED
#include <beast/hash/hardened_hash.h>
#include <ripple/basics/hardened_hash.h>
#include <beast/hash/hash_append.h>
#include <beast/hash/uhash.h>
#include <beast/hash/xxhasher.h>
@@ -67,22 +67,22 @@ using hash_multiset = std::unordered_multiset <Value, Hash, Pred, Allocator>;
using strong_hash = beast::xxhasher;
template <class Key, class Value, class Hash = beast::hardened_hash<strong_hash>,
template <class Key, class Value, class Hash = hardened_hash<strong_hash>,
class Pred = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<Key const, Value>>>
using hardened_hash_map = std::unordered_map <Key, Value, Hash, Pred, Allocator>;
template <class Key, class Value, class Hash = beast::hardened_hash<strong_hash>,
template <class Key, class Value, class Hash = hardened_hash<strong_hash>,
class Pred = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<Key const, Value>>>
using hardened_hash_multimap = std::unordered_multimap <Key, Value, Hash, Pred, Allocator>;
template <class Value, class Hash = beast::hardened_hash<strong_hash>,
template <class Value, class Hash = hardened_hash<strong_hash>,
class Pred = std::equal_to<Value>,
class Allocator = std::allocator<Value>>
using hardened_hash_set = std::unordered_set <Value, Hash, Pred, Allocator>;
template <class Value, class Hash = beast::hardened_hash<strong_hash>,
template <class Value, class Hash = hardened_hash<strong_hash>,
class Pred = std::equal_to<Value>,
class Allocator = std::allocator<Value>>
using hardened_hash_multiset = std::unordered_multiset <Value, Hash, Pred, Allocator>;

View File

@@ -28,8 +28,7 @@
#include <ripple/basics/ByteOrder.h>
#include <ripple/basics/Blob.h>
#include <ripple/basics/strHex.h>
#include <beast/hash/hardened_hash.h>
#include <ripple/basics/hardened_hash.h>
#include <beast/utility/Zero.h>
#include <boost/functional/hash.hpp>
@@ -98,7 +97,7 @@ public:
/** Value hashing function.
The seed prevents crafted inputs from causing degenarate parent containers.
*/
typedef beast::hardened_hash <> hasher;
typedef hardened_hash <> hasher;
/** Container equality testing function. */
class key_equal
@@ -537,7 +536,7 @@ struct hash<ripple::base_uint<Bits, Tag>>
std::size_t
operator()(argument_type const& u) const
{
return beast::hardened_hash<>{}(u);
return ripple::hardened_hash<>{}(u);
}
};

View File

@@ -0,0 +1,176 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 Ripple Labs Inc.
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 RIPPLE_BASICS_HARDENED_HASH_H_INCLUDED
#define RIPPLE_BASICS_HARDENED_HASH_H_INCLUDED
#include <beast/hash/hash_append.h>
#include <beast/hash/xxhasher.h>
#include <beast/cxx14/utility.h> // <utility>
#include <beast/cxx14/type_traits.h> // <type_traits>
#include <beast/utility/noexcept.h>
#include <beast/utility/static_initializer.h>
#include <cstdint>
#include <functional>
#include <mutex>
#include <random>
#include <unordered_map>
#include <unordered_set>
// When set to 1, makes the seed per-process instead
// of per default-constructed instance of hardened_hash
//
#ifndef RIPPLE_NO_HARDENED_HASH_INSTANCE_SEED
# ifdef __GLIBCXX__
# define RIPPLE_NO_HARDENED_HASH_INSTANCE_SEED 1
# else
# define RIPPLE_NO_HARDENED_HASH_INSTANCE_SEED 0
# endif
#endif
namespace ripple {
namespace detail {
using seed_pair = std::pair<std::uint64_t, std::uint64_t>;
template <bool = true>
seed_pair
make_seed_pair() noexcept
{
struct state_t
{
std::mutex mutex;
std::random_device rng;
std::mt19937_64 gen {rng()};
std::uniform_int_distribution <std::uint64_t> dist;
state_t() : gen(rng()) {}
// state_t(state_t const&) = delete;
// state_t& operator=(state_t const&) = delete;
};
static beast::static_initializer <state_t> state;
std::lock_guard <std::mutex> lock (state->mutex);
return {state->dist(state->gen), state->dist(state->gen)};
}
}
template <class HashAlgorithm, bool ProcessSeeded>
class basic_hardened_hash;
/**
* Seed functor once per process
*/
template <class HashAlgorithm>
class basic_hardened_hash <HashAlgorithm, true>
{
private:
static
detail::seed_pair const&
init_seed_pair()
{
static beast::static_initializer <detail::seed_pair,
basic_hardened_hash> const p (
detail::make_seed_pair<>());
return *p;
}
public:
using result_type = typename HashAlgorithm::result_type;
template <class T>
result_type
operator()(T const& t) const noexcept
{
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<result_type>(h);
}
};
/**
* Seed functor once per construction
*/
template <class HashAlgorithm>
class basic_hardened_hash<HashAlgorithm, false>
{
private:
detail::seed_pair m_seeds;
public:
using result_type = typename HashAlgorithm::result_type;
basic_hardened_hash()
: m_seeds (detail::make_seed_pair<>())
{}
template <class T>
result_type
operator()(T const& t) const noexcept
{
HashAlgorithm h(m_seeds.first, m_seeds.second);
hash_append(h, t);
return static_cast<result_type>(h);
}
};
//------------------------------------------------------------------------------
/** A std compatible hash adapter that resists adversarial inputs.
For this to work, T must implement in its own namespace:
@code
template <class Hasher>
void
hash_append (Hasher& h, T const& t) noexcept
{
// hash_append each base and member that should
// participate in forming the hash
using beast::hash_append;
hash_append (h, static_cast<T::base1 const&>(t));
hash_append (h, static_cast<T::base2 const&>(t));
// ...
hash_append (h, t.member1);
hash_append (h, t.member2);
// ...
}
@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
*/
#if RIPPLE_NO_HARDENED_HASH_INSTANCE_SEED
template <class HashAlgorithm = beast::xxhasher>
using hardened_hash = basic_hardened_hash<HashAlgorithm, true>;
#else
template <class HashAlgorithm = beast::xxhasher>
using hardened_hash = basic_hardened_hash<HashAlgorithm, false>;
#endif
} // ripple
#endif

View File

@@ -0,0 +1,306 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
#include <BeastConfig.h>
#include <ripple/basics/hardened_hash.h>
#include <beast/unit_test/suite.h>
#include <beast/crypto/Sha256.h>
#include <boost/functional/hash.hpp>
#include <array>
#include <cstdint>
#include <iomanip>
#include <functional>
#include <unordered_map>
#include <unordered_set>
namespace ripple {
namespace detail {
template <class T>
class test_user_type_member
{
private:
T t;
public:
explicit test_user_type_member (T const& t_ = T())
: t (t_)
{
}
template <class Hasher>
friend void hash_append (Hasher& h, test_user_type_member const& a) noexcept
{
using beast::hash_append;
hash_append (h, a.t);
}
};
template <class T>
class test_user_type_free
{
private:
T t;
public:
explicit test_user_type_free (T const& t_ = T())
: t (t_)
{
}
template <class Hasher>
friend void hash_append (Hasher& h, test_user_type_free const& a) noexcept
{
using beast::hash_append;
hash_append (h, a.t);
}
};
} // detail
} // ripple
//------------------------------------------------------------------------------
namespace ripple {
namespace detail {
template <class T>
using test_hardened_unordered_set =
std::unordered_set <T, hardened_hash <>>;
template <class T>
using test_hardened_unordered_map =
std::unordered_map <T, int, hardened_hash <>>;
template <class T>
using test_hardened_unordered_multiset =
std::unordered_multiset <T, hardened_hash <>>;
template <class T>
using test_hardened_unordered_multimap =
std::unordered_multimap <T, int, hardened_hash <>>;
} // detail
template <std::size_t Bits, class UInt = std::uint64_t>
class unsigned_integer
{
private:
static_assert (std::is_integral<UInt>::value &&
std::is_unsigned <UInt>::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 <UInt, size> m_vec;
public:
typedef UInt value_type;
static std::size_t const bits = Bits;
static std::size_t const bytes = bits / 8;
template <class Int>
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];
}
template <class Hasher>
friend void hash_append(Hasher& h, unsigned_integer const& a) noexcept
{
using beast::hash_append;
hash_append (h, a.m_vec);
}
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");
} // ripple
//------------------------------------------------------------------------------
namespace ripple {
class hardened_hash_test
: public beast::unit_test::suite
{
public:
template <class T>
void
check ()
{
T t{};
hardened_hash <>() (t);
pass();
}
template <template <class T> class U>
void
check_user_type()
{
check <U <bool>> ();
check <U <char>> ();
check <U <signed char>> ();
check <U <unsigned char>> ();
// These cause trouble for boost
//check <U <char16_t>> ();
//check <U <char32_t>> ();
check <U <wchar_t>> ();
check <U <short>> ();
check <U <unsigned short>> ();
check <U <int>> ();
check <U <unsigned int>> ();
check <U <long>> ();
check <U <long long>> ();
check <U <unsigned long>> ();
check <U <unsigned long long>> ();
check <U <float>> ();
check <U <double>> ();
check <U <long double>> ();
}
template <template <class T> class C >
void
check_container()
{
{
C <detail::test_user_type_member <std::string>> c;
}
pass();
{
C <detail::test_user_type_free <std::string>> c;
}
pass();
}
void
test_user_types()
{
testcase ("user types");
check_user_type <detail::test_user_type_member> ();
check_user_type <detail::test_user_type_free> ();
}
void
test_containers()
{
testcase ("containers");
check_container <detail::test_hardened_unordered_set>();
check_container <detail::test_hardened_unordered_map>();
check_container <detail::test_hardened_unordered_multiset>();
check_container <detail::test_hardened_unordered_multimap>();
}
void
run ()
{
test_user_types();
test_containers();
}
};
class hardened_hash_sha256_test
: public beast::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));
beast::Sha256::digest_type d;
beast::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,basics,ripple);
BEAST_DEFINE_TESTSUITE_MANUAL(hardened_hash_sha256,basics,ripple);
} // ripple

View File

@@ -21,6 +21,7 @@
#define RIPPLE_ECKEY_H
#include <ripple/basics/base_uint.h>
#include <cstdint>
namespace ripple {
namespace openssl {
@@ -73,7 +74,7 @@ public:
std::size_t get_public_key_size() const;
uint8_t get_public_key (uint8* buffer) const;
std::uint8_t get_public_key (std::uint8_t* buffer) const;
};
} // openssl

View File

@@ -28,6 +28,7 @@
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/hmac.h>
#include <cstdint>
namespace ripple {
@@ -75,7 +76,7 @@ ec_key ECDSAPublicKey (Blob const& serialized)
{
EC_KEY* key = new_initialized_EC_KEY();
uint8_t const* begin = &serialized[0];
std::uint8_t const* begin = &serialized[0];
if (o2i_ECPublicKey (&key, &begin, serialized.size()) != nullptr)
{
@@ -111,7 +112,7 @@ Blob ECDSASign (uint256 const& hash, const openssl::ec_key& key)
return result;
}
static bool ECDSAVerify (uint256 const& hash, uint8 const* sig, size_t sigLen, EC_KEY* key)
static bool ECDSAVerify (uint256 const& hash, std::uint8_t const* sig, size_t sigLen, EC_KEY* key)
{
// -1 = error, 0 = bad sig, 1 = good
return ECDSA_verify (0, hash.begin(), hash.size(), sig, sigLen, key) > 0;

View File

@@ -100,15 +100,15 @@ std::size_t ec_key::get_public_key_size() const
return size;
}
uint8_t ec_key::get_public_key (uint8* buffer) const
std::uint8_t ec_key::get_public_key (std::uint8_t* buffer) const
{
uint8_t* begin = buffer;
std::uint8_t* begin = buffer;
int const size = i2o_ECPublicKey (get_EC_KEY (*this), &begin);
assert (size == get_public_key_size());
return uint8_t (size);
return std::uint8_t (size);
}
} // openssl

View File

@@ -35,6 +35,7 @@
#include <ripple/basics/impl/UptimeTimer.cpp>
#include <ripple/basics/tests/CheckLibraryVersions.test.cpp>
#include <ripple/basics/tests/hardened_hash_test.cpp>
#include <ripple/basics/tests/KeyCache.test.cpp>
#include <ripple/basics/tests/RangeSet.test.cpp>
#include <ripple/basics/tests/StringUtilities.test.cpp>

View File

@@ -20,10 +20,10 @@
#ifndef RIPPLE_VALIDATORS_CONNECTIONIMP_H_INCLUDED
#define RIPPLE_VALIDATORS_CONNECTIONIMP_H_INCLUDED
#include <ripple/basics/hardened_hash.h>
#include <ripple/protocol/RippleAddress.h>
#include <ripple/validators/Connection.h>
#include <ripple/validators/impl/Logic.h>
#include <beast/hash/hardened_hash.h>
#include <beast/utility/WrappedSink.h>
#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>

View File

@@ -21,6 +21,7 @@
#define RIPPLE_VALIDATORS_LOGIC_H_INCLUDED
#include <ripple/protocol/Protocol.h>
#include <ripple/basics/hardened_hash.h>
#include <ripple/basics/seconds_clock.h>
#include <ripple/protocol/RippleLedgerHash.h>
#include <ripple/validators/impl/Store.h>
@@ -50,7 +51,7 @@ private:
{
std::uint32_t seq_no = 0;
std::unordered_set<RippleAddress,
beast::hardened_hash<>> keys;
hardened_hash<>> keys;
};
class Policy
@@ -70,7 +71,7 @@ private:
Policy policy_;
beast::aged_unordered_map <LedgerHash, LedgerMeta,
std::chrono::steady_clock, beast::hardened_hash<>> ledgers_;
std::chrono::steady_clock, hardened_hash<>> ledgers_;
std::pair<LedgerHash, LedgerMeta> latest_; // last fully validated
boost::container::flat_set<ConnectionImp*> connections_;