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 | } |