siphash.hpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. #ifndef BOOST_HASH2_SIPHASH_HPP_INCLUDED
  2. #define BOOST_HASH2_SIPHASH_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. // SipHash, https://131002.net/siphash/
  8. #include <boost/hash2/detail/read.hpp>
  9. #include <boost/hash2/detail/rot.hpp>
  10. #include <boost/hash2/detail/memcpy.hpp>
  11. #include <boost/hash2/detail/memset.hpp>
  12. #include <boost/hash2/detail/config.hpp>
  13. #include <boost/assert.hpp>
  14. #include <cstdint>
  15. #include <cstring>
  16. #include <cstddef>
  17. namespace boost
  18. {
  19. namespace hash2
  20. {
  21. class siphash_64
  22. {
  23. private:
  24. std::uint64_t v0 = 0x736f6d6570736575ULL;
  25. std::uint64_t v1 = 0x646f72616e646f6dULL;
  26. std::uint64_t v2 = 0x6c7967656e657261ULL;
  27. std::uint64_t v3 = 0x7465646279746573ULL;
  28. unsigned char buffer_[ 8 ] = {};
  29. std::size_t m_ = 0; // == n_ % 8
  30. std::uint64_t n_ = 0;
  31. private:
  32. BOOST_CXX14_CONSTEXPR void sipround()
  33. {
  34. v0 += v1;
  35. v1 = detail::rotl(v1, 13);
  36. v1 ^= v0;
  37. v0 = detail::rotl(v0, 32);
  38. v2 += v3;
  39. v3 = detail::rotl(v3, 16);
  40. v3 ^= v2;
  41. v0 += v3;
  42. v3 = detail::rotl(v3, 21);
  43. v3 ^= v0;
  44. v2 += v1;
  45. v1 = detail::rotl(v1, 17);
  46. v1 ^= v2;
  47. v2 = detail::rotl(v2, 32);
  48. }
  49. BOOST_CXX14_CONSTEXPR void update_( unsigned char const * p )
  50. {
  51. std::uint64_t m = detail::read64le( p );
  52. v3 ^= m;
  53. sipround();
  54. sipround();
  55. v0 ^= m;
  56. }
  57. public:
  58. using result_type = std::uint64_t;
  59. siphash_64() = default;
  60. BOOST_CXX14_CONSTEXPR explicit siphash_64( std::uint64_t seed )
  61. {
  62. v0 ^= seed;
  63. v2 ^= seed;
  64. }
  65. BOOST_CXX14_CONSTEXPR siphash_64( unsigned char const * p, std::size_t n )
  66. {
  67. if( n == 16 )
  68. {
  69. std::uint64_t k0 = detail::read64le( p + 0 );
  70. std::uint64_t k1 = detail::read64le( p + 8 );
  71. v0 ^= k0;
  72. v1 ^= k1;
  73. v2 ^= k0;
  74. v3 ^= k1;
  75. }
  76. else if( n != 0 )
  77. {
  78. update( p, n );
  79. result();
  80. }
  81. }
  82. siphash_64( void const * p, std::size_t n ): siphash_64( static_cast<unsigned char const*>( p ), n )
  83. {
  84. }
  85. BOOST_CXX14_CONSTEXPR void update( unsigned char const* p, std::size_t n )
  86. {
  87. BOOST_ASSERT( m_ == n_ % 8 );
  88. if( n == 0 ) return;
  89. n_ += n;
  90. if( m_ > 0 )
  91. {
  92. std::size_t k = 8 - m_;
  93. if( n < k )
  94. {
  95. k = n;
  96. }
  97. detail::memcpy( buffer_ + m_, p, k );
  98. p += k;
  99. n -= k;
  100. m_ += k;
  101. if( m_ < 8 ) return;
  102. BOOST_ASSERT( m_ == 8 );
  103. update_( buffer_ );
  104. m_ = 0;
  105. // clear buffered plaintext
  106. detail::memset( buffer_, 0, 8 );
  107. }
  108. BOOST_ASSERT( m_ == 0 );
  109. while( n >= 8 )
  110. {
  111. update_( p );
  112. p += 8;
  113. n -= 8;
  114. }
  115. BOOST_ASSERT( n < 8 );
  116. if( n > 0 )
  117. {
  118. detail::memcpy( buffer_, p, n );
  119. m_ = n;
  120. }
  121. BOOST_ASSERT( m_ == n_ % 8 );
  122. }
  123. void update( void const* pv, std::size_t n )
  124. {
  125. unsigned char const* p = static_cast<unsigned char const*>( pv );
  126. update( p, n );
  127. }
  128. BOOST_CXX14_CONSTEXPR std::uint64_t result()
  129. {
  130. BOOST_ASSERT( m_ == n_ % 8 );
  131. detail::memset( buffer_ + m_, 0, 8 - m_ );
  132. buffer_[ 7 ] = static_cast<unsigned char>( n_ & 0xFF );
  133. update_( buffer_ );
  134. v2 ^= 0xFF;
  135. sipround();
  136. sipround();
  137. sipround();
  138. sipround();
  139. n_ += 8 - m_;
  140. m_ = 0;
  141. // clear buffered plaintext
  142. detail::memset( buffer_, 0, 8 );
  143. return v0 ^ v1 ^ v2 ^ v3;
  144. }
  145. };
  146. class siphash_32
  147. {
  148. private:
  149. std::uint32_t v0 = 0;
  150. std::uint32_t v1 = 0;
  151. std::uint32_t v2 = 0x6c796765;
  152. std::uint32_t v3 = 0x74656462;
  153. unsigned char buffer_[ 4 ] = {};
  154. std::uint32_t m_ = 0; // == n_ % 4
  155. std::uint32_t n_ = 0;
  156. private:
  157. BOOST_CXX14_CONSTEXPR void sipround()
  158. {
  159. v0 += v1;
  160. v1 = detail::rotl(v1, 5);
  161. v1 ^= v0;
  162. v0 = detail::rotl(v0, 16);
  163. v2 += v3;
  164. v3 = detail::rotl(v3, 8);
  165. v3 ^= v2;
  166. v0 += v3;
  167. v3 = detail::rotl(v3, 7);
  168. v3 ^= v0;
  169. v2 += v1;
  170. v1 = detail::rotl(v1, 13);
  171. v1 ^= v2;
  172. v2 = detail::rotl(v2, 16);
  173. }
  174. BOOST_CXX14_CONSTEXPR void update_( unsigned char const * p )
  175. {
  176. std::uint32_t m = detail::read32le( p );
  177. v3 ^= m;
  178. sipround();
  179. sipround();
  180. v0 ^= m;
  181. }
  182. public:
  183. using result_type = std::uint32_t;
  184. siphash_32() = default;
  185. BOOST_CXX14_CONSTEXPR explicit siphash_32( std::uint64_t seed )
  186. {
  187. std::uint32_t k0 = static_cast<std::uint32_t>( seed );
  188. std::uint32_t k1 = static_cast<std::uint32_t>( seed >> 32 );
  189. v0 ^= k0;
  190. v1 ^= k1;
  191. v2 ^= k0;
  192. v3 ^= k1;
  193. }
  194. BOOST_CXX14_CONSTEXPR siphash_32( unsigned char const * p, std::size_t n )
  195. {
  196. if( n == 8 )
  197. {
  198. std::uint32_t k0 = detail::read32le( p + 0 );
  199. std::uint32_t k1 = detail::read32le( p + 4 );
  200. v0 ^= k0;
  201. v1 ^= k1;
  202. v2 ^= k0;
  203. v3 ^= k1;
  204. }
  205. else if( n != 0 )
  206. {
  207. update( p, n );
  208. result();
  209. }
  210. }
  211. siphash_32( void const * p, std::size_t n ): siphash_32( static_cast<unsigned char const*>( p ), n )
  212. {
  213. }
  214. BOOST_CXX14_CONSTEXPR void update( unsigned char const* p, std::size_t n )
  215. {
  216. BOOST_ASSERT( m_ == n_ % 4 );
  217. if( n == 0 ) return;
  218. n_ += static_cast<std::uint32_t>( n );
  219. if( m_ > 0 )
  220. {
  221. std::uint32_t k = 4 - m_;
  222. if( n < k )
  223. {
  224. k = static_cast<std::uint32_t>( n );
  225. }
  226. detail::memcpy( buffer_ + m_, p, k );
  227. p += k;
  228. n -= k;
  229. m_ += k;
  230. if( m_ < 4 ) return;
  231. BOOST_ASSERT( m_ == 4 );
  232. update_( buffer_ );
  233. m_ = 0;
  234. // clear buffered plaintext
  235. detail::memset( buffer_, 0, 4 );
  236. }
  237. BOOST_ASSERT( m_ == 0 );
  238. while( n >= 4 )
  239. {
  240. update_( p );
  241. p += 4;
  242. n -= 4;
  243. }
  244. BOOST_ASSERT( n < 4 );
  245. if( n > 0 )
  246. {
  247. detail::memcpy( buffer_, p, n );
  248. m_ = static_cast<std::uint32_t>( n );
  249. }
  250. BOOST_ASSERT( m_ == n_ % 4 );
  251. }
  252. void update( void const* pv, std::size_t n )
  253. {
  254. unsigned char const* p = static_cast<unsigned char const*>( pv );
  255. update( p, n );
  256. }
  257. BOOST_CXX14_CONSTEXPR std::uint32_t result()
  258. {
  259. BOOST_ASSERT( m_ == n_ % 4 );
  260. detail::memset( buffer_ + m_, 0, 4 - m_ );
  261. buffer_[ 3 ] = static_cast<unsigned char>( n_ & 0xFF );
  262. update_( buffer_ );
  263. v2 ^= 0xFF;
  264. sipround();
  265. sipround();
  266. sipround();
  267. sipround();
  268. n_ += 4 - m_;
  269. m_ = 0;
  270. // clear buffered plaintext
  271. detail::memset( buffer_, 0, 4 );
  272. return v1 ^ v3;
  273. }
  274. };
  275. } // namespace hash2
  276. } // namespace boost
  277. #endif // #ifndef BOOST_HASH2_SIPHASH_HPP_INCLUDED