Skip to content

Commit b2e5c4a

Browse files
siparandom-zebra
authored andcommitted
Add SipHash-2-4 primitives to hash
1 parent 91c373c commit b2e5c4a

File tree

4 files changed

+145
-0
lines changed

4 files changed

+145
-0
lines changed

src/blob_uint256.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,19 @@ class base_blob
7878
return sizeof(data);
7979
}
8080

81+
uint64_t GetUint64(int pos) const
82+
{
83+
const uint8_t* ptr = data + pos * 8;
84+
return ((uint64_t)ptr[0]) | \
85+
((uint64_t)ptr[1]) << 8 | \
86+
((uint64_t)ptr[2]) << 16 | \
87+
((uint64_t)ptr[3]) << 24 | \
88+
((uint64_t)ptr[4]) << 32 | \
89+
((uint64_t)ptr[5]) << 40 | \
90+
((uint64_t)ptr[6]) << 48 | \
91+
((uint64_t)ptr[7]) << 56;
92+
}
93+
8194
template<typename Stream>
8295
void Serialize(Stream& s) const
8396
{

src/hash.cpp

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,97 @@ void scrypt_hash(const char* pass, unsigned int pLen, const char* salt, unsigned
8585
{
8686
scrypt(pass, pLen, salt, sLen, output, N, r, p, dkLen);
8787
}
88+
89+
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
90+
91+
#define SIPROUND do { \
92+
v0 += v1; v1 = ROTL(v1, 13); v1 ^= v0; \
93+
v0 = ROTL(v0, 32); \
94+
v2 += v3; v3 = ROTL(v3, 16); v3 ^= v2; \
95+
v0 += v3; v3 = ROTL(v3, 21); v3 ^= v0; \
96+
v2 += v1; v1 = ROTL(v1, 17); v1 ^= v2; \
97+
v2 = ROTL(v2, 32); \
98+
} while (0)
99+
100+
CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
101+
{
102+
v[0] = 0x736f6d6570736575ULL ^ k0;
103+
v[1] = 0x646f72616e646f6dULL ^ k1;
104+
v[2] = 0x6c7967656e657261ULL ^ k0;
105+
v[3] = 0x7465646279746573ULL ^ k1;
106+
count = 0;
107+
}
108+
109+
CSipHasher& CSipHasher::Write(uint64_t data)
110+
{
111+
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
112+
113+
v3 ^= data;
114+
SIPROUND;
115+
SIPROUND;
116+
v0 ^= data;
117+
118+
v[0] = v0;
119+
v[1] = v1;
120+
v[2] = v2;
121+
v[3] = v3;
122+
123+
count++;
124+
return *this;
125+
}
126+
127+
uint64_t CSipHasher::Finalize() const
128+
{
129+
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
130+
131+
v3 ^= ((uint64_t)count) << 59;
132+
SIPROUND;
133+
SIPROUND;
134+
v0 ^= ((uint64_t)count) << 59;
135+
v2 ^= 0xFF;
136+
SIPROUND;
137+
SIPROUND;
138+
SIPROUND;
139+
SIPROUND;
140+
return v0 ^ v1 ^ v2 ^ v3;
141+
}
142+
143+
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const blob_uint256& val)
144+
{
145+
/* Specialized implementation for efficiency */
146+
uint64_t d = val.GetUint64(0);
147+
148+
uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
149+
uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
150+
uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
151+
uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
152+
153+
SIPROUND;
154+
SIPROUND;
155+
v0 ^= d;
156+
d = val.GetUint64(1);
157+
v3 ^= d;
158+
SIPROUND;
159+
SIPROUND;
160+
v0 ^= d;
161+
d = val.GetUint64(2);
162+
v3 ^= d;
163+
SIPROUND;
164+
SIPROUND;
165+
v0 ^= d;
166+
d = val.GetUint64(3);
167+
v3 ^= d;
168+
SIPROUND;
169+
SIPROUND;
170+
v0 ^= d;
171+
v3 ^= ((uint64_t)4) << 59;
172+
SIPROUND;
173+
SIPROUND;
174+
v0 ^= ((uint64_t)4) << 59;
175+
v2 ^= 0xFF;
176+
SIPROUND;
177+
SIPROUND;
178+
SIPROUND;
179+
SIPROUND;
180+
return v0 ^ v1 ^ v2 ^ v3;
181+
}

src/hash.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,4 +416,21 @@ inline uint256 HashQuark(const T1 pbegin, const T1 pend)
416416

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

419+
420+
/** SipHash-2-4, using a uint64_t-based (rather than byte-based) interface */
421+
class CSipHasher
422+
{
423+
private:
424+
uint64_t v[4];
425+
int count;
426+
427+
public:
428+
CSipHasher(uint64_t k0, uint64_t k1);
429+
CSipHasher& Write(uint64_t data);
430+
uint64_t Finalize() const;
431+
};
432+
433+
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const blob_uint256& val);
434+
419435
#endif // PIVX_HASH_H
436+

src/test/hash_tests.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,25 @@ BOOST_AUTO_TEST_CASE(murmurhash3)
4646
#undef T
4747
}
4848

49+
BOOST_AUTO_TEST_CASE(siphash)
50+
{
51+
CSipHasher hasher(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL);
52+
BOOST_CHECK_EQUAL(hasher.Finalize(), 0x726fdb47dd0e0e31ull);
53+
hasher.Write(0x0706050403020100ULL);
54+
BOOST_CHECK_EQUAL(hasher.Finalize(), 0x93f5f5799a932462ull);
55+
hasher.Write(0x0F0E0D0C0B0A0908ULL);
56+
BOOST_CHECK_EQUAL(hasher.Finalize(), 0x3f2acc7f57c29bdbull);
57+
hasher.Write(0x1716151413121110ULL);
58+
BOOST_CHECK_EQUAL(hasher.Finalize(), 0xb8ad50c6f649af94ull);
59+
hasher.Write(0x1F1E1D1C1B1A1918ULL);
60+
BOOST_CHECK_EQUAL(hasher.Finalize(), 0x7127512f72f27cceull);
61+
hasher.Write(0x2726252423222120ULL);
62+
BOOST_CHECK_EQUAL(hasher.Finalize(), 0x0e3ea96b5304a7d0ull);
63+
hasher.Write(0x2F2E2D2C2B2A2928ULL);
64+
BOOST_CHECK_EQUAL(hasher.Finalize(), 0xe612a3cb9ecba951ull);
65+
66+
const blob_uint256 hash = blob_uint256S("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100");
67+
BOOST_CHECK_EQUAL(SipHashUint256(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL, hash), 0x7127512f72f27cceull);
68+
}
69+
4970
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)