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) : 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 }