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