SHOW:
|
|
- or go back to the newest paste.
| 1 | #define __STDC_CONSTANT_MACROS | |
| 2 | ||
| 3 | #include <cassert> | |
| 4 | #include <climits> | |
| 5 | #include <cstddef> | |
| 6 | #include <memory.h> | |
| 7 | extern "C" | |
| 8 | {
| |
| 9 | #include <stdint.h> | |
| 10 | } | |
| 11 | ||
| 12 | #if defined (__GLIBC__) | |
| 13 | # include <endian.h> | |
| 14 | # if (__BYTE_ORDER == __BIG_ENDIAN) | |
| 15 | # define SPOOKY_BIG_ENDIAN 1 | |
| 16 | # endif | |
| 17 | #elif (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN)) | |
| 18 | # define SPOOKY_BIG_ENDIAN 1 | |
| 19 | #elif defined(__sparc) || defined(__sparc__) \ | |
| 20 | || defined(__ppc__) || defined(_POWER) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC) || defined(PPC) || defined(__powerpc__) || defined(__powerpc) || defined(powerpc) \ | |
| 21 | || defined(__hpux) || defined(__hppa) \ | |
| 22 | || defined(_MIPSEB) || defined(__s390__) | |
| 23 | # define SPOOKY_BIG_ENDIAN 1 | |
| 24 | #else | |
| 25 | # define SPOOKY_BIG_ENDIAN 0 | |
| 26 | #endif | |
| 27 | ||
| 28 | template <typename spooky_word, bool allow_unaligned_reads, bool little_endian> | |
| 29 | class SpookyHash | |
| 30 | {
| |
| 31 | public: | |
| 32 | // | |
| 33 | // SpookyHash: hash a single message in one call, produce 128-bit output | |
| 34 | // | |
| 35 | template<size_t hash_size> | |
| 36 | static inline void Hash( | |
| 37 | const void *message, // message to hash | |
| 38 | size_t length, // length of message in bytes | |
| 39 | spooky_word *hash) // in/out: in seed 2, out hash value 2 | |
| 40 | {
| |
| 41 | if(allow_unaligned_reads) | |
| 42 | _Hash<hash_size, 8>(message, length, hash); | |
| 43 | else | |
| 44 | {
| |
| 45 | switch((uintptr_t)message & 7) | |
| 46 | {
| |
| 47 | case 1: | |
| 48 | case 3: | |
| 49 | case 5: | |
| 50 | case 7: | |
| 51 | _Hash<hash_size, 1>(message, length, hash); | |
| 52 | break; | |
| 53 | case 2: | |
| 54 | case 6: | |
| 55 | if(sizeof(spooky_word) >= 2) | |
| 56 | _Hash<hash_size, 2>(message, length, hash); | |
| 57 | else | |
| 58 | _Hash<hash_size, sizeof(spooky_word)>(message, length, hash); | |
| 59 | break; | |
| 60 | case 4: | |
| 61 | if(sizeof(spooky_word) >= 4) | |
| 62 | _Hash<hash_size, 4>(message, length, hash); | |
| 63 | else | |
| 64 | _Hash<hash_size, sizeof(spooky_word)>(message, length, hash); | |
| 65 | break; | |
| 66 | break; | |
| 67 | case 0: | |
| 68 | if(sizeof(spooky_word) >= 8) | |
| 69 | _Hash<hash_size, 8>(message, length, hash); | |
| 70 | else | |
| 71 | _Hash<hash_size, sizeof(spooky_word)>(message, length, hash); | |
| 72 | break; | |
| 73 | } | |
| 74 | } | |
| 75 | } | |
| 76 | ||
| 77 | private: | |
| 78 | template<size_t hash_size, size_t access_size> | |
| 79 | static void _Hash( | |
| 80 | const void *message, // message to hash | |
| 81 | size_t length, // length of message in bytes | |
| 82 | spooky_word *hash); // in/out: in seed 2, out hash value 2 | |
| 83 | ||
| 84 | // | |
| 85 | // left rotate a 64-bit value by k bytes | |
| 86 | // | |
| 87 | static inline spooky_word Rot(spooky_word x, int k) | |
| 88 | {
| |
| 89 | return (x << k) | (x >> (word_bits - k)); | |
| 90 | } | |
| 91 | ||
| 92 | static inline spooky_word Bswap(spooky_word x) | |
| 93 | {
| |
| 94 | switch(sizeof(spooky_word)) | |
| 95 | {
| |
| 96 | case 1: | |
| 97 | return x; | |
| 98 | case 2: | |
| 99 | return ((x << 8) & 0xff00) | | |
| 100 | ((x >> 8) & 0x00ff); | |
| 101 | case 4: | |
| 102 | return ((x << 24) & 0xff000000) | | |
| 103 | ((x << 8) & 0x00ff0000) | | |
| 104 | ((x >> 8) & 0x0000ff00) | | |
| 105 | ((x >> 24) & 0x000000ff); | |
| 106 | case 8: | |
| 107 | return ((x << 56) & 0xff00000000000000) | | |
| 108 | ((x << 40) & 0x00ff000000000000) | | |
| 109 | ((x << 24) & 0x0000ff0000000000) | | |
| 110 | ((x << 8) & 0x000000ff00000000) | | |
| 111 | ((x >> 8) & 0x00000000ff000000) | | |
| 112 | ((x >> 24) & 0x0000000000ff0000) | | |
| 113 | ((x >> 40) & 0x000000000000ff00) | | |
| 114 | ((x >> 56) & 0x00000000000000ff); | |
| 115 | } | |
| 116 | } | |
| 117 | ||
| 118 | static inline spooky_word Read(spooky_word x) | |
| 119 | {
| |
| 120 | if(( little_endian && SPOOKY_BIG_ENDIAN) || | |
| 121 | (!little_endian && !SPOOKY_BIG_ENDIAN)) | |
| 122 | return Bswap(x); | |
| 123 | else | |
| 124 | return x; | |
| 125 | } | |
| 126 | // | |
| 127 | template<size_t access_size> | |
| 128 | static inline void Mix( | |
| 129 | const spooky_word *data, | |
| 130 | spooky_word &s0, spooky_word &s1, spooky_word &s2, spooky_word &s3, | |
| 131 | spooky_word &s4, spooky_word &s5, spooky_word &s6, spooky_word &s7, | |
| 132 | spooky_word &s8, spooky_word &s9, spooky_word &s10,spooky_word &s11) | |
| 133 | {
| |
| 134 | s0 += Read(data[0]); s2 ^= s10; s11 ^= s0; s0 = Rot(s0,shift0); s11 += s1; | |
| 135 | s1 += Read(data[1]); s3 ^= s11; s0 ^= s1; s1 = Rot(s1,shift1); s0 += s2; | |
| 136 | s2 += Read(data[2]); s4 ^= s0; s1 ^= s2; s2 = Rot(s2,shift2); s1 += s3; | |
| 137 | s3 += Read(data[3]); s5 ^= s1; s2 ^= s3; s3 = Rot(s3,shift3); s2 += s4; | |
| 138 | s4 += Read(data[4]); s6 ^= s2; s3 ^= s4; s4 = Rot(s4,shift4); s3 += s5; | |
| 139 | s5 += Read(data[5]); s7 ^= s3; s4 ^= s5; s5 = Rot(s5,shift5); s4 += s6; | |
| 140 | s6 += Read(data[6]); s8 ^= s4; s5 ^= s6; s6 = Rot(s6,shift6); s5 += s7; | |
| 141 | s7 += Read(data[7]); s9 ^= s5; s6 ^= s7; s7 = Rot(s7,shift7); s6 += s8; | |
| 142 | s8 += Read(data[8]); s10 ^= s6; s7 ^= s8; s8 = Rot(s8,shift8); s7 += s9; | |
| 143 | s9 += Read(data[9]); s11 ^= s7; s8 ^= s9; s9 = Rot(s9,shift9); s8 += s10; | |
| 144 | s10 += Read(data[10]); s0 ^= s8; s9 ^= s10; s10 = Rot(s10,shift10); s9 += s11; | |
| 145 | s11 += Read(data[11]); s1 ^= s9; s10 ^= s11; s11 = Rot(s11,shift11); s10 += s0; | |
| 146 | } | |
| 147 | ||
| 148 | // | |
| 149 | // Mix all 12 inputs together so that h0, h1 are a hash of them all. | |
| 150 | // | |
| 151 | static inline void EndPartial( | |
| 152 | spooky_word &h0, spooky_word &h1, spooky_word &h2, spooky_word &h3, | |
| 153 | spooky_word &h4, spooky_word &h5, spooky_word &h6, spooky_word &h7, | |
| 154 | spooky_word &h8, spooky_word &h9, spooky_word &h10,spooky_word &h11) | |
| 155 | {
| |
| 156 | h11+= h1; h2 ^= h11; h1 = Rot(h1, shift12); | |
| 157 | h0 += h2; h3 ^= h0; h2 = Rot(h2, shift13); | |
| 158 | h1 += h3; h4 ^= h1; h3 = Rot(h3, shift14); | |
| 159 | h2 += h4; h5 ^= h2; h4 = Rot(h4, shift15); | |
| 160 | h3 += h5; h6 ^= h3; h5 = Rot(h5, shift16); | |
| 161 | h4 += h6; h7 ^= h4; h6 = Rot(h6, shift17); | |
| 162 | h5 += h7; h8 ^= h5; h7 = Rot(h7, shift18); | |
| 163 | h6 += h8; h9 ^= h6; h8 = Rot(h8, shift19); | |
| 164 | h7 += h9; h10^= h7; h9 = Rot(h9, shift20); | |
| 165 | h8 += h10; h11^= h8; h10= Rot(h10,shift21); | |
| 166 | h9 += h11; h0 ^= h9; h11= Rot(h11,shift22); | |
| 167 | h10+= h0; h1 ^= h10; h0 = Rot(h0, shift23); | |
| 168 | } | |
| 169 | ||
| 170 | static inline void End( | |
| 171 | const spooky_word *data, | |
| 172 | spooky_word &h0, spooky_word &h1, spooky_word &h2, spooky_word &h3, | |
| 173 | spooky_word &h4, spooky_word &h5, spooky_word &h6, spooky_word &h7, | |
| 174 | spooky_word &h8, spooky_word &h9, spooky_word &h10,spooky_word &h11) | |
| 175 | {
| |
| 176 | h0 += Read(data[0]); h1 += Read(data[1]); h2 += Read(data[2]); h3 += Read(data[3]); | |
| 177 | h4 += Read(data[4]); h5 += Read(data[5]); h6 += Read(data[6]); h7 += Read(data[7]); | |
| 178 | h8 += Read(data[8]); h9 += Read(data[9]); h10 += Read(data[10]); h11 += Read(data[11]); | |
| 179 | EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); | |
| 180 | EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); | |
| 181 | EndPartial(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); | |
| 182 | } | |
| 183 | ||
| 184 | // number of spooky_word's in internal state | |
| 185 | static const size_t sc_numVars = 12; | |
| 186 | ||
| 187 | static const size_t word_bits = sizeof(spooky_word) * CHAR_BIT; | |
| 188 | ||
| 189 | // size of the internal state | |
| 190 | static const size_t sc_blockSize = sc_numVars*sizeof(spooky_word); | |
| 191 | ||
| 192 | // | |
| 193 | // sc_const: a constant which: | |
| 194 | // * is not zero | |
| 195 | // * is odd | |
| 196 | // * is a not-very-regular mix of 1's and 0's | |
| 197 | // * does not need any other special mathematical properties | |
| 198 | // | |
| 199 | static const spooky_word sc_const = (spooky_word)UINT64_C(0xdeadbeefdeadbeef); | |
| 200 | ||
| 201 | static const int shift0 = word_bits == 64 ? 11 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 202 | static const int shift1 = word_bits == 64 ? 32 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 203 | static const int shift2 = word_bits == 64 ? 43 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 204 | static const int shift3 = word_bits == 64 ? 31 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 205 | static const int shift4 = word_bits == 64 ? 17 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 206 | static const int shift5 = word_bits == 64 ? 28 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 207 | static const int shift6 = word_bits == 64 ? 39 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 208 | static const int shift7 = word_bits == 64 ? 57 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 209 | static const int shift8 = word_bits == 64 ? 55 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 210 | static const int shift9 = word_bits == 64 ? 54 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 211 | static const int shift10 = word_bits == 64 ? 22 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 212 | static const int shift11 = word_bits == 64 ? 46 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 213 | static const int shift12 = word_bits == 64 ? 44 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 214 | static const int shift13 = word_bits == 64 ? 15 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 215 | static const int shift14 = word_bits == 64 ? 34 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 216 | static const int shift15 = word_bits == 64 ? 21 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 217 | static const int shift16 = word_bits == 64 ? 38 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 218 | static const int shift17 = word_bits == 64 ? 33 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 219 | static const int shift18 = word_bits == 64 ? 10 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 220 | static const int shift19 = word_bits == 64 ? 13 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 221 | static const int shift20 = word_bits == 64 ? 38 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 222 | static const int shift21 = word_bits == 64 ? 53 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 223 | static const int shift22 = word_bits == 64 ? 42 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 224 | static const int shift23 = word_bits == 64 ? 54 : word_bits == 32 ? 5 : word_bits == 16 ? 3 : 1; | |
| 225 | }; | |
| 226 | ||
| 227 | ||
| 228 | // do the whole hash in one call | |
| 229 | template <typename spooky_word, bool allow_unaligned_reads, bool little_endian> | |
| 230 | template<size_t hash_size, size_t access_size> | |
| 231 | void SpookyHash<spooky_word, allow_unaligned_reads, little_endian>::_Hash( | |
| 232 | const void *message, | |
| 233 | size_t length, | |
| 234 | spooky_word *hash) | |
| 235 | {
| |
| 236 | assert(hash_size > 0 && sc_numVars <= sc_numVars); | |
| 237 | spooky_word h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11; | |
| 238 | spooky_word buf[sc_numVars]; | |
| 239 | const uint8_t *end; | |
| 240 | const uint8_t *p; | |
| 241 | size_t remainder; | |
| 242 | ||
| 243 | h0=h3=h6=h9 = hash[0]; | |
| 244 | h1=h4=h7=h10 = hash_size > 1 ? hash[1] : hash[0]; | |
| 245 | h2=h5=h8=h11 = sc_const; | |
| 246 | ||
| 247 | p = (const uint8_t *)message; | |
| 248 | end = p + length - length % sc_blockSize; | |
| 249 | ||
| 250 | // handle all whole sc_blockSize blocks of bytes | |
| 251 | while(p < end) | |
| 252 | {
| |
| 253 | if(allow_unaligned_reads || sizeof(spooky_word) <= access_size) | |
| 254 | {
| |
| 255 | Mix<access_size>((spooky_word*)p, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); | |
| 256 | } | |
| 257 | else | |
| 258 | {
| |
| 259 | for(unsigned i=0; i<sc_blockSize; ++i) | |
| 260 | ((uint8_t*)buf)[i] = p[i]; | |
| 261 | Mix<access_size>(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); | |
| 262 | } | |
| 263 | p += sc_blockSize; | |
| 264 | } | |
| 265 | ||
| 266 | // handle the last partial block of sc_blockSize bytes | |
| 267 | remainder = (length - (end - (const uint8_t *)message)); | |
| 268 | buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = 0; | |
| 269 | buf[6] = buf[7] = buf[8] = buf[9] = buf[10] = buf[11] = 0; | |
| 270 | memcpy(buf, end, remainder); | |
| 271 | ((uint8_t *)buf)[sc_blockSize-1] = remainder; | |
| 272 | ||
| 273 | // do some final mixing | |
| 274 | End(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11); | |
| 275 | hash[0] = h0; | |
| 276 | if(hash_size > 1) | |
| 277 | hash[1] = h1; | |
| 278 | if(hash_size > 2) | |
| 279 | hash[2] = h2; | |
| 280 | if(hash_size > 3) | |
| 281 | hash[3] = h3; | |
| 282 | if(hash_size > 4) | |
| 283 | hash[4] = h4; | |
| 284 | if(hash_size > 5) | |
| 285 | hash[5] = h5; | |
| 286 | if(hash_size > 6) | |
| 287 | hash[6] = h6; | |
| 288 | if(hash_size > 7) | |
| 289 | hash[7] = h7; | |
| 290 | if(hash_size > 8) | |
| 291 | hash[8] = h8; | |
| 292 | if(hash_size > 9) | |
| 293 | hash[9] = h9; | |
| 294 | if(hash_size > 10) | |
| 295 | hash[10] = h10; | |
| 296 | if(hash_size > 11) | |
| 297 | hash[11] = h11; | |
| 298 | } |