metrohash128.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. // metrohash128.cpp
  2. //
  3. // The MIT License (MIT)
  4. //
  5. // Copyright (c) 2015 J. Andrew Rogers
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in all
  15. // copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. // SOFTWARE.
  24. //
  25. #include "platform.h"
  26. #include "metrohash128.h"
  27. INLINE void MetroHash128::Initialize(const uint64_t seed)
  28. {
  29. // initialize internal hash registers
  30. state.v[0] = (seed - k0) * k3;
  31. state.v[1] = (seed + k1) * k2;
  32. state.v[2] = (seed + k0) * k2;
  33. state.v[3] = (seed - k1) * k3;
  34. // initialize total length of input
  35. bytes = 0;
  36. }
  37. INLINE void MetroHash128::Update(const uint8_t *data, const uint64_t length)
  38. {
  39. uint64_t input_size=(bytes&31);
  40. bytes+=length;
  41. const uint64_t copy=32-input_size;
  42. if(length<copy){memcpy(input.b+input_size, data, length); return;} // incomplete input buffer
  43. const uint8_t *const end=data+length;
  44. State state=this->state;
  45. if(input_size) // complete input buffer
  46. {
  47. // process full input buffer
  48. memcpy(input.b+input_size, data, copy); data+=copy;
  49. state.v[0] += read_u64(&input.b[ 0]) * k0; state.v[0] = rotate_right(state.v[0],29) + state.v[2];
  50. state.v[1] += read_u64(&input.b[ 8]) * k1; state.v[1] = rotate_right(state.v[1],29) + state.v[3];
  51. state.v[2] += read_u64(&input.b[16]) * k2; state.v[2] = rotate_right(state.v[2],29) + state.v[0];
  52. state.v[3] += read_u64(&input.b[24]) * k3; state.v[3] = rotate_right(state.v[3],29) + state.v[1];
  53. }
  54. const uint8_t *const limit=end-32;
  55. while(data<=limit)
  56. {
  57. state.v[0] += read_u64(data) * k0; data += 8; state.v[0] = rotate_right(state.v[0],29) + state.v[2];
  58. state.v[1] += read_u64(data) * k1; data += 8; state.v[1] = rotate_right(state.v[1],29) + state.v[3];
  59. state.v[2] += read_u64(data) * k2; data += 8; state.v[2] = rotate_right(state.v[2],29) + state.v[0];
  60. state.v[3] += read_u64(data) * k3; data += 8; state.v[3] = rotate_right(state.v[3],29) + state.v[1];
  61. }
  62. this->state=state;
  63. // store remaining bytes in input buffer
  64. if(data<end)memcpy(input.b, data, end-data);
  65. }
  66. INLINE void MetroHash128::Finalize(uint8_t *const hash)
  67. {
  68. State state = this->state; // ESENTHEL CHANGED (using these as temp variables works faster)
  69. // finalize bulk loop, if used
  70. if (bytes >= 32)
  71. {
  72. state.v[2] ^= rotate_right(((state.v[0] + state.v[3]) * k0) + state.v[1], 21) * k1;
  73. state.v[3] ^= rotate_right(((state.v[1] + state.v[2]) * k1) + state.v[0], 21) * k0;
  74. state.v[0] ^= rotate_right(((state.v[0] + state.v[2]) * k0) + state.v[3], 21) * k1;
  75. state.v[1] ^= rotate_right(((state.v[1] + state.v[3]) * k1) + state.v[2], 21) * k0;
  76. }
  77. // process any bytes remaining in the input buffer
  78. const uint8_t * data = input.b;
  79. const uint8_t * const end = data + (bytes & 31);
  80. if ((end - data) >= 16)
  81. {
  82. state.v[0] += read_u64(data) * k2; data += 8; state.v[0] = rotate_right(state.v[0],33) * k3;
  83. state.v[1] += read_u64(data) * k2; data += 8; state.v[1] = rotate_right(state.v[1],33) * k3;
  84. state.v[0] ^= rotate_right((state.v[0] * k2) + state.v[1], 45) * k1;
  85. state.v[1] ^= rotate_right((state.v[1] * k3) + state.v[0], 45) * k0;
  86. }
  87. if ((end - data) >= 8)
  88. {
  89. state.v[0] += read_u64(data) * k2; data += 8; state.v[0] = rotate_right(state.v[0],33) * k3;
  90. state.v[0] ^= rotate_right((state.v[0] * k2) + state.v[1], 27) * k1;
  91. }
  92. if ((end - data) >= 4)
  93. {
  94. state.v[1] += read_u32(data) * k2; data += 4; state.v[1] = rotate_right(state.v[1],33) * k3;
  95. state.v[1] ^= rotate_right((state.v[1] * k3) + state.v[0], 46) * k0;
  96. }
  97. if ((end - data) >= 2)
  98. {
  99. state.v[0] += read_u16(data) * k2; data += 2; state.v[0] = rotate_right(state.v[0],33) * k3;
  100. state.v[0] ^= rotate_right((state.v[0] * k2) + state.v[1], 22) * k1;
  101. }
  102. if ((end - data) >= 1)
  103. {
  104. state.v[1] += read_u8 (data) * k2; state.v[1] = rotate_right(state.v[1],33) * k3;
  105. state.v[1] ^= rotate_right((state.v[1] * k3) + state.v[0], 58) * k0;
  106. }
  107. state.v[0] += rotate_right((state.v[0] * k0) + state.v[1], 13);
  108. state.v[1] += rotate_right((state.v[1] * k1) + state.v[0], 37);
  109. state.v[0] += rotate_right((state.v[0] * k2) + state.v[1], 13);
  110. state.v[1] += rotate_right((state.v[1] * k3) + state.v[0], 37);
  111. bytes = 0;
  112. // do any endian conversion here
  113. memcpy(hash, state.v, 16);
  114. }
  115. INLINE void MetroHash128::Hash(const uint8_t *data, const uint64_t length, uint8_t * const hash, const uint64_t seed)
  116. {
  117. const uint8_t *const end = data + length;
  118. uint64_t v[4];
  119. v[0] = (seed - k0) * k3;
  120. v[1] = (seed + k1) * k2;
  121. if (length >= 32)
  122. {
  123. v[2] = (seed + k0) * k2;
  124. v[3] = (seed - k1) * k3;
  125. do
  126. {
  127. v[0] += read_u64(data) * k0; data += 8; v[0] = rotate_right(v[0],29) + v[2];
  128. v[1] += read_u64(data) * k1; data += 8; v[1] = rotate_right(v[1],29) + v[3];
  129. v[2] += read_u64(data) * k2; data += 8; v[2] = rotate_right(v[2],29) + v[0];
  130. v[3] += read_u64(data) * k3; data += 8; v[3] = rotate_right(v[3],29) + v[1];
  131. }
  132. while (data <= (end - 32));
  133. v[2] ^= rotate_right(((v[0] + v[3]) * k0) + v[1], 21) * k1;
  134. v[3] ^= rotate_right(((v[1] + v[2]) * k1) + v[0], 21) * k0;
  135. v[0] ^= rotate_right(((v[0] + v[2]) * k0) + v[3], 21) * k1;
  136. v[1] ^= rotate_right(((v[1] + v[3]) * k1) + v[2], 21) * k0;
  137. }
  138. if ((end - data) >= 16)
  139. {
  140. v[0] += read_u64(data) * k2; data += 8; v[0] = rotate_right(v[0],33) * k3;
  141. v[1] += read_u64(data) * k2; data += 8; v[1] = rotate_right(v[1],33) * k3;
  142. v[0] ^= rotate_right((v[0] * k2) + v[1], 45) * k1;
  143. v[1] ^= rotate_right((v[1] * k3) + v[0], 45) * k0;
  144. }
  145. if ((end - data) >= 8)
  146. {
  147. v[0] += read_u64(data) * k2; data += 8; v[0] = rotate_right(v[0],33) * k3;
  148. v[0] ^= rotate_right((v[0] * k2) + v[1], 27) * k1;
  149. }
  150. if ((end - data) >= 4)
  151. {
  152. v[1] += read_u32(data) * k2; data += 4; v[1] = rotate_right(v[1],33) * k3;
  153. v[1] ^= rotate_right((v[1] * k3) + v[0], 46) * k0;
  154. }
  155. if ((end - data) >= 2)
  156. {
  157. v[0] += read_u16(data) * k2; data += 2; v[0] = rotate_right(v[0],33) * k3;
  158. v[0] ^= rotate_right((v[0] * k2) + v[1], 22) * k1;
  159. }
  160. if ((end - data) >= 1)
  161. {
  162. v[1] += read_u8 (data) * k2; v[1] = rotate_right(v[1],33) * k3;
  163. v[1] ^= rotate_right((v[1] * k3) + v[0], 58) * k0;
  164. }
  165. v[0] += rotate_right((v[0] * k0) + v[1], 13);
  166. v[1] += rotate_right((v[1] * k1) + v[0], 37);
  167. v[0] += rotate_right((v[0] * k2) + v[1], 13);
  168. v[1] += rotate_right((v[1] * k3) + v[0], 37);
  169. // do any endian conversion here
  170. memcpy(hash, v, 16);
  171. }
  172. const char * MetroHash128::test_string = "012345678901234567890123456789012345678901234567890123456789012";
  173. const uint8_t MetroHash128::test_seed_0[16] = {
  174. 0xC7, 0x7C, 0xE2, 0xBF, 0xA4, 0xED, 0x9F, 0x9B,
  175. 0x05, 0x48, 0xB2, 0xAC, 0x50, 0x74, 0xA2, 0x97
  176. };
  177. const uint8_t MetroHash128::test_seed_1[16] = {
  178. 0x45, 0xA3, 0xCD, 0xB8, 0x38, 0x19, 0x9D, 0x7F,
  179. 0xBD, 0xD6, 0x8D, 0x86, 0x7A, 0x14, 0xEC, 0xEF
  180. };
  181. bool MetroHash128::ImplementationVerified()
  182. {
  183. uint8_t hash[16];
  184. const uint8_t * key = reinterpret_cast<const uint8_t *>(MetroHash128::test_string);
  185. // verify one-shot implementation
  186. MetroHash128::Hash(key, strlen(MetroHash128::test_string), hash, 0);
  187. if (memcmp(hash, MetroHash128::test_seed_0, 16) != 0) return false;
  188. MetroHash128::Hash(key, strlen(MetroHash128::test_string), hash, 1);
  189. if (memcmp(hash, MetroHash128::test_seed_1, 16) != 0) return false;
  190. // verify incremental implementation
  191. MetroHash128 metro;
  192. metro.Initialize(0);
  193. metro.Update(reinterpret_cast<const uint8_t *>(MetroHash128::test_string), strlen(MetroHash128::test_string));
  194. metro.Finalize(hash);
  195. if (memcmp(hash, MetroHash128::test_seed_0, 16) != 0) return false;
  196. metro.Initialize(1);
  197. metro.Update(reinterpret_cast<const uint8_t *>(MetroHash128::test_string), strlen(MetroHash128::test_string));
  198. metro.Finalize(hash);
  199. if (memcmp(hash, MetroHash128::test_seed_1, 16) != 0) return false;
  200. return true;
  201. }