/ src / crypto / siphash.cpp
siphash.cpp
  1  // Copyright (c) 2016-present The Bitcoin Core developers
  2  // Distributed under the MIT software license, see the accompanying
  3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4  
  5  #include <crypto/siphash.h>
  6  
  7  #include <uint256.h>
  8  
  9  #include <bit>
 10  #include <cassert>
 11  #include <span>
 12  
 13  #define SIPROUND do { \
 14      v0 += v1; v1 = std::rotl(v1, 13); v1 ^= v0; \
 15      v0 = std::rotl(v0, 32); \
 16      v2 += v3; v3 = std::rotl(v3, 16); v3 ^= v2; \
 17      v0 += v3; v3 = std::rotl(v3, 21); v3 ^= v0; \
 18      v2 += v1; v1 = std::rotl(v1, 17); v1 ^= v2; \
 19      v2 = std::rotl(v2, 32); \
 20  } while (0)
 21  
 22  CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
 23  {
 24      v[0] = 0x736f6d6570736575ULL ^ k0;
 25      v[1] = 0x646f72616e646f6dULL ^ k1;
 26      v[2] = 0x6c7967656e657261ULL ^ k0;
 27      v[3] = 0x7465646279746573ULL ^ k1;
 28      count = 0;
 29      tmp = 0;
 30  }
 31  
 32  CSipHasher& CSipHasher::Write(uint64_t data)
 33  {
 34      uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
 35  
 36      assert(count % 8 == 0);
 37  
 38      v3 ^= data;
 39      SIPROUND;
 40      SIPROUND;
 41      v0 ^= data;
 42  
 43      v[0] = v0;
 44      v[1] = v1;
 45      v[2] = v2;
 46      v[3] = v3;
 47  
 48      count += 8;
 49      return *this;
 50  }
 51  
 52  CSipHasher& CSipHasher::Write(std::span<const unsigned char> data)
 53  {
 54      uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
 55      uint64_t t = tmp;
 56      uint8_t c = count;
 57  
 58      while (data.size() > 0) {
 59          t |= uint64_t{data.front()} << (8 * (c % 8));
 60          c++;
 61          if ((c & 7) == 0) {
 62              v3 ^= t;
 63              SIPROUND;
 64              SIPROUND;
 65              v0 ^= t;
 66              t = 0;
 67          }
 68          data = data.subspan(1);
 69      }
 70  
 71      v[0] = v0;
 72      v[1] = v1;
 73      v[2] = v2;
 74      v[3] = v3;
 75      count = c;
 76      tmp = t;
 77  
 78      return *this;
 79  }
 80  
 81  uint64_t CSipHasher::Finalize() const
 82  {
 83      uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
 84  
 85      uint64_t t = tmp | (((uint64_t)count) << 56);
 86  
 87      v3 ^= t;
 88      SIPROUND;
 89      SIPROUND;
 90      v0 ^= t;
 91      v2 ^= 0xFF;
 92      SIPROUND;
 93      SIPROUND;
 94      SIPROUND;
 95      SIPROUND;
 96      return v0 ^ v1 ^ v2 ^ v3;
 97  }
 98  
 99  uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
100  {
101      /* Specialized implementation for efficiency */
102      uint64_t d = val.GetUint64(0);
103  
104      uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
105      uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
106      uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
107      uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
108  
109      SIPROUND;
110      SIPROUND;
111      v0 ^= d;
112      d = val.GetUint64(1);
113      v3 ^= d;
114      SIPROUND;
115      SIPROUND;
116      v0 ^= d;
117      d = val.GetUint64(2);
118      v3 ^= d;
119      SIPROUND;
120      SIPROUND;
121      v0 ^= d;
122      d = val.GetUint64(3);
123      v3 ^= d;
124      SIPROUND;
125      SIPROUND;
126      v0 ^= d;
127      v3 ^= (uint64_t{4}) << 59;
128      SIPROUND;
129      SIPROUND;
130      v0 ^= (uint64_t{4}) << 59;
131      v2 ^= 0xFF;
132      SIPROUND;
133      SIPROUND;
134      SIPROUND;
135      SIPROUND;
136      return v0 ^ v1 ^ v2 ^ v3;
137  }
138  
139  uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra)
140  {
141      /* Specialized implementation for efficiency */
142      uint64_t d = val.GetUint64(0);
143  
144      uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
145      uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
146      uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
147      uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
148  
149      SIPROUND;
150      SIPROUND;
151      v0 ^= d;
152      d = val.GetUint64(1);
153      v3 ^= d;
154      SIPROUND;
155      SIPROUND;
156      v0 ^= d;
157      d = val.GetUint64(2);
158      v3 ^= d;
159      SIPROUND;
160      SIPROUND;
161      v0 ^= d;
162      d = val.GetUint64(3);
163      v3 ^= d;
164      SIPROUND;
165      SIPROUND;
166      v0 ^= d;
167      d = ((uint64_t{36}) << 56) | extra;
168      v3 ^= d;
169      SIPROUND;
170      SIPROUND;
171      v0 ^= d;
172      v2 ^= 0xFF;
173      SIPROUND;
174      SIPROUND;
175      SIPROUND;
176      SIPROUND;
177      return v0 ^ v1 ^ v2 ^ v3;
178  }