SpookyV2.cpp 8.7 KB

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