diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2016-05-22 11:06:18 +0200 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2016-06-07 16:20:40 +0200 |
commit | 9bf156bb9ee4915fa7e8f84589d65f6598563c97 (patch) | |
tree | c9be046c2bcc72f0bb80d97e09543e633e68da04 | |
parent | 053930ffc41ba33fe7ce26bde7097951fe0b8462 (diff) |
Support SipHash with arbitrary byte writes
-rw-r--r-- | src/hash.cpp | 39 | ||||
-rw-r--r-- | src/hash.h | 21 | ||||
-rw-r--r-- | src/test/hash_tests.cpp | 17 |
3 files changed, 69 insertions, 8 deletions
diff --git a/src/hash.cpp b/src/hash.cpp index a518314a53..20a83342db 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -100,12 +100,15 @@ CSipHasher::CSipHasher(uint64_t k0, uint64_t k1) v[2] = 0x6c7967656e657261ULL ^ k0; v[3] = 0x7465646279746573ULL ^ k1; count = 0; + tmp = 0; } CSipHasher& CSipHasher::Write(uint64_t data) { uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; + assert(count % 8 == 0); + v3 ^= data; SIPROUND; SIPROUND; @@ -116,7 +119,35 @@ CSipHasher& CSipHasher::Write(uint64_t data) v[2] = v2; v[3] = v3; - count++; + count += 8; + return *this; +} + +CSipHasher& CSipHasher::Write(const unsigned char* data, size_t size) +{ + uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; + uint64_t t = tmp; + int c = count; + + while (size--) { + t |= ((uint64_t)(*(data++))) << (8 * (c % 8)); + c++; + if ((c & 7) == 0) { + v3 ^= t; + SIPROUND; + SIPROUND; + v0 ^= t; + t = 0; + } + } + + v[0] = v0; + v[1] = v1; + v[2] = v2; + v[3] = v3; + count = c; + tmp = t; + return *this; } @@ -124,10 +155,12 @@ uint64_t CSipHasher::Finalize() const { uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3]; - v3 ^= ((uint64_t)count) << 59; + uint64_t t = tmp | (((uint64_t)count) << 56); + + v3 ^= t; SIPROUND; SIPROUND; - v0 ^= ((uint64_t)count) << 59; + v0 ^= t; v2 ^= 0xFF; SIPROUND; SIPROUND; diff --git a/src/hash.h b/src/hash.h index 600dabec56..db4e130ae7 100644 --- a/src/hash.h +++ b/src/hash.h @@ -171,19 +171,38 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]); -/** SipHash-2-4, using a uint64_t-based (rather than byte-based) interface */ +/** SipHash-2-4 */ class CSipHasher { private: uint64_t v[4]; + uint64_t tmp; int count; public: + /** Construct a SipHash calculator initialized with 128-bit key (k0, k1) */ CSipHasher(uint64_t k0, uint64_t k1); + /** Hash a 64-bit integer worth of data + * It is treated as if this was the little-endian interpretation of 8 bytes. + * This function can only be used when a multiple of 8 bytes have been written so far. + */ CSipHasher& Write(uint64_t data); + /** Hash arbitrary bytes. */ + CSipHasher& Write(const unsigned char* data, size_t size); + /** Compute the 64-bit SipHash-2-4 of the data written so far. The object remains untouched. */ uint64_t Finalize() const; }; +/** Optimized SipHash-2-4 implementation for uint256. + * + * It is identical to: + * SipHasher(k0, k1) + * .Write(val.GetUint64(0)) + * .Write(val.GetUint64(1)) + * .Write(val.GetUint64(2)) + * .Write(val.GetUint64(3)) + * .Finalize() + */ uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val); #endif // BITCOIN_HASH_H diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp index 8baaf3645f..f62080c1d2 100644 --- a/src/test/hash_tests.cpp +++ b/src/test/hash_tests.cpp @@ -51,13 +51,22 @@ BOOST_AUTO_TEST_CASE(siphash) { CSipHasher hasher(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x726fdb47dd0e0e31ull); - hasher.Write(0x0706050403020100ULL); + static const unsigned char t0[1] = {0}; + hasher.Write(t0, 1); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x74f839c593dc67fdull); + static const unsigned char t1[7] = {1,2,3,4,5,6,7}; + hasher.Write(t1, 7); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x93f5f5799a932462ull); hasher.Write(0x0F0E0D0C0B0A0908ULL); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x3f2acc7f57c29bdbull); - hasher.Write(0x1716151413121110ULL); - BOOST_CHECK_EQUAL(hasher.Finalize(), 0xb8ad50c6f649af94ull); - hasher.Write(0x1F1E1D1C1B1A1918ULL); + static const unsigned char t2[2] = {16,17}; + hasher.Write(t2, 2); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x4bc1b3f0968dd39cull); + static const unsigned char t3[9] = {18,19,20,21,22,23,24,25,26}; + hasher.Write(t3, 9); + BOOST_CHECK_EQUAL(hasher.Finalize(), 0x2f2e6163076bcfadull); + static const unsigned char t4[5] = {27,28,29,30,31}; + hasher.Write(t4, 5); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x7127512f72f27cceull); hasher.Write(0x2726252423222120ULL); BOOST_CHECK_EQUAL(hasher.Finalize(), 0x0e3ea96b5304a7d0ull); |