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 }