From 402cc520d118b9943b0dc94fd033af9ec0cdd2fa Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sat, 6 Jan 2018 16:45:24 +0200 Subject: [PATCH] Initial commit --- .gitattributes | 96 ++++ .travis.yml | 189 ++++++++ appveyor.yml | 43 ++ benchmark/average.cpp | 83 ++++ benchmark/buffer.cpp | 76 +++ benchmark/unordered.cpp | 174 +++++++ include/boost/hash2/byte_type.hpp | 17 + include/boost/hash2/detail/read.hpp | 87 ++++ include/boost/hash2/detail/rot.hpp | 52 ++ include/boost/hash2/detail/write.hpp | 79 +++ include/boost/hash2/fnv1a.hpp | 123 +++++ include/boost/hash2/get_integral_result.hpp | 48 ++ include/boost/hash2/hash_append.hpp | 286 +++++++++++ include/boost/hash2/hmac.hpp | 108 +++++ .../boost/hash2/is_contiguously_hashable.hpp | 40 ++ include/boost/hash2/is_range.hpp | 65 +++ include/boost/hash2/is_tuple_like.hpp | 130 +++++ include/boost/hash2/is_unordered_range.hpp | 39 ++ include/boost/hash2/md5.hpp | 327 +++++++++++++ include/boost/hash2/murmur3.hpp | 381 +++++++++++++++ include/boost/hash2/sha1.hpp | 324 +++++++++++++ include/boost/hash2/siphash.hpp | 384 +++++++++++++++ include/boost/hash2/spooky2.hpp | 409 ++++++++++++++++ include/boost/hash2/underlying_type.hpp | 45 ++ include/boost/hash2/xxhash.hpp | 455 ++++++++++++++++++ test/Jamfile | 57 +++ test/concept.cpp | 201 ++++++++ test/fnv1a.cpp | 32 ++ test/get_integral_result.cpp | 97 ++++ test/hash_append.cpp | 53 ++ test/hash_append_2.cpp | 53 ++ test/hash_append_3.cpp | 48 ++ test/hash_append_4.cpp | 96 ++++ test/hash_append_range.cpp | 61 +++ test/hash_append_range_2.cpp | 59 +++ test/hmac_md5.cpp | 61 +++ test/hmac_sha1.cpp | 61 +++ test/integral_result.cpp | 46 ++ test/is_contiguously_hashable.cpp | 108 +++++ test/is_range.cpp | 98 ++++ test/is_tuple_like.cpp | 72 +++ test/is_unordered_range.cpp | 98 ++++ test/map.cpp | 84 ++++ test/md5.cpp | 56 +++ test/multiple_result.cpp | 49 ++ test/murmur3_128.cpp | 56 +++ test/murmur3_32.cpp | 45 ++ test/plaintext_leak.cpp | 70 +++ test/set.cpp | 82 ++++ test/sha1.cpp | 58 +++ test/siphash32.cpp | 143 ++++++ test/siphash64.cpp | 143 ++++++ test/spooky2.cpp | 108 +++++ test/underlying_type.cpp | 132 +++++ test/xxhash.cpp | 38 ++ 55 files changed, 6425 insertions(+) create mode 100644 .gitattributes create mode 100644 .travis.yml create mode 100644 appveyor.yml create mode 100644 benchmark/average.cpp create mode 100644 benchmark/buffer.cpp create mode 100644 benchmark/unordered.cpp create mode 100644 include/boost/hash2/byte_type.hpp create mode 100644 include/boost/hash2/detail/read.hpp create mode 100644 include/boost/hash2/detail/rot.hpp create mode 100644 include/boost/hash2/detail/write.hpp create mode 100644 include/boost/hash2/fnv1a.hpp create mode 100644 include/boost/hash2/get_integral_result.hpp create mode 100644 include/boost/hash2/hash_append.hpp create mode 100644 include/boost/hash2/hmac.hpp create mode 100644 include/boost/hash2/is_contiguously_hashable.hpp create mode 100644 include/boost/hash2/is_range.hpp create mode 100644 include/boost/hash2/is_tuple_like.hpp create mode 100644 include/boost/hash2/is_unordered_range.hpp create mode 100644 include/boost/hash2/md5.hpp create mode 100644 include/boost/hash2/murmur3.hpp create mode 100644 include/boost/hash2/sha1.hpp create mode 100644 include/boost/hash2/siphash.hpp create mode 100644 include/boost/hash2/spooky2.hpp create mode 100644 include/boost/hash2/underlying_type.hpp create mode 100644 include/boost/hash2/xxhash.hpp create mode 100644 test/Jamfile create mode 100644 test/concept.cpp create mode 100644 test/fnv1a.cpp create mode 100644 test/get_integral_result.cpp create mode 100644 test/hash_append.cpp create mode 100644 test/hash_append_2.cpp create mode 100644 test/hash_append_3.cpp create mode 100644 test/hash_append_4.cpp create mode 100644 test/hash_append_range.cpp create mode 100644 test/hash_append_range_2.cpp create mode 100644 test/hmac_md5.cpp create mode 100644 test/hmac_sha1.cpp create mode 100644 test/integral_result.cpp create mode 100644 test/is_contiguously_hashable.cpp create mode 100644 test/is_range.cpp create mode 100644 test/is_tuple_like.cpp create mode 100644 test/is_unordered_range.cpp create mode 100644 test/map.cpp create mode 100644 test/md5.cpp create mode 100644 test/multiple_result.cpp create mode 100644 test/murmur3_128.cpp create mode 100644 test/murmur3_32.cpp create mode 100644 test/plaintext_leak.cpp create mode 100644 test/set.cpp create mode 100644 test/sha1.cpp create mode 100644 test/siphash32.cpp create mode 100644 test/siphash64.cpp create mode 100644 test/spooky2.cpp create mode 100644 test/underlying_type.cpp create mode 100644 test/xxhash.cpp diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3e84d7c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,96 @@ +* text=auto !eol svneol=native#text/plain +*.gitattributes text svneol=native#text/plain + +# Scriptish formats +*.bat text svneol=native#text/plain +*.bsh text svneol=native#text/x-beanshell +*.cgi text svneol=native#text/plain +*.cmd text svneol=native#text/plain +*.js text svneol=native#text/javascript +*.php text svneol=native#text/x-php +*.pl text svneol=native#text/x-perl +*.pm text svneol=native#text/x-perl +*.py text svneol=native#text/x-python +*.sh eol=lf svneol=LF#text/x-sh +configure eol=lf svneol=LF#text/x-sh + +# Image formats +*.bmp binary svneol=unset#image/bmp +*.gif binary svneol=unset#image/gif +*.ico binary svneol=unset#image/ico +*.jpeg binary svneol=unset#image/jpeg +*.jpg binary svneol=unset#image/jpeg +*.png binary svneol=unset#image/png +*.tif binary svneol=unset#image/tiff +*.tiff binary svneol=unset#image/tiff +*.svg text svneol=native#image/svg%2Bxml + +# Data formats +*.pdf binary svneol=unset#application/pdf +*.avi binary svneol=unset#video/avi +*.doc binary svneol=unset#application/msword +*.dsp text svneol=crlf#text/plain +*.dsw text svneol=crlf#text/plain +*.eps binary svneol=unset#application/postscript +*.gz binary svneol=unset#application/gzip +*.mov binary svneol=unset#video/quicktime +*.mp3 binary svneol=unset#audio/mpeg +*.ppt binary svneol=unset#application/vnd.ms-powerpoint +*.ps binary svneol=unset#application/postscript +*.psd binary svneol=unset#application/photoshop +*.rdf binary svneol=unset#text/rdf +*.rss text svneol=unset#text/xml +*.rtf binary svneol=unset#text/rtf +*.sln text svneol=native#text/plain +*.swf binary svneol=unset#application/x-shockwave-flash +*.tgz binary svneol=unset#application/gzip +*.vcproj text svneol=native#text/xml +*.vcxproj text svneol=native#text/xml +*.vsprops text svneol=native#text/xml +*.wav binary svneol=unset#audio/wav +*.xls binary svneol=unset#application/vnd.ms-excel +*.zip binary svneol=unset#application/zip + +# Text formats +.htaccess text svneol=native#text/plain +*.bbk text svneol=native#text/xml +*.cmake text svneol=native#text/plain +*.css text svneol=native#text/css +*.dtd text svneol=native#text/xml +*.htm text svneol=native#text/html +*.html text svneol=native#text/html +*.ini text svneol=native#text/plain +*.log text svneol=native#text/plain +*.mak text svneol=native#text/plain +*.qbk text svneol=native#text/plain +*.rst text svneol=native#text/plain +*.sql text svneol=native#text/x-sql +*.txt text svneol=native#text/plain +*.xhtml text svneol=native#text/xhtml%2Bxml +*.xml text svneol=native#text/xml +*.xsd text svneol=native#text/xml +*.xsl text svneol=native#text/xml +*.xslt text svneol=native#text/xml +*.xul text svneol=native#text/xul +*.yml text svneol=native#text/plain +boost-no-inspect text svneol=native#text/plain +CHANGES text svneol=native#text/plain +COPYING text svneol=native#text/plain +INSTALL text svneol=native#text/plain +Jamfile text svneol=native#text/plain +Jamroot text svneol=native#text/plain +Jamfile.v2 text svneol=native#text/plain +Jamrules text svneol=native#text/plain +Makefile* text svneol=native#text/plain +README text svneol=native#text/plain +TODO text svneol=native#text/plain + +# Code formats +*.c text svneol=native#text/plain +*.cpp text svneol=native#text/plain +*.h text svneol=native#text/plain +*.hpp text svneol=native#text/plain +*.ipp text svneol=native#text/plain +*.tpp text svneol=native#text/plain +*.jam text svneol=native#text/plain +*.java text svneol=native#text/plain diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..781965c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,189 @@ +# Copyright 2016, 2017 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +language: cpp + +sudo: false + +python: "2.7" + +branches: + only: + - master + - develop + - /feature\/.*/ + +env: + matrix: + - BOGUS_JOB=true + +matrix: + + exclude: + - env: BOGUS_JOB=true + + include: + - os: linux + compiler: g++-4.7 + env: TOOLSET=gcc COMPILER=g++-4.7 CXXSTD=03,11 + addons: + apt: + packages: + - g++-4.7 + sources: + - ubuntu-toolchain-r-test + + - os: linux + compiler: g++-4.8 + env: TOOLSET=gcc COMPILER=g++-4.8 CXXSTD=03,11 + addons: + apt: + packages: + - g++-4.8 + sources: + - ubuntu-toolchain-r-test + + - os: linux + compiler: g++-4.9 + env: TOOLSET=gcc COMPILER=g++-4.9 CXXSTD=03,11 + addons: + apt: + packages: + - g++-4.9 + sources: + - ubuntu-toolchain-r-test + + - os: linux + compiler: g++-5 + env: TOOLSET=gcc COMPILER=g++-5 CXXSTD=03,11,14,1z + addons: + apt: + packages: + - g++-5 + sources: + - ubuntu-toolchain-r-test + + - os: linux + compiler: g++-6 + env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=03,11,14,1z + addons: + apt: + packages: + - g++-6 + sources: + - ubuntu-toolchain-r-test + + - os: linux + compiler: g++-7 + env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=03,11,14,1z + addons: + apt: + packages: + - g++-7 + sources: + - ubuntu-toolchain-r-test + + - os: linux + compiler: clang++-3.5 + env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=03,11,14,1z + addons: + apt: + packages: + - clang-3.5 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.5 + + - os: linux + compiler: clang++-3.6 + env: TOOLSET=clang COMPILER=clang++-3.6 CXXSTD=03,11,14,1z + addons: + apt: + packages: + - clang-3.6 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + + - os: linux + compiler: clang++-3.7 + env: TOOLSET=clang COMPILER=clang++-3.7 CXXSTD=03,11,14,1z + addons: + apt: + packages: + - clang-3.7 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + + - os: linux + compiler: clang++-3.8 + env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD=03,11,14,1z + addons: + apt: + packages: + - clang-3.8 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + + - os: linux + compiler: clang++-3.9 + env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD=03,11,14,1z + addons: + apt: + packages: + - clang-3.9 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.9 + + - os: linux + compiler: clang++-4.0 + env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=03,11,14,1z + addons: + apt: + packages: + - clang-4.0 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-4.0 + + - os: linux + compiler: clang++-5.0 + env: TOOLSET=clang COMPILER=clang++-5.0 CXXSTD=03,11,14,1z + addons: + apt: + packages: + - clang-5.0 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-5.0 + + - os: osx + compiler: clang++ + env: TOOLSET=clang COMPILER=clang++ CXXSTD=03,11,14,1z + +install: + - BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true + - cd .. + - git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + - cd boost-root + - git submodule update --init tools/build + - git submodule update --init libs/config + - git submodule update --init tools/boostdep + - mkdir -p libs/hash2 + - cp -r $TRAVIS_BUILD_DIR/* libs/hash2 + - python tools/boostdep/depinst/depinst.py hash2 + - ./bootstrap.sh + - ./b2 headers + +script: + - |- + echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam + - ./b2 -j3 libs/hash2/test toolset=$TOOLSET cxxstd=$CXXSTD + +notifications: + email: + on_success: always diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..b3b29ec --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,43 @@ +# Copyright 2016, 2017 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +version: 1.0.{build}-{branch} + +shallow_clone: true + +branches: + only: + - master + - develop + - /feature\/.*/ + +environment: + matrix: + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013 + TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0,msvc-12.0 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + TOOLSET: msvc-14.0 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + TOOLSET: msvc-14.1 + CXXSTD: 14,17 + +install: + - set BOOST_BRANCH=develop + - if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master + - cd .. + - git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root + - cd boost-root + - git submodule update --init tools/build + - git submodule update --init libs/config + - git submodule update --init tools/boostdep + - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\hash2\ + - python tools/boostdep/depinst/depinst.py hash2 + - cmd /c bootstrap + - b2 -d0 headers + +build: off + +test_script: + - if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% + - b2 -j3 libs/hash2/test toolset=%TOOLSET% diff --git a/benchmark/average.cpp b/benchmark/average.cpp new file mode 100644 index 0000000..bd7a7d3 --- /dev/null +++ b/benchmark/average.cpp @@ -0,0 +1,83 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template void test_( int N ) +{ + typedef boost::chrono::steady_clock clock_type; + + clock_type::time_point t1 = clock_type::now(); + + double r = 0; + + H h; + + for( int i = 0; i < N; ++i ) + { + using boost::hash2::get_integral_result; + r += get_integral_result( h.result() ); + r += 0.5; + } + + clock_type::time_point t2 = clock_type::now(); + + long long ms = boost::chrono::duration_cast( t2 - t1 ).count(); + + r /= N; + + // Standard deviation of Bates distribution + double stddev = static_cast( std::numeric_limits::max() ) - static_cast( std::numeric_limits::min() ) / std::sqrt( 12.0 * N ); + + r /= stddev; + + printf( "%s: r=%e, %lld ms\n", boost::core::demangle( typeid(H).name() ).c_str(), r, ms ); +} + +template void test( int N ) +{ + printf( "Integral result type `%s`:\n\n", boost::core::demangle( typeid(R).name() ).c_str() ); + + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + + puts( "" ); +} + +int main() +{ + int const N = 64 * 1024 * 1024; + + test( N ); + test( N ); + test( N ); + test( N ); +} diff --git a/benchmark/buffer.cpp b/benchmark/buffer.cpp new file mode 100644 index 0000000..102d8e4 --- /dev/null +++ b/benchmark/buffer.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template void test_( unsigned char const * p, int N, int M ) +{ + H h; + + typedef boost::chrono::steady_clock clock_type; + + clock_type::time_point t1 = clock_type::now(); + + for( int i = 0; i < M; ++i ) + { + hash_append_range( h, p, p + N ); + } + + clock_type::time_point t2 = clock_type::now(); + + long long ms = boost::chrono::duration_cast( t2 - t1 ).count(); + + using boost::hash2::get_integral_result; + unsigned r = get_integral_result( h.result() ); + + std::printf( "%s (N=%d): %u: %lld ms, %.2f MB/s\n", boost::core::demangle( typeid( H ).name() ).c_str(), N, r, ms, 1000.0 * N * M / ms / 1048576 ); +} + +extern unsigned char data[]; + +void test( int N, int M ) +{ + test_( data, N, M ); + test_( data, N, M ); + test_( data, N, M ); + test_( data, N, M ); + test_( data, N, M ); + test_( data, N, M ); + test_( data, N, M ); + test_( data, N, M ); + test_( data, N, M ); + test_( data, N, M ); + test_( data, N, M ); + test_( data, N, M ); + test_( data, N, M ); + + puts( "--" ); +} + +unsigned const N1 = 65536; +unsigned const M1 = 65535; + +unsigned const N2 = 15; +unsigned const M2 = M1 * N1 / N2; + +unsigned const N3 = 4; +unsigned const M3 = M1 * N1 / N3; + +int main() +{ + test( N1, M1 ); + test( N2, M2 ); + test( N3, M3 ); +} + +unsigned char data[ N1 ]; diff --git a/benchmark/unordered.cpp b/benchmark/unordered.cpp new file mode 100644 index 0000000..2dcddcb --- /dev/null +++ b/benchmark/unordered.cpp @@ -0,0 +1,174 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) + +#include +using boost::unordered_set; + +#else + +#include +using std::unordered_set; + +#endif + +template struct hasher +{ + template std::size_t operator()( T const& v ) const + { + H h; + + using boost::hash2::hash_append; + hash_append( h, v ); + + using boost::hash2::get_integral_result; + return get_integral_result( h.result() ); + } +}; + +template void test_( int N ) +{ + unordered_set< K, hasher > s; + + typedef boost::chrono::steady_clock clock_type; + + clock_type::time_point t1 = clock_type::now(); + + for( int i = 0; i < N; ++i ) + { + s.insert( i ); + } + + std::size_t q = 0; + + for( int j = 0; j < 16; ++j ) + { + for( int i = N * 15 / 16; i < 4 * N; ++i ) + { + q += s.count( i ); + } + } + + clock_type::time_point t2 = clock_type::now(); + + long long ms = boost::chrono::duration_cast( t2 - t1 ).count(); + + std::size_t n = s.bucket_count(); + std::size_t m = 0; + + for( std::size_t i = 0; i < n; ++i ) + { + std::size_t k = s.bucket_size( i ); + + if( k > m ) + { + m = k; + } + } + +#if defined( _MSC_VER ) + + std::printf( "%s: n=%Iu, m=%Iu, q=%Iu, %lld ms\n", boost::core::demangle( typeid(H).name() ).c_str(), n, m, q, ms ); + +#else + + std::printf( "%s: n=%zu, m=%zu, q=%zu, %lld ms\n", boost::core::demangle( typeid(H).name() ).c_str(), n, m, q, ms ); + +#endif +} + +template void test( int N ) +{ + std::printf( "Key type `%s`:\n\n", boost::core::demangle( typeid(K).name() ).c_str() ); + + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + test_( N ); + + std::puts( "" ); +} + +class X +{ +private: + + int key_; + std::string value_; + +public: + + X( int k ): key_( k ), value_( "0123456789ABCDE" ) + { + } + + int key() const + { + return key_; + } + + std::string value() const + { + return value_; + } +}; + +inline bool operator==( X const & x1, X const & x2 ) +{ + return x1.key() == x2.key() && x1.value() == x2.value(); +} + +template inline void hash_append( H & h, X const & x ) +{ + using boost::hash2::hash_append; + + hash_append( h, x.key() ); + hash_append( h, x.value() ); +} + +int main() +{ +#if defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) + + std::puts( "Using boost::unordered_set for lack of :\n" ); + +#else + + std::puts( "Using std::unordered_set:\n" ); + +#endif + + int const N = 1048576; + + test( N ); + test( N ); + test( N ); +} diff --git a/include/boost/hash2/byte_type.hpp b/include/boost/hash2/byte_type.hpp new file mode 100644 index 0000000..591c4f4 --- /dev/null +++ b/include/boost/hash2/byte_type.hpp @@ -0,0 +1,17 @@ +#ifndef BOOST_HASH2_BYTE_TYPE_HPP_INCLUDED +#define BOOST_HASH2_BYTE_TYPE_HPP_INCLUDED + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +namespace boost +{ +namespace hash2 +{ + +typedef unsigned char byte_type; + +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_BYTE_TYPE_HPP_INCLUDED diff --git a/include/boost/hash2/detail/read.hpp b/include/boost/hash2/detail/read.hpp new file mode 100644 index 0000000..7e0af0a --- /dev/null +++ b/include/boost/hash2/detail/read.hpp @@ -0,0 +1,87 @@ +#ifndef BOOST_HASH2_DETAIL_READ_HPP_INCLUDED +#define BOOST_HASH2_DETAIL_READ_HPP_INCLUDED + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ +namespace detail +{ + +BOOST_FORCEINLINE boost::uint32_t read32le( byte_type const * p ) +{ +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) + + boost::uint32_t v; + std::memcpy( &v, p, sizeof(v) ); + return v; + +#else + + return + static_cast( p[0] ) + + ( static_cast( p[1] ) << 8 ) + + ( static_cast( p[2] ) << 16 ) + + ( static_cast( p[3] ) << 24 ); + +#endif +} + +BOOST_FORCEINLINE boost::uint64_t read64le( byte_type const * p ) +{ +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) + + boost::uint64_t v; + std::memcpy( &v, p, sizeof(v) ); + return v; + +#else + + return + static_cast( p[0] ) + + ( static_cast( p[1] ) << 8 ) + + ( static_cast( p[2] ) << 16 ) + + ( static_cast( p[3] ) << 24 ) + + ( static_cast( p[4] ) << 32 ) + + ( static_cast( p[5] ) << 40 ) + + ( static_cast( p[6] ) << 48 ) + + ( static_cast( p[7] ) << 56 ); + +#endif +} + +BOOST_FORCEINLINE boost::uint32_t read32be( byte_type const * p ) +{ + return + static_cast( p[3] ) + + ( static_cast( p[2] ) << 8 ) + + ( static_cast( p[1] ) << 16 ) + + ( static_cast( p[0] ) << 24 ); +} + +BOOST_FORCEINLINE boost::uint64_t read64be( byte_type const * p ) +{ + return + static_cast( p[7] ) + + ( static_cast( p[6] ) << 8 ) + + ( static_cast( p[5] ) << 16 ) + + ( static_cast( p[4] ) << 24 ) + + ( static_cast( p[3] ) << 32 ) + + ( static_cast( p[2] ) << 40 ) + + ( static_cast( p[1] ) << 48 ) + + ( static_cast( p[0] ) << 56 ); +} + +} // namespace detail +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_DETAIL_READ_HPP_INCLUDED diff --git a/include/boost/hash2/detail/rot.hpp b/include/boost/hash2/detail/rot.hpp new file mode 100644 index 0000000..b6f31ee --- /dev/null +++ b/include/boost/hash2/detail/rot.hpp @@ -0,0 +1,52 @@ +#ifndef BOOST_HASH2_DETAIL_ROT_HPP_INCLUDED +#define BOOST_HASH2_DETAIL_ROT_HPP_INCLUDED + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ +namespace detail +{ + +#if defined( _MSC_VER ) + +BOOST_FORCEINLINE boost::uint32_t rotl( boost::uint32_t v, int k ) +{ + return _rotl( v, k ); +} + +BOOST_FORCEINLINE boost::uint64_t rotl( boost::uint64_t v, int k ) +{ + return _rotl64( v, k ); +} + +#else + +// k must not be 0 +BOOST_FORCEINLINE boost::uint32_t rotl( boost::uint32_t v, int k ) +{ + return ( v << k ) + ( v >> ( 32 - k ) ); +} + +// k must not be 0 +BOOST_FORCEINLINE boost::uint64_t rotl( boost::uint64_t v, int k ) +{ + return ( v << k ) + ( v >> ( 64 - k ) ); +} + +#endif + +} // namespace detail +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_DETAIL_ROT_HPP_INCLUDED diff --git a/include/boost/hash2/detail/write.hpp b/include/boost/hash2/detail/write.hpp new file mode 100644 index 0000000..64cffb7 --- /dev/null +++ b/include/boost/hash2/detail/write.hpp @@ -0,0 +1,79 @@ +#ifndef BOOST_HASH2_DETAIL_WRITE_HPP_INCLUDED +#define BOOST_HASH2_DETAIL_WRITE_HPP_INCLUDED + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ +namespace detail +{ + +BOOST_FORCEINLINE void write32le( byte_type * p, boost::uint32_t v ) +{ +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) + + std::memcpy( p, &v, sizeof(v) ); + +#else + + p[0] = static_cast( v & 0xFF ); + p[1] = static_cast( ( v >> 8 ) & 0xFF ); + p[2] = static_cast( ( v >> 16 ) & 0xFF ); + p[3] = static_cast( ( v >> 24 ) & 0xFF ); + +#endif +} + +BOOST_FORCEINLINE void write64le( byte_type * p, boost::uint64_t v ) +{ +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) + + std::memcpy( p, &v, sizeof(v) ); + +#else + + p[0] = static_cast( v & 0xFF ); + p[1] = static_cast( ( v >> 8 ) & 0xFF ); + p[2] = static_cast( ( v >> 16 ) & 0xFF ); + p[3] = static_cast( ( v >> 24 ) & 0xFF ); + p[4] = static_cast( ( v >> 32 ) & 0xFF ); + p[5] = static_cast( ( v >> 40 ) & 0xFF ); + p[6] = static_cast( ( v >> 48 ) & 0xFF ); + p[7] = static_cast( ( v >> 56 ) & 0xFF ); + +#endif +} + +BOOST_FORCEINLINE void write32be( byte_type * p, boost::uint32_t v ) +{ + p[0] = static_cast( ( v >> 24 ) & 0xFF ); + p[1] = static_cast( ( v >> 16 ) & 0xFF ); + p[2] = static_cast( ( v >> 8 ) & 0xFF ); + p[3] = static_cast( v & 0xFF ); +} + +BOOST_FORCEINLINE void write64be( byte_type * p, boost::uint64_t v ) +{ + p[0] = static_cast( ( v >> 56 ) & 0xFF ); + p[1] = static_cast( ( v >> 48 ) & 0xFF ); + p[2] = static_cast( ( v >> 40 ) & 0xFF ); + p[3] = static_cast( ( v >> 32 ) & 0xFF ); + p[4] = static_cast( ( v >> 24 ) & 0xFF ); + p[5] = static_cast( ( v >> 16 ) & 0xFF ); + p[6] = static_cast( ( v >> 8 ) & 0xFF ); + p[7] = static_cast( v & 0xFF ); +} + +} // namespace detail +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_DETAIL_WRITE_HPP_INCLUDED diff --git a/include/boost/hash2/fnv1a.hpp b/include/boost/hash2/fnv1a.hpp new file mode 100644 index 0000000..20f4324 --- /dev/null +++ b/include/boost/hash2/fnv1a.hpp @@ -0,0 +1,123 @@ +#ifndef BOOST_HASH2_FNV1A_HPP_INCLUDED +#define BOOST_HASH2_FNV1A_HPP_INCLUDED + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// FNV-1a +// +// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function + +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ + +namespace detail +{ + +template struct fnv1a_const; + +template<> struct fnv1a_const +{ + BOOST_STATIC_CONSTEXPR boost::uint32_t basis = 0x811C9DC5ul; + BOOST_STATIC_CONSTEXPR boost::uint32_t prime = 0x01000193ul; +}; + +template<> struct fnv1a_const +{ + BOOST_STATIC_CONSTEXPR boost::uint64_t basis = 0xCBF29CE484222325ull; + BOOST_STATIC_CONSTEXPR boost::uint64_t prime = 0x00000100000001B3ull; +}; + +template class fnv1a +{ +private: + + T st_; + +public: + + typedef T result_type; + typedef T size_type; + + fnv1a(): st_( fnv1a_const::basis ) + { + } + + explicit fnv1a( byte_type const * p, std::ptrdiff_t n ): st_( fnv1a_const::basis ) + { + BOOST_ASSERT( n >= 0 ); + + if( n != 0 ) + { + update( p, n ); + } + } + + void update( byte_type const * p, std::ptrdiff_t n ) + { + BOOST_ASSERT( n >= 0 ); + + T h = st_; + + for( std::ptrdiff_t i = 0; i < n; ++i ) + { + h ^= static_cast( p[i] ); + h *= fnv1a_const::prime; + } + + st_ = h; + } + + T result() + { + T r = st_; + + // advance as if by update( "\xFF", 1 ), to allow + // multiple result() calls to generate a sequence + // of distinct values + + st_ = ( st_ ^ 0xFF ) * fnv1a_const::prime; + + return r; + } +}; + +} // namespace detail + +class fnv1a_32: public detail::fnv1a +{ +public: + + fnv1a_32(): detail::fnv1a() + { + } + + explicit fnv1a_32( byte_type const * p, std::ptrdiff_t n ): detail::fnv1a( p, n ) + { + } +}; + +class fnv1a_64: public detail::fnv1a +{ +public: + + fnv1a_64(): detail::fnv1a() + { + } + + explicit fnv1a_64( byte_type const * p, std::ptrdiff_t n ): detail::fnv1a( p, n ) + { + } +}; + +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_FNV1A_HPP_INCLUDED diff --git a/include/boost/hash2/get_integral_result.hpp b/include/boost/hash2/get_integral_result.hpp new file mode 100644 index 0000000..9819c33 --- /dev/null +++ b/include/boost/hash2/get_integral_result.hpp @@ -0,0 +1,48 @@ +#ifndef BOOST_HASH2_GET_INTEGRAL_RESULT_HPP_INCLUDED +#define BOOST_HASH2_GET_INTEGRAL_RESULT_HPP_INCLUDED + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ + +template + typename boost::enable_if_c::value && (sizeof(R) >= sizeof(T)), T>::type + get_integral_result( R const & r ) +{ + typedef typename boost::make_unsigned::type U; + return static_cast( static_cast( r ) ); +} + +template + typename boost::enable_if_c::value && sizeof(R) == 4 && sizeof(T) == 8, T>::type + get_integral_result( R const & r ) +{ + typedef typename boost::make_unsigned::type U; + return static_cast( ( static_cast( r ) << 32 ) + r ); +} + +template + T get_integral_result( boost::array const & r ) +{ + BOOST_STATIC_ASSERT( N >= 8 ); + return static_cast( detail::read64le( &r[0] ) ); +} + +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_GET_INTEGRAL_RESULT_HPP_INCLUDED diff --git a/include/boost/hash2/hash_append.hpp b/include/boost/hash2/hash_append.hpp new file mode 100644 index 0000000..2b3e025 --- /dev/null +++ b/include/boost/hash2/hash_append.hpp @@ -0,0 +1,286 @@ +#ifndef BOOST_HASH2_HASH_APPEND_HPP_INCLUDED +#define BOOST_HASH2_HASH_APPEND_HPP_INCLUDED + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// Based on +// +// Types Don't Know # +// Howard E. Hinnant, Vinnie Falco, John Bytheway +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3980.html + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) +# include +#endif +#include + +namespace boost +{ +namespace hash2 +{ + +// hash_append_range + +template + typename boost::enable_if_c< + !boost::is_same::value, void >::type + hash_append_range( H & h, It first, It last ) +{ + for( ; first != last; ++first ) + { + hash_append( h, *first ); + } +} + +template + typename boost::enable_if_c< + is_contiguously_hashable::value && + !boost::is_same::value, void >::type + hash_append_range( H & h, T * first, T * last ) +{ + hash_append_range( h, reinterpret_cast( first ), reinterpret_cast( last ) ); +} + +template + typename boost::enable_if_c< + boost::is_same::value, void >::type + hash_append_range( H & h, T * first, T * last ) +{ + h.update( first, last - first ); +} + +// hash_append_size + +template void hash_append_size( H & h, T const & v ) +{ + hash_append( h, static_cast( v ) ); +} + +// hash_append_sized_range + +namespace detail +{ + +template void hash_append_sized_range_( H & h, It first, It last, std::input_iterator_tag ) +{ + typename std::iterator_traits::difference_type m = 0; + + for( ; first != last; ++first, ++m ) + { + hash_append( h, *first ); + } + + hash_append_size( h, m ); +} + +template void hash_append_sized_range_( H & h, It first, It last, std::random_access_iterator_tag ) +{ + hash_append_range( h, first, last ); + hash_append_size( h, last - first ); +} + +} // namespace detail + +template void hash_append_sized_range( H & h, It first, It last ) +{ + detail::hash_append_sized_range_( h, first, last, typename std::iterator_traits::iterator_category() ); +} + +// hash_append + +// contiguously hashable (this includes byte_type const&) + +template + typename boost::enable_if_c< + is_contiguously_hashable::value, void >::type + hash_append( H & h, T const & v ) +{ + byte_type const * p = reinterpret_cast( &v ); + hash_append_range( h, p, p + sizeof(T) ); +} + +// floating point + +template + typename boost::enable_if_c< is_floating_point::value, void >::type + hash_append( H & h, T const & v ) +{ + T w = v == 0? 0: v; + + byte_type const * p = reinterpret_cast( &w ); + hash_append_range( h, p, p + sizeof(T) ); +} + +// C arrays + +template void hash_append( H & h, T const (&v)[ N ] ) +{ + hash_append_range( h, v + 0, v + N ); +} + +// containers and ranges, w/ size + +template + typename boost::enable_if_c< is_range::value && !is_tuple_like::value && !is_unordered_range::value, void >::type + hash_append( H & h, T const & v ) +{ + hash_append_sized_range( h, v.begin(), v.end() ); +} + +// std::array (both range and tuple-like) + +template + typename boost::enable_if_c< is_range::value && is_tuple_like::value, void >::type + hash_append( H & h, T const & v ) +{ + hash_append_range( h, v.begin(), v.end() ); +} + +// unordered containers (is_unordered_range implies is_range) + +namespace detail +{ + +template void hash_append_unordered_range_( H & h, It first, It last ) +{ + typename std::iterator_traits::difference_type m = 0; + + boost::uint64_t w = 0; + + for( ; first != last; ++first, ++m ) + { + H h2( h ); + + hash_append( h2, *first ); + + w += get_integral_result( h2.result() ); + } + + hash_append( h, w ); + hash_append_size( h, m ); +} + +} // namespace detail + +template + typename boost::enable_if_c< is_unordered_range::value, void >::type + hash_append( H & h, T const & v ) +{ + detail::hash_append_unordered_range_( h, v.begin(), v.end() ); +} + +// tuple-likes + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + +namespace detail +{ + +template void hash_append_tuple( H & h, T const& v, boost::mp11::integer_sequence ) +{ + using std::get; + int a[] = { ((void)hash_append( h, get(v) ), 0)... }; + (void)a; +} + +template void hash_append_tuple( H & /*h*/, T const& /*v*/, boost::mp11::integer_sequence ) +{ +} + +} // namespace detail + +template + typename boost::enable_if_c< !is_range::value && is_tuple_like::value, void >::type + hash_append( H & h, T const & v ) +{ + typedef boost::mp11::make_index_sequence::value> seq; + detail::hash_append_tuple( h, v, seq() ); +} + +#else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + +template void hash_append( H & h, std::pair const & v ) +{ + hash_append( h, v.first ); + hash_append( h, v.second ); +} + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) + +} // namespace hash2 +} // namespace boost + +#include + +template void hash_append( H & /*h*/, std::tuple<> const & /*v*/ ) +{ +} + +template void hash_append( H & h, std::tuple const & v ) +{ + hash_append( h, std::get<0>(v) ); +} + +template void hash_append( H & h, std::tuple const & v ) +{ + hash_append( h, std::get<0>(v) ); + hash_append( h, std::get<1>(v) ); +} + +template void hash_append( H & h, std::tuple const & v ) +{ + hash_append( h, std::get<0>(v) ); + hash_append( h, std::get<1>(v) ); + hash_append( h, std::get<2>(v) ); +} + +template void hash_append( H & h, std::tuple const & v ) +{ + hash_append( h, std::get<0>(v) ); + hash_append( h, std::get<1>(v) ); + hash_append( h, std::get<2>(v) ); + hash_append( h, std::get<3>(v) ); +} + +template void hash_append( H & h, std::tuple const & v ) +{ + hash_append( h, std::get<0>(v) ); + hash_append( h, std::get<1>(v) ); + hash_append( h, std::get<2>(v) ); + hash_append( h, std::get<3>(v) ); + hash_append( h, std::get<4>(v) ); +} + +template void hash_append( H & h, std::tuple const & v ) +{ + hash_append( h, std::get<0>(v) ); + hash_append( h, std::get<1>(v) ); + hash_append( h, std::get<2>(v) ); + hash_append( h, std::get<3>(v) ); + hash_append( h, std::get<4>(v) ); + hash_append( h, std::get<5>(v) ); +} + +namespace boost +{ +namespace hash2 +{ + +#endif // !defined(BOOST_NO_CXX11_HDR_TUPLE) + +#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) + +} // namespace hash2 +} // namespace boost + +#endif diff --git a/include/boost/hash2/hmac.hpp b/include/boost/hash2/hmac.hpp new file mode 100644 index 0000000..94dcfba --- /dev/null +++ b/include/boost/hash2/hmac.hpp @@ -0,0 +1,108 @@ +#ifndef BOOST_HASH2_HMAC_HPP_INCLUDED +#define BOOST_HASH2_HMAC_HPP_INCLUDED + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// HMAC message authentication algorithm, https://tools.ietf.org/html/rfc2104 + +#include +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ + +template class hmac +{ +public: + + typedef typename H::result_type result_type; + typedef typename H::size_type size_type; + + static const int block_size = H::block_size; + +private: + + H outer_; + H inner_; + +private: + + void init( byte_type const * p, std::ptrdiff_t n ) + { + int const m = block_size; + + byte_type key[ m ] = {}; + + if( n == 0 ) + { + // memcpy from (NULL, 0) is undefined + } + else if( n <= m ) + { + std::memcpy( key, p, n ); + } + else + { + H h; + + h.update( p, n ); + + result_type r = h.result(); + + std::memcpy( key, &r[0], r.size() ); + } + + for( int i = 0; i < m; ++i ) + { + key[ i ] = static_cast( key[ i ] ^ 0x36 ); + } + + inner_.update( key, m ); + + for( int i = 0; i < m; ++i ) + { + key[ i ] = static_cast( key[ i ] ^ 0x36 ^ 0x5C ); + } + + outer_.update( key, m ); + } + +public: + + hmac() + { + init( 0, 0 ); + } + + explicit hmac( byte_type const * p, std::ptrdiff_t n ) + { + BOOST_ASSERT( n >= 0 ); + init( p, n ); + } + + void update( byte_type const * p, std::ptrdiff_t n ) + { + BOOST_ASSERT( n >= 0 ); + inner_.update( p, n ); + } + + result_type result() + { + result_type r = inner_.result(); + + outer_.update( &r[0], r.size() ); + + return outer_.result(); + } +}; + +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_HMAC_HPP_INCLUDED diff --git a/include/boost/hash2/is_contiguously_hashable.hpp b/include/boost/hash2/is_contiguously_hashable.hpp new file mode 100644 index 0000000..76e5403 --- /dev/null +++ b/include/boost/hash2/is_contiguously_hashable.hpp @@ -0,0 +1,40 @@ +#ifndef BOOST_HASH2_IS_CONTIGUOUSLY_HASHABLE_HPP_INCLUDED +#define BOOST_HASH2_IS_CONTIGUOUSLY_HASHABLE_HPP_INCLUDED + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ + +template struct is_contiguously_hashable: + integral_constant< bool, is_integral::value || is_enum::value || is_pointer::value > +{ +}; + +template struct is_contiguously_hashable: + is_contiguously_hashable +{ +}; + +template struct is_contiguously_hashable: + is_contiguously_hashable +{ +}; + +template struct is_contiguously_hashable: + is_contiguously_hashable +{ +}; + +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_IS_CONTIGUOUSLY_HASHABLE_HPP_INCLUDED diff --git a/include/boost/hash2/is_range.hpp b/include/boost/hash2/is_range.hpp new file mode 100644 index 0000000..d47c652 --- /dev/null +++ b/include/boost/hash2/is_range.hpp @@ -0,0 +1,65 @@ + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#ifndef BOOST_HASH2_IS_RANGE_HPP_INCLUDED +#define BOOST_HASH2_IS_RANGE_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ + +#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) + +namespace detail +{ + +template true_type is_range_check( It first, It last, typename std::iterator_traits::difference_type* = 0 ); + +template decltype( is_range_check( declval().begin(), declval().end() ) ) is_range_( int ); +template false_type is_range_( ... ); + +} // namespace detail + +template struct is_range: decltype( detail::is_range_( 0 ) ) +{ +}; + +#else + +namespace detail +{ + +template struct is_range_: false_type +{ +}; + +template struct is_range_< T, integral_constant< bool, + is_same::value_type>::value && + is_same::value_type>::value && + is_integral::value + > >: true_type +{ +}; + +} // namespace detail + +template struct is_range: detail::is_range_ +{ +}; + +#endif // !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_SFINAE_EXPR) + +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_IS_RANGE_HPP_INCLUDED diff --git a/include/boost/hash2/is_tuple_like.hpp b/include/boost/hash2/is_tuple_like.hpp new file mode 100644 index 0000000..f72d930 --- /dev/null +++ b/include/boost/hash2/is_tuple_like.hpp @@ -0,0 +1,130 @@ +#ifndef BOOST_HASH2_IS_TUPLE_LIKE_HPP_INCLUDED +#define BOOST_HASH2_IS_TUPLE_LIKE_HPP_INCLUDED + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) && !BOOST_WORKAROUND(BOOST_MSVC, == 1800) + +namespace boost +{ +namespace hash2 +{ + +namespace detail +{ + +template struct is_tuple_like_: false_type +{ +}; + +template struct is_tuple_like_::value == std::tuple_size::value> >: true_type +{ +}; + +} // namespace detail + +template struct is_tuple_like: detail::is_tuple_like_::type> +{ +}; + +} // namespace hash2 +} // namespace boost + +#else + +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) +# include +#endif + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) +# include +#endif + +namespace boost +{ +namespace hash2 +{ + +template struct is_tuple_like: false_type +{ +}; + +template struct is_tuple_like: is_tuple_like +{ +}; + +template struct is_tuple_like< std::pair >: true_type +{ +}; + +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) + +template struct is_tuple_like< std::array >: true_type +{ +}; + +#endif // !defined(BOOST_NO_CXX11_HDR_ARRAY) + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +template struct is_tuple_like< std::tuple >: true_type +{ +}; + +#else + +template<> struct is_tuple_like< std::tuple<> >: true_type +{ +}; + +template struct is_tuple_like< std::tuple >: true_type +{ +}; + +template struct is_tuple_like< std::tuple >: true_type +{ +}; + +template struct is_tuple_like< std::tuple >: true_type +{ +}; + +template struct is_tuple_like< std::tuple >: true_type +{ +}; + +template struct is_tuple_like< std::tuple >: true_type +{ +}; + +template struct is_tuple_like< std::tuple >: true_type +{ +}; + +template struct is_tuple_like< std::tuple >: true_type +{ +}; + +template struct is_tuple_like< std::tuple >: true_type +{ +}; + +#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#endif // !defined(BOOST_NO_CXX11_HDR_TUPLE) + +} // namespace hash2 +} // namespace boost + +#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_HDR_TUPLE) && !BOOST_WORKAROUND(BOOST_MSVC, == 1800) + +#endif // #ifndef BOOST_HASH2_IS_TUPLE_LIKE_HPP_INCLUDED diff --git a/include/boost/hash2/is_unordered_range.hpp b/include/boost/hash2/is_unordered_range.hpp new file mode 100644 index 0000000..cc0cd3b --- /dev/null +++ b/include/boost/hash2/is_unordered_range.hpp @@ -0,0 +1,39 @@ + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#ifndef BOOST_HASH2_IS_UNORDERED_RANGE_HPP_INCLUDED +#define BOOST_HASH2_IS_UNORDERED_RANGE_HPP_INCLUDED + +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ + +namespace detail +{ + +template struct has_hasher_: false_type +{ +}; + +template struct has_hasher_< T, integral_constant< bool, + is_same::value + > >: true_type +{ +}; + +} // namespace detail + +template struct is_unordered_range: integral_constant< bool, is_range::value && detail::has_hasher_::value > +{ +}; + +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_IS_UNORDERED_RANGE_HPP_INCLUDED diff --git a/include/boost/hash2/md5.hpp b/include/boost/hash2/md5.hpp new file mode 100644 index 0000000..f0a236a --- /dev/null +++ b/include/boost/hash2/md5.hpp @@ -0,0 +1,327 @@ +#ifndef BOOST_HASH2_MD5_HPP_INCLUDED +#define BOOST_HASH2_MD5_HPP_INCLUDED + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// MD5 message digest algorithm, https://tools.ietf.org/html/rfc1321 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ + +class md5_128 +{ +private: + + boost::uint32_t state_[ 4 ]; + + static const int N = 64; + + byte_type buffer_[ N ]; + int m_; + + boost::uint64_t n_; + +private: + + static BOOST_FORCEINLINE boost::uint32_t F( boost::uint32_t x, boost::uint32_t y, boost::uint32_t z ) + { + return (x & y) | (~x & z); + } + + static BOOST_FORCEINLINE boost::uint32_t G( boost::uint32_t x, boost::uint32_t y, boost::uint32_t z ) + { + return (x & z) | (y & ~z); + } + + static BOOST_FORCEINLINE boost::uint32_t H( boost::uint32_t x, boost::uint32_t y, boost::uint32_t z ) + { + return x ^ y ^ z; + } + + static BOOST_FORCEINLINE boost::uint32_t I( boost::uint32_t x, boost::uint32_t y, boost::uint32_t z ) + { + return y ^ (x | ~z); + } + + static BOOST_FORCEINLINE void FF( boost::uint32_t & a, boost::uint32_t b, boost::uint32_t c, boost::uint32_t d, boost::uint32_t x, int s, boost::uint32_t ac ) + { + a += F( b, c, d ) + x + ac; + a = detail::rotl( a, s ); + a += b; + } + + static BOOST_FORCEINLINE void GG( boost::uint32_t & a, boost::uint32_t b, boost::uint32_t c, boost::uint32_t d, boost::uint32_t x, int s, boost::uint32_t ac ) + { + a += G( b, c, d ) + x + ac; + a = detail::rotl( a, s ); + a += b; + } + + static BOOST_FORCEINLINE void HH( boost::uint32_t & a, boost::uint32_t b, boost::uint32_t c, boost::uint32_t d, boost::uint32_t x, int s, boost::uint32_t ac ) + { + a += H( b, c, d ) + x + ac; + a = detail::rotl( a, s ); + a += b; + } + + static BOOST_FORCEINLINE void II( boost::uint32_t & a, boost::uint32_t b, boost::uint32_t c, boost::uint32_t d, boost::uint32_t x, int s, boost::uint32_t ac ) + { + a += I( b, c, d ) + x + ac; + a = detail::rotl( a, s ); + a += b; + } + + void init() + { + state_[ 0 ] = 0x67452301u; + state_[ 1 ] = 0xefcdab89u; + state_[ 2 ] = 0x98badcfeu; + state_[ 3 ] = 0x10325476u; + } + + static const int S11 = 7; + static const int S12 = 12; + static const int S13 = 17; + static const int S14 = 22; + static const int S21 = 5; + static const int S22 = 9; + static const int S23 = 14; + static const int S24 = 20; + static const int S31 = 4; + static const int S32 = 11; + static const int S33 = 16; + static const int S34 = 23; + static const int S41 = 6; + static const int S42 = 10; + static const int S43 = 15; + static const int S44 = 21; + + void transform( byte_type const block[ 64 ] ) + { + boost::uint32_t a = state_[ 0 ]; + boost::uint32_t b = state_[ 1 ]; + boost::uint32_t c = state_[ 2 ]; + boost::uint32_t d = state_[ 3 ]; + + boost::uint32_t x[ 16 ]; + + for( int i = 0; i < 16; ++i ) + { + x[ i ] = detail::read32le( block + i * 4 ); + } + + FF( a, b, c, d, x[ 0], S11, 0xd76aa478 ); + FF( d, a, b, c, x[ 1], S12, 0xe8c7b756 ); + FF( c, d, a, b, x[ 2], S13, 0x242070db ); + FF( b, c, d, a, x[ 3], S14, 0xc1bdceee ); + FF( a, b, c, d, x[ 4], S11, 0xf57c0faf ); + FF( d, a, b, c, x[ 5], S12, 0x4787c62a ); + FF( c, d, a, b, x[ 6], S13, 0xa8304613 ); + FF( b, c, d, a, x[ 7], S14, 0xfd469501 ); + FF( a, b, c, d, x[ 8], S11, 0x698098d8 ); + FF( d, a, b, c, x[ 9], S12, 0x8b44f7af ); + FF( c, d, a, b, x[10], S13, 0xffff5bb1 ); + FF( b, c, d, a, x[11], S14, 0x895cd7be ); + FF( a, b, c, d, x[12], S11, 0x6b901122 ); + FF( d, a, b, c, x[13], S12, 0xfd987193 ); + FF( c, d, a, b, x[14], S13, 0xa679438e ); + FF( b, c, d, a, x[15], S14, 0x49b40821 ); + + GG( a, b, c, d, x[ 1], S21, 0xf61e2562 ); + GG( d, a, b, c, x[ 6], S22, 0xc040b340 ); + GG( c, d, a, b, x[11], S23, 0x265e5a51 ); + GG( b, c, d, a, x[ 0], S24, 0xe9b6c7aa ); + GG( a, b, c, d, x[ 5], S21, 0xd62f105d ); + GG( d, a, b, c, x[10], S22, 0x2441453 ); + GG( c, d, a, b, x[15], S23, 0xd8a1e681 ); + GG( b, c, d, a, x[ 4], S24, 0xe7d3fbc8 ); + GG( a, b, c, d, x[ 9], S21, 0x21e1cde6 ); + GG( d, a, b, c, x[14], S22, 0xc33707d6 ); + GG( c, d, a, b, x[ 3], S23, 0xf4d50d87 ); + GG( b, c, d, a, x[ 8], S24, 0x455a14ed ); + GG( a, b, c, d, x[13], S21, 0xa9e3e905 ); + GG( d, a, b, c, x[ 2], S22, 0xfcefa3f8 ); + GG( c, d, a, b, x[ 7], S23, 0x676f02d9 ); + GG( b, c, d, a, x[12], S24, 0x8d2a4c8a ); + + HH( a, b, c, d, x[ 5], S31, 0xfffa3942 ); + HH( d, a, b, c, x[ 8], S32, 0x8771f681 ); + HH( c, d, a, b, x[11], S33, 0x6d9d6122 ); + HH( b, c, d, a, x[14], S34, 0xfde5380c ); + HH( a, b, c, d, x[ 1], S31, 0xa4beea44 ); + HH( d, a, b, c, x[ 4], S32, 0x4bdecfa9 ); + HH( c, d, a, b, x[ 7], S33, 0xf6bb4b60 ); + HH( b, c, d, a, x[10], S34, 0xbebfbc70 ); + HH( a, b, c, d, x[13], S31, 0x289b7ec6 ); + HH( d, a, b, c, x[ 0], S32, 0xeaa127fa ); + HH( c, d, a, b, x[ 3], S33, 0xd4ef3085 ); + HH( b, c, d, a, x[ 6], S34, 0x4881d05 ); + HH( a, b, c, d, x[ 9], S31, 0xd9d4d039 ); + HH( d, a, b, c, x[12], S32, 0xe6db99e5 ); + HH( c, d, a, b, x[15], S33, 0x1fa27cf8 ); + HH( b, c, d, a, x[ 2], S34, 0xc4ac5665 ); + + II( a, b, c, d, x[ 0], S41, 0xf4292244 ); + II( d, a, b, c, x[ 7], S42, 0x432aff97 ); + II( c, d, a, b, x[14], S43, 0xab9423a7 ); + II( b, c, d, a, x[ 5], S44, 0xfc93a039 ); + II( a, b, c, d, x[12], S41, 0x655b59c3 ); + II( d, a, b, c, x[ 3], S42, 0x8f0ccc92 ); + II( c, d, a, b, x[10], S43, 0xffeff47d ); + II( b, c, d, a, x[ 1], S44, 0x85845dd1 ); + II( a, b, c, d, x[ 8], S41, 0x6fa87e4f ); + II( d, a, b, c, x[15], S42, 0xfe2ce6e0 ); + II( c, d, a, b, x[ 6], S43, 0xa3014314 ); + II( b, c, d, a, x[13], S44, 0x4e0811a1 ); + II( a, b, c, d, x[ 4], S41, 0xf7537e82 ); + II( d, a, b, c, x[11], S42, 0xbd3af235 ); + II( c, d, a, b, x[ 2], S43, 0x2ad7d2bb ); + II( b, c, d, a, x[ 9], S44, 0xeb86d391 ); + + state_[ 0 ] += a; + state_[ 1 ] += b; + state_[ 2 ] += c; + state_[ 3 ] += d; + } + +public: + + typedef boost::array result_type; + typedef boost::uint64_t size_type; + + static const int block_size = 64; + + md5_128(): m_( 0 ), n_( 0 ) + { + init(); + } + + explicit md5_128( byte_type const * p, std::ptrdiff_t n ): m_( 0 ), n_( 0 ) + { + BOOST_ASSERT( n >= 0 ); + + init(); + + if( n != 0 ) + { + update( p, n ); + result(); + } + } + + void update( byte_type const * p, std::ptrdiff_t n ) + { + BOOST_ASSERT( n >= 0 ); + + BOOST_ASSERT( m_ == static_cast( n_ & (N-1) ) ); + + if( n == 0 ) return; + + n_ += n; + + if( m_ > 0 ) + { + int k = N - m_; + + if( n < k ) + { + k = static_cast( n ); + } + + std::memcpy( buffer_ + m_, p, k ); + + p += k; + n -= k; + m_ += k; + + if( m_ < N ) return; + + BOOST_ASSERT( m_ == N ); + + transform( buffer_ ); + m_ = 0; + + std::memset( buffer_, 0, N ); + } + + BOOST_ASSERT( m_ == 0 ); + + while( n >= N ) + { + transform( p ); + + p += N; + n -= N; + } + + BOOST_ASSERT( n < N ); + + if( n > 0 ) + { + std::memcpy( buffer_, p, n ); + m_ = static_cast( n ); + } + + BOOST_ASSERT( m_ == static_cast( n_ & (N-1) ) ); + } + + result_type result() + { + BOOST_ASSERT( m_ == static_cast( n_ & (N-1) ) ); + + byte_type bits[ 8 ]; + + detail::write64le( bits, n_ * 8 ); + + int k = m_ < 56? 56 - m_: 120 - m_; + + byte_type padding[ 64 ] = { 0x80 }; + + update( padding, k ); + + update( bits, 8 ); + + BOOST_ASSERT( m_ == 0 ); + + result_type digest; + + for( int i = 0; i < 4; ++i ) + { + detail::write32le( &digest[ i * 4 ], state_[ i ] ); + } + + return digest; + } +}; + +class hmac_md5_128: public hmac +{ +public: + + hmac_md5_128() + { + } + + explicit hmac_md5_128( byte_type const * p, std::ptrdiff_t n ): hmac( p, n ) + { + } +}; + +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_MD5_HPP_INCLUDED diff --git a/include/boost/hash2/murmur3.hpp b/include/boost/hash2/murmur3.hpp new file mode 100644 index 0000000..218d6b4 --- /dev/null +++ b/include/boost/hash2/murmur3.hpp @@ -0,0 +1,381 @@ +#ifndef BOOST_HASH2_MURMUR3_HPP_INCLUDED +#define BOOST_HASH2_MURMUR3_HPP_INCLUDED + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// MurmurHash3, https://github.com/aappleby/smhasher/wiki/MurmurHash3 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ + +class murmur3_32 +{ +private: + + boost::uint32_t h_; + + byte_type buffer_[ 4 ]; + int m_; + + std::size_t n_; + +private: + + static const boost::uint32_t c1 = 0xcc9e2d51u; + static const boost::uint32_t c2 = 0x1b873593u; + +private: + + void update_( byte_type const * p, std::ptrdiff_t m ) + { + boost::uint32_t h = h_; + + for( std::ptrdiff_t i = 0; i < m; ++i, p += 4 ) + { + boost::uint32_t k = detail::read32le( p ); + + k *= c1; + k = detail::rotl( k, 15 ); + k *= c2; + + h ^= k; + h = detail::rotl( h, 13 ); + h = h * 5 + 0xe6546b64; + } + + h_ = h; + } + +public: + + typedef boost::uint32_t result_type; + typedef boost::uint32_t size_type; + + explicit murmur3_32( boost::uint32_t seed = 0 ): m_( 0 ), n_( 0 ) + { + h_ = seed; + } + + explicit murmur3_32( byte_type const * p, std::ptrdiff_t n ): m_( 0 ), n_( 0 ) + { + BOOST_ASSERT( n >= 0 ); + + if( n <= 4 ) + { + byte_type q[ 4 ] = {}; + std::memcpy( q, p, n ); + + h_ = detail::read32le( q ); + } + else + { + h_ = detail::read32le( p ); + + p += 4; + n -= 4; + + update( p, n ); + result(); + } + } + + void update( byte_type const * p, std::ptrdiff_t n ) + { + BOOST_ASSERT( n >= 0 ); + + BOOST_ASSERT( m_ == static_cast( n_ & 3 ) ); + + if( n == 0 ) return; + + n_ += n; + + if( m_ > 0 ) + { + int k = 4 - m_; + + if( n < k ) + { + k = static_cast( n ); + } + + std::memcpy( buffer_ + m_, p, k ); + + p += k; + n -= k; + m_ += k; + + if( m_ < 4 ) return; + + BOOST_ASSERT( m_ == 4 ); + + update_( buffer_, 1 ); + m_ = 0; + } + + BOOST_ASSERT( m_ == 0 ); + + { + std::ptrdiff_t k = n / 4; + + update_( p, k ); + + p += 4 * k; + n -= 4 * k; + } + + BOOST_ASSERT( n < 4 ); + + if( n > 0 ) + { + std::memcpy( buffer_, p, n ); + m_ = static_cast( n ); + } + + BOOST_ASSERT( m_ == static_cast( n_ & 3 ) ); + } + + boost::uint32_t result() + { + BOOST_ASSERT( m_ == static_cast( n_ & 3 ) ); + + std::memset( buffer_ + m_, 0, 4 - m_ ); + + boost::uint32_t k = detail::read32le( buffer_ ); + + k *= c1; + k = detail::rotl( k, 15 ); + k *= c2; + + boost::uint32_t h = h_; + + h ^= k; + h ^= static_cast( n_ ); + + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + n_ += 4 - m_; + m_ = 0; + + // clear buffered plaintext + std::memset( buffer_, 0, 4 ); + + return h; + } +}; + +class murmur3_128 +{ +private: + + boost::uint64_t h1_, h2_; + + byte_type buffer_[ 16 ]; + int m_; + + std::size_t n_; + +private: + + static const boost::uint64_t c1 = 0x87c37b91114253d5ull; + static const boost::uint64_t c2 = 0x4cf5ad432745937full; + +private: + + void update_( byte_type const * p, std::ptrdiff_t k ) + { + boost::uint64_t h1 = h1_, h2 = h2_; + + for( std::ptrdiff_t i = 0; i < k; ++i, p += 16 ) + { + boost::uint64_t k1 = detail::read64le( p + 0 ); + boost::uint64_t k2 = detail::read64le( p + 8 ); + + k1 *= c1; k1 = detail::rotl( k1, 31 ); k1 *= c2; h1 ^= k1; + + h1 = detail::rotl( h1, 27 ); h1 += h2; h1 = h1 * 5 + 0x52dce729; + + k2 *= c2; k2 = detail::rotl( k2, 33 ); k2 *= c1; h2 ^= k2; + + h2 = detail::rotl( h2, 31 ); h2 += h1; h2 = h2 * 5 + 0x38495ab5; + } + + h1_ = h1; h2_ = h2; + } + + static boost::uint64_t fmix( boost::uint64_t k ) + { + k ^= k >> 33; + k *= 0xff51afd7ed558ccdull; + k ^= k >> 33; + k *= 0xc4ceb9fe1a85ec53ull; + k ^= k >> 33; + + return k; + } + +public: + + typedef boost::array result_type; + typedef boost::uint64_t size_type; + + explicit murmur3_128( boost::uint64_t seed = 0 ): m_( 0 ), n_( 0 ) + { + h1_ = seed; + h2_ = seed; + } + + explicit murmur3_128( boost::uint64_t seed1, boost::uint64_t seed2 ): m_( 0 ), n_( 0 ) + { + h1_ = seed1; + h2_ = seed2; + } + + explicit murmur3_128( byte_type const * p, std::ptrdiff_t n ): m_( 0 ), n_( 0 ) + { + BOOST_ASSERT( n >= 0 ); + + if( n <= 8 ) + { + byte_type q[ 8 ] = {}; + std::memcpy( q, p, n ); + + h1_ = h2_ = detail::read64le( q ); + } + else if( n <= 16 ) + { + byte_type q[ 18 ] = {}; + std::memcpy( q, p, n ); + + h1_ = detail::read64le( q + 0 ); + h2_ = detail::read64le( q + 8 ); + } + else + { + h1_ = detail::read64le( p + 0 ); + h2_ = detail::read64le( p + 8 ); + + p += 16; + n -= 16; + + update( p, n ); + result(); + } + } + + void update( byte_type const * p, std::ptrdiff_t n ) + { + BOOST_ASSERT( n >= 0 ); + + BOOST_ASSERT( m_ == static_cast( n_ & 15 ) ); + + if( n == 0 ) return; + + n_ += n; + + if( m_ > 0 ) + { + int k = 16 - m_; + + if( n < k ) + { + k = static_cast( n ); + } + + std::memcpy( buffer_ + m_, p, k ); + + p += k; + n -= k; + m_ += k; + + if( m_ < 16 ) return; + + BOOST_ASSERT( m_ == 16 ); + + update_( buffer_, 1 ); + m_ = 0; + } + + BOOST_ASSERT( m_ == 0 ); + + { + std::ptrdiff_t k = n / 16; + + update_( p, k ); + + p += 16 * k; + n -= 16 * k; + } + + BOOST_ASSERT( n < 16 ); + + if( n > 0 ) + { + std::memcpy( buffer_, p, n ); + m_ = static_cast( n ); + } + + BOOST_ASSERT( m_ == static_cast( n_ & 15 ) ); + } + + result_type result() + { + BOOST_ASSERT( m_ == static_cast( n_ & 15 ) ); + + std::memset( buffer_ + m_, 0, 16 - m_ ); + + boost::uint64_t h1 = h1_, h2 = h2_; + + boost::uint64_t k1 = detail::read64le( buffer_ + 0 ); + boost::uint64_t k2 = detail::read64le( buffer_ + 8 ); + + k1 *= c1; k1 = detail::rotl( k1, 31 ); k1 *= c2; h1 ^= k1; + k2 *= c2; k2 = detail::rotl( k2, 33 ); k2 *= c1; h2 ^= k2; + + h1 ^= n_; + h2 ^= n_; + + h1 += h2; + h2 += h1; + + h1 = fmix( h1 ); + h2 = fmix( h2 ); + + h1 += h2; + h2 += h1; + + n_ += 16 - m_; + m_ = 0; + + // clear buffered plaintext + std::memset( buffer_, 0, 16 ); + + result_type r; + + detail::write64le( &r[ 0 ], h1 ); + detail::write64le( &r[ 8 ], h2 ); + + return r; + } +}; + +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_MURMUR3_HPP_INCLUDED diff --git a/include/boost/hash2/sha1.hpp b/include/boost/hash2/sha1.hpp new file mode 100644 index 0000000..0f64a92 --- /dev/null +++ b/include/boost/hash2/sha1.hpp @@ -0,0 +1,324 @@ +#ifndef BOOST_HASH2_SHA1_HPP_INCLUDED +#define BOOST_HASH2_SHA1_HPP_INCLUDED + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// SHA1 message digest algorithm, https://tools.ietf.org/html/rfc3174 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ + +class sha1_160 +{ +private: + + boost::uint32_t state_[ 5 ]; + + static const int N = 64; + + byte_type buffer_[ N ]; + int m_; + + boost::uint64_t n_; + +private: + + void init() + { + state_[ 0 ] = 0x67452301u; + state_[ 1 ] = 0xefcdab89u; + state_[ 2 ] = 0x98badcfeu; + state_[ 3 ] = 0x10325476u; + state_[ 4 ] = 0xc3d2e1f0u; + } + + static BOOST_FORCEINLINE void R1( boost::uint32_t a, boost::uint32_t & b, boost::uint32_t c, boost::uint32_t d, boost::uint32_t & e, boost::uint32_t w[], byte_type const block[ 64 ], int i ) + { + w[ i ] = detail::read32be( block + i * 4 ); + + boost::uint32_t f = (b & c) | (~b & d); + + e += detail::rotl( a, 5 ) + f + 0x5A827999 + w[ i ]; + b = detail::rotl( b, 30 ); + } + + static BOOST_FORCEINLINE boost::uint32_t W( boost::uint32_t w[], int i ) + { + return w[ i ] = detail::rotl( w[ i - 3 ] ^ w[ i - 8 ] ^ w[ i - 14 ] ^ w[ i - 16 ], 1 ); + } + + static BOOST_FORCEINLINE void R2( boost::uint32_t a, boost::uint32_t & b, boost::uint32_t c, boost::uint32_t d, boost::uint32_t & e, boost::uint32_t w[], int i ) + { + boost::uint32_t f = (b & c) | (~b & d); + + e += detail::rotl( a, 5 ) + f + 0x5A827999 + W( w, i ); + b = detail::rotl( b, 30 ); + } + + static BOOST_FORCEINLINE void R3( boost::uint32_t a, boost::uint32_t & b, boost::uint32_t c, boost::uint32_t d, boost::uint32_t & e, boost::uint32_t w[], int i ) + { + boost::uint32_t f = b ^ c ^ d; + + e += detail::rotl( a, 5 ) + f + 0x6ED9EBA1 + W( w, i ); + b = detail::rotl( b, 30 ); + } + + static BOOST_FORCEINLINE void R4( boost::uint32_t a, boost::uint32_t & b, boost::uint32_t c, boost::uint32_t d, boost::uint32_t & e, boost::uint32_t w[], int i ) + { + boost::uint32_t f = (b & c) | (b & d) | (c & d); + + e += detail::rotl( a, 5 ) + f + 0x8F1BBCDC + W( w, i ); + b = detail::rotl( b, 30 ); + } + + static BOOST_FORCEINLINE void R5( boost::uint32_t a, boost::uint32_t & b, boost::uint32_t c, boost::uint32_t d, boost::uint32_t & e, boost::uint32_t w[], int i ) + { + boost::uint32_t f = b ^ c ^ d; + + e += detail::rotl( a, 5 ) + f + 0xCA62C1D6 + W( w, i ); + b = detail::rotl( b, 30 ); + } + + void transform( byte_type const block[ 64 ] ) + { + boost::uint32_t a = state_[ 0 ]; + boost::uint32_t b = state_[ 1 ]; + boost::uint32_t c = state_[ 2 ]; + boost::uint32_t d = state_[ 3 ]; + boost::uint32_t e = state_[ 4 ]; + + boost::uint32_t w[ 80 ]; + + R1( a, b, c, d, e, w, block, 0 ); + R1( e, a, b, c, d, w, block, 1 ); + R1( d, e, a, b, c, w, block, 2 ); + R1( c, d, e, a, b, w, block, 3 ); + R1( b, c, d, e, a, w, block, 4 ); + R1( a, b, c, d, e, w, block, 5 ); + R1( e, a, b, c, d, w, block, 6 ); + R1( d, e, a, b, c, w, block, 7 ); + R1( c, d, e, a, b, w, block, 8 ); + R1( b, c, d, e, a, w, block, 9 ); + R1( a, b, c, d, e, w, block, 10 ); + R1( e, a, b, c, d, w, block, 11 ); + R1( d, e, a, b, c, w, block, 12 ); + R1( c, d, e, a, b, w, block, 13 ); + R1( b, c, d, e, a, w, block, 14 ); + R1( a, b, c, d, e, w, block, 15 ); + + R2( e, a, b, c, d, w, 16 ); + R2( d, e, a, b, c, w, 17 ); + R2( c, d, e, a, b, w, 18 ); + R2( b, c, d, e, a, w, 19 ); + + R3( a, b, c, d, e, w, 20 ); + R3( e, a, b, c, d, w, 21 ); + R3( d, e, a, b, c, w, 22 ); + R3( c, d, e, a, b, w, 23 ); + R3( b, c, d, e, a, w, 24 ); + R3( a, b, c, d, e, w, 25 ); + R3( e, a, b, c, d, w, 26 ); + R3( d, e, a, b, c, w, 27 ); + R3( c, d, e, a, b, w, 28 ); + R3( b, c, d, e, a, w, 29 ); + R3( a, b, c, d, e, w, 30 ); + R3( e, a, b, c, d, w, 31 ); + R3( d, e, a, b, c, w, 32 ); + R3( c, d, e, a, b, w, 33 ); + R3( b, c, d, e, a, w, 34 ); + R3( a, b, c, d, e, w, 35 ); + R3( e, a, b, c, d, w, 36 ); + R3( d, e, a, b, c, w, 37 ); + R3( c, d, e, a, b, w, 38 ); + R3( b, c, d, e, a, w, 39 ); + + R4( a, b, c, d, e, w, 40 ); + R4( e, a, b, c, d, w, 41 ); + R4( d, e, a, b, c, w, 42 ); + R4( c, d, e, a, b, w, 43 ); + R4( b, c, d, e, a, w, 44 ); + R4( a, b, c, d, e, w, 45 ); + R4( e, a, b, c, d, w, 46 ); + R4( d, e, a, b, c, w, 47 ); + R4( c, d, e, a, b, w, 48 ); + R4( b, c, d, e, a, w, 49 ); + R4( a, b, c, d, e, w, 50 ); + R4( e, a, b, c, d, w, 51 ); + R4( d, e, a, b, c, w, 52 ); + R4( c, d, e, a, b, w, 53 ); + R4( b, c, d, e, a, w, 54 ); + R4( a, b, c, d, e, w, 55 ); + R4( e, a, b, c, d, w, 56 ); + R4( d, e, a, b, c, w, 57 ); + R4( c, d, e, a, b, w, 58 ); + R4( b, c, d, e, a, w, 59 ); + + R5( a, b, c, d, e, w, 60 ); + R5( e, a, b, c, d, w, 61 ); + R5( d, e, a, b, c, w, 62 ); + R5( c, d, e, a, b, w, 63 ); + R5( b, c, d, e, a, w, 64 ); + R5( a, b, c, d, e, w, 65 ); + R5( e, a, b, c, d, w, 66 ); + R5( d, e, a, b, c, w, 67 ); + R5( c, d, e, a, b, w, 68 ); + R5( b, c, d, e, a, w, 69 ); + R5( a, b, c, d, e, w, 70 ); + R5( e, a, b, c, d, w, 71 ); + R5( d, e, a, b, c, w, 72 ); + R5( c, d, e, a, b, w, 73 ); + R5( b, c, d, e, a, w, 74 ); + R5( a, b, c, d, e, w, 75 ); + R5( e, a, b, c, d, w, 76 ); + R5( d, e, a, b, c, w, 77 ); + R5( c, d, e, a, b, w, 78 ); + R5( b, c, d, e, a, w, 79 ); + + state_[ 0 ] += a; + state_[ 1 ] += b; + state_[ 2 ] += c; + state_[ 3 ] += d; + state_[ 4 ] += e; + } + +public: + + typedef boost::array result_type; + typedef boost::uint64_t size_type; + + static const int block_size = 64; + + sha1_160(): m_( 0 ), n_( 0 ) + { + init(); + } + + explicit sha1_160( byte_type const * p, std::ptrdiff_t n ): m_( 0 ), n_( 0 ) + { + BOOST_ASSERT( n >= 0 ); + + init(); + + if( n != 0 ) + { + update( p, n ); + result(); + } + } + + void update( byte_type const * p, std::ptrdiff_t n ) + { + BOOST_ASSERT( n >= 0 ); + + BOOST_ASSERT( m_ == static_cast( n_ & (N-1) ) ); + + if( n == 0 ) return; + + n_ += n; + + if( m_ > 0 ) + { + int k = N - m_; + + if( n < k ) + { + k = static_cast( n ); + } + + std::memcpy( buffer_ + m_, p, k ); + + p += k; + n -= k; + m_ += k; + + if( m_ < N ) return; + + BOOST_ASSERT( m_ == N ); + + transform( buffer_ ); + m_ = 0; + + std::memset( buffer_, 0, N ); + } + + BOOST_ASSERT( m_ == 0 ); + + while( n >= N ) + { + transform( p ); + + p += N; + n -= N; + } + + BOOST_ASSERT( n < N ); + + if( n > 0 ) + { + std::memcpy( buffer_, p, n ); + m_ = static_cast( n ); + } + + BOOST_ASSERT( m_ == static_cast( n_ & (N-1) ) ); + } + + result_type result() + { + BOOST_ASSERT( m_ == static_cast( n_ & (N-1) ) ); + + byte_type bits[ 8 ]; + + detail::write64be( bits, n_ * 8 ); + + int k = m_ < 56? 56 - m_: 120 - m_; + + byte_type padding[ 64 ] = { 0x80 }; + + update( padding, k ); + + update( bits, 8 ); + + BOOST_ASSERT( m_ == 0 ); + + result_type digest; + + for( int i = 0; i < 5; ++i ) + { + detail::write32be( &digest[ i * 4 ], state_[ i ] ); + } + + return digest; + } +}; + +class hmac_sha1_160: public hmac +{ +public: + + hmac_sha1_160() + { + } + + explicit hmac_sha1_160( byte_type const * p, std::ptrdiff_t n ): hmac( p, n ) + { + } +}; + +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_SHA1_HPP_INCLUDED diff --git a/include/boost/hash2/siphash.hpp b/include/boost/hash2/siphash.hpp new file mode 100644 index 0000000..f49df70 --- /dev/null +++ b/include/boost/hash2/siphash.hpp @@ -0,0 +1,384 @@ +#ifndef BOOST_HASH2_SIPHASH_HPP_INCLUDED +#define BOOST_HASH2_SIPHASH_HPP_INCLUDED + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// SipHash, https://131002.net/siphash/ + +#include +#include +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ + +class siphash_64 +{ +private: + + boost::uint64_t v0, v1, v2, v3; + + byte_type buffer_[ 8 ]; + int m_; + + boost::uint64_t n_; + +private: + + void sipround() + { + v0 += v1; + v1 = detail::rotl(v1, 13); + v1 ^= v0; + v0 = detail::rotl(v0, 32); + v2 += v3; + v3 = detail::rotl(v3, 16); + v3 ^= v2; + v0 += v3; + v3 = detail::rotl(v3, 21); + v3 ^= v0; + v2 += v1; + v1 = detail::rotl(v1, 17); + v1 ^= v2; + v2 = detail::rotl(v2, 32); + } + + void update_( byte_type const * p ) + { + boost::uint64_t m = detail::read64le( p ); + + v3 ^= m; + + sipround(); + sipround(); + + v0 ^= m; + } + + void init( boost::uint64_t k0, boost::uint64_t k1 ) + { + v0 = 0x736f6d6570736575ULL; + v1 = 0x646f72616e646f6dULL; + v2 = 0x6c7967656e657261ULL; + v3 = 0x7465646279746573ULL; + + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + } + +public: + + typedef boost::uint64_t result_type; + typedef boost::uint64_t size_type; + + explicit siphash_64( boost::uint64_t k0 = 0, boost::uint64_t k1 = 0 ): m_( 0 ), n_( 0 ) + { + init( k0, k1 ); + } + + explicit siphash_64( byte_type const * p, std::ptrdiff_t n ): m_( 0 ), n_( 0 ) + { + BOOST_ASSERT( n >= 0 ); + + if( n <= 16 ) + { + byte_type q[ 16 ] = { 0 }; + std::memcpy( q, p, n ); + + boost::uint64_t k0 = detail::read64le( q + 0 ); + boost::uint64_t k1 = detail::read64le( q + 8 ); + + init( k0, k1 ); + } + else + { + boost::uint64_t k0 = detail::read64le( p + 0 ); + boost::uint64_t k1 = detail::read64le( p + 8 ); + + init( k0, k1 ); + + p += 16; + n -= 16; + + update( p, n ); + + result(); + } + } + + void update( byte_type const * p, std::ptrdiff_t n ) + { + BOOST_ASSERT( n >= 0 ); + + BOOST_ASSERT( m_ == static_cast( n_ & 7 ) ); + + if( n == 0 ) return; + + n_ += n; + + if( m_ > 0 ) + { + int k = 8 - m_; + + if( n < k ) + { + k = static_cast( n ); + } + + std::memcpy( buffer_ + m_, p, k ); + + p += k; + n -= k; + m_ += k; + + if( m_ < 8 ) return; + + BOOST_ASSERT( m_ == 8 ); + + update_( buffer_ ); + m_ = 0; + + // clear buffered plaintext + std::memset( buffer_, 0, 8 ); + } + + BOOST_ASSERT( m_ == 0 ); + + while( n >= 8 ) + { + update_( p ); + + p += 8; + n -= 8; + } + + BOOST_ASSERT( n < 8 ); + + if( n > 0 ) + { + std::memcpy( buffer_, p, n ); + m_ = static_cast( n ); + } + + BOOST_ASSERT( m_ == static_cast( n_ & 7 ) ); + } + + boost::uint64_t result() + { + BOOST_ASSERT( m_ == static_cast( n_ & 7 ) ); + + std::memset( buffer_ + m_, 0, 8 - m_ ); + + buffer_[ 7 ] = static_cast( n_ & 0xFF ); + + update_( buffer_ ); + + v2 ^= 0xFF; + + sipround(); + sipround(); + sipround(); + sipround(); + + n_ += 8 - m_; + m_ = 0; + + // clear buffered plaintext + std::memset( buffer_, 0, 8 ); + + return v0 ^ v1 ^ v2 ^ v3; + } +}; + +class siphash_32 +{ +private: + + boost::uint32_t v0, v1, v2, v3; + + byte_type buffer_[ 4 ]; + int m_; + + boost::uint32_t n_; + +private: + + void sipround() + { + v0 += v1; + v1 = detail::rotl(v1, 5); + v1 ^= v0; + v0 = detail::rotl(v0, 16); + v2 += v3; + v3 = detail::rotl(v3, 8); + v3 ^= v2; + v0 += v3; + v3 = detail::rotl(v3, 7); + v3 ^= v0; + v2 += v1; + v1 = detail::rotl(v1, 13); + v1 ^= v2; + v2 = detail::rotl(v2, 16); + } + + void update_( byte_type const * p ) + { + boost::uint32_t m = detail::read32le( p ); + + v3 ^= m; + + sipround(); + sipround(); + + v0 ^= m; + } + + void init( boost::uint32_t k0, boost::uint32_t k1 ) + { + v0 = 0; + v1 = 0; + v2 = 0x6c796765; + v3 = 0x74656462; + + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + } + +public: + + typedef boost::uint32_t result_type; + typedef boost::uint32_t size_type; + + explicit siphash_32( boost::uint32_t k0 = 0, boost::uint32_t k1 = 0 ): m_( 0 ), n_( 0 ) + { + init( k0, k1 ); + } + + explicit siphash_32( byte_type const * p, std::ptrdiff_t n ): m_( 0 ), n_( 0 ) + { + BOOST_ASSERT( n >= 0 ); + + if( n <= 8 ) + { + byte_type q[ 8 ] = { 0 }; + std::memcpy( q, p, n ); + + boost::uint32_t k0 = detail::read32le( q + 0 ); + boost::uint32_t k1 = detail::read32le( q + 4 ); + + init( k0, k1 ); + } + else + { + boost::uint32_t k0 = detail::read32le( p + 0 ); + boost::uint32_t k1 = detail::read32le( p + 4 ); + + init( k0, k1 ); + + p += 8; + n -= 8; + + update( p, n ); + + result(); + } + } + + void update( byte_type const * p, std::ptrdiff_t n ) + { + BOOST_ASSERT( n >= 0 ); + + BOOST_ASSERT( m_ == static_cast( n_ & 3 ) ); + + if( n == 0 ) return; + + n_ += static_cast( n ); + + if( m_ > 0 ) + { + int k = 4 - m_; + + if( n < k ) + { + k = static_cast( n ); + } + + std::memcpy( buffer_ + m_, p, k ); + + p += k; + n -= k; + m_ += k; + + if( m_ < 4 ) return; + + BOOST_ASSERT( m_ == 4 ); + + update_( buffer_ ); + m_ = 0; + + // clear buffered plaintext + std::memset( buffer_, 0, 4 ); + } + + BOOST_ASSERT( m_ == 0 ); + + while( n >= 4 ) + { + update_( p ); + + p += 4; + n -= 4; + } + + BOOST_ASSERT( n < 4 ); + + if( n > 0 ) + { + std::memcpy( buffer_, p, n ); + m_ = static_cast( n ); + } + + BOOST_ASSERT( m_ == static_cast( n_ & 3 ) ); + } + + boost::uint32_t result() + { + BOOST_ASSERT( m_ == static_cast( n_ & 3 ) ); + + std::memset( buffer_ + m_, 0, 4 - m_ ); + + buffer_[ 3 ] = static_cast( n_ & 0xFF ); + + update_( buffer_ ); + + v2 ^= 0xFF; + + sipround(); + sipround(); + sipround(); + sipround(); + + n_ += 4 - m_; + m_ = 0; + + // clear buffered plaintext + std::memset( buffer_, 0, 4 ); + + return v1 ^ v3; + } +}; + +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_SIPHASH_HPP_INCLUDED diff --git a/include/boost/hash2/spooky2.hpp b/include/boost/hash2/spooky2.hpp new file mode 100644 index 0000000..0eaec21 --- /dev/null +++ b/include/boost/hash2/spooky2.hpp @@ -0,0 +1,409 @@ +#ifndef BOOST_HASH2_SPOOKY2_HPP_INCLUDED +#define BOOST_HASH2_SPOOKY2_HPP_INCLUDED + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// SpookyHash V2, http://burtleburtle.net/bob/hash/spooky.html + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ + +class spooky2_128 +{ +private: + + static const boost::uint64_t sc_const = 0xdeadbeefdeadbeefULL; + +private: + + static const int M = 12; + boost::uint64_t v_[ M ]; + + static const int N = 192; + byte_type buffer_[ N ]; + + int m_; + + std::size_t n_; + +private: + + static inline void short_mix( boost::uint64_t & h0, boost::uint64_t & h1, boost::uint64_t & h2, boost::uint64_t & h3 ) + { + h2 = detail::rotl( h2, 50 ); h2 += h3; h0 ^= h2; + h3 = detail::rotl( h3, 52 ); h3 += h0; h1 ^= h3; + h0 = detail::rotl( h0, 30 ); h0 += h1; h2 ^= h0; + h1 = detail::rotl( h1, 41 ); h1 += h2; h3 ^= h1; + h2 = detail::rotl( h2, 54 ); h2 += h3; h0 ^= h2; + h3 = detail::rotl( h3, 48 ); h3 += h0; h1 ^= h3; + h0 = detail::rotl( h0, 38 ); h0 += h1; h2 ^= h0; + h1 = detail::rotl( h1, 37 ); h1 += h2; h3 ^= h1; + h2 = detail::rotl( h2, 62 ); h2 += h3; h0 ^= h2; + h3 = detail::rotl( h3, 34 ); h3 += h0; h1 ^= h3; + h0 = detail::rotl( h0, 5 ); h0 += h1; h2 ^= h0; + h1 = detail::rotl( h1, 36 ); h1 += h2; h3 ^= h1; + } + + static inline void short_end( boost::uint64_t & h0, boost::uint64_t & h1, boost::uint64_t & h2, boost::uint64_t & h3 ) + { + h3 ^= h2; h2 = detail::rotl( h2, 15 ); h3 += h2; + h0 ^= h3; h3 = detail::rotl( h3, 52 ); h0 += h3; + h1 ^= h0; h0 = detail::rotl( h0, 26 ); h1 += h0; + h2 ^= h1; h1 = detail::rotl( h1, 51 ); h2 += h1; + h3 ^= h2; h2 = detail::rotl( h2, 28 ); h3 += h2; + h0 ^= h3; h3 = detail::rotl( h3, 9 ); h0 += h3; + h1 ^= h0; h0 = detail::rotl( h0, 47 ); h1 += h0; + h2 ^= h1; h1 = detail::rotl( h1, 54 ); h2 += h1; + h3 ^= h2; h2 = detail::rotl( h2, 32 ); h3 += h2; + h0 ^= h3; h3 = detail::rotl( h3, 25 ); h0 += h3; + h1 ^= h0; h0 = detail::rotl( h0, 63 ); h1 += h0; + } + + static void short_hash( byte_type const * p, std::size_t n, boost::uint64_t & hash1, boost::uint64_t & hash2 ) + { + boost::uint64_t a = hash1; + boost::uint64_t b = hash2; + boost::uint64_t c = sc_const; + boost::uint64_t d = sc_const; + + std::size_t m = n; + + while( m >= 32 ) + { + c += detail::read64le( p + 0 ); + d += detail::read64le( p + 8 ); + + short_mix( a, b, c, d ); + + a += detail::read64le( p + 16 ); + b += detail::read64le( p + 24 ); + + p += 32; + m -= 32; + } + + if( m >= 16 ) + { + c += detail::read64le( p + 0 ); + d += detail::read64le( p + 8 ); + + short_mix( a, b, c, d ); + + p += 16; + m -= 16; + } + + if( m == 0 ) + { + c += sc_const; + d += sc_const; + } + else + { + BOOST_ASSERT( m < 16 ); + + byte_type tmp[ 16 ] = { 0 }; + std::memcpy( tmp, p, m ); + + c += detail::read64le( tmp + 0 ); + d += detail::read64le( tmp + 8 ); + } + + d += static_cast( n ) << 56; + + short_end( a, b, c, d ); + + hash1 = a; + hash2 = b; + } + +private: + + static inline void mix( byte_type const * p, + boost::uint64_t & s0, boost::uint64_t & s1, boost::uint64_t & s2, boost::uint64_t & s3, + boost::uint64_t & s4, boost::uint64_t & s5, boost::uint64_t & s6, boost::uint64_t & s7, + boost::uint64_t & s8, boost::uint64_t & s9, boost::uint64_t & s10, boost::uint64_t & s11 ) + { + s0 += detail::read64le( p + 0 ); s2 ^= s10; s11 ^= s0; s0 = detail::rotl( s0, 11 ); s11 += s1; + s1 += detail::read64le( p + 8 ); s3 ^= s11; s0 ^= s1; s1 = detail::rotl( s1, 32 ); s0 += s2; + s2 += detail::read64le( p + 16 ); s4 ^= s0; s1 ^= s2; s2 = detail::rotl( s2, 43 ); s1 += s3; + s3 += detail::read64le( p + 24 ); s5 ^= s1; s2 ^= s3; s3 = detail::rotl( s3, 31 ); s2 += s4; + s4 += detail::read64le( p + 32 ); s6 ^= s2; s3 ^= s4; s4 = detail::rotl( s4, 17 ); s3 += s5; + s5 += detail::read64le( p + 40 ); s7 ^= s3; s4 ^= s5; s5 = detail::rotl( s5, 28 ); s4 += s6; + s6 += detail::read64le( p + 48 ); s8 ^= s4; s5 ^= s6; s6 = detail::rotl( s6, 39 ); s5 += s7; + s7 += detail::read64le( p + 56 ); s9 ^= s5; s6 ^= s7; s7 = detail::rotl( s7, 57 ); s6 += s8; + s8 += detail::read64le( p + 64 ); s10 ^= s6; s7 ^= s8; s8 = detail::rotl( s8, 55 ); s7 += s9; + s9 += detail::read64le( p + 72 ); s11 ^= s7; s8 ^= s9; s9 = detail::rotl( s9, 54 ); s8 += s10; + s10 += detail::read64le( p + 80 ); s0 ^= s8; s9 ^= s10; s10 = detail::rotl( s10, 22 ); s9 += s11; + s11 += detail::read64le( p + 88 ); s1 ^= s9; s10 ^= s11; s11 = detail::rotl( s11, 46 ); s10 += s0; + } + + void update_( byte_type const * p, std::ptrdiff_t k ) + { + boost::uint64_t h0 = v_[ 0]; + boost::uint64_t h1 = v_[ 1]; + boost::uint64_t h2 = v_[ 2]; + boost::uint64_t h3 = v_[ 3]; + boost::uint64_t h4 = v_[ 4]; + boost::uint64_t h5 = v_[ 5]; + boost::uint64_t h6 = v_[ 6]; + boost::uint64_t h7 = v_[ 7]; + boost::uint64_t h8 = v_[ 8]; + boost::uint64_t h9 = v_[ 9]; + boost::uint64_t h10 = v_[10]; + boost::uint64_t h11 = v_[11]; + + for( std::ptrdiff_t i = 0; i < k; ++i, p += 96 ) + { + mix( p, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 ); + } + + v_[ 0] = h0; + v_[ 1] = h1; + v_[ 2] = h2; + v_[ 3] = h3; + v_[ 4] = h4; + v_[ 5] = h5; + v_[ 6] = h6; + v_[ 7] = h7; + v_[ 8] = h8; + v_[ 9] = h9; + v_[10] = h10; + v_[11] = h11; + } + + static inline void end_partial( + boost::uint64_t & h0, boost::uint64_t & h1, boost::uint64_t & h2, boost::uint64_t & h3, + boost::uint64_t & h4, boost::uint64_t & h5, boost::uint64_t & h6, boost::uint64_t & h7, + boost::uint64_t & h8, boost::uint64_t & h9, boost::uint64_t & h10, boost::uint64_t & h11 ) + { + h11 += h1; h2 ^= h11; h1 = detail::rotl( h1, 44 ); + h0 += h2; h3 ^= h0; h2 = detail::rotl( h2, 15 ); + h1 += h3; h4 ^= h1; h3 = detail::rotl( h3, 34 ); + h2 += h4; h5 ^= h2; h4 = detail::rotl( h4, 21); + h3 += h5; h6 ^= h3; h5 = detail::rotl( h5, 38); + h4 += h6; h7 ^= h4; h6 = detail::rotl( h6, 33); + h5 += h7; h8 ^= h5; h7 = detail::rotl( h7, 10); + h6 += h8; h9 ^= h6; h8 = detail::rotl( h8, 13); + h7 += h9; h10 ^= h7; h9 = detail::rotl( h9, 38); + h8 += h10; h11 ^= h8; h10 = detail::rotl( h10, 53); + h9 += h11; h0 ^= h9; h11 = detail::rotl( h11, 42); + h10 += h0; h1 ^= h10; h0 = detail::rotl( h0, 54); + } + + static inline void end( byte_type const * p, + boost::uint64_t & h0, boost::uint64_t & h1, boost::uint64_t & h2, boost::uint64_t & h3, + boost::uint64_t & h4, boost::uint64_t & h5, boost::uint64_t & h6, boost::uint64_t & h7, + boost::uint64_t & h8, boost::uint64_t & h9, boost::uint64_t & h10, boost::uint64_t & h11 ) + { + h0 += detail::read64le( p + 0 ); + h1 += detail::read64le( p + 8 ); + h2 += detail::read64le( p + 16 ); + h3 += detail::read64le( p + 24 ); + h4 += detail::read64le( p + 32 ); + h5 += detail::read64le( p + 40 ); + h6 += detail::read64le( p + 48 ); + h7 += detail::read64le( p + 56 ); + h8 += detail::read64le( p + 64 ); + h9 += detail::read64le( p + 72 ); + h10 += detail::read64le( p + 80 ); + h11 += detail::read64le( p + 88 ); + + end_partial( h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 ); + end_partial( h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 ); + end_partial( h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 ); + } + + void init( boost::uint64_t seed1, boost::uint64_t seed2 ) + { + v_[ 0 ] = v_[ 3 ] = v_[ 6 ] = v_[ 9 ] = seed1; + v_[ 1 ] = v_[ 4 ] = v_[ 7 ] = v_[ 10 ] = seed2; + v_[ 2 ] = v_[ 5 ] = v_[ 8 ] = v_[ 11 ] = sc_const; + } + +public: + + typedef boost::array result_type; + typedef boost::uint64_t size_type; + + explicit spooky2_128( boost::uint64_t seed1 = 0, boost::uint64_t seed2 = 0 ): m_( 0 ), n_( 0 ) + { + init( seed1, seed2 ); + } + + explicit spooky2_128( byte_type const * p, std::ptrdiff_t n ): m_( 0 ), n_( 0 ) + { + BOOST_ASSERT( n >= 0 ); + + if( n <= 16 ) + { + byte_type q[ 18 ] = {}; + std::memcpy( q, p, n ); + + boost::uint64_t seed1 = detail::read64le( q + 0 ); + boost::uint64_t seed2 = detail::read64le( q + 8 ); + + init( seed1, seed2 ); + } + else + { + boost::uint64_t seed1 = detail::read64le( p + 0 ); + boost::uint64_t seed2 = detail::read64le( p + 8 ); + + init( seed1, seed2 ); + + p += 16; + n -= 16; + + update( p, n ); + result(); + } + } + + void update( byte_type const * p, std::ptrdiff_t n ) + { + BOOST_ASSERT( n >= 0 ); + + BOOST_ASSERT( m_ == static_cast( n_ % N ) ); + + if( n == 0 ) return; + + n_ += n; + + if( m_ > 0 ) + { + int k = N - m_; + + if( n < k ) + { + k = static_cast( n ); + } + + std::memcpy( buffer_ + m_, p, k ); + + p += k; + n -= k; + m_ += k; + + if( m_ < N ) return; + + BOOST_ASSERT( m_ == N ); + + update_( buffer_, 2 ); + m_ = 0; + } + + BOOST_ASSERT( m_ == 0 ); + + { + std::ptrdiff_t k = n / N; + + update_( p, k * 2 ); + + p += k * N; + n -= k * N; + } + + BOOST_ASSERT( n < N ); + + if( n > 0 ) + { + std::memcpy( buffer_, p, n ); + m_ = static_cast( n ); + } + + BOOST_ASSERT( m_ == static_cast( n_ % N ) ); + } + + result_type result() + { + BOOST_ASSERT( m_ == static_cast( n_ % N ) ); + + boost::uint64_t h0 = v_[ 0 ]; + boost::uint64_t h1 = v_[ 1 ]; + + if( n_ < N ) + { + short_hash( buffer_, n_, h0, h1 ); + } + else + { + boost::uint64_t h2 = v_[ 2 ]; + boost::uint64_t h3 = v_[ 3 ]; + boost::uint64_t h4 = v_[ 4 ]; + boost::uint64_t h5 = v_[ 5 ]; + boost::uint64_t h6 = v_[ 6 ]; + boost::uint64_t h7 = v_[ 7 ]; + boost::uint64_t h8 = v_[ 8 ]; + boost::uint64_t h9 = v_[ 9 ]; + boost::uint64_t h10 = v_[ 10 ]; + boost::uint64_t h11 = v_[ 11 ]; + + byte_type * p = buffer_; + int m = m_; + + if( m >= 96 ) + { + mix( p, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 ); + + p += 96; + m -= 96; + } + + std::memset( p + m, 0, 96 - m ); + p[ 95 ] = static_cast( m & 0xFF ); + + end( p, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 ); + + v_[ 2 ] = h2; + v_[ 3 ] = h3; + v_[ 4 ] = h4; + v_[ 5 ] = h5; + v_[ 6 ] = h6; + v_[ 7 ] = h7; + v_[ 8 ] = h8; + v_[ 9 ] = h9; + v_[ 10 ] = h10; + v_[ 11 ] = h11; + } + + v_[ 0 ] = h0; + v_[ 1 ] = h1; + + n_ += N - m_; + m_ = 0; + + if( n_ < N ) + { + n_ = 0; // in case of overflow (N does not divide 2^32) + } + + // clear buffered plaintext + std::memset( buffer_, 0, N ); + + result_type r; + + detail::write64le( &r[ 0 ], h0 ); + detail::write64le( &r[ 8 ], h1 ); + + return r; + } +}; + +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_SPOOKY2_HPP_INCLUDED diff --git a/include/boost/hash2/underlying_type.hpp b/include/boost/hash2/underlying_type.hpp new file mode 100644 index 0000000..fec231e --- /dev/null +++ b/include/boost/hash2/underlying_type.hpp @@ -0,0 +1,45 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#ifndef BOOST_HASH2_UNDERLYING_TYPE_HPP_INCLUDED +#define BOOST_HASH2_UNDERLYING_TYPE_HPP_INCLUDED + +#include +#include +#include +#include +#include + +#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) + +#include + +namespace boost +{ +namespace hash2 +{ + +using std::underlying_type; + +} // namespace hash2 +} // namespace boost + +#else + +namespace boost +{ +namespace hash2 +{ + +template struct underlying_type: + conditional< is_signed::value, make_signed, make_unsigned >::type +{ +}; + +} // namespace hash2 +} // namespace boost + +#endif // !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) + +#endif // #ifndef BOOST_HASH2_UNDERLYING_TYPE_HPP_INCLUDED diff --git a/include/boost/hash2/xxhash.hpp b/include/boost/hash2/xxhash.hpp new file mode 100644 index 0000000..52e7a5f --- /dev/null +++ b/include/boost/hash2/xxhash.hpp @@ -0,0 +1,455 @@ +#ifndef BOOST_HASH2_XXHASH_HPP_INCLUDED +#define BOOST_HASH2_XXHASH_HPP_INCLUDED + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// xxHash, https://cyan4973.github.io/xxHash/ + +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ +namespace hash2 +{ + +class xxhash_32 +{ +private: + + boost::uint32_t v1_, v2_, v3_, v4_; + + byte_type buffer_[ 16 ]; + int m_; + + std::size_t n_; + +private: + + static const boost::uint32_t P1 = 2654435761U; + static const boost::uint32_t P2 = 2246822519U; + static const boost::uint32_t P3 = 3266489917U; + static const boost::uint32_t P4 = 668265263U; + static const boost::uint32_t P5 = 374761393U; + +private: + + static boost::uint32_t round( boost::uint32_t seed, boost::uint32_t input ) + { + seed += input * P2; + seed = detail::rotl( seed, 13 ); + seed *= P1; + return seed; + } + + void update_( byte_type const * p, std::ptrdiff_t k ) + { + boost::uint32_t v1 = v1_; + boost::uint32_t v2 = v2_; + boost::uint32_t v3 = v3_; + boost::uint32_t v4 = v4_; + + for( std::ptrdiff_t i = 0; i < k; ++i, p += 16 ) + { + v1 = round( v1, detail::read32le( p + 0 ) ); + v2 = round( v2, detail::read32le( p + 4 ) ); + v3 = round( v3, detail::read32le( p + 8 ) ); + v4 = round( v4, detail::read32le( p + 12 ) ); + } + + v1_ = v1; + v2_ = v2; + v3_ = v3; + v4_ = v4; + } + + void init( boost::uint32_t seed ) + { + v1_ = seed + P1 + P2; + v2_ = seed + P2; + v3_ = seed; + v4_ = seed - P1; + } + +public: + + typedef boost::uint32_t result_type; + typedef boost::uint32_t size_type; + + explicit xxhash_32( boost::uint32_t seed = 0 ): m_( 0 ), n_( 0 ) + { + init( seed ); + } + + explicit xxhash_32( byte_type const * p, std::ptrdiff_t n ): m_( 0 ), n_( 0 ) + { + BOOST_ASSERT( n >= 0 ); + + if( n <= 4 ) + { + byte_type q[ 4 ] = {}; + std::memcpy( q, p, n ); + + boost::uint32_t seed = detail::read32le( q ); + init( seed ); + } + else + { + boost::uint32_t seed = detail::read32le( p ); + init( seed ); + + p += 4; + n -= 4; + + update( p, n ); + result(); + } + } + + void update( byte_type const * p, std::ptrdiff_t n ) + { + BOOST_ASSERT( n >= 0 ); + + BOOST_ASSERT( m_ == static_cast( n_ & 15 ) ); + + if( n == 0 ) return; + + n_ += n; + + if( m_ > 0 ) + { + int k = 16 - m_; + + if( n < k ) + { + k = static_cast( n ); + } + + std::memcpy( buffer_ + m_, p, k ); + + p += k; + n -= k; + m_ += k; + + if( m_ < 16 ) return; + + BOOST_ASSERT( m_ == 16 ); + + update_( buffer_, 1 ); + m_ = 0; + } + + BOOST_ASSERT( m_ == 0 ); + + { + std::ptrdiff_t k = n / 16; + + update_( p, k ); + + p += 16 * k; + n -= 16 * k; + } + + BOOST_ASSERT( n < 16 ); + + if( n > 0 ) + { + std::memcpy( buffer_, p, n ); + m_ = static_cast( n ); + } + + BOOST_ASSERT( m_ == static_cast( n_ & 15 ) ); + } + + boost::uint32_t result() + { + BOOST_ASSERT( m_ == static_cast( n_ & 15 ) ); + + boost::uint32_t h; + + if( n_ >= 16 ) + { + h = detail::rotl( v1_, 1 ) + detail::rotl( v2_, 7 ) + detail::rotl( v3_, 12 ) + detail::rotl( v4_, 18 ); + } + else + { + h = v3_ + P5; + } + + h += static_cast( n_ ); + + byte_type const * p = buffer_; + + int m = m_; + + while( m >= 4 ) + { + h += detail::read32le( p ) * P3; + h = detail::rotl( h, 17 ) * P4; + + p += 4; + m -= 4; + } + + while( m > 0 ) + { + h += p[0] * P5; + h = detail::rotl( h, 11 ) * P1; + + ++p; + --m; + } + + n_ += 16 - m_; + m_ = 0; + + // clear buffered plaintext + std::memset( buffer_, 0, 16 ); + + h ^= h >> 15; + h *= P2; + h ^= h >> 13; + h *= P3; + h ^= h >> 16; + + return h; + } +}; + +class xxhash_64 +{ +private: + + boost::uint64_t v1_, v2_, v3_, v4_; + + byte_type buffer_[ 32 ]; + int m_; + + boost::uint64_t n_; + +private: + + static const boost::uint64_t P1 = 11400714785074694791ULL; + static const boost::uint64_t P2 = 14029467366897019727ULL; + static const boost::uint64_t P3 = 1609587929392839161ULL; + static const boost::uint64_t P4 = 9650029242287828579ULL; + static const boost::uint64_t P5 = 2870177450012600261ULL; + +private: + + static boost::uint64_t round( boost::uint64_t seed, boost::uint64_t input ) + { + seed += input * P2; + seed = detail::rotl( seed, 31 ); + seed *= P1; + return seed; + } + + static boost::uint64_t merge_round( boost::uint64_t acc, boost::uint64_t val ) + { + val = round( 0, val ); + acc ^= val; + acc = acc * P1 + P4; + return acc; + } + + void update_( byte_type const * p, std::ptrdiff_t k ) + { + boost::uint64_t v1 = v1_; + boost::uint64_t v2 = v2_; + boost::uint64_t v3 = v3_; + boost::uint64_t v4 = v4_; + + for( int i = 0; i < k; ++i, p += 32 ) + { + v1 = round( v1, detail::read64le( p + 0 ) ); + v2 = round( v2, detail::read64le( p + 8 ) ); + v3 = round( v3, detail::read64le( p + 16 ) ); + v4 = round( v4, detail::read64le( p + 24 ) ); + } + + v1_ = v1; + v2_ = v2; + v3_ = v3; + v4_ = v4; + } + + void init( boost::uint64_t seed ) + { + v1_ = seed + P1 + P2; + v2_ = seed + P2; + v3_ = seed; + v4_ = seed - P1; + } + +public: + + typedef boost::uint64_t result_type; + typedef boost::uint64_t size_type; + + explicit xxhash_64( boost::uint64_t seed = 0 ): m_( 0 ), n_( 0 ) + { + init( seed ); + } + + explicit xxhash_64( byte_type const * p, std::ptrdiff_t n ): m_( 0 ), n_( 0 ) + { + BOOST_ASSERT( n >= 0 ); + + if( n <= 8 ) + { + byte_type q[ 8 ] = {}; + std::memcpy( q, p, n ); + + boost::uint64_t seed = detail::read64le( q ); + init( seed ); + } + else + { + boost::uint64_t seed = detail::read64le( p ); + init( seed ); + + p += 8; + n -= 8; + + update( p, n ); + result(); + } + } + + void update( byte_type const * p, std::ptrdiff_t n ) + { + BOOST_ASSERT( n >= 0 ); + + BOOST_ASSERT( m_ == static_cast( n_ & 31 ) ); + + if( n == 0 ) return; + + n_ += n; + + if( m_ > 0 ) + { + int k = 32 - m_; + + if( n < k ) + { + k = static_cast( n ); + } + + std::memcpy( buffer_ + m_, p, k ); + + p += k; + n -= k; + m_ += k; + + if( m_ < 32 ) return; + + BOOST_ASSERT( m_ == 32 ); + + update_( buffer_, 1 ); + m_ = 0; + } + + BOOST_ASSERT( m_ == 0 ); + + { + std::ptrdiff_t k = n / 32; + + update_( p, k ); + + p += 32 * k; + n -= 32 * k; + } + + BOOST_ASSERT( n < 32 ); + + if( n > 0 ) + { + std::memcpy( buffer_, p, n ); + m_ = static_cast( n ); + } + + BOOST_ASSERT( m_ == static_cast( n_ & 31 ) ); + } + + boost::uint64_t result() + { + BOOST_ASSERT( m_ == static_cast( n_ & 31 ) ); + + boost::uint64_t h; + + if( n_ >= 32 ) + { + h = detail::rotl( v1_, 1 ) + detail::rotl( v2_, 7 ) + detail::rotl( v3_, 12 ) + detail::rotl( v4_, 18 ); + + h = merge_round( h, v1_ ); + h = merge_round( h, v2_ ); + h = merge_round( h, v3_ ); + h = merge_round( h, v4_ ); + } + else + { + h = v3_ + P5; + } + + h += n_; + + byte_type const * p = buffer_; + + int m = m_; + + while( m >= 8 ) + { + boost::uint64_t k1 = round( 0, detail::read64le( p ) ); + + h ^= k1; + h = detail::rotl( h, 27 ) * P1 + P4; + + p += 8; + m -= 8; + } + + while( m >= 4 ) + { + h ^= static_cast( detail::read32le( p ) ) * P1; + h = detail::rotl( h, 23 ) * P2 + P3; + + p += 4; + m -= 4; + } + + while( m > 0 ) + { + h ^= p[0] * P5; + h = detail::rotl( h, 11 ) * P1; + + ++p; + --m; + } + + n_ += 32 - m_; + m_ = 0; + + // clear buffered plaintext + std::memset( buffer_, 0, 32 ); + + h ^= h >> 33; + h *= P2; + h ^= h >> 29; + h *= P3; + h ^= h >> 32; + + return h; + } +}; + +} // namespace hash2 +} // namespace boost + +#endif // #ifndef BOOST_HASH2_XXHASH_HPP_INCLUDED diff --git a/test/Jamfile b/test/Jamfile new file mode 100644 index 0000000..59d9a08 --- /dev/null +++ b/test/Jamfile @@ -0,0 +1,57 @@ +# Copyright 2017, 2018 Peter Dimov +# Distributed under the Boost Software License, Version 1.0. + +import testing ; + +# traits + +run is_contiguously_hashable.cpp ; +run is_range.cpp ; +run is_unordered_range.cpp ; +run is_tuple_like.cpp ; +run underlying_type.cpp ; + +# helpers + +run get_integral_result.cpp ; + +# hash_append + +run hash_append.cpp ; +run hash_append_2.cpp ; +run hash_append_3.cpp ; +run hash_append_4.cpp ; +run hash_append_range.cpp ; +run hash_append_range_2.cpp ; +run set.cpp ; +run map.cpp ; + +# non-cryptographic + +run fnv1a.cpp ; +run siphash32.cpp ; +run siphash64.cpp ; +run xxhash.cpp ; +run spooky2.cpp ; +run murmur3_32.cpp ; +run murmur3_128.cpp ; + +# cryptographic + +run md5.cpp ; +run hmac_md5.cpp ; +run sha1.cpp ; +run hmac_sha1.cpp ; + +# general requirements + +run concept.cpp ; +run plaintext_leak.cpp ; +run multiple_result.cpp ; +run integral_result.cpp ; + +# compile benchmarks + +compile ../benchmark/buffer.cpp ; +compile ../benchmark/unordered.cpp ; +compile ../benchmark/average.cpp ; diff --git a/test/concept.cpp b/test/concept.cpp new file mode 100644 index 0000000..ddf43e7 --- /dev/null +++ b/test/concept.cpp @@ -0,0 +1,201 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using boost::hash2::byte_type; + +template struct is_valid_result: + boost::integral_constant::value && !boost::is_signed::value + > +{ +}; + +template struct is_valid_result< boost::array >: + boost::integral_constant= 8> +{ +}; + +template void test_result_type() +{ + BOOST_TEST_TRAIT_TRUE((is_valid_result)); +} + +template void test_size_type() +{ + BOOST_TEST_TRAIT_TRUE((boost::is_integral)); + + BOOST_TEST_EQ( std::numeric_limits::min(), 0 ); + BOOST_TEST_GE( std::numeric_limits::max(), 0xFFFFFFFFu ); +} + +template void test_default_constructible() +{ + H h1; + typename H::result_type r1 = h1.result(); + + H h2; + typename H::result_type r2 = h2.result(); + + BOOST_TEST( r1 == r2 ); +} + +template void test_seed_constructible() +{ + byte_type const seed[ 3 ] = { 0x01, 0x02, 0x03 }; + + { + H h1; + H h2( 0, 0 ); + + BOOST_TEST( h1.result() == h2.result() ); + } + + { + H h1; + H h2( seed, 0 ); + + BOOST_TEST( h1.result() == h2.result() ); + } + + { + H h1; + H h2( seed, 3 ); + + BOOST_TEST( h1.result() != h2.result() ); + } + + { + H h1( seed, 3 ); + H h2( seed, 3 ); + + BOOST_TEST( h1.result() == h2.result() ); + } + + { + H h1( seed, 2 ); + H h2( seed, 3 ); + + BOOST_TEST( h1.result() != h2.result() ); + } +} + +template void test_copy_constructible() +{ + byte_type const seed[ 3 ] = { 0x01, 0x02, 0x03 }; + + { + H h1; + H h2( h1 ); + + BOOST_TEST( h1.result() == h2.result() ); + } + + { + H h1( seed, 3 ); + H h2( h1 ); + + BOOST_TEST( h1.result() == h2.result() ); + } + + { + H h1; + h1.update( seed, 3 ); + + H h2( h1 ); + + BOOST_TEST( h1.result() == h2.result() ); + } +} + +template void test_update() +{ + byte_type const data[ 3 ] = {}; + + { + H h1; + + H h2; + h2.update( data, 3 ); + + BOOST_TEST( h1.result() != h2.result() ); + } + + { + H h1; + h1.update( data, 3 ); + + H h2; + h2.update( data, 3 ); + + BOOST_TEST( h1.result() == h2.result() ); + } + + { + H h1; + h1.update( data, 3 ); + + H h2; + h2.update( data, 2 ); + + BOOST_TEST( h1.result() != h2.result() ); + } + + { + H h1; + h1.update( data, 3 ); + + H h2( h1 ); + + h1.update( data, 3 ); + h2.update( data, 3 ); + + BOOST_TEST( h1.result() == h2.result() ); + } +} + +template void test() +{ + test_result_type(); + test_size_type(); + test_default_constructible(); + test_seed_constructible(); + test_copy_constructible(); + test_update(); +} + +int main() +{ + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + + return boost::report_errors(); +} diff --git a/test/fnv1a.cpp b/test/fnv1a.cpp new file mode 100644 index 0000000..b3e1728 --- /dev/null +++ b/test/fnv1a.cpp @@ -0,0 +1,32 @@ + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include + +template void test( char const * s, R r ) +{ + H h; + + h.update( reinterpret_cast( s ), std::strlen( s ) ); + + BOOST_TEST_EQ( h.result(), r ); +} + +int main() +{ + // Test vectors from https://tools.ietf.org/html/draft-eastlake-fnv-14 + + test( "", 0x811c9dc5ul ); + test( "a", 0xe40c292cul ); + test( "foobar", 0xbf9cf968ul ); + + test( "", 0xcbf29ce484222325ull ); + test( "a", 0xaf63dc4c8601ec8cull ); + test( "foobar", 0x85944171f73967e8ull ); + + return boost::report_errors(); +} diff --git a/test/get_integral_result.cpp b/test/get_integral_result.cpp new file mode 100644 index 0000000..2442dfc --- /dev/null +++ b/test/get_integral_result.cpp @@ -0,0 +1,97 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include +#include + +int main() +{ + using boost::hash2::get_integral_result; + + { + boost::uint32_t u32 = 0x12345678; + + BOOST_TEST_EQ( get_integral_result( u32 ), 0x78 ); + BOOST_TEST_EQ( get_integral_result( u32 ), 0x78 ); + BOOST_TEST_EQ( get_integral_result( u32 ), 0x5678 ); + BOOST_TEST_EQ( get_integral_result( u32 ), 0x5678 ); + BOOST_TEST_EQ( get_integral_result( u32 ), 0x12345678 ); + BOOST_TEST_EQ( get_integral_result( u32 ), 0x12345678 ); + BOOST_TEST_EQ( get_integral_result( u32 ), 0x1234567812345678ull ); + BOOST_TEST_EQ( get_integral_result( u32 ), 0x1234567812345678ull ); + } + + { + boost::uint32_t s32 = 0xFFFFFFFFu; + + BOOST_TEST_EQ( get_integral_result( s32 ), 0xFF ); + BOOST_TEST_EQ( get_integral_result( s32 ), -1 ); + BOOST_TEST_EQ( get_integral_result( s32 ), 0xFFFF ); + BOOST_TEST_EQ( get_integral_result( s32 ), -1 ); + BOOST_TEST_EQ( get_integral_result( s32 ), 0xFFFFFFFFu ); + BOOST_TEST_EQ( get_integral_result( s32 ), -1 ); + BOOST_TEST_EQ( get_integral_result( s32 ), 0xFFFFFFFFFFFFFFFFull ); + BOOST_TEST_EQ( get_integral_result( s32 ), -1 ); + } + + { + boost::uint64_t u64 = 0x0123456789ABCDEFull; + + BOOST_TEST_EQ( get_integral_result( u64 ), 0xEF ); + BOOST_TEST_EQ( get_integral_result( u64 ), -0x11 ); + BOOST_TEST_EQ( get_integral_result( u64 ), 0xCDEF ); + BOOST_TEST_EQ( get_integral_result( u64 ), -0x3211 ); + BOOST_TEST_EQ( get_integral_result( u64 ), 0x89ABCDEF ); + BOOST_TEST_EQ( get_integral_result( u64 ), 0x89ABCDEF ); + BOOST_TEST_EQ( get_integral_result( u64 ), 0x0123456789ABCDEFull ); + BOOST_TEST_EQ( get_integral_result( u64 ), 0x0123456789ABCDEFull ); + } + + { + boost::uint64_t s64 = 0xFFFFFFFFFFFFFFFFull; + + BOOST_TEST_EQ( get_integral_result( s64 ), 0xFF ); + BOOST_TEST_EQ( get_integral_result( s64 ), -1 ); + BOOST_TEST_EQ( get_integral_result( s64 ), 0xFFFF ); + BOOST_TEST_EQ( get_integral_result( s64 ), -1 ); + BOOST_TEST_EQ( get_integral_result( s64 ), 0xFFFFFFFFu ); + BOOST_TEST_EQ( get_integral_result( s64 ), -1 ); + BOOST_TEST_EQ( get_integral_result( s64 ), 0xFFFFFFFFFFFFFFFFull ); + BOOST_TEST_EQ( get_integral_result( s64 ), -1 ); + } + + using boost::hash2::byte_type; + + { + boost::array a64 = {{ 0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01 }}; + + BOOST_TEST_EQ( get_integral_result( a64 ), 0xEF ); + BOOST_TEST_EQ( get_integral_result( a64 ), -0x11 ); + BOOST_TEST_EQ( get_integral_result( a64 ), 0xCDEF ); + BOOST_TEST_EQ( get_integral_result( a64 ), -0x3211 ); + BOOST_TEST_EQ( get_integral_result( a64 ), 0x89ABCDEF ); + BOOST_TEST_EQ( get_integral_result( a64 ), 0x89ABCDEF ); + BOOST_TEST_EQ( get_integral_result( a64 ), 0x0123456789ABCDEFull ); + BOOST_TEST_EQ( get_integral_result( a64 ), 0x0123456789ABCDEFull ); + } + + { + boost::array b64 = {{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }}; + + BOOST_TEST_EQ( get_integral_result( b64 ), 0xFF ); + BOOST_TEST_EQ( get_integral_result( b64 ), -1 ); + BOOST_TEST_EQ( get_integral_result( b64 ), 0xFFFF ); + BOOST_TEST_EQ( get_integral_result( b64 ), -1 ); + BOOST_TEST_EQ( get_integral_result( b64 ), 0xFFFFFFFFu ); + BOOST_TEST_EQ( get_integral_result( b64 ), -1 ); + BOOST_TEST_EQ( get_integral_result( b64 ), 0xFFFFFFFFFFFFFFFFull ); + BOOST_TEST_EQ( get_integral_result( b64 ), -1 ); + } + + return boost::report_errors(); +} diff --git a/test/hash_append.cpp b/test/hash_append.cpp new file mode 100644 index 0000000..1ba804f --- /dev/null +++ b/test/hash_append.cpp @@ -0,0 +1,53 @@ + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// Endian-independent test + +#include +#include +#include + +template void test( R r ) +{ + { + unsigned char v[4] = { 1, 2, 3, 4 }; + + H h; + + hash_append( h, v[0] ); + hash_append( h, v[1] ); + hash_append( h, v[2] ); + hash_append( h, v[3] ); + + BOOST_TEST_EQ( h.result(), r ); + } + + { + unsigned char v[4] = { 1, 2, 3, 4 }; + + H h; + + hash_append( h, v ); + + BOOST_TEST_EQ( h.result(), r ); + } + + { + unsigned char v[2][2] = { { 1, 2 }, { 3, 4 } }; + + H h; + + hash_append( h, v ); + + BOOST_TEST_EQ( h.result(), r ); + } +} + +int main() +{ + test( 1463068797ul ); + test( 13725386680924731485ull ); + + return boost::report_errors(); +} diff --git a/test/hash_append_2.cpp b/test/hash_append_2.cpp new file mode 100644 index 0000000..de33526 --- /dev/null +++ b/test/hash_append_2.cpp @@ -0,0 +1,53 @@ + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// Endian-dependent test + +#include +#include +#include + +template void test( R r ) +{ + { + int v[4] = { 1, 2, 3, 4 }; + + H h; + + hash_append( h, v[0] ); + hash_append( h, v[1] ); + hash_append( h, v[2] ); + hash_append( h, v[3] ); + + BOOST_TEST_EQ( h.result(), r ); + } + + { + int v[4] = { 1, 2, 3, 4 }; + + H h; + + hash_append( h, v ); + + BOOST_TEST_EQ( h.result(), r ); + } + + { + int v[2][2] = { { 1, 2 }, { 3, 4 } }; + + H h; + + hash_append( h, v ); + + BOOST_TEST_EQ( h.result(), r ); + } +} + +int main() +{ + test( 1041505217ul ); + test( 9566659391000707361ull ); + + return boost::report_errors(); +} diff --git a/test/hash_append_3.cpp b/test/hash_append_3.cpp new file mode 100644 index 0000000..b4c66a3 --- /dev/null +++ b/test/hash_append_3.cpp @@ -0,0 +1,48 @@ + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// Endian-dependent test + +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST) +# include +#endif + +template void test_sized_range( R r ) +{ + int w[] = { 1, 2, 3, 4 }; + T v( w, w + sizeof(w) / sizeof(w[0]) ); + + H h; + + hash_append( h, v ); + + BOOST_TEST_EQ( h.result(), r ); +} + +template void test( R r ) +{ + test_sized_range< H, std::vector >( r ); + test_sized_range< H, std::list >( r ); + test_sized_range< H, std::deque >( r ); + test_sized_range< H, std::set >( r ); + test_sized_range< H, std::multiset >( r ); +#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST) + test_sized_range< H, std::forward_list >( r ); +#endif +} + +int main() +{ + test( 1745310485ul ); + test( 8602726560470947781ull ); + + return boost::report_errors(); +} diff --git a/test/hash_append_4.cpp b/test/hash_append_4.cpp new file mode 100644 index 0000000..5858bbf --- /dev/null +++ b/test/hash_append_4.cpp @@ -0,0 +1,96 @@ + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// Endian-independent test + +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) +# include +#endif +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) +# include +#endif + +template void test( R r ) +{ + { + unsigned char v[2] = { 1, 2 }; + + H h; + + h.update( v, 2 ); + + BOOST_TEST_EQ( h.result(), r ); + } + + { + unsigned char v[2] = { 1, 2 }; + + H h; + + hash_append( h, v[0] ); + hash_append( h, v[1] ); + + BOOST_TEST_EQ( h.result(), r ); + } + + { + unsigned char v[2] = { 1, 2 }; + + H h; + + hash_append( h, v ); + + BOOST_TEST_EQ( h.result(), r ); + } + + { + std::pair v( 1, 2 ); + + H h; + + hash_append( h, v ); + + BOOST_TEST_EQ( h.result(), r ); + } + +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) + + { + std::array v = { { 1, 2 } }; + + H h; + + hash_append( h, v ); + + BOOST_TEST_EQ( h.result(), r ); + } + +#endif + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) + + { + std::tuple v( 1, 2 ); + + H h; + + hash_append( h, v ); + + BOOST_TEST_EQ( h.result(), r ); + } + +#endif +} + +int main() +{ + test( 3983810698ul ); + test( 589729691727335466ull ); + + return boost::report_errors(); +} diff --git a/test/hash_append_range.cpp b/test/hash_append_range.cpp new file mode 100644 index 0000000..53fc0e1 --- /dev/null +++ b/test/hash_append_range.cpp @@ -0,0 +1,61 @@ + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// Endian-independent test + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST) +# include +#endif + +template void test_unsized_range( R r ) +{ + unsigned char w[] = { 1, 2, 3, 4 }; + T v( w, w + sizeof(w) / sizeof(w[0]) ); + + H h; + + hash_append_range( h, v.begin(), v.end() ); + + BOOST_TEST_EQ( h.result(), r ); +} + +template void test( R r ) +{ + test_unsized_range< H, std::string >( r ); + test_unsized_range< H, std::vector >( r ); + test_unsized_range< H, std::list >( r ); + test_unsized_range< H, std::deque >( r ); + test_unsized_range< H, std::set >( r ); + test_unsized_range< H, std::multiset >( r ); +#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST) + test_unsized_range< H, std::forward_list >( r ); +#endif + + { + unsigned char v[2][2] = { { 1, 2 }, { 3, 4 } }; + + H h; + + hash_append_range( h, v, v + 2 ); + + BOOST_TEST_EQ( h.result(), r ); + } +} + +int main() +{ + test( 1463068797ul ); + test( 13725386680924731485ull ); + + return boost::report_errors(); +} diff --git a/test/hash_append_range_2.cpp b/test/hash_append_range_2.cpp new file mode 100644 index 0000000..323f838 --- /dev/null +++ b/test/hash_append_range_2.cpp @@ -0,0 +1,59 @@ + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// Endian-dependent test + +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST) +# include +#endif + +template void test_unsized_range( R r ) +{ + int w[] = { 1, 2, 3, 4 }; + T v( w, w + sizeof(w) / sizeof(w[0]) ); + + H h; + + hash_append_range( h, v.begin(), v.end() ); + + BOOST_TEST_EQ( h.result(), r ); +} + +template void test( R r ) +{ + test_unsized_range< H, std::vector >( r ); + test_unsized_range< H, std::list >( r ); + test_unsized_range< H, std::deque >( r ); + test_unsized_range< H, std::set >( r ); + test_unsized_range< H, std::multiset >( r ); +#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST) + test_unsized_range< H, std::forward_list >( r ); +#endif + + { + int v[2][2] = { { 1, 2 }, { 3, 4 } }; + + H h; + + hash_append_range( h, v, v + 2 ); + + BOOST_TEST_EQ( h.result(), r ); + } +} + +int main() +{ + test( 1041505217ul ); + test( 9566659391000707361ull ); + + return boost::report_errors(); +} diff --git a/test/hmac_md5.cpp b/test/hmac_md5.cpp new file mode 100644 index 0000000..689eea2 --- /dev/null +++ b/test/hmac_md5.cpp @@ -0,0 +1,61 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include + +using boost::hash2::byte_type; + +template std::string to_string( boost::array const & v ) +{ + std::string r; + + for( std::size_t i = 0; i < N; ++i ) + { + char buffer[ 8 ]; + + std::sprintf( buffer, "%02x", static_cast( v[ i ] ) ); + + r += buffer; + } + + return r; +} + +template std::string digest( std::string const k, std::string const & s ) +{ + H h( reinterpret_cast( k.data() ), k.size() ); + + h.update( reinterpret_cast( s.data() ), s.size() ); + + return to_string( h.result() ); +} + +using boost::hash2::hmac_md5_128; + +int main() +{ + // Test vectors from https://en.wikipedia.org/wiki/Hash-based_message_authentication_code + + BOOST_TEST_EQ( digest( "", "" ), std::string( "74e6f7298a9c2d168935f58c001bad88" ) ); + BOOST_TEST_EQ( digest( "key", "The quick brown fox jumps over the lazy dog" ), std::string( "80070713463e7749b90c2dc24911e275" ) ); + + // Test vectors from https://tools.ietf.org/html/rfc2202 + + BOOST_TEST_EQ( digest( std::string( 16, 0x0B ), "Hi There" ), std::string( "9294727a3638bb1c13f48ef8158bfc9d" ) ); + BOOST_TEST_EQ( digest( "Jefe", "what do ya want for nothing?" ), std::string( "750c783e6ab0b503eaa86e310a5db738" ) ); + BOOST_TEST_EQ( digest( std::string( 16, 0xAA ), std::string( 50, 0xDD ) ), std::string( "56be34521d144c88dbb8c733f0e8b3f6" ) ); + BOOST_TEST_EQ( digest( "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", std::string( 50, 0xCD ) ), std::string( "697eaf0aca3a3aea3a75164746ffaa79" ) ); + BOOST_TEST_EQ( digest( std::string( 16, 0x0C ), "Test With Truncation" ), std::string( "56461ef2342edc00f9bab995690efd4c" ) ); + BOOST_TEST_EQ( digest( std::string( 80, 0xAA ), "Test Using Larger Than Block-Size Key - Hash Key First" ), std::string( "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd" ) ); + BOOST_TEST_EQ( digest( std::string( 80, 0xAA ), "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" ), std::string( "6f630fad67cda0ee1fb1f562db3aa53e" ) ); + + return boost::report_errors(); +} diff --git a/test/hmac_sha1.cpp b/test/hmac_sha1.cpp new file mode 100644 index 0000000..09e9b3f --- /dev/null +++ b/test/hmac_sha1.cpp @@ -0,0 +1,61 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include + +using boost::hash2::byte_type; + +template std::string to_string( boost::array const & v ) +{ + std::string r; + + for( std::size_t i = 0; i < N; ++i ) + { + char buffer[ 8 ]; + + std::sprintf( buffer, "%02x", static_cast( v[ i ] ) ); + + r += buffer; + } + + return r; +} + +template std::string digest( std::string const & k, std::string const & s ) +{ + H h( reinterpret_cast( k.data() ), k.size() ); + + h.update( reinterpret_cast( s.data() ), s.size() ); + + return to_string( h.result() ); +} + +using boost::hash2::hmac_sha1_160; + +int main() +{ + // Test vectors from https://en.wikipedia.org/wiki/Hash-based_message_authentication_code + + BOOST_TEST_EQ( digest( "", "" ), std::string( "fbdb1d1b18aa6c08324b7d64b71fb76370690e1d" ) ); + BOOST_TEST_EQ( digest( "key", "The quick brown fox jumps over the lazy dog" ), std::string( "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9" ) ); + + // Test vectors from https://tools.ietf.org/html/rfc2202 + + BOOST_TEST_EQ( digest( std::string( 20, 0x0B ), "Hi There" ), std::string( "b617318655057264e28bc0b6fb378c8ef146be00" ) ); + BOOST_TEST_EQ( digest( "Jefe", "what do ya want for nothing?" ), std::string( "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79" ) ); + BOOST_TEST_EQ( digest( std::string( 20, 0xAA ), std::string( 50, 0xDD ) ), std::string( "125d7342b9ac11cd91a39af48aa17b4f63f175d3" ) ); + BOOST_TEST_EQ( digest( "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", std::string( 50, 0xCD ) ), std::string( "4c9007f4026250c6bc8414f9bf50c86c2d7235da" ) ); + BOOST_TEST_EQ( digest( std::string( 20, 0x0C ), "Test With Truncation" ), std::string( "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04" ) ); + BOOST_TEST_EQ( digest( std::string( 80, 0xAA ), "Test Using Larger Than Block-Size Key - Hash Key First" ), std::string( "aa4ae5e15272d00e95705637ce8a3b55ed402112" ) ); + BOOST_TEST_EQ( digest( std::string( 80, 0xAA ), "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" ), std::string( "e8e99d0f45237d786d6bbaa7965c7808bbff1a91" ) ); + + return boost::report_errors(); +} diff --git a/test/integral_result.cpp b/test/integral_result.cpp new file mode 100644 index 0000000..a598be3 --- /dev/null +++ b/test/integral_result.cpp @@ -0,0 +1,46 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using boost::hash2::get_integral_result; + +template void test() +{ + H h; + + get_integral_result( h.result() ); + get_integral_result( h.result() ); + get_integral_result( h.result() ); +} + +int main() +{ + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + + return boost::report_errors(); +} diff --git a/test/is_contiguously_hashable.cpp b/test/is_contiguously_hashable.cpp new file mode 100644 index 0000000..57a40ec --- /dev/null +++ b/test/is_contiguously_hashable.cpp @@ -0,0 +1,108 @@ + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include + +struct H +{ +}; + +class X; + +struct Y +{ +}; + +enum E +{ + v +}; + +template void test_true_() +{ + using boost::hash2::is_contiguously_hashable; + + BOOST_TEST_TRAIT_TRUE((is_contiguously_hashable)); + BOOST_TEST_TRAIT_TRUE((is_contiguously_hashable)); + BOOST_TEST_TRAIT_TRUE((is_contiguously_hashable)); + BOOST_TEST_TRAIT_TRUE((is_contiguously_hashable)); +} + +template void test_false_() +{ + using boost::hash2::is_contiguously_hashable; + + BOOST_TEST_TRAIT_FALSE((is_contiguously_hashable)); + BOOST_TEST_TRAIT_FALSE((is_contiguously_hashable)); + BOOST_TEST_TRAIT_FALSE((is_contiguously_hashable)); + BOOST_TEST_TRAIT_FALSE((is_contiguously_hashable)); +} + +template void test_true() +{ + test_true_(); + test_true_(); + test_true_(); + test_true_(); +} + +template void test_false() +{ + test_false_(); + test_true_(); + test_false_(); + test_false_(); +} + +int main() +{ + test_true_(); + + test_true_(); + test_true_(); + test_true_(); + test_true_(); + +#if !defined(BOOST_NO_CXX11_CHAR16_T) + test_true_(); +#endif + +#if !defined(BOOST_NO_CXX11_CHAR32_T) + test_true_(); +#endif + + test_true_(); + test_true_(); + test_true_(); + test_true_(); + test_true_(); + test_true_(); + test_true_(); + + test_false_(); + test_false_(); + test_false_(); + +#if !defined(BOOST_NO_CXX11_NULLPTR) + test_false_(); +#endif + + test_true_(); + test_true_(); + + test_true_(); + + test_true_(); + + test_false_(); + test_false_(); + + test_true_(); + + return boost::report_errors(); +} diff --git a/test/is_range.cpp b/test/is_range.cpp new file mode 100644 index 0000000..7f24065 --- /dev/null +++ b/test/is_range.cpp @@ -0,0 +1,98 @@ + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) +# include +#endif +#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST) +# include +#endif +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) +# include +#endif +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) +# include +#endif + +struct X +{ +}; + +int main() +{ + using boost::hash2::is_range; + + BOOST_TEST_TRAIT_FALSE((is_range)); + BOOST_TEST_TRAIT_FALSE((is_range)); + + BOOST_TEST_TRAIT_FALSE((is_range)); + BOOST_TEST_TRAIT_FALSE((is_range)); + + BOOST_TEST_TRAIT_FALSE((is_range)); + BOOST_TEST_TRAIT_FALSE((is_range)); + + BOOST_TEST_TRAIT_FALSE((is_range)); + BOOST_TEST_TRAIT_FALSE((is_range)); + + BOOST_TEST_TRAIT_TRUE((is_range)); + BOOST_TEST_TRAIT_TRUE((is_range)); + + BOOST_TEST_TRAIT_TRUE((is_range)); + BOOST_TEST_TRAIT_TRUE((is_range)); + + BOOST_TEST_TRAIT_TRUE((is_range< std::vector >)); + BOOST_TEST_TRAIT_TRUE((is_range< std::vector const >)); + + BOOST_TEST_TRAIT_TRUE((is_range< std::deque >)); + BOOST_TEST_TRAIT_TRUE((is_range< std::deque const >)); + + BOOST_TEST_TRAIT_TRUE((is_range< std::set >)); + BOOST_TEST_TRAIT_TRUE((is_range< std::set const >)); + + BOOST_TEST_TRAIT_TRUE((is_range< std::multiset >)); + BOOST_TEST_TRAIT_TRUE((is_range< std::multiset const >)); + + BOOST_TEST_TRAIT_TRUE((is_range< std::map >)); + BOOST_TEST_TRAIT_TRUE((is_range< std::map const >)); + + BOOST_TEST_TRAIT_TRUE((is_range< std::multimap >)); + BOOST_TEST_TRAIT_TRUE((is_range< std::multimap const >)); + +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) + BOOST_TEST_TRAIT_TRUE((is_range< std::array >)); + BOOST_TEST_TRAIT_TRUE((is_range< std::array const >)); +#endif + +#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST) + BOOST_TEST_TRAIT_TRUE((is_range< std::forward_list >)); + BOOST_TEST_TRAIT_TRUE((is_range< std::forward_list const >)); +#endif + +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) + BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_set >)); + BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_set const >)); + + BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_multiset >)); + BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_multiset const >)); +#endif + +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) + BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_map >)); + BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_map const >)); + + BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_multimap >)); + BOOST_TEST_TRAIT_TRUE((is_range< std::unordered_multimap const >)); +#endif + + return boost::report_errors(); +} diff --git a/test/is_tuple_like.cpp b/test/is_tuple_like.cpp new file mode 100644 index 0000000..5a445e9 --- /dev/null +++ b/test/is_tuple_like.cpp @@ -0,0 +1,72 @@ + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) +# include +#endif +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) +# include +#endif + +struct X +{ +}; + +int main() +{ + using boost::hash2::is_tuple_like; + + BOOST_TEST_TRAIT_FALSE((is_tuple_like)); + BOOST_TEST_TRAIT_FALSE((is_tuple_like)); + + BOOST_TEST_TRAIT_FALSE((is_tuple_like)); + BOOST_TEST_TRAIT_FALSE((is_tuple_like)); + + BOOST_TEST_TRAIT_FALSE((is_tuple_like)); + BOOST_TEST_TRAIT_FALSE((is_tuple_like)); + + BOOST_TEST_TRAIT_FALSE((is_tuple_like)); + BOOST_TEST_TRAIT_FALSE((is_tuple_like)); + + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::pair >)); + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::pair const >)); + +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) + + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::array >)); + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::array const >)); + + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::array >)); + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::array const >)); + + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::array >)); + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::array const >)); + + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::array >)); + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::array const >)); + +#endif + +#if !defined(BOOST_NO_CXX11_HDR_TUPLE) + + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<> >)); + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple<> const >)); + + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple >)); + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple const >)); + + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple >)); + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple const >)); + + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple >)); + BOOST_TEST_TRAIT_TRUE((is_tuple_like< std::tuple const >)); + +#endif + + return boost::report_errors(); +} diff --git a/test/is_unordered_range.cpp b/test/is_unordered_range.cpp new file mode 100644 index 0000000..42a4fd1 --- /dev/null +++ b/test/is_unordered_range.cpp @@ -0,0 +1,98 @@ + +// Copyright 2017 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) +# include +#endif +#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST) +# include +#endif +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) +# include +#endif +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) +# include +#endif + +struct X +{ +}; + +int main() +{ + using boost::hash2::is_unordered_range; + + BOOST_TEST_TRAIT_FALSE((is_unordered_range)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range)); + + BOOST_TEST_TRAIT_FALSE((is_unordered_range)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range)); + + BOOST_TEST_TRAIT_FALSE((is_unordered_range)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range)); + + BOOST_TEST_TRAIT_FALSE((is_unordered_range)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range)); + + BOOST_TEST_TRAIT_FALSE((is_unordered_range)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range)); + + BOOST_TEST_TRAIT_FALSE((is_unordered_range)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range)); + + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::vector >)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::vector const >)); + + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::deque >)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::deque const >)); + + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::set >)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::set const >)); + + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::multiset >)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::multiset const >)); + + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::map >)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::map const >)); + + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::multimap >)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::multimap const >)); + +#if !defined(BOOST_NO_CXX11_HDR_ARRAY) + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::array >)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::array const >)); +#endif + +#if !defined(BOOST_NO_CXX11_HDR_FORWARD_LIST) + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::forward_list >)); + BOOST_TEST_TRAIT_FALSE((is_unordered_range< std::forward_list const >)); +#endif + +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) + BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_set >)); + BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_set const >)); + + BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_multiset >)); + BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_multiset const >)); +#endif + +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) + BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_map >)); + BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_map const >)); + + BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_multimap >)); + BOOST_TEST_TRAIT_TRUE((is_unordered_range< std::unordered_multimap const >)); +#endif + + return boost::report_errors(); +} diff --git a/test/map.cpp b/test/map.cpp new file mode 100644 index 0000000..d4eebc8 --- /dev/null +++ b/test/map.cpp @@ -0,0 +1,84 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// Endian-dependent test + +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) +# include +#endif + +template void test( R r ) +{ + { + M m; + + for( int i = 0; i < 64; ++i ) + { + m.insert( typename M::value_type( i, 3 * i + 1 ) ); + } + + H h; + + hash_append( h, m ); + + BOOST_TEST_EQ( h.result(), r ); + } + + { + M m; + + for( int i = 0; i < 64; ++i ) + { + int j = 63 - i; + m.insert( typename M::value_type( j, 3 * j + 1 ) ); + } + + H h; + + hash_append( h, m ); + + BOOST_TEST_EQ( h.result(), r ); + } + + { + M m; + + for( int i = 0; i < 64; ++i ) + { + int j = ( i * 17 ) % 64; + m.insert( typename M::value_type( j, 3 * j + 1 ) ); + } + + H h; + + hash_append( h, m ); + + BOOST_TEST_EQ( h.result(), r ); + } +} + +int main() +{ + test< boost::hash2::fnv1a_32, std::map >( 3152726101ul ); + test< boost::hash2::fnv1a_64, std::map >( 12051529320333828229ull ); + + test< boost::hash2::fnv1a_32, std::multimap >( 3152726101ul ); + test< boost::hash2::fnv1a_64, std::multimap >( 12051529320333828229ull ); + +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) + + test< boost::hash2::fnv1a_32, std::unordered_map >( 2742410178ul ); + test< boost::hash2::fnv1a_64, std::unordered_map >( 2617313294186790738ull ); + + test< boost::hash2::fnv1a_32, std::unordered_multimap >( 2742410178ul ); + test< boost::hash2::fnv1a_64, std::unordered_multimap >( 2617313294186790738ull ); + +#endif + + return boost::report_errors(); +} diff --git a/test/md5.cpp b/test/md5.cpp new file mode 100644 index 0000000..5cdbc6f --- /dev/null +++ b/test/md5.cpp @@ -0,0 +1,56 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include + +using boost::hash2::byte_type; + +template std::string to_string( boost::array const & v ) +{ + std::string r; + + for( std::size_t i = 0; i < N; ++i ) + { + char buffer[ 8 ]; + + std::sprintf( buffer, "%02x", static_cast( v[ i ] ) ); + + r += buffer; + } + + return r; +} + +template std::string digest( char const * s ) +{ + H h; + + h.update( reinterpret_cast( s ), std::strlen( s ) ); + + return to_string( h.result() ); +} + +using boost::hash2::md5_128; + +int main() +{ + // Test vectors from https://tools.ietf.org/html/rfc1321 + + BOOST_TEST_EQ( digest( "" ), std::string( "d41d8cd98f00b204e9800998ecf8427e" ) ); + BOOST_TEST_EQ( digest( "a" ), std::string( "0cc175b9c0f1b6a831c399e269772661" ) ); + BOOST_TEST_EQ( digest( "abc" ), std::string( "900150983cd24fb0d6963f7d28e17f72" ) ); + BOOST_TEST_EQ( digest( "message digest" ), std::string( "f96b697d7cb7938d525a2f31aaf161d0" ) ); + BOOST_TEST_EQ( digest( "abcdefghijklmnopqrstuvwxyz" ), std::string( "c3fcd3d76192e4007dfb496cca67e13b" ) ); + BOOST_TEST_EQ( digest( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" ), std::string( "d174ab98d277d9f5a5611c2c9f419d9f" ) ); + BOOST_TEST_EQ( digest( "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ), std::string( "57edf4a22be3c955ac49da2e2107b67a" ) ); + + return boost::report_errors(); +} diff --git a/test/multiple_result.cpp b/test/multiple_result.cpp new file mode 100644 index 0000000..c5d4f14 --- /dev/null +++ b/test/multiple_result.cpp @@ -0,0 +1,49 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template void test() +{ + H h; + + typename H::result_type r1 = h.result(); + + typename H::result_type r2 = h.result(); + BOOST_TEST( r1 != r2 ); + + typename H::result_type r3 = h.result(); + BOOST_TEST( r2 != r3 ); + + typename H::result_type r4 = h.result(); + BOOST_TEST( r3 != r4 ); +} + +int main() +{ + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + + return boost::report_errors(); +} diff --git a/test/murmur3_128.cpp b/test/murmur3_128.cpp new file mode 100644 index 0000000..67d2951 --- /dev/null +++ b/test/murmur3_128.cpp @@ -0,0 +1,56 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include +#include + +using boost::hash2::byte_type; + +template std::string to_string( boost::array const & v ) +{ + std::string r; + + for( std::size_t i = 0; i < N; ++i ) + { + char buffer[ 8 ]; + + std::sprintf( buffer, "%02x", static_cast( v[ i ] ) ); + + r += buffer; + } + + return r; +} + +template std::string hash( char const (&s)[ N ], S seed ) +{ + H h( seed ); + + h.update( reinterpret_cast( s ), N-1 ); + + return to_string( h.result() ); +} + +int main() +{ + // Test vectors from https://pastebin.com/k2VDbWkF + + BOOST_TEST_EQ( hash( "The quick brown fox jumps over the lazy dog", 0 ), std::string( "6c1b07bc7bbc4be347939ac4a93c437a" ) ); + BOOST_TEST_EQ( hash( "The quick brown fox jumps over the lazy cog", 0 ), std::string( "9a2685ff70a98c653e5c8ea6eae3fe43" ) ); + + BOOST_TEST_EQ( hash( "The quick brown fox jumps over the lazy dog", 0x9747B28Cu ), std::string( "213163d23b7f8a73e516c07e727345f9" ) ); + BOOST_TEST_EQ( hash( "The quick brown fox jumps over the lazy cog", 0x9747B28Cu ), std::string( "94618270b057cdb83cf873585b456f55" ) ); + + BOOST_TEST_EQ( hash( "The quick brown fox jumps over the lazy dog", 0xC58F1A7Bu ), std::string( "ff9d0cd2ee401fac26f5efde525c9338" ) ); + BOOST_TEST_EQ( hash( "The quick brown fox jumps over the lazy cog", 0xC58F1A7Bu ), std::string( "8c935c5b843839f964b24f7ad58bbccd" ) ); + + return boost::report_errors(); +} diff --git a/test/murmur3_32.cpp b/test/murmur3_32.cpp new file mode 100644 index 0000000..2b68f8a --- /dev/null +++ b/test/murmur3_32.cpp @@ -0,0 +1,45 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include + +template typename H::result_type hash( char const (&s)[ N ], S seed ) +{ + H h( seed ); + + h.update( reinterpret_cast( s ), N-1 ); + + return h.result(); +} + +int main() +{ + // Test vectors from https://stackoverflow.com/questions/14747343/murmurhash3-test-vectors + + BOOST_TEST_EQ( hash( "", 0 ), 0 ); + BOOST_TEST_EQ( hash( "", 1 ), 0x514E28B7u ); + BOOST_TEST_EQ( hash( "", 0xFFFFFFFFu ), 0x81F16F39u ); + + BOOST_TEST_EQ( hash( "\xFF\xFF\xFF\xFF", 0 ), 0x76293B50u ); + BOOST_TEST_EQ( hash( "\x21\x43\x65\x87", 0 ), 0xF55B516Bu ); + BOOST_TEST_EQ( hash( "\x21\x43\x65\x87", 0x5082EDEEu ), 0x2362F9DEu ); + BOOST_TEST_EQ( hash( "\x21\x43\x65", 0 ), 0x7E4A8634u ); + BOOST_TEST_EQ( hash( "\x21\x43", 0 ), 0xA0F7B07Au ); + BOOST_TEST_EQ( hash( "\x21", 0 ), 0x72661CF4u ); + + BOOST_TEST_EQ( hash( "\x00\x00\x00\x00", 0 ), 0x2362F9DEu ); + BOOST_TEST_EQ( hash( "\x00\x00\x00", 0 ), 0x85F0B427u ); + BOOST_TEST_EQ( hash( "\x00\x00", 0 ), 0x30F4C306u ); + BOOST_TEST_EQ( hash( "\x00", 0 ), 0x514E28B7u ); + + BOOST_TEST_EQ( hash( "abc", 0 ), 0xB3DD93FAu ); + BOOST_TEST_EQ( hash( "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 0 ), 0xEE925B90u ); + BOOST_TEST_EQ( hash( "The quick brown fox jumps over the lazy dog", 0x9747B28Cu ), 0x2FA826CDu ); + + return boost::report_errors(); +} diff --git a/test/plaintext_leak.cpp b/test/plaintext_leak.cpp new file mode 100644 index 0000000..4557178 --- /dev/null +++ b/test/plaintext_leak.cpp @@ -0,0 +1,70 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using boost::hash2::byte_type; + +template void test() +{ + char const * s = "xxxx"; + + { + H h; + + h.update( reinterpret_cast( s ), 4 ); + + h.result(); + + unsigned char const * p = reinterpret_cast( &h ); + std::size_t n = sizeof( h ); + + BOOST_TEST_EQ( std::search( p, p + n, s, s + 4 ) - p, n ); + } + + { + H h; + + byte_type buffer[ 1024 ] = {}; + h.update( buffer, 1024 ); + + h.update( reinterpret_cast( s ), 4 ); + + h.result(); + + unsigned char const * p = reinterpret_cast( &h ); + std::size_t n = sizeof( h ); + + BOOST_TEST_EQ( std::search( p, p + n, s, s + 4 ) - p, n ); + } +} + +int main() +{ + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + + return boost::report_errors(); +} diff --git a/test/set.cpp b/test/set.cpp new file mode 100644 index 0000000..7464a80 --- /dev/null +++ b/test/set.cpp @@ -0,0 +1,82 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// +// Endian-dependent test + +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) +# include +#endif + +template void test( R r ) +{ + { + S s; + + for( int i = 0; i < 64; ++i ) + { + s.insert( i ); + } + + H h; + + hash_append( h, s ); + + BOOST_TEST_EQ( h.result(), r ); + } + + { + S s; + + for( int i = 0; i < 64; ++i ) + { + s.insert( 63 - i ); + } + + H h; + + hash_append( h, s ); + + BOOST_TEST_EQ( h.result(), r ); + } + + { + S s; + + for( int i = 0; i < 64; ++i ) + { + s.insert( ( i * 17 ) % 64 ); + } + + H h; + + hash_append( h, s ); + + BOOST_TEST_EQ( h.result(), r ); + } +} + +int main() +{ + test< boost::hash2::fnv1a_32, std::set >( 2078558933ul ); + test< boost::hash2::fnv1a_64, std::set >( 17046016161958689285ull ); + + test< boost::hash2::fnv1a_32, std::multiset >( 2078558933ul ); + test< boost::hash2::fnv1a_64, std::multiset >( 17046016161958689285ull ); + +#if !defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) + + test< boost::hash2::fnv1a_32, std::unordered_set >( 2270492092ul ); + test< boost::hash2::fnv1a_64, std::unordered_set >( 3232503781718511241ull ); + + test< boost::hash2::fnv1a_32, std::unordered_multiset >( 2270492092ul ); + test< boost::hash2::fnv1a_64, std::unordered_multiset >( 3232503781718511241ull ); + +#endif + + return boost::report_errors(); +} diff --git a/test/sha1.cpp b/test/sha1.cpp new file mode 100644 index 0000000..a0c5ec1 --- /dev/null +++ b/test/sha1.cpp @@ -0,0 +1,58 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include + +using boost::hash2::byte_type; + +template std::string to_string( boost::array const & v ) +{ + std::string r; + + for( std::size_t i = 0; i < N; ++i ) + { + char buffer[ 8 ]; + + std::sprintf( buffer, "%02x", static_cast( v[ i ] ) ); + + r += buffer; + } + + return r; +} + +template std::string digest( std::string const & s ) +{ + H h; + + h.update( reinterpret_cast( s.data() ), s.size() ); + + return to_string( h.result() ); +} + +using boost::hash2::sha1_160; + +int main() +{ + // Test vectors from https://en.wikipedia.org/wiki/SHA-1 + + BOOST_TEST_EQ( digest( "" ), std::string( "da39a3ee5e6b4b0d3255bfef95601890afd80709" ) ); + BOOST_TEST_EQ( digest( "The quick brown fox jumps over the lazy dog" ), std::string( "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12" ) ); + BOOST_TEST_EQ( digest( "The quick brown fox jumps over the lazy cog" ), std::string( "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3" ) ); + + // Test vectors from https://tools.ietf.org/html/rfc3174 + + BOOST_TEST_EQ( digest( "abc" ), std::string( "a9993e364706816aba3e25717850c26c9cd0d89d" ) ); + BOOST_TEST_EQ( digest( "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" ), std::string( "84983e441c3bd26ebaae4aa1f95129e5e54670f1" ) ); + BOOST_TEST_EQ( digest( std::string( 1000000, 'a' ) ), std::string( "34aa973cd4c4daa4f61eeb2bdbad27316534016f" ) ); + + return boost::report_errors(); +} diff --git a/test/siphash32.cpp b/test/siphash32.cpp new file mode 100644 index 0000000..d1e6647 --- /dev/null +++ b/test/siphash32.cpp @@ -0,0 +1,143 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include +#include + +static const boost::uint32_t vectors_sip32[64] = +{ + 0x5b9f35a9, + 0xb85a4727, + 0x03a662fa, + 0x04e7fe8a, + 0x89466e2a, + 0x69b6fac5, + 0x23fc6358, + 0xc563cf8b, + 0x8f84b8d0, + 0x79e706f8, + 0x3479b094, + 0x50300808, + 0x2f87f057, + 0xff63e677, + 0x7cf8ffd6, + 0x972bfe74, + 0x84acb5d9, + 0x5b6474c4, + 0x9b8d5b46, + 0x87e3ef7b, + 0x45104de3, + 0xb3623f61, + 0xfe67f370, + 0xbdb8ade6, + 0x630c4027, + 0x75787826, + 0x5f7b564f, + 0x69e6b03a, + 0x004064b0, + 0xb40f67ff, + 0x8b339e50, + 0x1a9f585d, + 0x1221e7fe, + 0x59327533, + 0x8c4f436a, + 0x29b728fe, + 0xecc65ce7, + 0x548d7e69, + 0x0f8b6863, + 0xb4620b65, + 0x4018bcb6, + 0x0545075d, + 0x2efd4224, + 0x3a86b77b, + 0x48d50577, + 0xb10852d7, + 0xc899d4b6, + 0x2e209208, + 0xe32ce169, + 0xe580b58d, + 0xc6649736, + 0x04026e01, + 0xd4f3853b, + 0xbe66dbfe, + 0x3a2a691e, + 0xc08489c6, + 0x40b9c5a5, + 0x8ce8e99b, + 0x4081bc7d, + 0xc58e077c, + 0x736ce7d4, + 0xb9cb8f42, + 0x7a9983bd, + 0x744aea59, +}; + +int main() +{ + { + unsigned char in[ 64 ]; + + for( int i = 0; i < 64; ++i ) + { + in[ i ] = static_cast( i ); + + boost::hash2::siphash_32 h( 0x03020100, 0x07060504 ); + + h.update( reinterpret_cast( in ), i ); + + BOOST_TEST_EQ( h.result(), vectors_sip32[ i ] ); + } + } + + { + unsigned char in[ 64 ]; + + for( int i = 0; i < 64; ++i ) + { + in[ i ] = static_cast( i ); + + boost::hash2::siphash_32 h( 0x03020100, 0x07060504 ); + + hash_append_range( h, in, in + i ); + + BOOST_TEST_EQ( h.result(), vectors_sip32[ i ] ); + } + } + + { + std::vector in; + + for( int i = 0; i < 64; ++i ) + { + boost::hash2::siphash_32 h( 0x03020100, 0x07060504 ); + + hash_append_range( h, in.begin(), in.end() ); + + BOOST_TEST_EQ( h.result(), vectors_sip32[ i ] ); + + in.push_back( static_cast( i ) ); + } + } + + { + std::list in; + + for( int i = 0; i < 64; ++i ) + { + boost::hash2::siphash_32 h( 0x03020100, 0x07060504 ); + + hash_append_range( h, in.begin(), in.end() ); + + BOOST_TEST_EQ( h.result(), vectors_sip32[ i ] ); + + in.push_back( static_cast( i ) ); + } + } + + return boost::report_errors(); +} diff --git a/test/siphash64.cpp b/test/siphash64.cpp new file mode 100644 index 0000000..17e26d7 --- /dev/null +++ b/test/siphash64.cpp @@ -0,0 +1,143 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include +#include + +static const boost::uint64_t vectors_sip64[64] = +{ + 0x726fdb47dd0e0e31, + 0x74f839c593dc67fd, + 0x0d6c8009d9a94f5a, + 0x85676696d7fb7e2d, + 0xcf2794e0277187b7, + 0x18765564cd99a68d, + 0xcbc9466e58fee3ce, + 0xab0200f58b01d137, + 0x93f5f5799a932462, + 0x9e0082df0ba9e4b0, + 0x7a5dbbc594ddb9f3, + 0xf4b32f46226bada7, + 0x751e8fbc860ee5fb, + 0x14ea5627c0843d90, + 0xf723ca908e7af2ee, + 0xa129ca6149be45e5, + 0x3f2acc7f57c29bdb, + 0x699ae9f52cbe4794, + 0x4bc1b3f0968dd39c, + 0xbb6dc91da77961bd, + 0xbed65cf21aa2ee98, + 0xd0f2cbb02e3b67c7, + 0x93536795e3a33e88, + 0xa80c038ccd5ccec8, + 0xb8ad50c6f649af94, + 0xbce192de8a85b8ea, + 0x17d835b85bbb15f3, + 0x2f2e6163076bcfad, + 0xde4daaaca71dc9a5, + 0xa6a2506687956571, + 0xad87a3535c49ef28, + 0x32d892fad841c342, + 0x7127512f72f27cce, + 0xa7f32346f95978e3, + 0x12e0b01abb051238, + 0x15e034d40fa197ae, + 0x314dffbe0815a3b4, + 0x027990f029623981, + 0xcadcd4e59ef40c4d, + 0x9abfd8766a33735c, + 0x0e3ea96b5304a7d0, + 0xad0c42d6fc585992, + 0x187306c89bc215a9, + 0xd4a60abcf3792b95, + 0xf935451de4f21df2, + 0xa9538f0419755787, + 0xdb9acddff56ca510, + 0xd06c98cd5c0975eb, + 0xe612a3cb9ecba951, + 0xc766e62cfcadaf96, + 0xee64435a9752fe72, + 0xa192d576b245165a, + 0x0a8787bf8ecb74b2, + 0x81b3e73d20b49b6f, + 0x7fa8220ba3b2ecea, + 0x245731c13ca42499, + 0xb78dbfaf3a8d83bd, + 0xea1ad565322a1a0b, + 0x60e61c23a3795013, + 0x6606d7e446282b93, + 0x6ca4ecb15c5f91e1, + 0x9f626da15c9625f3, + 0xe51b38608ef25f57, + 0x958a324ceb064572, +}; + +int main() +{ + { + unsigned char in[ 64 ]; + + for( int i = 0; i < 64; ++i ) + { + in[ i ] = static_cast( i ); + + boost::hash2::siphash_64 h( 0x0706050403020100ull, 0x0F0E0D0C0B0A0908ull ); + + h.update( reinterpret_cast( in ), i ); + + BOOST_TEST_EQ( h.result(), vectors_sip64[ i ] ); + } + } + + { + unsigned char in[ 64 ]; + + for( int i = 0; i < 64; ++i ) + { + in[ i ] = static_cast( i ); + + boost::hash2::siphash_64 h( 0x0706050403020100ull, 0x0F0E0D0C0B0A0908ull ); + + hash_append_range( h, in, in + i ); + + BOOST_TEST_EQ( h.result(), vectors_sip64[ i ] ); + } + } + + { + std::vector in; + + for( int i = 0; i < 64; ++i ) + { + boost::hash2::siphash_64 h( 0x0706050403020100ull, 0x0F0E0D0C0B0A0908ull ); + + hash_append_range( h, in.begin(), in.end() ); + + BOOST_TEST_EQ( h.result(), vectors_sip64[ i ] ); + + in.push_back( static_cast( i ) ); + } + } + + { + std::list in; + + for( int i = 0; i < 64; ++i ) + { + boost::hash2::siphash_64 h( 0x0706050403020100ull, 0x0F0E0D0C0B0A0908ull ); + + hash_append_range( h, in.begin(), in.end() ); + + BOOST_TEST_EQ( h.result(), vectors_sip64[ i ] ); + + in.push_back( static_cast( i ) ); + } + } + + return boost::report_errors(); +} diff --git a/test/spooky2.cpp b/test/spooky2.cpp new file mode 100644 index 0000000..c94407e --- /dev/null +++ b/test/spooky2.cpp @@ -0,0 +1,108 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include + +int const N = 512; + +static const boost::uint32_t expected[ N ] = +{ + 0x6bf50919,0x70de1d26,0xa2b37298,0x35bc5fbf,0x8223b279,0x5bcb315e,0x53fe88a1,0xf9f1a233, + 0xee193982,0x54f86f29,0xc8772d36,0x9ed60886,0x5f23d1da,0x1ed9f474,0xf2ef0c89,0x83ec01f9, + 0xf274736c,0x7e9ac0df,0xc7aed250,0xb1015811,0xe23470f5,0x48ac20c4,0xe2ab3cd5,0x608f8363, + 0xd0639e68,0xc4e8e7ab,0x863c7c5b,0x4ea63579,0x99ae8622,0x170c658b,0x149ba493,0x027bca7c, + 0xe5cfc8b6,0xce01d9d7,0x11103330,0x5d1f5ed4,0xca720ecb,0xef408aec,0x733b90ec,0x855737a6, + 0x9856c65f,0x647411f7,0x50777c74,0xf0f1a8b7,0x9d7e55a5,0xc68dd371,0xfc1af2cc,0x75728d0a, + 0x390e5fdc,0xf389b84c,0xfb0ccf23,0xc95bad0e,0x5b1cb85a,0x6bdae14f,0x6deb4626,0x93047034, + 0x6f3266c6,0xf529c3bd,0x396322e7,0x3777d042,0x1cd6a5a2,0x197b402e,0xc28d0d2b,0x09c1afb4, + + 0x069c8bb7,0x6f9d4e1e,0xd2621b5c,0xea68108d,0x8660cb8f,0xd61e6de6,0x7fba15c7,0xaacfaa97, + 0xdb381902,0x4ea22649,0x5d414a1e,0xc3fc5984,0xa0fc9e10,0x347dc51c,0x37545fb6,0x8c84b26b, + 0xf57efa5d,0x56afaf16,0xb6e1eb94,0x9218536a,0xe3cc4967,0xd3275ef4,0xea63536e,0x6086e499, + 0xaccadce7,0xb0290d82,0x4ebfd0d6,0x46ccc185,0x2eeb10d3,0x474e3c8c,0x23c84aee,0x3abae1cb, + 0x1499b81a,0xa2993951,0xeed176ad,0xdfcfe84c,0xde4a961f,0x4af13fe6,0xe0069c42,0xc14de8f5, + 0x6e02ce8f,0x90d19f7f,0xbca4a484,0xd4efdd63,0x780fd504,0xe80310e3,0x03abbc12,0x90023849, + 0xd6f6fb84,0xd6b354c5,0x5b8575f0,0x758f14e4,0x450de862,0x90704afb,0x47209a33,0xf226b726, + 0xf858dab8,0x7c0d6de9,0xb05ce777,0xee5ff2d4,0x7acb6d5c,0x2d663f85,0x41c72a91,0x82356bf2, + + 0x94e948ec,0xd358d448,0xeca7814d,0x78cd7950,0xd6097277,0x97782a5d,0xf43fc6f4,0x105f0a38, + 0x9e170082,0x4bfe566b,0x4371d25f,0xef25a364,0x698eb672,0x74f850e4,0x4678ff99,0x4a290dc6, + 0x3918f07c,0x32c7d9cd,0x9f28e0af,0x0d3c5a86,0x7bfc8a45,0xddf0c7e1,0xdeacb86b,0x970b3c5c, + 0x5e29e199,0xea28346d,0x6b59e71b,0xf8a8a46a,0x862f6ce4,0x3ccb740b,0x08761e9e,0xbfa01e5f, + 0xf17cfa14,0x2dbf99fb,0x7a0be420,0x06137517,0xe020b266,0xd25bfc61,0xff10ed00,0x42e6be8b, + 0x029ef587,0x683b26e0,0xb08afc70,0x7c1fd59e,0xbaae9a70,0x98c8c801,0xb6e35a26,0x57083971, + 0x90a6a680,0x1b44169e,0x1dce237c,0x518e0a59,0xccb11358,0x7b8175fb,0xb8fe701a,0x10d259bb, + 0xe806ce10,0x9212be79,0x4604ae7b,0x7fa22a84,0xe715b13a,0x0394c3b2,0x11efbbae,0xe13d9e19, + + 0x77e012bd,0x2d05114c,0xaecf2ddd,0xb2a2b4aa,0xb9429546,0x55dce815,0xc89138f8,0x46dcae20, + 0x1f6f7162,0x0c557ebc,0x5b996932,0xafbbe7e2,0xd2bd5f62,0xff475b9f,0x9cec7108,0xeaddcffb, + 0x5d751aef,0xf68f7bdf,0xf3f4e246,0x00983fcd,0x00bc82bb,0xbf5fd3e7,0xe80c7e2c,0x187d8b1f, + 0xefafb9a7,0x8f27a148,0x5c9606a9,0xf2d2be3e,0xe992d13a,0xe4bcd152,0xce40b436,0x63d6a1fc, + 0xdc1455c4,0x64641e39,0xd83010c9,0x2d535ae0,0x5b748f3e,0xf9a9146b,0x80f10294,0x2859acd4, + 0x5fc846da,0x56d190e9,0x82167225,0x98e4daba,0xbf7865f3,0x00da7ae4,0x9b7cd126,0x644172f8, + 0xde40c78f,0xe8803efc,0xdd331a2b,0x48485c3c,0x4ed01ddc,0x9c0b2d9e,0xb1c6e9d7,0xd797d43c, + 0x274101ff,0x3bf7e127,0x91ebbc56,0x7ffeb321,0x4d42096f,0xd6e9456a,0x0bade318,0x2f40ee0b, + + 0x38cebf03,0x0cbc2e72,0xbf03e704,0x7b3e7a9a,0x8e985acd,0x90917617,0x413895f8,0xf11dde04, + 0xc66f8244,0xe5648174,0x6c420271,0x2469d463,0x2540b033,0xdc788e7b,0xe4140ded,0x0990630a, + 0xa54abed4,0x6e124829,0xd940155a,0x1c8836f6,0x38fda06c,0x5207ab69,0xf8be9342,0x774882a8, + 0x56fc0d7e,0x53a99d6e,0x8241f634,0x9490954d,0x447130aa,0x8cc4a81f,0x0868ec83,0xc22c642d, + 0x47880140,0xfbff3bec,0x0f531f41,0xf845a667,0x08c15fb7,0x1996cd81,0x86579103,0xe21dd863, + 0x513d7f97,0x3984a1f1,0xdfcdc5f4,0x97766a5e,0x37e2b1da,0x41441f3f,0xabd9ddba,0x23b755a9, + 0xda937945,0x103e650e,0x3eef7c8f,0x2760ff8d,0x2493a4cd,0x1d671225,0x3bf4bd4c,0xed6e1728, + 0xc70e9e30,0x4e05e529,0x928d5aa6,0x164d0220,0xb5184306,0x4bd7efb3,0x63830f11,0xf3a1526c, + + 0xf1545450,0xd41d5df5,0x25a5060d,0x77b368da,0x4fe33c7e,0xeae09021,0xfdb053c4,0x2930f18d, + 0xd37109ff,0x8511a781,0xc7e7cdd7,0x6aeabc45,0xebbeaeaa,0x9a0c4f11,0xda252cbb,0x5b248f41, + 0x5223b5eb,0xe32ab782,0x8e6a1c97,0x11d3f454,0x3e05bd16,0x0059001d,0xce13ac97,0xf83b2b4c, + 0x71db5c9a,0xdc8655a6,0x9e98597b,0x3fcae0a2,0x75e63ccd,0x076c72df,0x4754c6ad,0x26b5627b, + 0xd818c697,0x998d5f3d,0xe94fc7b2,0x1f49ad1a,0xca7ff4ea,0x9fe72c05,0xfbd0cbbf,0xb0388ceb, + 0xb76031e3,0xd0f53973,0xfb17907c,0xa4c4c10f,0x9f2d8af9,0xca0e56b0,0xb0d9b689,0xfcbf37a3, + 0xfede8f7d,0xf836511c,0x744003fc,0x89eba576,0xcfdcf6a6,0xc2007f52,0xaaaf683f,0x62d2f9ca, + 0xc996f77f,0x77a7b5b3,0x8ba7d0a4,0xef6a0819,0xa0d903c0,0x01b27431,0x58fffd4c,0x4827f45c, + + 0x44eb5634,0xae70edfc,0x591c740b,0x478bf338,0x2f3b513b,0x67bf518e,0x6fef4a0c,0x1e0b6917, + 0x5ac0edc5,0x2e328498,0x077de7d5,0x5726020b,0x2aeda888,0x45b637ca,0xcf60858d,0x3dc91ae2, + 0x3e6d5294,0xe6900d39,0x0f634c71,0x827a5fa4,0xc713994b,0x1c363494,0x3d43b615,0xe5fe7d15, + 0xf6ada4f2,0x472099d5,0x04360d39,0x7f2a71d0,0x88a4f5ff,0x2c28fac5,0x4cd64801,0xfd78dd33, + 0xc9bdd233,0x21e266cc,0x9bbf419d,0xcbf7d81d,0x80f15f96,0x04242657,0x53fb0f66,0xded11e46, + 0xf2fdba97,0x8d45c9f1,0x4eeae802,0x17003659,0xb9db81a7,0xe734b1b2,0x9503c54e,0xb7c77c3e, + 0x271dd0ab,0xd8b906b5,0x0d540ec6,0xf03b86e0,0x0fdb7d18,0x95e261af,0xad9ec04e,0x381f4a64, + 0xfec798d7,0x09ea20be,0x0ef4ca57,0x1e6195bb,0xfd0da78b,0xcea1653b,0x157d9777,0xf04af50f, + + 0xad7baa23,0xd181714a,0x9bbdab78,0x6c7d1577,0x645eb1e7,0xa0648264,0x35839ca6,0x2287ef45, + 0x32a64ca3,0x26111f6f,0x64814946,0xb0cddaf1,0x4351c59e,0x1b30471c,0xb970788a,0x30e9f597, + 0xd7e58df1,0xc6d2b953,0xf5f37cf4,0x3d7c419e,0xf91ecb2d,0x9c87fd5d,0xb22384ce,0x8c7ac51c, + 0x62c96801,0x57e54091,0x964536fe,0x13d3b189,0x4afd1580,0xeba62239,0xb82ea667,0xae18d43a, + 0xbef04402,0x1942534f,0xc54bf260,0x3c8267f5,0xa1020ddd,0x112fcc8a,0xde596266,0xe91d0856, + 0xf300c914,0xed84478e,0x5b65009e,0x4764da16,0xaf8e07a2,0x4088dc2c,0x9a0cad41,0x2c3f179b, + 0xa67b83f7,0xf27eab09,0xdbe10e28,0xf04c911f,0xd1169f87,0x8e1e4976,0x17f57744,0xe4f5a33f, + 0x27c2e04b,0x0b7523bd,0x07305776,0xc6be7503,0x918fa7c9,0xaf2e2cd9,0x82046f8e,0xcc1c8250 +}; + +int main() +{ + using boost::hash2::byte_type; + using boost::hash2::get_integral_result; + + byte_type buf[ N ]; + + for( int i = 0; i < N; ++i ) + { + buf[ i ] = static_cast( i + 128 ); + + boost::hash2::spooky2_128 h; + + h.update( buf, i ); + + boost::uint32_t r = get_integral_result( h.result() ); + + BOOST_TEST_EQ( r, expected[ i ] ); + } + + return boost::report_errors(); +} diff --git a/test/underlying_type.cpp b/test/underlying_type.cpp new file mode 100644 index 0000000..79a9d52 --- /dev/null +++ b/test/underlying_type.cpp @@ -0,0 +1,132 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include +#include +#include +#include + +enum E1 +{ + e1 +}; + +enum E2 +{ + e2 = SCHAR_MAX +}; + +enum E3 +{ + e3 = SCHAR_MIN +}; + +enum E4 +{ + e4 = UCHAR_MAX +}; + +enum E5 +{ + e5 = SHRT_MAX +}; + +enum E6 +{ + e6 = SHRT_MIN +}; + +enum E7 +{ + e7 = USHRT_MAX +}; + +enum E8 +{ + e8 = INT_MAX +}; + +enum E9 +{ + e9 = INT_MIN +}; + +enum E10 +{ + e10 = UINT_MAX +}; + +enum E11 +{ + e11 = LONG_MAX +}; + +enum E12 +{ + e12 = LONG_MIN +}; + +enum E13 +{ + e13 = ULONG_MAX +}; + +enum E14 +{ + e14 = LLONG_MAX +}; + +enum E15 +{ + e15 = LLONG_MIN +}; + +enum E16 +{ + e16 = ULLONG_MAX +}; + +template void test( E e ) +{ + typedef typename boost::hash2::underlying_type::type U; + + BOOST_TEST_TRAIT_TRUE(( boost::is_enum )); + BOOST_TEST_TRAIT_TRUE(( boost::is_integral )); + + BOOST_TEST_EQ( sizeof(E), sizeof(U) ); + + U u = static_cast( e ); + + BOOST_TEST_EQ( u, e ); + + unsigned char const * pe = reinterpret_cast( &e ); + unsigned char const * pu = reinterpret_cast( &u ); + + BOOST_TEST_ALL_EQ( pe, pe + sizeof( e ), pu, pu + sizeof( u ) ); +} + +int main() +{ + test( e1 ); + test( e2 ); + test( e3 ); + test( e4 ); + test( e5 ); + test( e6 ); + test( e7 ); + test( e8 ); + test( e9 ); + test( e10 ); + test( e11 ); + test( e12 ); + test( e13 ); + test( e14 ); + test( e15 ); + test( e16 ); + + return boost::report_errors(); +} diff --git a/test/xxhash.cpp b/test/xxhash.cpp new file mode 100644 index 0000000..0f54b2d --- /dev/null +++ b/test/xxhash.cpp @@ -0,0 +1,38 @@ + +// Copyright 2017, 2018 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. + +#include +#include +#include +#include + +template typename H::result_type hash( char const * s, S seed ) +{ + H h( seed ); + + h.update( reinterpret_cast( s ), std::strlen( s ) ); + + return h.result(); +} + +int main() +{ + // Test vectors from https://pixinsight.com/developer/pcl/doc/html/group__hash__functions.html + + BOOST_TEST_EQ( hash( "", 0 ), 0x2cc5d05u ); + BOOST_TEST_EQ( hash( "The quick brown fox jumps over the lazy dog", 43 ), 0x752cd1b8u ); + + BOOST_TEST_EQ( hash( "", 0 ), 0xef46db3751d8e999ull ); + BOOST_TEST_EQ( hash( "The quick brown fox jumps over the lazy dog", 43 ), 0x9a11f5e9468d7425ull ); + + // Test vectors from https://github.com/nashby/xxhash/blob/master/test/xxhash_test.rb + + BOOST_TEST_EQ( hash( "test", 0 ), 1042293711u ); + BOOST_TEST_EQ( hash( "test", 123 ), 2758658570u ); + + BOOST_TEST_EQ( hash( "test", 0 ), 5754696928334414137ull ); + BOOST_TEST_EQ( hash( "test", 123 ), 3134990500624303823ull ); + + return boost::report_errors(); +}