Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:33:43

0001 #ifndef BOOST_HASH2_SPOOKY2_HPP_INCLUDED
0002 #define BOOST_HASH2_SPOOKY2_HPP_INCLUDED
0003 
0004 // Copyright 2017, 2018 Peter Dimov.
0005 // Distributed under the Boost Software License, Version 1.0.
0006 // https://www.boost.org/LICENSE_1_0.txt
0007 //
0008 // SpookyHash V2, http://burtleburtle.net/bob/hash/spooky.html
0009 
0010 #include <boost/hash2/detail/read.hpp>
0011 #include <boost/hash2/detail/write.hpp>
0012 #include <boost/hash2/detail/rot.hpp>
0013 #include <boost/assert.hpp>
0014 #include <cstdint>
0015 #include <array>
0016 #include <utility>
0017 #include <cstring>
0018 
0019 namespace boost
0020 {
0021 namespace hash2
0022 {
0023 
0024 class spooky2_128
0025 {
0026 private:
0027 
0028     static const std::uint64_t sc_const = 0xdeadbeefdeadbeefULL;
0029 
0030 private:
0031 
0032     static const int M = 12;
0033     std::uint64_t v_[ M ];
0034 
0035     static const int N = 192;
0036     unsigned char buffer_[ N ];
0037 
0038     std::size_t m_; // == n_ % N
0039 
0040     std::size_t n_;
0041 
0042 private:
0043 
0044     static inline void short_mix( std::uint64_t & h0, std::uint64_t & h1, std::uint64_t & h2, std::uint64_t & h3 )
0045     {
0046         h2 = detail::rotl( h2, 50 ); h2 += h3; h0 ^= h2;
0047         h3 = detail::rotl( h3, 52 ); h3 += h0; h1 ^= h3;
0048         h0 = detail::rotl( h0, 30 ); h0 += h1; h2 ^= h0;
0049         h1 = detail::rotl( h1, 41 ); h1 += h2; h3 ^= h1;
0050         h2 = detail::rotl( h2, 54 ); h2 += h3; h0 ^= h2;
0051         h3 = detail::rotl( h3, 48 ); h3 += h0; h1 ^= h3;
0052         h0 = detail::rotl( h0, 38 ); h0 += h1; h2 ^= h0;
0053         h1 = detail::rotl( h1, 37 ); h1 += h2; h3 ^= h1;
0054         h2 = detail::rotl( h2, 62 ); h2 += h3; h0 ^= h2;
0055         h3 = detail::rotl( h3, 34 ); h3 += h0; h1 ^= h3;
0056         h0 = detail::rotl( h0,  5 ); h0 += h1; h2 ^= h0;
0057         h1 = detail::rotl( h1, 36 ); h1 += h2; h3 ^= h1;
0058     }
0059 
0060     static inline void short_end( std::uint64_t & h0, std::uint64_t & h1, std::uint64_t & h2, std::uint64_t & h3 )
0061     {
0062         h3 ^= h2; h2 = detail::rotl( h2, 15 ); h3 += h2;
0063         h0 ^= h3; h3 = detail::rotl( h3, 52 ); h0 += h3;
0064         h1 ^= h0; h0 = detail::rotl( h0, 26 ); h1 += h0;
0065         h2 ^= h1; h1 = detail::rotl( h1, 51 ); h2 += h1;
0066         h3 ^= h2; h2 = detail::rotl( h2, 28 ); h3 += h2;
0067         h0 ^= h3; h3 = detail::rotl( h3,  9 ); h0 += h3;
0068         h1 ^= h0; h0 = detail::rotl( h0, 47 ); h1 += h0;
0069         h2 ^= h1; h1 = detail::rotl( h1, 54 ); h2 += h1;
0070         h3 ^= h2; h2 = detail::rotl( h2, 32 ); h3 += h2;
0071         h0 ^= h3; h3 = detail::rotl( h3, 25 ); h0 += h3;
0072         h1 ^= h0; h0 = detail::rotl( h0, 63 ); h1 += h0;
0073     }
0074 
0075     static void short_hash( unsigned char const * p, std::size_t n, std::uint64_t & hash1, std::uint64_t & hash2 )
0076     {
0077         std::uint64_t a = hash1;
0078         std::uint64_t b = hash2;
0079         std::uint64_t c = sc_const;
0080         std::uint64_t d = sc_const;
0081 
0082         std::size_t m = n;
0083 
0084         while( m >= 32 )
0085         {
0086             c += detail::read64le( p +  0 );
0087             d += detail::read64le( p +  8 );
0088 
0089             short_mix( a, b, c, d );
0090 
0091             a += detail::read64le( p + 16 );
0092             b += detail::read64le( p + 24 );
0093 
0094             p += 32;
0095             m -= 32;
0096         }
0097 
0098         if( m >= 16 )
0099         {
0100             c += detail::read64le( p +  0 );
0101             d += detail::read64le( p +  8 );
0102 
0103             short_mix( a, b, c, d );
0104 
0105             p += 16;
0106             m -= 16;
0107         }
0108 
0109         if( m == 0 )
0110         {
0111             c += sc_const;
0112             d += sc_const;
0113         }
0114         else
0115         {
0116             BOOST_ASSERT( m < 16 );
0117 
0118             unsigned char tmp[ 16 ] = { 0 };
0119             std::memcpy( tmp, p, m );
0120 
0121             c += detail::read64le( tmp + 0 );
0122             d += detail::read64le( tmp + 8 );
0123         }
0124 
0125         d += static_cast<std::uint64_t>( n ) << 56;
0126 
0127         short_end( a, b, c, d );
0128 
0129         hash1 = a;
0130         hash2 = b;
0131     }
0132 
0133 private:
0134 
0135     static inline void mix( unsigned char const * p,
0136         std::uint64_t & s0, std::uint64_t & s1, std::uint64_t &  s2, std::uint64_t &  s3,
0137         std::uint64_t & s4, std::uint64_t & s5, std::uint64_t &  s6, std::uint64_t &  s7,
0138         std::uint64_t & s8, std::uint64_t & s9, std::uint64_t & s10, std::uint64_t & s11 )
0139     {
0140         s0  += detail::read64le( p +  0 ); s2  ^= s10; s11 ^= s0;  s0  = detail::rotl( s0,  11 ); s11 += s1;
0141         s1  += detail::read64le( p +  8 ); s3  ^= s11; s0  ^= s1;  s1  = detail::rotl( s1,  32 ); s0  += s2;
0142         s2  += detail::read64le( p + 16 ); s4  ^= s0;  s1  ^= s2;  s2  = detail::rotl( s2,  43 ); s1  += s3;
0143         s3  += detail::read64le( p + 24 ); s5  ^= s1;  s2  ^= s3;  s3  = detail::rotl( s3,  31 ); s2  += s4;
0144         s4  += detail::read64le( p + 32 ); s6  ^= s2;  s3  ^= s4;  s4  = detail::rotl( s4,  17 ); s3  += s5;
0145         s5  += detail::read64le( p + 40 ); s7  ^= s3;  s4  ^= s5;  s5  = detail::rotl( s5,  28 ); s4  += s6;
0146         s6  += detail::read64le( p + 48 ); s8  ^= s4;  s5  ^= s6;  s6  = detail::rotl( s6,  39 ); s5  += s7;
0147         s7  += detail::read64le( p + 56 ); s9  ^= s5;  s6  ^= s7;  s7  = detail::rotl( s7,  57 ); s6  += s8;
0148         s8  += detail::read64le( p + 64 ); s10 ^= s6;  s7  ^= s8;  s8  = detail::rotl( s8,  55 ); s7  += s9;
0149         s9  += detail::read64le( p + 72 ); s11 ^= s7;  s8  ^= s9;  s9  = detail::rotl( s9,  54 ); s8  += s10;
0150         s10 += detail::read64le( p + 80 ); s0  ^= s8;  s9  ^= s10; s10 = detail::rotl( s10, 22 ); s9  += s11;
0151         s11 += detail::read64le( p + 88 ); s1  ^= s9;  s10 ^= s11; s11 = detail::rotl( s11, 46 ); s10 += s0;
0152     }
0153 
0154     void update_( unsigned char const * p, std::size_t k )
0155     {
0156         std::uint64_t h0  = v_[ 0];
0157         std::uint64_t h1  = v_[ 1];
0158         std::uint64_t h2  = v_[ 2];
0159         std::uint64_t h3  = v_[ 3];
0160         std::uint64_t h4  = v_[ 4];
0161         std::uint64_t h5  = v_[ 5];
0162         std::uint64_t h6  = v_[ 6];
0163         std::uint64_t h7  = v_[ 7];
0164         std::uint64_t h8  = v_[ 8];
0165         std::uint64_t h9  = v_[ 9];
0166         std::uint64_t h10 = v_[10];
0167         std::uint64_t h11 = v_[11];
0168 
0169         for( std::size_t i = 0; i < k; ++i, p += 96 )
0170         {
0171             mix( p, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
0172         }
0173 
0174         v_[ 0] = h0;
0175         v_[ 1] = h1;
0176         v_[ 2] = h2;
0177         v_[ 3] = h3;
0178         v_[ 4] = h4;
0179         v_[ 5] = h5;
0180         v_[ 6] = h6;
0181         v_[ 7] = h7;
0182         v_[ 8] = h8;
0183         v_[ 9] = h9;
0184         v_[10] = h10;
0185         v_[11] = h11;
0186     }
0187 
0188     static inline void end_partial(
0189         std::uint64_t & h0, std::uint64_t & h1, std::uint64_t &  h2, std::uint64_t &  h3,
0190         std::uint64_t & h4, std::uint64_t & h5, std::uint64_t &  h6, std::uint64_t &  h7, 
0191         std::uint64_t & h8, std::uint64_t & h9, std::uint64_t & h10, std::uint64_t & h11 )
0192     {
0193         h11 += h1;    h2  ^= h11;   h1  = detail::rotl( h1,  44 );
0194         h0  += h2;    h3  ^= h0;    h2  = detail::rotl( h2,  15 );
0195         h1  += h3;    h4  ^= h1;    h3  = detail::rotl( h3,  34 );
0196         h2  += h4;    h5  ^= h2;    h4  = detail::rotl( h4,  21);
0197         h3  += h5;    h6  ^= h3;    h5  = detail::rotl( h5,  38);
0198         h4  += h6;    h7  ^= h4;    h6  = detail::rotl( h6,  33);
0199         h5  += h7;    h8  ^= h5;    h7  = detail::rotl( h7,  10);
0200         h6  += h8;    h9  ^= h6;    h8  = detail::rotl( h8,  13);
0201         h7  += h9;    h10 ^= h7;    h9  = detail::rotl( h9,  38);
0202         h8  += h10;   h11 ^= h8;    h10 = detail::rotl( h10, 53);
0203         h9  += h11;   h0  ^= h9;    h11 = detail::rotl( h11, 42);
0204         h10 += h0;    h1  ^= h10;   h0  = detail::rotl( h0,  54);
0205     }
0206 
0207     static inline void end( unsigned char const * p,
0208         std::uint64_t & h0, std::uint64_t & h1, std::uint64_t &  h2, std::uint64_t &  h3,
0209         std::uint64_t & h4, std::uint64_t & h5, std::uint64_t &  h6, std::uint64_t &  h7, 
0210         std::uint64_t & h8, std::uint64_t & h9, std::uint64_t & h10, std::uint64_t & h11 )
0211     {
0212         h0  += detail::read64le( p +  0 );
0213         h1  += detail::read64le( p +  8 );
0214         h2  += detail::read64le( p + 16 );
0215         h3  += detail::read64le( p + 24 );
0216         h4  += detail::read64le( p + 32 );
0217         h5  += detail::read64le( p + 40 );
0218         h6  += detail::read64le( p + 48 );
0219         h7  += detail::read64le( p + 56 );
0220         h8  += detail::read64le( p + 64 );
0221         h9  += detail::read64le( p + 72 );
0222         h10 += detail::read64le( p + 80 );
0223         h11 += detail::read64le( p + 88 );
0224 
0225         end_partial( h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
0226         end_partial( h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
0227         end_partial( h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
0228     }
0229 
0230     void init( std::uint64_t seed1, std::uint64_t seed2 )
0231     {
0232         v_[ 0 ] = v_[ 3 ] = v_[ 6 ] = v_[  9 ] = seed1;
0233         v_[ 1 ] = v_[ 4 ] = v_[ 7 ] = v_[ 10 ] = seed2;
0234         v_[ 2 ] = v_[ 5 ] = v_[ 8 ] = v_[ 11 ] = sc_const;
0235     }
0236 
0237 public:
0238 
0239     typedef std::array<unsigned char, 16> result_type;
0240     typedef std::uint64_t size_type;
0241 
0242     explicit spooky2_128( std::uint64_t seed1 = 0, std::uint64_t seed2 = 0 ): m_( 0 ), n_( 0 )
0243     {
0244         init( seed1, seed2 );
0245     }
0246 
0247     spooky2_128( unsigned char const * p, std::size_t n ): m_( 0 ), n_( 0 )
0248     {
0249         if( n == 0 )
0250         {
0251             init( 0, 0 );
0252         }
0253         else if( n <= 16 )
0254         {
0255             unsigned char q[ 18 ] = {};
0256             std::memcpy( q, p, n );
0257 
0258             std::uint64_t seed1 = detail::read64le( q + 0 );
0259             std::uint64_t seed2 = detail::read64le( q + 8 );
0260 
0261             init( seed1, seed2 );
0262         }
0263         else
0264         {
0265             std::uint64_t seed1 = detail::read64le( p + 0 );
0266             std::uint64_t seed2 = detail::read64le( p + 8 );
0267 
0268             init( seed1, seed2 );
0269 
0270             p += 16;
0271             n -= 16;
0272 
0273             update( p, n );
0274             result();
0275         }
0276     }
0277 
0278     void update( void const * pv, std::size_t n )
0279     {
0280         unsigned char const* p = static_cast<unsigned char const*>( pv );
0281 
0282         BOOST_ASSERT( m_ == n_ % N );
0283 
0284         if( n == 0 ) return;
0285 
0286         n_ += n;
0287 
0288         if( m_ > 0 )
0289         {
0290             std::size_t k = N - m_;
0291 
0292             if( n < k )
0293             {
0294                 k = n;
0295             }
0296 
0297             std::memcpy( buffer_ + m_, p, k );
0298 
0299             p += k;
0300             n -= k;
0301             m_ += k;
0302 
0303             if( m_ < N ) return;
0304 
0305             BOOST_ASSERT( m_ == N );
0306 
0307             update_( buffer_, 2 );
0308             m_ = 0;
0309         }
0310 
0311         BOOST_ASSERT( m_ == 0 );
0312 
0313         {
0314             std::size_t k = n / N;
0315 
0316             update_( p, k * 2 );
0317 
0318             p += k * N;
0319             n -= k * N;
0320         }
0321 
0322         BOOST_ASSERT( n < N );
0323 
0324         if( n > 0 )
0325         {
0326             std::memcpy( buffer_, p, n );
0327             m_ = n;
0328         }
0329 
0330         BOOST_ASSERT( m_ == n_ % N );
0331     }
0332 
0333     result_type result()
0334     {
0335         BOOST_ASSERT( m_ == n_ % N );
0336 
0337         std::uint64_t h0 = v_[ 0 ];
0338         std::uint64_t h1 = v_[ 1 ];
0339 
0340         if( n_ < N )
0341         {
0342             short_hash( buffer_, n_, h0, h1 );
0343         }
0344         else
0345         {
0346             std::uint64_t h2  = v_[  2 ];
0347             std::uint64_t h3  = v_[  3 ];
0348             std::uint64_t h4  = v_[  4 ];
0349             std::uint64_t h5  = v_[  5 ];
0350             std::uint64_t h6  = v_[  6 ];
0351             std::uint64_t h7  = v_[  7 ];
0352             std::uint64_t h8  = v_[  8 ];
0353             std::uint64_t h9  = v_[  9 ];
0354             std::uint64_t h10 = v_[ 10 ];
0355             std::uint64_t h11 = v_[ 11 ];
0356 
0357             unsigned char * p = buffer_;
0358             std::size_t m = m_;
0359 
0360             if( m >= 96 )
0361             {
0362                 mix( p, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
0363 
0364                 p += 96;
0365                 m -= 96;
0366             }
0367 
0368             std::memset( p + m, 0, 96 - m );
0369             p[ 95 ] = static_cast<unsigned char>( m & 0xFF );
0370 
0371             end( p, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11 );
0372 
0373             v_[  2 ] = h2;
0374             v_[  3 ] = h3;
0375             v_[  4 ] = h4;
0376             v_[  5 ] = h5;
0377             v_[  6 ] = h6;
0378             v_[  7 ] = h7;
0379             v_[  8 ] = h8;
0380             v_[  9 ] = h9;
0381             v_[ 10 ] = h10;
0382             v_[ 11 ] = h11;
0383         }
0384 
0385         v_[ 0 ] = h0;
0386         v_[ 1 ] = h1;
0387 
0388         n_ += N - m_;
0389         m_ = 0;
0390 
0391         if( n_ < N )
0392         {
0393             n_ = 0; // in case of overflow (N does not divide 2^32)
0394         }
0395 
0396         // clear buffered plaintext
0397         std::memset( buffer_, 0, N );
0398 
0399         result_type r;
0400 
0401         detail::write64le( &r[ 0 ], h0 );
0402         detail::write64le( &r[ 8 ], h1 );
0403 
0404         return r;
0405     }
0406 };
0407 
0408 } // namespace hash2
0409 } // namespace boost
0410 
0411 #endif // #ifndef BOOST_HASH2_SPOOKY2_HPP_INCLUDED