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