Skip to content

Commit 9bf156b

Browse files
committed
Support SipHash with arbitrary byte writes
1 parent 053930f commit 9bf156b

File tree

3 files changed

+69
-8
lines changed

3 files changed

+69
-8
lines changed

src/hash.cpp

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,15 @@ CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
100100
v[2] = 0x6c7967656e657261ULL ^ k0;
101101
v[3] = 0x7465646279746573ULL ^ k1;
102102
count = 0;
103+
tmp = 0;
103104
}
104105

105106
CSipHasher& CSipHasher::Write(uint64_t data)
106107
{
107108
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
108109

110+
assert(count % 8 == 0);
111+
109112
v3 ^= data;
110113
SIPROUND;
111114
SIPROUND;
@@ -116,18 +119,48 @@ CSipHasher& CSipHasher::Write(uint64_t data)
116119
v[2] = v2;
117120
v[3] = v3;
118121

119-
count++;
122+
count += 8;
123+
return *this;
124+
}
125+
126+
CSipHasher& CSipHasher::Write(const unsigned char* data, size_t size)
127+
{
128+
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
129+
uint64_t t = tmp;
130+
int c = count;
131+
132+
while (size--) {
133+
t |= ((uint64_t)(*(data++))) << (8 * (c % 8));
134+
c++;
135+
if ((c & 7) == 0) {
136+
v3 ^= t;
137+
SIPROUND;
138+
SIPROUND;
139+
v0 ^= t;
140+
t = 0;
141+
}
142+
}
143+
144+
v[0] = v0;
145+
v[1] = v1;
146+
v[2] = v2;
147+
v[3] = v3;
148+
count = c;
149+
tmp = t;
150+
120151
return *this;
121152
}
122153

123154
uint64_t CSipHasher::Finalize() const
124155
{
125156
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
126157

127-
v3 ^= ((uint64_t)count) << 59;
158+
uint64_t t = tmp | (((uint64_t)count) << 56);
159+
160+
v3 ^= t;
128161
SIPROUND;
129162
SIPROUND;
130-
v0 ^= ((uint64_t)count) << 59;
163+
v0 ^= t;
131164
v2 ^= 0xFF;
132165
SIPROUND;
133166
SIPROUND;

src/hash.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,19 +171,38 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char
171171

172172
void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);
173173

174-
/** SipHash-2-4, using a uint64_t-based (rather than byte-based) interface */
174+
/** SipHash-2-4 */
175175
class CSipHasher
176176
{
177177
private:
178178
uint64_t v[4];
179+
uint64_t tmp;
179180
int count;
180181

181182
public:
183+
/** Construct a SipHash calculator initialized with 128-bit key (k0, k1) */
182184
CSipHasher(uint64_t k0, uint64_t k1);
185+
/** Hash a 64-bit integer worth of data
186+
* It is treated as if this was the little-endian interpretation of 8 bytes.
187+
* This function can only be used when a multiple of 8 bytes have been written so far.
188+
*/
183189
CSipHasher& Write(uint64_t data);
190+
/** Hash arbitrary bytes. */
191+
CSipHasher& Write(const unsigned char* data, size_t size);
192+
/** Compute the 64-bit SipHash-2-4 of the data written so far. The object remains untouched. */
184193
uint64_t Finalize() const;
185194
};
186195

196+
/** Optimized SipHash-2-4 implementation for uint256.
197+
*
198+
* It is identical to:
199+
* SipHasher(k0, k1)
200+
* .Write(val.GetUint64(0))
201+
* .Write(val.GetUint64(1))
202+
* .Write(val.GetUint64(2))
203+
* .Write(val.GetUint64(3))
204+
* .Finalize()
205+
*/
187206
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
188207

189208
#endif // BITCOIN_HASH_H

src/test/hash_tests.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,22 @@ BOOST_AUTO_TEST_CASE(siphash)
5151
{
5252
CSipHasher hasher(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL);
5353
BOOST_CHECK_EQUAL(hasher.Finalize(), 0x726fdb47dd0e0e31ull);
54-
hasher.Write(0x0706050403020100ULL);
54+
static const unsigned char t0[1] = {0};
55+
hasher.Write(t0, 1);
56+
BOOST_CHECK_EQUAL(hasher.Finalize(), 0x74f839c593dc67fdull);
57+
static const unsigned char t1[7] = {1,2,3,4,5,6,7};
58+
hasher.Write(t1, 7);
5559
BOOST_CHECK_EQUAL(hasher.Finalize(), 0x93f5f5799a932462ull);
5660
hasher.Write(0x0F0E0D0C0B0A0908ULL);
5761
BOOST_CHECK_EQUAL(hasher.Finalize(), 0x3f2acc7f57c29bdbull);
58-
hasher.Write(0x1716151413121110ULL);
59-
BOOST_CHECK_EQUAL(hasher.Finalize(), 0xb8ad50c6f649af94ull);
60-
hasher.Write(0x1F1E1D1C1B1A1918ULL);
62+
static const unsigned char t2[2] = {16,17};
63+
hasher.Write(t2, 2);
64+
BOOST_CHECK_EQUAL(hasher.Finalize(), 0x4bc1b3f0968dd39cull);
65+
static const unsigned char t3[9] = {18,19,20,21,22,23,24,25,26};
66+
hasher.Write(t3, 9);
67+
BOOST_CHECK_EQUAL(hasher.Finalize(), 0x2f2e6163076bcfadull);
68+
static const unsigned char t4[5] = {27,28,29,30,31};
69+
hasher.Write(t4, 5);
6170
BOOST_CHECK_EQUAL(hasher.Finalize(), 0x7127512f72f27cceull);
6271
hasher.Write(0x2726252423222120ULL);
6372
BOOST_CHECK_EQUAL(hasher.Finalize(), 0x0e3ea96b5304a7d0ull);

0 commit comments

Comments
 (0)