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.

t1ha1.c 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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. /* xor-mul-xor mixer */
  45. static __inline uint64_t mix64(uint64_t v, uint64_t p) {
  46. v *= p;
  47. return v ^ rot64(v, 41);
  48. }
  49. static __inline uint64_t final_weak_avalanche(uint64_t a, uint64_t b) {
  50. /* LY: for performance reason on a some not high-end CPUs
  51. * I replaced the second mux64() operation by mix64().
  52. * Unfortunately this approach fails the "strict avalanche criteria",
  53. * see test results at https://github.com/demerphq/smhasher. */
  54. return mux64(rot64(a + b, 17), prime_4) + mix64(a ^ b, prime_0);
  55. }
  56. /* TODO: C++ template in the next version */
  57. #define T1HA1_BODY(ENDIANNES, ALIGNESS) \
  58. const uint64_t *v = (const uint64_t *)data; \
  59. if (unlikely(len > 32)) { \
  60. uint64_t c = rot64(len, 17) + seed; \
  61. uint64_t d = len ^ rot64(seed, 17); \
  62. const uint64_t *detent = \
  63. (const uint64_t *)((const uint8_t *)data + len - 31); \
  64. do { \
  65. const uint64_t w0 = fetch64_##ENDIANNES##_##ALIGNESS(v + 0); \
  66. const uint64_t w1 = fetch64_##ENDIANNES##_##ALIGNESS(v + 1); \
  67. const uint64_t w2 = fetch64_##ENDIANNES##_##ALIGNESS(v + 2); \
  68. const uint64_t w3 = fetch64_##ENDIANNES##_##ALIGNESS(v + 3); \
  69. v += 4; \
  70. prefetch(v); \
  71. \
  72. const uint64_t d02 = w0 ^ rot64(w2 + d, 17); \
  73. const uint64_t c13 = w1 ^ rot64(w3 + c, 17); \
  74. c += a ^ rot64(w0, 41); \
  75. d -= b ^ rot64(w1, 31); \
  76. a ^= prime_1 * (d02 + w3); \
  77. b ^= prime_0 * (c13 + w2); \
  78. } while (likely(v < detent)); \
  79. \
  80. a ^= prime_6 * (rot64(c, 17) + d); \
  81. b ^= prime_5 * (c + rot64(d, 17)); \
  82. len &= 31; \
  83. } \
  84. \
  85. switch (len) { \
  86. default: \
  87. b += mux64(fetch64_##ENDIANNES##_##ALIGNESS(v++), prime_4); \
  88. /* fall through */ \
  89. case 24: \
  90. case 23: \
  91. case 22: \
  92. case 21: \
  93. case 20: \
  94. case 19: \
  95. case 18: \
  96. case 17: \
  97. a += mux64(fetch64_##ENDIANNES##_##ALIGNESS(v++), prime_3); \
  98. /* fall through */ \
  99. case 16: \
  100. case 15: \
  101. case 14: \
  102. case 13: \
  103. case 12: \
  104. case 11: \
  105. case 10: \
  106. case 9: \
  107. b += mux64(fetch64_##ENDIANNES##_##ALIGNESS(v++), prime_2); \
  108. /* fall through */ \
  109. case 8: \
  110. case 7: \
  111. case 6: \
  112. case 5: \
  113. case 4: \
  114. case 3: \
  115. case 2: \
  116. case 1: \
  117. a += mux64(tail64_##ENDIANNES##_##ALIGNESS(v, len), prime_1); \
  118. /* fall through */ \
  119. case 0: \
  120. return final_weak_avalanche(a, b); \
  121. }
  122. uint64_t t1ha1_le(const void *data, size_t len, uint64_t seed) {
  123. uint64_t a = seed;
  124. uint64_t b = len;
  125. #if T1HA_CONFIG_UNALIGNED_ACCESS == T1HA_CONFIG_UNALIGNED_ACCESS__EFFICIENT
  126. T1HA1_BODY(le, unaligned);
  127. #else
  128. const bool misaligned = (((uintptr_t)data) & (ALIGNMENT_64 - 1)) != 0;
  129. if (misaligned) {
  130. T1HA1_BODY(le, unaligned);
  131. } else {
  132. T1HA1_BODY(le, aligned);
  133. }
  134. #endif
  135. }
  136. uint64_t t1ha1_be(const void *data, size_t len, uint64_t seed) {
  137. uint64_t a = seed;
  138. uint64_t b = len;
  139. #if T1HA_CONFIG_UNALIGNED_ACCESS == T1HA_CONFIG_UNALIGNED_ACCESS__EFFICIENT
  140. T1HA1_BODY(be, unaligned);
  141. #else
  142. const bool misaligned = (((uintptr_t)data) & (ALIGNMENT_64 - 1)) != 0;
  143. if (misaligned) {
  144. T1HA1_BODY(be, unaligned);
  145. } else {
  146. T1HA1_BODY(be, aligned);
  147. }
  148. #endif
  149. }