You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

t1ha2.c 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /*
  2. * Copyright (c) 2016-2018 Positive Technologies, https://www.ptsecurity.com,
  3. * Fast Positive Hash.
  4. *
  5. * Portions Copyright (c) 2010-2018 Leonid Yuriev <leo@yuriev.ru>,
  6. * The 1Hippeus project (t1h).
  7. *
  8. * This software is provided 'as-is', without any express or implied
  9. * warranty. In no event will the authors be held liable for any damages
  10. * arising from the use of this software.
  11. *
  12. * Permission is granted to anyone to use this software for any purpose,
  13. * including commercial applications, and to alter it and redistribute it
  14. * freely, subject to the following restrictions:
  15. *
  16. * 1. The origin of this software must not be misrepresented; you must not
  17. * claim that you wrote the original software. If you use this software
  18. * in a product, an acknowledgement in the product documentation would be
  19. * appreciated but is not required.
  20. * 2. Altered source versions must be plainly marked as such, and must not be
  21. * misrepresented as being the original software.
  22. * 3. This notice may not be removed or altered from any source distribution.
  23. */
  24. /*
  25. * t1ha = { Fast Positive Hash, aka "Позитивный Хэш" }
  26. * by [Positive Technologies](https://www.ptsecurity.ru)
  27. *
  28. * Briefly, it is a 64-bit Hash Function:
  29. * 1. Created for 64-bit little-endian platforms, in predominantly for x86_64,
  30. * but portable and without penalties it can run on any 64-bit CPU.
  31. * 2. In most cases up to 15% faster than City64, xxHash, mum-hash, metro-hash
  32. * and all others portable hash-functions (which do not use specific
  33. * hardware tricks).
  34. * 3. Not suitable for cryptography.
  35. *
  36. * The Future will Positive. Всё будет хорошо.
  37. *
  38. * ACKNOWLEDGEMENT:
  39. * The t1ha was originally developed by Leonid Yuriev (Леонид Юрьев)
  40. * for The 1Hippeus project - zerocopy messaging in the spirit of Sparta!
  41. */
  42. #include "config.h"
  43. #include "t1ha_bits.h"
  44. static __always_inline void init_ab(t1ha_state256_t *s, uint64_t x,
  45. uint64_t y) {
  46. s->n.a = x;
  47. s->n.b = y;
  48. }
  49. static __always_inline void init_cd(t1ha_state256_t *s, uint64_t x,
  50. uint64_t y) {
  51. s->n.c = rot64(y, 23) + ~x;
  52. s->n.d = ~y + rot64(x, 19);
  53. }
  54. /* TODO: C++ template in the next version */
  55. #define T1HA2_UPDATE(ENDIANNES, ALIGNESS, state, v) \
  56. do { \
  57. t1ha_state256_t *const s = state; \
  58. const uint64_t w0 = fetch64_##ENDIANNES##_##ALIGNESS(v + 0); \
  59. const uint64_t w1 = fetch64_##ENDIANNES##_##ALIGNESS(v + 1); \
  60. const uint64_t w2 = fetch64_##ENDIANNES##_##ALIGNESS(v + 2); \
  61. const uint64_t w3 = fetch64_##ENDIANNES##_##ALIGNESS(v + 3); \
  62. \
  63. const uint64_t d02 = w0 + rot64(w2 + s->n.d, 56); \
  64. const uint64_t c13 = w1 + rot64(w3 + s->n.c, 19); \
  65. s->n.c ^= s->n.a + rot64(w0, 57); \
  66. s->n.d ^= s->n.b + rot64(w1, 38); \
  67. s->n.b ^= prime_6 * (c13 + w2); \
  68. s->n.a ^= prime_5 * (d02 + w3); \
  69. } while (0)
  70. static __always_inline void squash(t1ha_state256_t *s) {
  71. s->n.a ^= prime_6 * (s->n.c + rot64(s->n.d, 23));
  72. s->n.b ^= prime_5 * (rot64(s->n.c, 19) + s->n.d);
  73. }
  74. /* TODO: C++ template in the next version */
  75. #define T1HA2_LOOP(ENDIANNES, ALIGNESS, state, data, len) \
  76. do { \
  77. const void *detent = (const uint8_t *)data + len - 31; \
  78. do { \
  79. const uint64_t *v = (const uint64_t *)data; \
  80. data = (const uint64_t *)data + 4; \
  81. prefetch(data); \
  82. T1HA2_UPDATE(le, ALIGNESS, state, v); \
  83. } while (likely(data < detent)); \
  84. } while (0)
  85. /* TODO: C++ template in the next version */
  86. #define T1HA2_TAIL_AB(ENDIANNES, ALIGNESS, state, data, len) \
  87. do { \
  88. t1ha_state256_t *const s = state; \
  89. const uint64_t *v = (const uint64_t *)data; \
  90. switch (len) { \
  91. default: \
  92. mixup64(&s->n.a, &s->n.b, fetch64_##ENDIANNES##_##ALIGNESS(v++), \
  93. prime_4); \
  94. /* fall through */ \
  95. case 24: \
  96. case 23: \
  97. case 22: \
  98. case 21: \
  99. case 20: \
  100. case 19: \
  101. case 18: \
  102. case 17: \
  103. mixup64(&s->n.b, &s->n.a, fetch64_##ENDIANNES##_##ALIGNESS(v++), \
  104. prime_3); \
  105. /* fall through */ \
  106. case 16: \
  107. case 15: \
  108. case 14: \
  109. case 13: \
  110. case 12: \
  111. case 11: \
  112. case 10: \
  113. case 9: \
  114. mixup64(&s->n.a, &s->n.b, fetch64_##ENDIANNES##_##ALIGNESS(v++), \
  115. prime_2); \
  116. /* fall through */ \
  117. case 8: \
  118. case 7: \
  119. case 6: \
  120. case 5: \
  121. case 4: \
  122. case 3: \
  123. case 2: \
  124. case 1: \
  125. mixup64(&s->n.b, &s->n.a, tail64_##ENDIANNES##_##ALIGNESS(v, len), \
  126. prime_1); \
  127. /* fall through */ \
  128. case 0: \
  129. return final64(s->n.a, s->n.b); \
  130. } \
  131. } while (0)
  132. /* TODO: C++ template in the next version */
  133. #define T1HA2_TAIL_ABCD(ENDIANNES, ALIGNESS, state, data, len) \
  134. do { \
  135. t1ha_state256_t *const s = state; \
  136. const uint64_t *v = (const uint64_t *)data; \
  137. switch (len) { \
  138. default: \
  139. mixup64(&s->n.a, &s->n.d, fetch64_##ENDIANNES##_##ALIGNESS(v++), \
  140. prime_4); \
  141. /* fall through */ \
  142. case 24: \
  143. case 23: \
  144. case 22: \
  145. case 21: \
  146. case 20: \
  147. case 19: \
  148. case 18: \
  149. case 17: \
  150. mixup64(&s->n.b, &s->n.a, fetch64_##ENDIANNES##_##ALIGNESS(v++), \
  151. prime_3); \
  152. /* fall through */ \
  153. case 16: \
  154. case 15: \
  155. case 14: \
  156. case 13: \
  157. case 12: \
  158. case 11: \
  159. case 10: \
  160. case 9: \
  161. mixup64(&s->n.c, &s->n.b, fetch64_##ENDIANNES##_##ALIGNESS(v++), \
  162. prime_2); \
  163. /* fall through */ \
  164. case 8: \
  165. case 7: \
  166. case 6: \
  167. case 5: \
  168. case 4: \
  169. case 3: \
  170. case 2: \
  171. case 1: \
  172. mixup64(&s->n.d, &s->n.c, tail64_##ENDIANNES##_##ALIGNESS(v, len), \
  173. prime_1); \
  174. /* fall through */ \
  175. case 0: \
  176. return final128(s->n.a, s->n.b, s->n.c, s->n.d, extra_result); \
  177. } \
  178. } while (0)
  179. static __always_inline uint64_t final128(uint64_t a, uint64_t b, uint64_t c,
  180. uint64_t d, uint64_t *h) {
  181. mixup64(&a, &b, rot64(c, 41) ^ d, prime_0);
  182. mixup64(&b, &c, rot64(d, 23) ^ a, prime_6);
  183. mixup64(&c, &d, rot64(a, 19) ^ b, prime_5);
  184. mixup64(&d, &a, rot64(b, 31) ^ c, prime_4);
  185. *h = c + d;
  186. return a ^ b;
  187. }
  188. //------------------------------------------------------------------------------
  189. uint64_t t1ha2_atonce(const void *data, size_t length, uint64_t seed) {
  190. t1ha_state256_t state;
  191. init_ab(&state, seed, length);
  192. #if T1HA_CONFIG_UNALIGNED_ACCESS == T1HA_CONFIG_UNALIGNED_ACCESS__EFFICIENT
  193. if (unlikely(length > 32)) {
  194. init_cd(&state, seed, length);
  195. T1HA2_LOOP(le, unaligned, &state, data, length);
  196. squash(&state);
  197. length &= 31;
  198. }
  199. T1HA2_TAIL_AB(le, unaligned, &state, data, length);
  200. #else
  201. const bool misaligned = (((uintptr_t)data) & (ALIGNMENT_64 - 1)) != 0;
  202. if (misaligned) {
  203. if (unlikely(length > 32)) {
  204. init_cd(&state, seed, length);
  205. T1HA2_LOOP(le, unaligned, &state, data, length);
  206. squash(&state);
  207. length &= 31;
  208. }
  209. T1HA2_TAIL_AB(le, unaligned, &state, data, length);
  210. } else {
  211. if (unlikely(length > 32)) {
  212. init_cd(&state, seed, length);
  213. T1HA2_LOOP(le, aligned, &state, data, length);
  214. squash(&state);
  215. length &= 31;
  216. }
  217. T1HA2_TAIL_AB(le, aligned, &state, data, length);
  218. }
  219. #endif
  220. }
  221. uint64_t t1ha2_atonce128(uint64_t *__restrict extra_result,
  222. const void *__restrict data, size_t length,
  223. uint64_t seed) {
  224. t1ha_state256_t state;
  225. init_ab(&state, seed, length);
  226. init_cd(&state, seed, length);
  227. #if T1HA_CONFIG_UNALIGNED_ACCESS == T1HA_CONFIG_UNALIGNED_ACCESS__EFFICIENT
  228. if (unlikely(length > 32)) {
  229. T1HA2_LOOP(le, unaligned, &state, data, length);
  230. length &= 31;
  231. }
  232. T1HA2_TAIL_ABCD(le, unaligned, &state, data, length);
  233. #else
  234. const bool misaligned = (((uintptr_t)data) & (ALIGNMENT_64 - 1)) != 0;
  235. if (misaligned) {
  236. if (unlikely(length > 32)) {
  237. T1HA2_LOOP(le, unaligned, &state, data, length);
  238. length &= 31;
  239. }
  240. T1HA2_TAIL_ABCD(le, unaligned, &state, data, length);
  241. } else {
  242. if (unlikely(length > 32)) {
  243. T1HA2_LOOP(le, aligned, &state, data, length);
  244. length &= 31;
  245. }
  246. T1HA2_TAIL_ABCD(le, aligned, &state, data, length);
  247. }
  248. #endif
  249. }
  250. //------------------------------------------------------------------------------
  251. void t1ha2_init(t1ha_context_t *ctx, uint64_t seed_x, uint64_t seed_y) {
  252. init_ab(&ctx->state, seed_x, seed_y);
  253. init_cd(&ctx->state, seed_x, seed_y);
  254. ctx->partial = 0;
  255. ctx->total = 0;
  256. }
  257. void t1ha2_update(t1ha_context_t *__restrict ctx, const void *__restrict data,
  258. size_t length) {
  259. ctx->total += length;
  260. if (ctx->partial) {
  261. const size_t left = 32 - ctx->partial;
  262. const size_t chunk = (length >= left) ? left : length;
  263. memcpy(ctx->buffer.bytes + ctx->partial, data, chunk);
  264. ctx->partial += chunk;
  265. if (ctx->partial < 32) {
  266. assert(left >= length);
  267. return;
  268. }
  269. ctx->partial = 0;
  270. data = (const uint8_t *)data + chunk;
  271. length -= chunk;
  272. T1HA2_UPDATE(le, aligned, &ctx->state, ctx->buffer.u64);
  273. }
  274. if (length >= 32) {
  275. #if T1HA_CONFIG_UNALIGNED_ACCESS == T1HA_CONFIG_UNALIGNED_ACCESS__EFFICIENT
  276. T1HA2_LOOP(le, unaligned, &ctx->state, data, length);
  277. #else
  278. const bool misaligned = (((uintptr_t)data) & (ALIGNMENT_64 - 1)) != 0;
  279. if (misaligned) {
  280. T1HA2_LOOP(le, unaligned, &ctx->state, data, length);
  281. } else {
  282. T1HA2_LOOP(le, aligned, &ctx->state, data, length);
  283. }
  284. #endif
  285. length &= 31;
  286. }
  287. if (length)
  288. memcpy(ctx->buffer.bytes, data, ctx->partial = length);
  289. }
  290. uint64_t t1ha2_final(t1ha_context_t *__restrict ctx,
  291. uint64_t *__restrict extra_result) {
  292. uint64_t bits = (ctx->total << 3) ^ (UINT64_C(1) << 63);
  293. #if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
  294. bits = bswap64(bits);
  295. #endif
  296. t1ha2_update(ctx, &bits, 8);
  297. if (likely(!extra_result)) {
  298. squash(&ctx->state);
  299. T1HA2_TAIL_AB(le, aligned, &ctx->state, ctx->buffer.u64, ctx->partial);
  300. }
  301. T1HA2_TAIL_ABCD(le, aligned, &ctx->state, ctx->buffer.u64, ctx->partial);
  302. }