siphash.cpp raw

   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) : m_state{k0, k1} {}
  23  
  24  CSipHasher& CSipHasher::Write(uint64_t data)
  25  {
  26      uint64_t v0 = m_state.v[0], v1 = m_state.v[1], v2 = m_state.v[2], v3 = m_state.v[3];
  27  
  28      assert(m_count % 8 == 0);
  29  
  30      v3 ^= data;
  31      SIPROUND;
  32      SIPROUND;
  33      v0 ^= data;
  34  
  35      m_state.v[0] = v0;
  36      m_state.v[1] = v1;
  37      m_state.v[2] = v2;
  38      m_state.v[3] = v3;
  39  
  40      m_count += 8;
  41      return *this;
  42  }
  43  
  44  CSipHasher& CSipHasher::Write(std::span<const unsigned char> data)
  45  {
  46      uint64_t v0 = m_state.v[0], v1 = m_state.v[1], v2 = m_state.v[2], v3 = m_state.v[3];
  47      uint64_t t = m_tmp;
  48      uint8_t c = m_count;
  49  
  50      while (data.size() > 0) {
  51          t |= uint64_t{data.front()} << (8 * (c % 8));
  52          c++;
  53          if ((c & 7) == 0) {
  54              v3 ^= t;
  55              SIPROUND;
  56              SIPROUND;
  57              v0 ^= t;
  58              t = 0;
  59          }
  60          data = data.subspan(1);
  61      }
  62  
  63      m_state.v[0] = v0;
  64      m_state.v[1] = v1;
  65      m_state.v[2] = v2;
  66      m_state.v[3] = v3;
  67      m_count = c;
  68      m_tmp = t;
  69  
  70      return *this;
  71  }
  72  
  73  uint64_t CSipHasher::Finalize() const
  74  {
  75      uint64_t v0 = m_state.v[0], v1 = m_state.v[1], v2 = m_state.v[2], v3 = m_state.v[3];
  76  
  77      uint64_t t = m_tmp | (((uint64_t)m_count) << 56);
  78  
  79      v3 ^= t;
  80      SIPROUND;
  81      SIPROUND;
  82      v0 ^= t;
  83      v2 ^= 0xFF;
  84      SIPROUND;
  85      SIPROUND;
  86      SIPROUND;
  87      SIPROUND;
  88      return v0 ^ v1 ^ v2 ^ v3;
  89  }
  90  
  91  uint64_t PresaltedSipHasher::operator()(const uint256& val) const noexcept
  92  {
  93      uint64_t v0 = m_state.v[0], v1 = m_state.v[1], v2 = m_state.v[2], v3 = m_state.v[3];
  94      uint64_t d = val.GetUint64(0);
  95      v3 ^= d;
  96  
  97      SIPROUND;
  98      SIPROUND;
  99      v0 ^= d;
 100      d = val.GetUint64(1);
 101      v3 ^= d;
 102      SIPROUND;
 103      SIPROUND;
 104      v0 ^= d;
 105      d = val.GetUint64(2);
 106      v3 ^= d;
 107      SIPROUND;
 108      SIPROUND;
 109      v0 ^= d;
 110      d = val.GetUint64(3);
 111      v3 ^= d;
 112      SIPROUND;
 113      SIPROUND;
 114      v0 ^= d;
 115      v3 ^= (uint64_t{4}) << 59;
 116      SIPROUND;
 117      SIPROUND;
 118      v0 ^= (uint64_t{4}) << 59;
 119      v2 ^= 0xFF;
 120      SIPROUND;
 121      SIPROUND;
 122      SIPROUND;
 123      SIPROUND;
 124      return v0 ^ v1 ^ v2 ^ v3;
 125  }
 126  
 127  /** Specialized implementation for efficiency */
 128  uint64_t PresaltedSipHasher::operator()(const uint256& val, uint32_t extra) const noexcept
 129  {
 130      uint64_t v0 = m_state.v[0], v1 = m_state.v[1], v2 = m_state.v[2], v3 = m_state.v[3];
 131      uint64_t d = val.GetUint64(0);
 132      v3 ^= d;
 133      SIPROUND;
 134      SIPROUND;
 135      v0 ^= d;
 136      d = val.GetUint64(1);
 137      v3 ^= d;
 138      SIPROUND;
 139      SIPROUND;
 140      v0 ^= d;
 141      d = val.GetUint64(2);
 142      v3 ^= d;
 143      SIPROUND;
 144      SIPROUND;
 145      v0 ^= d;
 146      d = val.GetUint64(3);
 147      v3 ^= d;
 148      SIPROUND;
 149      SIPROUND;
 150      v0 ^= d;
 151      d = ((uint64_t{36}) << 56) | extra;
 152      v3 ^= d;
 153      SIPROUND;
 154      SIPROUND;
 155      v0 ^= d;
 156      v2 ^= 0xFF;
 157      SIPROUND;
 158      SIPROUND;
 159      SIPROUND;
 160      SIPROUND;
 161      return v0 ^ v1 ^ v2 ^ v3;
 162  }
 163