Siphash.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /**
  2. This code is licensed under the MCGSI Public License
  3. Copyright 2018 Jeff Becker
  4. Kovri go write your own code
  5. */
  6. #ifndef SIPHASH_H
  7. #define SIPHASH_H
  8. #include <cstdint>
  9. #include "Crypto.h"
  10. #if !OPENSSL_SIPHASH
  11. namespace i2p
  12. {
  13. namespace crypto
  14. {
  15. namespace siphash
  16. {
  17. constexpr int crounds = 2;
  18. constexpr int drounds = 4;
  19. inline uint64_t rotl(const uint64_t & x, int b)
  20. {
  21. uint64_t ret = x << b;
  22. ret |= x >> (64 - b);
  23. return ret;
  24. }
  25. inline void u32to8le(const uint32_t & v, uint8_t * p)
  26. {
  27. p[0] = (uint8_t) v;
  28. p[1] = (uint8_t) (v >> 8);
  29. p[2] = (uint8_t) (v >> 16);
  30. p[3] = (uint8_t) (v >> 24);
  31. }
  32. inline void u64to8le(const uint64_t & v, uint8_t * p)
  33. {
  34. p[0] = v & 0xff;
  35. p[1] = (v >> 8) & 0xff;
  36. p[2] = (v >> 16) & 0xff;
  37. p[3] = (v >> 24) & 0xff;
  38. p[4] = (v >> 32) & 0xff;
  39. p[5] = (v >> 40) & 0xff;
  40. p[6] = (v >> 48) & 0xff;
  41. p[7] = (v >> 56) & 0xff;
  42. }
  43. inline uint64_t u8to64le(const uint8_t * p)
  44. {
  45. uint64_t i = 0;
  46. int idx = 0;
  47. while(idx < 8)
  48. {
  49. i |= ((uint64_t) p[idx]) << (idx * 8);
  50. ++idx;
  51. }
  52. return i;
  53. }
  54. inline void round(uint64_t & _v0, uint64_t & _v1, uint64_t & _v2, uint64_t & _v3)
  55. {
  56. _v0 += _v1;
  57. _v1 = rotl(_v1, 13);
  58. _v1 ^= _v0;
  59. _v0 = rotl(_v0, 32);
  60. _v2 += _v3;
  61. _v3 = rotl(_v3, 16);
  62. _v3 ^= _v2;
  63. _v0 += _v3;
  64. _v3 = rotl(_v3, 21);
  65. _v3 ^= _v0;
  66. _v2 += _v1;
  67. _v1 = rotl(_v1, 17);
  68. _v1 ^= _v2;
  69. _v2 = rotl(_v2, 32);
  70. }
  71. }
  72. /** hashsz must be 8 or 16 */
  73. template<std::size_t hashsz>
  74. inline void Siphash(uint8_t * h, const uint8_t * buf, std::size_t bufsz, const uint8_t * key)
  75. {
  76. uint64_t v0 = 0x736f6d6570736575ULL;
  77. uint64_t v1 = 0x646f72616e646f6dULL;
  78. uint64_t v2 = 0x6c7967656e657261ULL;
  79. uint64_t v3 = 0x7465646279746573ULL;
  80. const uint64_t k0 = siphash::u8to64le(key);
  81. const uint64_t k1 = siphash::u8to64le(key + 8);
  82. uint64_t msg;
  83. int i;
  84. const uint8_t * end = buf + bufsz - (bufsz % sizeof(uint64_t));
  85. auto left = bufsz & 7;
  86. uint64_t b = ((uint64_t)bufsz) << 56;
  87. v3 ^= k1;
  88. v2 ^= k0;
  89. v1 ^= k1;
  90. v0 ^= k0;
  91. if(hashsz == 16) v1 ^= 0xee;
  92. while(buf != end)
  93. {
  94. msg = siphash::u8to64le(buf);
  95. v3 ^= msg;
  96. for(i = 0; i < siphash::crounds; ++i)
  97. siphash::round(v0, v1, v2, v3);
  98. v0 ^= msg;
  99. buf += 8;
  100. }
  101. while(left)
  102. {
  103. --left;
  104. b |= ((uint64_t)(buf[left])) << (left * 8);
  105. }
  106. v3 ^= b;
  107. for(i = 0; i < siphash::crounds; ++i)
  108. siphash::round(v0, v1, v2, v3);
  109. v0 ^= b;
  110. if(hashsz == 16)
  111. v2 ^= 0xee;
  112. else
  113. v2 ^= 0xff;
  114. for(i = 0; i < siphash::drounds; ++i)
  115. siphash::round(v0, v1, v2, v3);
  116. b = v0 ^ v1 ^ v2 ^ v3;
  117. siphash::u64to8le(b, h);
  118. if(hashsz == 8) return;
  119. v1 ^= 0xdd;
  120. for (i = 0; i < siphash::drounds; ++i)
  121. siphash::round(v0, v1, v2, v3);
  122. b = v0 ^ v1 ^ v2 ^ v3;
  123. siphash::u64to8le(b, h + 8);
  124. }
  125. }
  126. }
  127. #endif
  128. #endif