spooky2.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. #ifndef BOOST_HASH2_SPOOKY2_HPP_INCLUDED
  2. #define BOOST_HASH2_SPOOKY2_HPP_INCLUDED
  3. // Copyright 2017, 2018 Peter Dimov.
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // https://www.boost.org/LICENSE_1_0.txt
  6. //
  7. // SpookyHash V2, http://burtleburtle.net/bob/hash/spooky.html
  8. #include <boost/hash2/detail/read.hpp>
  9. #include <boost/hash2/detail/write.hpp>
  10. #include <boost/hash2/detail/rot.hpp>
  11. #include <boost/assert.hpp>
  12. #include <cstdint>
  13. #include <array>
  14. #include <utility>
  15. #include <cstring>
  16. namespace boost
  17. {
  18. namespace hash2
  19. {
  20. class spooky2_128
  21. {
  22. private:
  23. static const std::uint64_t sc_const = 0xdeadbeefdeadbeefULL;
  24. private:
  25. static const int M = 12;
  26. std::uint64_t v_[ M ];
  27. static const int N = 192;
  28. unsigned char buffer_[ N ];
  29. std::size_t m_; // == n_ % N
  30. std::size_t n_;
  31. private:
  32. static inline void short_mix( std::uint64_t & h0, std::uint64_t & h1, std::uint64_t & h2, std::uint64_t & h3 )
  33. {
  34. h2 = detail::rotl( h2, 50 ); h2 += h3; h0 ^= h2;
  35. h3 = detail::rotl( h3, 52 ); h3 += h0; h1 ^= h3;
  36. h0 = detail::rotl( h0, 30 ); h0 += h1; h2 ^= h0;
  37. h1 = detail::rotl( h1, 41 ); h1 += h2; h3 ^= h1;
  38. h2 = detail::rotl( h2, 54 ); h2 += h3; h0 ^= h2;
  39. h3 = detail::rotl( h3, 48 ); h3 += h0; h1 ^= h3;
  40. h0 = detail::rotl( h0, 38 ); h0 += h1; h2 ^= h0;
  41. h1 = detail::rotl( h1, 37 ); h1 += h2; h3 ^= h1;
  42. h2 = detail::rotl( h2, 62 ); h2 += h3; h0 ^= h2;
  43. h3 = detail::rotl( h3, 34 ); h3 += h0; h1 ^= h3;
  44. h0 = detail::rotl( h0, 5 ); h0 += h1; h2 ^= h0;
  45. h1 = detail::rotl( h1, 36 ); h1 += h2; h3 ^= h1;
  46. }
  47. static inline void short_end( std::uint64_t & h0, std::uint64_t & h1, std::uint64_t & h2, std::uint64_t & h3 )
  48. {
  49. h3 ^= h2; h2 = detail::rotl( h2, 15 ); h3 += h2;
  50. h0 ^= h3; h3 = detail::rotl( h3, 52 ); h0 += h3;
  51. h1 ^= h0; h0 = detail::rotl( h0, 26 ); h1 += h0;
  52. h2 ^= h1; h1 = detail::rotl( h1, 51 ); h2 += h1;
  53. h3 ^= h2; h2 = detail::rotl( h2, 28 ); h3 += h2;
  54. h0 ^= h3; h3 = detail::rotl( h3, 9 ); h0 += h3;
  55. h1 ^= h0; h0 = detail::rotl( h0, 47 ); h1 += h0;
  56. h2 ^= h1; h1 = detail::rotl( h1, 54 ); h2 += h1;
  57. h3 ^= h2; h2 = detail::rotl( h2, 32 ); h3 += h2;
  58. h0 ^= h3; h3 = detail::rotl( h3, 25 ); h0 += h3;
  59. h1 ^= h0; h0 = detail::rotl( h0, 63 ); h1 += h0;
  60. }
  61. static void short_hash( unsigned char const * p, std::size_t n, std::uint64_t & hash1, std::uint64_t & hash2 )
  62. {
  63. std::uint64_t a = hash1;
  64. std::uint64_t b = hash2;
  65. std::uint64_t c = sc_const;
  66. std::uint64_t d = sc_const;
  67. std::size_t m = n;
  68. while( m >= 32 )
  69. {
  70. c += detail::read64le( p + 0 );
  71. d += detail::read64le( p + 8 );
  72. short_mix( a, b, c, d );
  73. a += detail::read64le( p + 16 );
  74. b += detail::read64le( p + 24 );
  75. p += 32;
  76. m -= 32;
  77. }
  78. if( m >= 16 )
  79. {
  80. c += detail::read64le( p + 0 );
  81. d += detail::read64le( p + 8 );
  82. short_mix( a, b, c, d );
  83. p += 16;
  84. m -= 16;
  85. }
  86. if( m == 0 )
  87. {
  88. c += sc_const;
  89. d += sc_const;
  90. }
  91. else
  92. {
  93. BOOST_ASSERT( m < 16 );
  94. unsigned char tmp[ 16 ] = { 0 };
  95. std::memcpy( tmp, p, m );
  96. c += detail::read64le( tmp + 0 );
  97. d += detail::read64le( tmp + 8 );
  98. }
  99. d += static_cast<std::uint64_t>( n ) << 56;
  100. short_end( a, b, c, d );
  101. hash1 = a;
  102. hash2 = b;
  103. }
  104. private:
  105. static inline void mix( unsigned char const * p,
  106. std::uint64_t & s0, std::uint64_t & s1, std::uint64_t & s2, std::uint64_t & s3,
  107. std::uint64_t & s4, std::uint64_t & s5, std::uint64_t & s6, std::uint64_t & s7,
  108. std::uint64_t & s8, std::uint64_t & s9, std::uint64_t & s10, std::uint64_t & s11 )
  109. {
  110. s0 += detail::read64le( p + 0 ); s2 ^= s10; s11 ^= s0; s0 = detail::rotl( s0, 11 ); s11 += s1;
  111. s1 += detail::read64le( p + 8 ); s3 ^= s11; s0 ^= s1; s1 = detail::rotl( s1, 32 ); s0 += s2;
  112. s2 += detail::read64le( p + 16 ); s4 ^= s0; s1 ^= s2; s2 = detail::rotl( s2, 43 ); s1 += s3;
  113. s3 += detail::read64le( p + 24 ); s5 ^= s1; s2 ^= s3; s3 = detail::rotl( s3, 31 ); s2 += s4;
  114. s4 += detail::read64le( p + 32 ); s6 ^= s2; s3 ^= s4; s4 = detail::rotl( s4, 17 ); s3 += s5;
  115. s5 += detail::read64le( p + 40 ); s7 ^= s3; s4 ^= s5; s5 = detail::rotl( s5, 28 ); s4 += s6;
  116. s6 += detail::read64le( p + 48 ); s8 ^= s4; s5 ^= s6; s6 = detail::rotl( s6, 39 ); s5 += s7;
  117. s7 += detail::read64le( p + 56 ); s9 ^= s5; s6 ^= s7; s7 = detail::rotl( s7, 57 ); s6 += s8;
  118. s8 += detail::read64le( p + 64 ); s10 ^= s6; s7 ^= s8; s8 = detail::rotl( s8, 55 ); s7 += s9;
  119. s9 += detail::read64le( p + 72 ); s11 ^= s7; s8 ^= s9; s9 = detail::rotl( s9, 54 ); s8 += s10;
  120. s10 += detail::read64le( p + 80 ); s0 ^= s8; s9 ^= s10; s10 = detail::rotl( s10, 22 ); s9 += s11;
  121. s11 += detail::read64le( p + 88 ); s1 ^= s9; s10 ^= s11; s11 = detail::rotl( s11, 46 ); s10 += s0;
  122. }
  123. void update_( unsigned char const * p, std::size_t k )
  124. {
  125. std::uint64_t h0 = v_[ 0];
  126. std::uint64_t h1 = v_[ 1];
  127. std::uint64_t h2 = v_[ 2];
  128. std::uint64_t h3 = v_[ 3];
  129. std::uint64_t h4 = v_[ 4];
  130. std::uint64_t h5 = v_[ 5];
  131. std::uint64_t h6 = v_[ 6];
  132. std::uint64_t h7 = v_[ 7];
  133. std::uint64_t h8 = v_[ 8];
  134. std::uint64_t h9 = v_[ 9];
  135. std::uint64_t h10 = v_[10];
  136. std::uint64_t h11 = v_[11];
  137. for( std::size_t i = 0; i < k; ++i, p += 96 )
  138. {
  139. mix( p, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
  140. }
  141. v_[ 0] = h0;
  142. v_[ 1] = h1;
  143. v_[ 2] = h2;
  144. v_[ 3] = h3;
  145. v_[ 4] = h4;
  146. v_[ 5] = h5;
  147. v_[ 6] = h6;
  148. v_[ 7] = h7;
  149. v_[ 8] = h8;
  150. v_[ 9] = h9;
  151. v_[10] = h10;
  152. v_[11] = h11;
  153. }
  154. static inline void end_partial(
  155. std::uint64_t & h0, std::uint64_t & h1, std::uint64_t & h2, std::uint64_t & h3,
  156. std::uint64_t & h4, std::uint64_t & h5, std::uint64_t & h6, std::uint64_t & h7,
  157. std::uint64_t & h8, std::uint64_t & h9, std::uint64_t & h10, std::uint64_t & h11 )
  158. {
  159. h11 += h1; h2 ^= h11; h1 = detail::rotl( h1, 44 );
  160. h0 += h2; h3 ^= h0; h2 = detail::rotl( h2, 15 );
  161. h1 += h3; h4 ^= h1; h3 = detail::rotl( h3, 34 );
  162. h2 += h4; h5 ^= h2; h4 = detail::rotl( h4, 21);
  163. h3 += h5; h6 ^= h3; h5 = detail::rotl( h5, 38);
  164. h4 += h6; h7 ^= h4; h6 = detail::rotl( h6, 33);
  165. h5 += h7; h8 ^= h5; h7 = detail::rotl( h7, 10);
  166. h6 += h8; h9 ^= h6; h8 = detail::rotl( h8, 13);
  167. h7 += h9; h10 ^= h7; h9 = detail::rotl( h9, 38);
  168. h8 += h10; h11 ^= h8; h10 = detail::rotl( h10, 53);
  169. h9 += h11; h0 ^= h9; h11 = detail::rotl( h11, 42);
  170. h10 += h0; h1 ^= h10; h0 = detail::rotl( h0, 54);
  171. }
  172. static inline void end( unsigned char const * p,
  173. std::uint64_t & h0, std::uint64_t & h1, std::uint64_t & h2, std::uint64_t & h3,
  174. std::uint64_t & h4, std::uint64_t & h5, std::uint64_t & h6, std::uint64_t & h7,
  175. std::uint64_t & h8, std::uint64_t & h9, std::uint64_t & h10, std::uint64_t & h11 )
  176. {
  177. h0 += detail::read64le( p + 0 );
  178. h1 += detail::read64le( p + 8 );
  179. h2 += detail::read64le( p + 16 );
  180. h3 += detail::read64le( p + 24 );
  181. h4 += detail::read64le( p + 32 );
  182. h5 += detail::read64le( p + 40 );
  183. h6 += detail::read64le( p + 48 );
  184. h7 += detail::read64le( p + 56 );
  185. h8 += detail::read64le( p + 64 );
  186. h9 += detail::read64le( p + 72 );
  187. h10 += detail::read64le( p + 80 );
  188. h11 += detail::read64le( p + 88 );
  189. end_partial( h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
  190. end_partial( h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
  191. end_partial( h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
  192. }
  193. void init( std::uint64_t seed1, std::uint64_t seed2 )
  194. {
  195. v_[ 0 ] = v_[ 3 ] = v_[ 6 ] = v_[ 9 ] = seed1;
  196. v_[ 1 ] = v_[ 4 ] = v_[ 7 ] = v_[ 10 ] = seed2;
  197. v_[ 2 ] = v_[ 5 ] = v_[ 8 ] = v_[ 11 ] = sc_const;
  198. }
  199. public:
  200. typedef std::array<unsigned char, 16> result_type;
  201. typedef std::uint64_t size_type;
  202. explicit spooky2_128( std::uint64_t seed1 = 0, std::uint64_t seed2 = 0 ): m_( 0 ), n_( 0 )
  203. {
  204. init( seed1, seed2 );
  205. }
  206. spooky2_128( unsigned char const * p, std::size_t n ): m_( 0 ), n_( 0 )
  207. {
  208. if( n == 0 )
  209. {
  210. init( 0, 0 );
  211. }
  212. else if( n <= 16 )
  213. {
  214. unsigned char q[ 18 ] = {};
  215. std::memcpy( q, p, n );
  216. std::uint64_t seed1 = detail::read64le( q + 0 );
  217. std::uint64_t seed2 = detail::read64le( q + 8 );
  218. init( seed1, seed2 );
  219. }
  220. else
  221. {
  222. std::uint64_t seed1 = detail::read64le( p + 0 );
  223. std::uint64_t seed2 = detail::read64le( p + 8 );
  224. init( seed1, seed2 );
  225. p += 16;
  226. n -= 16;
  227. update( p, n );
  228. result();
  229. }
  230. }
  231. void update( void const * pv, std::size_t n )
  232. {
  233. unsigned char const* p = static_cast<unsigned char const*>( pv );
  234. BOOST_ASSERT( m_ == n_ % N );
  235. if( n == 0 ) return;
  236. n_ += n;
  237. if( m_ > 0 )
  238. {
  239. std::size_t k = N - m_;
  240. if( n < k )
  241. {
  242. k = n;
  243. }
  244. std::memcpy( buffer_ + m_, p, k );
  245. p += k;
  246. n -= k;
  247. m_ += k;
  248. if( m_ < N ) return;
  249. BOOST_ASSERT( m_ == N );
  250. update_( buffer_, 2 );
  251. m_ = 0;
  252. }
  253. BOOST_ASSERT( m_ == 0 );
  254. {
  255. std::size_t k = n / N;
  256. update_( p, k * 2 );
  257. p += k * N;
  258. n -= k * N;
  259. }
  260. BOOST_ASSERT( n < N );
  261. if( n > 0 )
  262. {
  263. std::memcpy( buffer_, p, n );
  264. m_ = n;
  265. }
  266. BOOST_ASSERT( m_ == n_ % N );
  267. }
  268. result_type result()
  269. {
  270. BOOST_ASSERT( m_ == n_ % N );
  271. std::uint64_t h0 = v_[ 0 ];
  272. std::uint64_t h1 = v_[ 1 ];
  273. if( n_ < N )
  274. {
  275. short_hash( buffer_, n_, h0, h1 );
  276. }
  277. else
  278. {
  279. std::uint64_t h2 = v_[ 2 ];
  280. std::uint64_t h3 = v_[ 3 ];
  281. std::uint64_t h4 = v_[ 4 ];
  282. std::uint64_t h5 = v_[ 5 ];
  283. std::uint64_t h6 = v_[ 6 ];
  284. std::uint64_t h7 = v_[ 7 ];
  285. std::uint64_t h8 = v_[ 8 ];
  286. std::uint64_t h9 = v_[ 9 ];
  287. std::uint64_t h10 = v_[ 10 ];
  288. std::uint64_t h11 = v_[ 11 ];
  289. unsigned char * p = buffer_;
  290. std::size_t m = m_;
  291. if( m >= 96 )
  292. {
  293. mix( p, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
  294. p += 96;
  295. m -= 96;
  296. }
  297. std::memset( p + m, 0, 96 - m );
  298. p[ 95 ] = static_cast<unsigned char>( m & 0xFF );
  299. end( p, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
  300. v_[ 2 ] = h2;
  301. v_[ 3 ] = h3;
  302. v_[ 4 ] = h4;
  303. v_[ 5 ] = h5;
  304. v_[ 6 ] = h6;
  305. v_[ 7 ] = h7;
  306. v_[ 8 ] = h8;
  307. v_[ 9 ] = h9;
  308. v_[ 10 ] = h10;
  309. v_[ 11 ] = h11;
  310. }
  311. v_[ 0 ] = h0;
  312. v_[ 1 ] = h1;
  313. n_ += N - m_;
  314. m_ = 0;
  315. if( n_ < N )
  316. {
  317. n_ = 0; // in case of overflow (N does not divide 2^32)
  318. }
  319. // clear buffered plaintext
  320. std::memset( buffer_, 0, N );
  321. result_type r;
  322. detail::write64le( &r[ 0 ], h0 );
  323. detail::write64le( &r[ 8 ], h1 );
  324. return r;
  325. }
  326. };
  327. } // namespace hash2
  328. } // namespace boost
  329. #endif // #ifndef BOOST_HASH2_SPOOKY2_HPP_INCLUDED