From 7e0032290669fae5f52c256856c53038511c7db4 Mon Sep 17 00:00:00 2001
From: Pieter Wuille <pieter.wuille@gmail.com>
Date: Tue, 25 Apr 2017 11:29:16 -0700
Subject: Add specialization of SipHash for 256 + 32 bit data

We'll need a version of SipHash for tuples of 256 bits and 32 bits
data, when CCoinsViewCache switches from using txids to COutPoints as
keys.
---
 src/hash.cpp            | 41 +++++++++++++++++++++++++++++++++++++++++
 src/hash.h              |  1 +
 src/test/hash_tests.cpp | 17 +++++++++++++++++
 3 files changed, 59 insertions(+)

diff --git a/src/hash.cpp b/src/hash.cpp
index a14a2386a2..b361c90d16 100644
--- a/src/hash.cpp
+++ b/src/hash.cpp
@@ -208,3 +208,44 @@ uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
     SIPROUND;
     return v0 ^ v1 ^ v2 ^ v3;
 }
+
+uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra)
+{
+    /* Specialized implementation for efficiency */
+    uint64_t d = val.GetUint64(0);
+
+    uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
+    uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
+    uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
+    uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ d;
+
+    SIPROUND;
+    SIPROUND;
+    v0 ^= d;
+    d = val.GetUint64(1);
+    v3 ^= d;
+    SIPROUND;
+    SIPROUND;
+    v0 ^= d;
+    d = val.GetUint64(2);
+    v3 ^= d;
+    SIPROUND;
+    SIPROUND;
+    v0 ^= d;
+    d = val.GetUint64(3);
+    v3 ^= d;
+    SIPROUND;
+    SIPROUND;
+    v0 ^= d;
+    d = (((uint64_t)36) << 56) | extra;
+    v3 ^= d;
+    SIPROUND;
+    SIPROUND;
+    v0 ^= d;
+    v2 ^= 0xFF;
+    SIPROUND;
+    SIPROUND;
+    SIPROUND;
+    SIPROUND;
+    return v0 ^ v1 ^ v2 ^ v3;
+}
diff --git a/src/hash.h b/src/hash.h
index b8de19c0fd..b9952d39fc 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -241,5 +241,6 @@ public:
  *      .Finalize()
  */
 uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
+uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra);
 
 #endif // BITCOIN_HASH_H
diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp
index d8de765db1..bb7e473248 100644
--- a/src/test/hash_tests.cpp
+++ b/src/test/hash_tests.cpp
@@ -128,6 +128,23 @@ BOOST_AUTO_TEST_CASE(siphash)
     tx.nVersion = 1;
     ss << tx;
     BOOST_CHECK_EQUAL(SipHashUint256(1, 2, ss.GetHash()), 0x79751e980c2a0a35ULL);
+
+    // Check consistency between CSipHasher and SipHashUint256[Extra].
+    FastRandomContext ctx;
+    for (int i = 0; i < 16; ++i) {
+        uint64_t k1 = ctx.rand64();
+        uint64_t k2 = ctx.rand64();
+        uint256 x = GetRandHash();
+        uint32_t n = ctx.rand32();
+        uint8_t nb[4];
+        WriteLE32(nb, n);
+        CSipHasher sip256(k1, k2);
+        sip256.Write(x.begin(), 32);
+        CSipHasher sip288 = sip256;
+        sip288.Write(nb, 4);
+        BOOST_CHECK_EQUAL(SipHashUint256(k1, k2, x), sip256.Finalize());
+        BOOST_CHECK_EQUAL(SipHashUint256Extra(k1, k2, x, n), sip288.Finalize());
+    }
 }
 
 BOOST_AUTO_TEST_SUITE_END()
-- 
cgit v1.2.3