refactor: extract shared SipHash state into SipHashState
Split the repeated `SipHash` v[0..3] initialization into a small `SipHashState` helper that is used by both `CSipHasher` and `PresaltedSipHasher`. Added explanatory comments to clarify behavior, documenting the equivalence of `PresaltedSipHasher` `operator()` overloads to `CSipHasher` usage. Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
This commit is contained in:
2 files changed
+47
-48
No files matched your search
+21
-29
@@ -19,41 +19,33 @@
|
|||||||
v2 = std::rotl(v2, 32); \
|
v2 = std::rotl(v2, 32); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
|
CSipHasher::CSipHasher(uint64_t k0, uint64_t k1) : m_state{k0, k1} {}
|
||||||
{
|
|
||||||
v[0] = C0 ^ k0;
|
|
||||||
v[1] = C1 ^ k1;
|
|
||||||
v[2] = C2 ^ k0;
|
|
||||||
v[3] = C3 ^ k1;
|
|
||||||
count = 0;
|
|
||||||
tmp = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CSipHasher& CSipHasher::Write(uint64_t data)
|
CSipHasher& CSipHasher::Write(uint64_t data)
|
||||||
{
|
{
|
||||||
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
|
uint64_t v0 = m_state.v[0], v1 = m_state.v[1], v2 = m_state.v[2], v3 = m_state.v[3];
|
||||||
|
|
||||||
assert(count % 8 == 0);
|
assert(m_count % 8 == 0);
|
||||||
|
|
||||||
v3 ^= data;
|
v3 ^= data;
|
||||||
SIPROUND;
|
SIPROUND;
|
||||||
SIPROUND;
|
SIPROUND;
|
||||||
v0 ^= data;
|
v0 ^= data;
|
||||||
|
|
||||||
v[0] = v0;
|
m_state.v[0] = v0;
|
||||||
v[1] = v1;
|
m_state.v[1] = v1;
|
||||||
v[2] = v2;
|
m_state.v[2] = v2;
|
||||||
v[3] = v3;
|
m_state.v[3] = v3;
|
||||||
|
|
||||||
count += 8;
|
m_count += 8;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSipHasher& CSipHasher::Write(std::span<const unsigned char> data)
|
CSipHasher& CSipHasher::Write(std::span<const unsigned char> data)
|
||||||
{
|
{
|
||||||
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
|
uint64_t v0 = m_state.v[0], v1 = m_state.v[1], v2 = m_state.v[2], v3 = m_state.v[3];
|
||||||
uint64_t t = tmp;
|
uint64_t t = m_tmp;
|
||||||
uint8_t c = count;
|
uint8_t c = m_count;
|
||||||
|
|
||||||
while (data.size() > 0) {
|
while (data.size() > 0) {
|
||||||
t |= uint64_t{data.front()} << (8 * (c % 8));
|
t |= uint64_t{data.front()} << (8 * (c % 8));
|
||||||
@@ -68,21 +60,21 @@ CSipHasher& CSipHasher::Write(std::span<const unsigned char> data)
|
|||||||
data = data.subspan(1);
|
data = data.subspan(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
v[0] = v0;
|
m_state.v[0] = v0;
|
||||||
v[1] = v1;
|
m_state.v[1] = v1;
|
||||||
v[2] = v2;
|
m_state.v[2] = v2;
|
||||||
v[3] = v3;
|
m_state.v[3] = v3;
|
||||||
count = c;
|
m_count = c;
|
||||||
tmp = t;
|
m_tmp = t;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t CSipHasher::Finalize() const
|
uint64_t CSipHasher::Finalize() const
|
||||||
{
|
{
|
||||||
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
|
uint64_t v0 = m_state.v[0], v1 = m_state.v[1], v2 = m_state.v[2], v3 = m_state.v[3];
|
||||||
|
|
||||||
uint64_t t = tmp | (((uint64_t)count) << 56);
|
uint64_t t = m_tmp | (((uint64_t)m_count) << 56);
|
||||||
|
|
||||||
v3 ^= t;
|
v3 ^= t;
|
||||||
SIPROUND;
|
SIPROUND;
|
||||||
@@ -98,7 +90,7 @@ uint64_t CSipHasher::Finalize() const
|
|||||||
|
|
||||||
uint64_t PresaltedSipHasher::operator()(const uint256& val) const noexcept
|
uint64_t PresaltedSipHasher::operator()(const uint256& val) const noexcept
|
||||||
{
|
{
|
||||||
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
|
uint64_t v0 = m_state.v[0], v1 = m_state.v[1], v2 = m_state.v[2], v3 = m_state.v[3];
|
||||||
uint64_t d = val.GetUint64(0);
|
uint64_t d = val.GetUint64(0);
|
||||||
v3 ^= d;
|
v3 ^= d;
|
||||||
|
|
||||||
@@ -135,7 +127,7 @@ uint64_t PresaltedSipHasher::operator()(const uint256& val) const noexcept
|
|||||||
/** Specialized implementation for efficiency */
|
/** Specialized implementation for efficiency */
|
||||||
uint64_t PresaltedSipHasher::operator()(const uint256& val, uint32_t extra) const noexcept
|
uint64_t PresaltedSipHasher::operator()(const uint256& val, uint32_t extra) const noexcept
|
||||||
{
|
{
|
||||||
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
|
uint64_t v0 = m_state.v[0], v1 = m_state.v[1], v2 = m_state.v[2], v3 = m_state.v[3];
|
||||||
uint64_t d = val.GetUint64(0);
|
uint64_t d = val.GetUint64(0);
|
||||||
v3 ^= d;
|
v3 ^= d;
|
||||||
SIPROUND;
|
SIPROUND;
|
||||||
|
|||||||
+26
-19
@@ -5,28 +5,34 @@
|
|||||||
#ifndef BITCOIN_CRYPTO_SIPHASH_H
|
#ifndef BITCOIN_CRYPTO_SIPHASH_H
|
||||||
#define BITCOIN_CRYPTO_SIPHASH_H
|
#define BITCOIN_CRYPTO_SIPHASH_H
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
|
||||||
class uint256;
|
class uint256;
|
||||||
|
|
||||||
/** SipHash-2-4 */
|
/** Shared SipHash internal state v[0..3], initialized from (k0, k1). */
|
||||||
class CSipHasher
|
class SipHashState
|
||||||
{
|
{
|
||||||
private:
|
static constexpr uint64_t C0{0x736f6d6570736575ULL}, C1{0x646f72616e646f6dULL}, C2{0x6c7967656e657261ULL}, C3{0x7465646279746573ULL};
|
||||||
uint64_t v[4];
|
|
||||||
uint64_t tmp;
|
|
||||||
uint8_t count; // Only the low 8 bits of the input size matter.
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr uint64_t C0{0x736f6d6570736575ULL};
|
explicit SipHashState(uint64_t k0, uint64_t k1) noexcept : v{C0 ^ k0, C1 ^ k1, C2 ^ k0, C3 ^ k1} {}
|
||||||
static constexpr uint64_t C1{0x646f72616e646f6dULL};
|
|
||||||
static constexpr uint64_t C2{0x6c7967656e657261ULL};
|
|
||||||
static constexpr uint64_t C3{0x7465646279746573ULL};
|
|
||||||
|
|
||||||
/** Construct a SipHash calculator initialized with 128-bit key (k0, k1) */
|
std::array<uint64_t, 4> v{};
|
||||||
|
};
|
||||||
|
|
||||||
|
/** General SipHash-2-4 implementation. */
|
||||||
|
class CSipHasher
|
||||||
|
{
|
||||||
|
SipHashState m_state;
|
||||||
|
uint64_t m_tmp{0};
|
||||||
|
uint8_t m_count{0}; //!< Only the low 8 bits of the input size matter.
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Construct a SipHash calculator initialized with 128-bit key (k0, k1). */
|
||||||
CSipHasher(uint64_t k0, uint64_t k1);
|
CSipHasher(uint64_t k0, uint64_t k1);
|
||||||
/** Hash a 64-bit integer worth of data
|
/** Hash a 64-bit integer worth of data.
|
||||||
* It is treated as if this was the little-endian interpretation of 8 bytes.
|
* 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.
|
* This function can only be used when a multiple of 8 bytes have been written so far.
|
||||||
*/
|
*/
|
||||||
@@ -48,17 +54,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
class PresaltedSipHasher
|
class PresaltedSipHasher
|
||||||
{
|
{
|
||||||
uint64_t v[4];
|
const SipHashState m_state;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PresaltedSipHasher(uint64_t k0, uint64_t k1) noexcept {
|
explicit PresaltedSipHasher(uint64_t k0, uint64_t k1) noexcept : m_state{k0, k1} {}
|
||||||
v[0] = CSipHasher::C0 ^ k0;
|
|
||||||
v[1] = CSipHasher::C1 ^ k1;
|
|
||||||
v[2] = CSipHasher::C2 ^ k0;
|
|
||||||
v[3] = CSipHasher::C3 ^ k1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/** Equivalent to CSipHasher(k0, k1).Write(val).Finalize(). */
|
||||||
uint64_t operator()(const uint256& val) const noexcept;
|
uint64_t operator()(const uint256& val) const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equivalent to CSipHasher(k0, k1).Write(val).Write(extra).Finalize(),
|
||||||
|
* with `extra` encoded as 4 little-endian bytes.
|
||||||
|
*/
|
||||||
uint64_t operator()(const uint256& val, uint32_t extra) const noexcept;
|
uint64_t operator()(const uint256& val, uint32_t extra) const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user