1 : // Spooky Hash
2 : // A 128-bit noncryptographic hash, for checksums and table lookup
3 : // By Bob Jenkins. Public domain.
4 : // Oct 31 2010: published framework, disclaimer ShortHash isn't right
5 : // Nov 7 2010: disabled ShortHash
6 : // Oct 31 2011: replace End, ShortMix, ShortEnd, enable ShortHash again
7 :
8 : #include <memory.h>
9 : #include <string.h>
10 : #include "spooky.h"
11 :
12 : #define ALLOW_UNALIGNED_READS 1
13 :
14 : //
15 : // short hash ... it could be used on any message,
16 : // but it's used by Spooky just for short messages.
17 : //
18 0 : void SpookyHash::Short(
19 : const void *message,
20 : size_t length,
21 : uint64 *hash1,
22 : uint64 *hash2)
23 : {
24 : uint64 buf[sc_numVars];
25 : union
26 : {
27 : const uint8 *p8;
28 : uint32 *p32;
29 : uint64 *p64;
30 : size_t i;
31 : } u;
32 :
33 0 : u.p8 = (const uint8 *)message;
34 :
35 : if (!ALLOW_UNALIGNED_READS && (u.i & 0x7))
36 : {
37 : memcpy(buf, message, length);
38 : u.p64 = buf;
39 : }
40 :
41 0 : size_t remainder = length%32;
42 0 : uint64 a=*hash1;
43 0 : uint64 b=*hash2;
44 0 : uint64 c=sc_const;
45 0 : uint64 d=sc_const;
46 :
47 0 : if (length > 15)
48 : {
49 0 : const uint64 *end = u.p64 + (length/32)*4;
50 :
51 : // handle all complete sets of 32 bytes
52 0 : for (; u.p64 < end; u.p64 += 4)
53 : {
54 0 : c += u.p64[0];
55 0 : d += u.p64[1];
56 0 : ShortMix(a,b,c,d);
57 0 : a += u.p64[2];
58 0 : b += u.p64[3];
59 : }
60 :
61 : //Handle the case of 16+ remaining bytes.
62 0 : if (remainder >= 16)
63 : {
64 0 : c += u.p64[0];
65 0 : d += u.p64[1];
66 0 : ShortMix(a,b,c,d);
67 0 : u.p64 += 2;
68 0 : remainder -= 16;
69 : }
70 : }
71 :
72 : // Handle the last 0..15 bytes, and its length
73 0 : d = ((uint64)length) << 56;
74 0 : switch (remainder)
75 : {
76 : case 15:
77 0 : d += ((uint64)u.p8[14]) << 48;
78 : case 14:
79 0 : d += ((uint64)u.p8[13]) << 40;
80 : case 13:
81 0 : d += ((uint64)u.p8[12]) << 32;
82 : case 12:
83 0 : d += u.p32[2];
84 0 : c += u.p64[0];
85 0 : break;
86 : case 11:
87 0 : d += ((uint64)u.p8[10]) << 16;
88 : case 10:
89 0 : d += ((uint64)u.p8[9]) << 8;
90 : case 9:
91 0 : d += (uint64)u.p8[8];
92 : case 8:
93 0 : c += u.p64[0];
94 0 : break;
95 : case 7:
96 0 : c += ((uint64)u.p8[6]) << 48;
97 : case 6:
98 0 : c += ((uint64)u.p8[5]) << 40;
99 : case 5:
100 0 : c += ((uint64)u.p8[4]) << 32;
101 : case 4:
102 0 : c += u.p32[0];
103 0 : break;
104 : case 3:
105 0 : c += ((uint64)u.p8[2]) << 16;
106 : case 2:
107 0 : c += ((uint64)u.p8[1]) << 8;
108 : case 1:
109 0 : c += (uint64)u.p8[0];
110 0 : break;
111 : case 0:
112 0 : c += sc_const;
113 0 : d += sc_const;
114 : }
115 0 : ShortEnd(a,b,c,d);
116 0 : *hash1 = a;
117 0 : *hash2 = b;
118 0 : }
119 :
120 :
121 :
122 :
123 : // do the whole hash in one call
124 0 : void SpookyHash::Hash128(
125 : const void *message,
126 : size_t length,
127 : uint64 *hash1,
128 : uint64 *hash2)
129 : {
130 0 : if (length < sc_bufSize)
131 : {
132 0 : Short(message, length, hash1, hash2);
133 0 : return;
134 : }
135 :
136 : uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
137 : uint64 buf[sc_numVars];
138 : uint64 *end;
139 : union
140 : {
141 : const uint8 *p8;
142 : uint64 *p64;
143 : size_t i;
144 : } u;
145 : size_t remainder;
146 :
147 0 : h0=h3=h6=h9 = *hash1;
148 0 : h1=h4=h7=h10 = *hash2;
149 0 : h2=h5=h8=h11 = sc_const;
150 :
151 0 : u.p8 = (const uint8 *)message;
152 0 : end = u.p64 + (length/sc_blockSize)*sc_numVars;
153 :
154 : // handle all whole sc_blockSize blocks of bytes
155 : if (ALLOW_UNALIGNED_READS || ((u.i & 0x7) == 0))
156 : {
157 0 : while (u.p64 < end)
158 : {
159 0 : Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
160 0 : u.p64 += sc_numVars;
161 : }
162 : }
163 : else
164 : {
165 : while (u.p64 < end)
166 : {
167 : memcpy(buf, u.p64, sc_blockSize);
168 : Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
169 : u.p64 += sc_numVars;
170 : }
171 : }
172 :
173 : // handle the last partial block of sc_blockSize bytes
174 0 : remainder = (length - ((const uint8 *)end-(const uint8 *)message));
175 0 : memcpy(buf, end, remainder);
176 0 : memset(((uint8 *)buf)+remainder, 0, sc_blockSize-remainder);
177 0 : ((uint8 *)buf)[sc_blockSize-1] = remainder;
178 0 : Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
179 :
180 : // do some final mixing
181 0 : End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
182 0 : *hash1 = h0;
183 0 : *hash2 = h1;
184 : }
185 :
186 :
187 :
188 : // init spooky state
189 0 : void SpookyHash::Init(uint64 seed1, uint64 seed2)
190 : {
191 0 : m_length = 0;
192 0 : m_remainder = 0;
193 0 : m_state[0] = seed1;
194 0 : m_state[1] = seed2;
195 0 : }
196 :
197 :
198 : // add a message fragment to the state
199 0 : void SpookyHash::Update(const void *message, size_t length)
200 : {
201 : uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
202 0 : size_t newLength = length + m_remainder;
203 : uint8 remainder;
204 : union
205 : {
206 : const uint8 *p8;
207 : uint64 *p64;
208 : size_t i;
209 : } u;
210 : const uint64 *end;
211 :
212 : // Is this message fragment too short? If it is, stuff it away.
213 0 : if (newLength < sc_bufSize)
214 : {
215 0 : memcpy(&((uint8 *)m_data)[m_remainder], message, length);
216 0 : m_length = length + m_length;
217 0 : m_remainder = (uint8)newLength;
218 0 : return;
219 : }
220 :
221 : // init the variables
222 0 : if (m_length < sc_bufSize)
223 : {
224 0 : h0=h3=h6=h9 = m_state[0];
225 0 : h1=h4=h7=h10 = m_state[1];
226 0 : h2=h5=h8=h11 = sc_const;
227 : }
228 : else
229 : {
230 0 : h0 = m_state[0];
231 0 : h1 = m_state[1];
232 0 : h2 = m_state[2];
233 0 : h3 = m_state[3];
234 0 : h4 = m_state[4];
235 0 : h5 = m_state[5];
236 0 : h6 = m_state[6];
237 0 : h7 = m_state[7];
238 0 : h8 = m_state[8];
239 0 : h9 = m_state[9];
240 0 : h10 = m_state[10];
241 0 : h11 = m_state[11];
242 : }
243 0 : m_length = length + m_length;
244 :
245 : // if we've got anything stuffed away, use it now
246 0 : if (m_remainder)
247 : {
248 0 : uint8 prefix = sc_bufSize-m_remainder;
249 0 : memcpy(&(((uint8 *)m_data)[m_remainder]), message, prefix);
250 0 : u.p64 = m_data;
251 0 : Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
252 0 : Mix(&u.p64[sc_numVars], h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
253 0 : u.p8 = ((const uint8 *)message) + prefix;
254 0 : length -= prefix;
255 : }
256 : else
257 : {
258 0 : u.p8 = (const uint8 *)message;
259 : }
260 :
261 : // handle all whole blocks of sc_blockSize bytes
262 0 : end = u.p64 + (length/sc_blockSize)*sc_numVars;
263 0 : remainder = (uint8)(length-((const uint8 *)end-u.p8));
264 : if (ALLOW_UNALIGNED_READS || (u.i & 0x7) == 0)
265 : {
266 0 : while (u.p64 < end)
267 : {
268 0 : Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
269 0 : u.p64 += sc_numVars;
270 : }
271 : }
272 : else
273 : {
274 : while (u.p64 < end)
275 : {
276 : memcpy(m_data, u.p8, sc_blockSize);
277 : Mix(m_data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
278 : u.p64 += sc_numVars;
279 : }
280 : }
281 :
282 : // stuff away the last few bytes
283 0 : m_remainder = remainder;
284 0 : memcpy(m_data, end, remainder);
285 :
286 : // stuff away the variables
287 0 : m_state[0] = h0;
288 0 : m_state[1] = h1;
289 0 : m_state[2] = h2;
290 0 : m_state[3] = h3;
291 0 : m_state[4] = h4;
292 0 : m_state[5] = h5;
293 0 : m_state[6] = h6;
294 0 : m_state[7] = h7;
295 0 : m_state[8] = h8;
296 0 : m_state[9] = h9;
297 0 : m_state[10] = h10;
298 0 : m_state[11] = h11;
299 : }
300 :
301 :
302 : // report the hash for the concatenation of all message fragments so far
303 0 : void SpookyHash::Final(uint64 *hash1, uint64 *hash2)
304 : {
305 : // init the variables
306 0 : if (m_length < sc_bufSize)
307 : {
308 0 : Short( m_data, m_length, hash1, hash2);
309 0 : return;
310 : }
311 :
312 0 : const uint64 *data = (const uint64 *)m_data;
313 0 : uint8 remainder = m_remainder;
314 :
315 0 : uint64 h0 = m_state[0];
316 0 : uint64 h1 = m_state[1];
317 0 : uint64 h2 = m_state[2];
318 0 : uint64 h3 = m_state[3];
319 0 : uint64 h4 = m_state[4];
320 0 : uint64 h5 = m_state[5];
321 0 : uint64 h6 = m_state[6];
322 0 : uint64 h7 = m_state[7];
323 0 : uint64 h8 = m_state[8];
324 0 : uint64 h9 = m_state[9];
325 0 : uint64 h10 = m_state[10];
326 0 : uint64 h11 = m_state[11];
327 :
328 0 : if (remainder >= sc_blockSize)
329 : {
330 : // m_data can contain two blocks; handle any whole first block
331 0 : Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
332 0 : data += sc_numVars;
333 0 : remainder -= sc_blockSize;
334 : }
335 :
336 : // mix in the last partial block, and the length mod sc_blockSize
337 0 : memset(&((uint8 *)data)[remainder], 0, (sc_blockSize-remainder));
338 :
339 0 : ((uint8 *)data)[sc_blockSize-1] = remainder;
340 0 : Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
341 :
342 : // do some final mixing
343 0 : End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
344 :
345 0 : *hash1 = h0;
346 0 : *hash2 = h1;
347 : }
348 :
|