Skip to content

Commit d81973a

Browse files
siparandom-zebra
authored andcommitted
Support SipHash with arbitrary byte writes
1 parent 03dba42 commit d81973a

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
@@ -104,12 +104,15 @@ CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
104104
v[2] = 0x6c7967656e657261ULL ^ k0;
105105
v[3] = 0x7465646279746573ULL ^ k1;
106106
count = 0;
107+
tmp = 0;
107108
}
108109

109110
CSipHasher& CSipHasher::Write(uint64_t data)
110111
{
111112
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
112113

114+
assert(count % 8 == 0);
115+
113116
v3 ^= data;
114117
SIPROUND;
115118
SIPROUND;
@@ -120,18 +123,48 @@ CSipHasher& CSipHasher::Write(uint64_t data)
120123
v[2] = v2;
121124
v[3] = v3;
122125

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

127158
uint64_t CSipHasher::Finalize() const
128159
{
129160
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
130161

131-
v3 ^= ((uint64_t)count) << 59;
162+
uint64_t t = tmp | (((uint64_t)count) << 56);
163+
164+
v3 ^= t;
132165
SIPROUND;
133166
SIPROUND;
134-
v0 ^= ((uint64_t)count) << 59;
167+
v0 ^= t;
135168
v2 ^= 0xFF;
136169
SIPROUND;
137170
SIPROUND;

src/hash.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,19 +417,38 @@ inline uint256 HashQuark(const T1 pbegin, const T1 pend)
417417
void scrypt_hash(const char* pass, unsigned int pLen, const char* salt, unsigned int sLen, char* output, unsigned int N, unsigned int r, unsigned int p, unsigned int dkLen);
418418

419419

420-
/** SipHash-2-4, using a uint64_t-based (rather than byte-based) interface */
420+
/** SipHash-2-4 */
421421
class CSipHasher
422422
{
423423
private:
424424
uint64_t v[4];
425+
uint64_t tmp;
425426
int count;
426427

427428
public:
429+
/** Construct a SipHash calculator initialized with 128-bit key (k0, k1) */
428430
CSipHasher(uint64_t k0, uint64_t k1);
431+
/** Hash a 64-bit integer worth of data
432+
* It is treated as if this was the little-endian interpretation of 8 bytes.
433+
* This function can only be used when a multiple of 8 bytes have been written so far.
434+
*/
429435
CSipHasher& Write(uint64_t data);
436+
/** Hash arbitrary bytes. */
437+
CSipHasher& Write(const unsigned char* data, size_t size);
438+
/** Compute the 64-bit SipHash-2-4 of the data written so far. The object remains untouched. */
430439
uint64_t Finalize() const;
431440
};
432441

442+
/** Optimized SipHash-2-4 implementation for uint256.
443+
*
444+
* It is identical to:
445+
* SipHasher(k0, k1)
446+
* .Write(val.GetUint64(0))
447+
* .Write(val.GetUint64(1))
448+
* .Write(val.GetUint64(2))
449+
* .Write(val.GetUint64(3))
450+
* .Finalize()
451+
*/
433452
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
434453

435454
#endif // PIVX_HASH_H

src/test/hash_tests.cpp

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

0 commit comments

Comments
 (0)