Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r81973 - trunk/libs/unordered/examples/siphash
From: dnljms_at_[hidden]
Date: 2012-12-15 11:42:45


Author: danieljames
Date: 2012-12-15 11:42:44 EST (Sat, 15 Dec 2012)
New Revision: 81973
URL: http://svn.boost.org/trac/boost/changeset/81973

Log:
Unordered: Initial stab at siphash example.
Added:
   trunk/libs/unordered/examples/siphash/
   trunk/libs/unordered/examples/siphash/Jamfile.v2 (contents, props changed)
   trunk/libs/unordered/examples/siphash/README.txt (contents, props changed)
   trunk/libs/unordered/examples/siphash/siphash.cpp (contents, props changed)
   trunk/libs/unordered/examples/siphash/siphash.hpp (contents, props changed)
   trunk/libs/unordered/examples/siphash/siphash_example.cpp (contents, props changed)
   trunk/libs/unordered/examples/siphash/siphash_generate.cpp (contents, props changed)

Added: trunk/libs/unordered/examples/siphash/Jamfile.v2
==============================================================================
--- (empty file)
+++ trunk/libs/unordered/examples/siphash/Jamfile.v2 2012-12-15 11:42:44 EST (Sat, 15 Dec 2012)
@@ -0,0 +1,18 @@
+
+# Copyright 2012 Daniel James.
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+import testing ;
+
+project unordered-test/example/siphash
+ : requirements
+ <warnings>all
+ <toolset>intel:<warnings>on
+ <toolset>gcc:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wno-long-long -Wfloat-equal"
+ <toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal"
+ ;
+
+lib siphash : siphash.cpp siphash_generate.cpp /boost/random//boost_random ;
+
+run siphash_example.cpp siphash ;
\ No newline at end of file

Added: trunk/libs/unordered/examples/siphash/README.txt
==============================================================================
--- (empty file)
+++ trunk/libs/unordered/examples/siphash/README.txt 2012-12-15 11:42:44 EST (Sat, 15 Dec 2012)
@@ -0,0 +1,35 @@
+Siphash example
+---------------
+
+Most of the commonly used hash functions are vunerable to
+'hash-flooding' attacks. These can happen if the table is filled with
+values which are likely to cause hash collisions. SipHash[1] is a fast
+hash function proposed by Jean-Philippe Aumasson and Daniel J.
+Bernstein2 to resist these attacks. While young and relatively untested,
+it's been demonstrated that it's less vulnerable to attacks than popular
+hash functions, such as MurmurHash and CityHash.
+
+This a nice example, as it has a distinct practial use to boost::hash
+and demonstrates a hash function with state. It also shows how a generic
+hash function might be built on top of a binary hash function.
+
+Note that this is an example, and far from fully polished. Some issues
+with the current implementation:
+
+ - It's slow.
+ - Only works on little endian machines.
+ - Only supports a subset of the standard library.
+
+I should improve it a bit before it's properly released. But if you wish
+to implement something better, there are several C implementations
+listed on the SipHash page[1]. I probably won't even try to compete with
+them. If anyone is willing to implement a high quality SipHash library for
+boost, that would be very much appreciated.
+
+[1] https://131002.net/siphash/
+
+--------------------------------------------------------------------------------
+
+Copyright 2012 Daniel James.
+Distributed under the Boost Software License, Version 1.0. (See accompanying
+file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

Added: trunk/libs/unordered/examples/siphash/siphash.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/unordered/examples/siphash/siphash.cpp 2012-12-15 11:42:44 EST (Sat, 15 Dec 2012)
@@ -0,0 +1,91 @@
+
+// Copyright 2012 Daniel James.
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// This is also released into the public domain.
+
+#include "siphash.hpp"
+
+namespace hash
+{
+ const unsigned siphash_c = 2;
+ const unsigned siphash_d = 4;
+
+ siphash_state::siphash_state(sipkey const& key) :
+ v0(0x736f6d6570736575ull ^ key.k0),
+ v1(0x646f72616e646f6dull ^ key.k1),
+ v2(0x6c7967656e657261ull ^ key.k0),
+ v3(0x7465646279746573ull ^ key.k1),
+ buffered(0), b(0)
+ {
+ }
+
+ namespace
+ {
+ inline boost::uint64_t rotate_left(boost::uint64_t x, unsigned c)
+ {
+ return (x << c) | (x >> (64-c));
+ }
+ }
+
+ void siphash_state::sip_round(unsigned rounds)
+ {
+ for (unsigned i = 0; i < rounds; ++i) {
+ v0 += v1;
+ v1 = rotate_left(v1, 13);
+ v1 ^= v0;
+ v0 = rotate_left(v0, 32);
+
+ v2 += v3;
+ v3 = rotate_left(v3, 16);
+ v3 ^= v2;
+
+ v2 += v1;
+ v1 = rotate_left(v1, 17);
+ v1 ^= v2;
+ v2 = rotate_left(v2, 32);
+
+ v0 += v3;
+ v3 = rotate_left(v3, 21);
+ v3 ^= v0;
+ }
+ }
+
+ void siphash_state::update(void const* data, unsigned length)
+ {
+ char const* ptr = static_cast<char const*>(data);
+
+ while (length > 0) {
+ buffer[buffered++] = *ptr++;
+ ++b;
+ --length;
+
+ if (buffered == 8)
+ {
+ v3 ^= m;
+ sip_round(siphash_c);
+ v0 ^= m;
+ buffered = 0;
+ }
+ }
+ }
+
+ boost::uint64_t siphash_state::finalize()
+ {
+ // Compress the final 8 bytes.
+ while (buffered < 7) buffer[buffered++] = 0;
+ buffer[7] = b;
+
+ v3 ^= m;
+ sip_round(siphash_c);
+ v0 ^= m;
+
+ // Finalize the hash
+
+ v2 ^= 0xff;
+ sip_round(siphash_d);
+
+ return v0 ^ v1 ^ v2 ^ v3;
+ }
+}
\ No newline at end of file

Added: trunk/libs/unordered/examples/siphash/siphash.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/unordered/examples/siphash/siphash.hpp 2012-12-15 11:42:44 EST (Sat, 15 Dec 2012)
@@ -0,0 +1,204 @@
+
+// Copyright 2012 Daniel James.
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// This is also released into the public domain.
+
+#if !defined(BOOST_HASH_EXAMPLES_SIPHASH_HEADER)
+#define BOOST_HASH_EXAMPLES_SIPHASH_HEADER
+
+#include <boost/cstdint.hpp>
+#include <boost/utility/enable_if.hpp>
+
+#include <string>
+#include <vector>
+#include <list>
+
+namespace hash
+{
+ // Random key used to make sure the hash function isn't predictable.
+
+ struct sipkey
+ {
+ boost::uint64_t k0, k1;
+ };
+
+ // Generate a secure sipkey.
+ // This only works when boost::random_device is available.
+ sipkey generate_sipkey();
+
+ // This is the class that does the actual hashing.
+
+ struct siphash_state
+ {
+ boost::uint64_t v0, v1, v2, v3;
+ union {
+ boost::uint64_t m;
+ unsigned char buffer[8];
+ };
+ unsigned char buffered;
+ unsigned char b;
+
+ explicit siphash_state(sipkey const&);
+ void update(void const*, unsigned);
+ boost::uint64_t finalize();
+
+ private:
+ void sip_round(unsigned);
+ };
+
+ // The genereric hash function.
+ //
+ // Don't sepecialize this. Unless you really want to.
+
+ template <typename T>
+ struct siphash
+ {
+ sipkey key;
+
+ /* implicit */ siphash(sipkey const& k) : key(k) {}
+ std::size_t operator()(T const&) const;
+ };
+
+ // Add support for a type by specializing this class.
+ //
+ // 'Enable' is used as a SFINAE hook.
+
+ template <typename T, typename Enable = void>
+ struct siphash_impl
+ {
+ static void update(siphash_state&, T const&);
+ };
+
+ // The implementation of the generic hash function.
+
+ template <typename T>
+ std::size_t siphash<T>::operator()(T const& x) const
+ {
+ siphash_state state(key);
+ siphash_impl<T>::update(state, x);
+ return static_cast<std::size_t>(state.finalize());
+ }
+
+ // A couple of basic traits for hashing binary data.
+
+ struct enable_siphash_false { enum { value = false }; };
+ struct enable_siphash_true { enum { value = true }; };
+
+ template <typename T>
+ struct enable_siphash_binary : enable_siphash_false {};
+
+ template <typename T>
+ struct enable_siphash_binary_array
+ {
+ enum { value = enable_siphash_binary<T>::value &&
+ sizeof(T[2]) == sizeof(T) * 2 };
+ };
+
+ // Some general purpose hash implementations, siphash_impl<T>
+ // can inherit from these.
+
+ template <typename T>
+ struct siphash_binary_impl
+ {
+ static void update(siphash_state& state, int x)
+ {
+ state.update(&x, sizeof(x));
+ }
+ };
+
+ template <typename T>
+ struct siphash_container_impl
+ {
+ static void update(siphash_state& state, T const& x)
+ {
+ siphash_impl<typename T::value_type> value_impl;
+
+ for (typename T::const_iterator begin = x.begin(),
+ end = x.end(); begin != end; ++begin)
+ {
+ value_impl.update(state, *begin);
+ }
+ }
+ };
+
+ template <typename T, bool Enable = enable_siphash_binary_array<T>::value>
+ struct siphash_binary_container_impl;
+
+ template <typename T>
+ struct siphash_binary_container_impl<T, false> :
+ siphash_container_impl<T> {};
+
+ template <typename T>
+ struct siphash_binary_container_impl<T, true>
+ {
+ static void update(siphash_state& state, T const& x)
+ {
+ state.update(&*x.cbegin(), sizeof(T) * x.size());
+ }
+ };
+
+ // Specialize siphash_impl for various types.
+
+ template <typename T>
+ struct siphash_impl<T,
+ typename boost::enable_if_c<enable_siphash_binary<T>::value>::type
+ > : siphash_binary_impl<T> {};
+
+ template <typename T, typename Alloc>
+ struct siphash_impl<std::list<T, Alloc> > :
+ siphash_container_impl<T> {};
+
+ template <typename T, typename Alloc>
+ struct siphash_impl<std::vector<T, Alloc> > :
+ siphash_binary_container_impl<T> {};
+
+ template <typename T, typename Alloc>
+ struct siphash_impl<std::basic_string<T, std::char_traits<T>, Alloc> > :
+ siphash_binary_container_impl<T> {};
+
+ // Specialize the binary trait for builtin types.
+
+ template <> struct enable_siphash_binary<bool> :
+ enable_siphash_true {};
+ template <> struct enable_siphash_binary<char> :
+ enable_siphash_true {};
+ template <> struct enable_siphash_binary<unsigned char> :
+ enable_siphash_true {};
+ template <> struct enable_siphash_binary<signed char> :
+ enable_siphash_true {};
+ template <> struct enable_siphash_binary<short> :
+ enable_siphash_true {};
+ template <> struct enable_siphash_binary<unsigned short> :
+ enable_siphash_true {};
+ template <> struct enable_siphash_binary<int> :
+ enable_siphash_true {};
+ template <> struct enable_siphash_binary<unsigned int> :
+ enable_siphash_true {};
+ template <> struct enable_siphash_binary<long> :
+ enable_siphash_true {};
+ template <> struct enable_siphash_binary<unsigned long> :
+ enable_siphash_true {};
+
+#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
+ template <> struct enable_siphash_binary<wchar_t> :
+ enable_siphash_true {};
+#endif
+
+#if !defined(BOOST_NO_LONG_LONG)
+ template <> struct enable_siphash_binary<boost::long_long_type> :
+ enable_siphash_true {};
+ template <> struct enable_siphash_binary<boost::ulong_long_type> :
+ enable_siphash_true {};
+#endif
+
+#if defined(BOOST_HAS_INT128)
+ template <> struct enable_siphash_binary<boost::int128_type> :
+ boost::hash_detail::enable_hash_value {};
+ template <> struct enable_siphash_binary<boost::uint128_type> :
+ boost::hash_detail::enable_hash_value {};
+#endif
+}
+
+#endif
\ No newline at end of file

Added: trunk/libs/unordered/examples/siphash/siphash_example.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/unordered/examples/siphash/siphash_example.cpp 2012-12-15 11:42:44 EST (Sat, 15 Dec 2012)
@@ -0,0 +1,38 @@
+
+// Copyright 2012 Daniel James.
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// This is also released into the public domain.
+
+#include <boost/unordered_set.hpp>
+#include <cassert>
+#include "siphash.hpp"
+
+int main()
+{
+ boost::unordered_set<int, hash::siphash<int> > x1(0, hash::generate_sipkey());
+ boost::unordered_set<int, hash::siphash<int> > x2(0, hash::generate_sipkey());
+
+ assert(x1 == x2);
+
+ x1.insert(10);
+ x1.insert(30);
+ x1.insert(50);
+ assert(x1 != x2);
+
+ x2.insert(100);
+ assert(x1 != x2);
+
+ x1.insert(x2.begin(), x2.end());
+ x2.insert(x1.begin(), x1.end());
+ assert(x1 == x2);
+
+ assert(x1.bucket(10) != x2.bucket(10));
+ assert(x1.bucket(30) != x2.bucket(30));
+
+ x1 = x2;
+
+ assert(x1.bucket(10) == x2.bucket(10));
+ assert(x1.bucket(30) == x2.bucket(30));
+}
\ No newline at end of file

Added: trunk/libs/unordered/examples/siphash/siphash_generate.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/unordered/examples/siphash/siphash_generate.cpp 2012-12-15 11:42:44 EST (Sat, 15 Dec 2012)
@@ -0,0 +1,27 @@
+
+// Copyright 2012 Daniel James.
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// This is also released into the public domain.
+
+#include "siphash.hpp"
+#include <boost/random/random_device.hpp>
+#include <boost/random/variate_generator.hpp>
+#include <boost/random/uniform_int.hpp>
+
+namespace hash
+{
+ sipkey generate_sipkey()
+ {
+ boost::random_device rng;
+ boost::variate_generator<boost::random_device&,
+ boost::uniform_int<boost::uint64_t> > gen(rng,
+ boost::uniform_int<boost::uint64_t>());
+
+ sipkey k;
+ k.k0 = gen();
+ k.k1 = gen();
+ return k;
+ }
+}
\ No newline at end of file


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk