mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-05 18:52:29 +02:00
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:
@@ -19,41 +19,33 @@
|
||||
v2 = std::rotl(v2, 32); \
|
||||
} while (0)
|
||||
|
||||
CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
|
||||
{
|
||||
v[0] = C0 ^ k0;
|
||||
v[1] = C1 ^ k1;
|
||||
v[2] = C2 ^ k0;
|
||||
v[3] = C3 ^ k1;
|
||||
count = 0;
|
||||
tmp = 0;
|
||||
}
|
||||
CSipHasher::CSipHasher(uint64_t k0, uint64_t k1) : m_state{k0, k1} {}
|
||||
|
||||
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;
|
||||
SIPROUND;
|
||||
SIPROUND;
|
||||
v0 ^= data;
|
||||
|
||||
v[0] = v0;
|
||||
v[1] = v1;
|
||||
v[2] = v2;
|
||||
v[3] = v3;
|
||||
m_state.v[0] = v0;
|
||||
m_state.v[1] = v1;
|
||||
m_state.v[2] = v2;
|
||||
m_state.v[3] = v3;
|
||||
|
||||
count += 8;
|
||||
m_count += 8;
|
||||
return *this;
|
||||
}
|
||||
|
||||
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 t = tmp;
|
||||
uint8_t c = count;
|
||||
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 = m_tmp;
|
||||
uint8_t c = m_count;
|
||||
|
||||
while (data.size() > 0) {
|
||||
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);
|
||||
}
|
||||
|
||||
v[0] = v0;
|
||||
v[1] = v1;
|
||||
v[2] = v2;
|
||||
v[3] = v3;
|
||||
count = c;
|
||||
tmp = t;
|
||||
m_state.v[0] = v0;
|
||||
m_state.v[1] = v1;
|
||||
m_state.v[2] = v2;
|
||||
m_state.v[3] = v3;
|
||||
m_count = c;
|
||||
m_tmp = t;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
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;
|
||||
SIPROUND;
|
||||
@@ -98,7 +90,7 @@ uint64_t CSipHasher::Finalize() const
|
||||
|
||||
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);
|
||||
v3 ^= d;
|
||||
|
||||
@@ -135,7 +127,7 @@ uint64_t PresaltedSipHasher::operator()(const uint256& val) const noexcept
|
||||
/** Specialized implementation for efficiency */
|
||||
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);
|
||||
v3 ^= d;
|
||||
SIPROUND;
|
||||
|
||||
@@ -5,28 +5,34 @@
|
||||
#ifndef BITCOIN_CRYPTO_SIPHASH_H
|
||||
#define BITCOIN_CRYPTO_SIPHASH_H
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <span>
|
||||
|
||||
class uint256;
|
||||
|
||||
/** SipHash-2-4 */
|
||||
class CSipHasher
|
||||
/** Shared SipHash internal state v[0..3], initialized from (k0, k1). */
|
||||
class SipHashState
|
||||
{
|
||||
private:
|
||||
uint64_t v[4];
|
||||
uint64_t tmp;
|
||||
uint8_t count; // Only the low 8 bits of the input size matter.
|
||||
static constexpr uint64_t C0{0x736f6d6570736575ULL}, C1{0x646f72616e646f6dULL}, C2{0x6c7967656e657261ULL}, C3{0x7465646279746573ULL};
|
||||
|
||||
public:
|
||||
static constexpr uint64_t C0{0x736f6d6570736575ULL};
|
||||
static constexpr uint64_t C1{0x646f72616e646f6dULL};
|
||||
static constexpr uint64_t C2{0x6c7967656e657261ULL};
|
||||
static constexpr uint64_t C3{0x7465646279746573ULL};
|
||||
explicit SipHashState(uint64_t k0, uint64_t k1) noexcept : v{C0 ^ k0, C1 ^ k1, C2 ^ k0, C3 ^ k1} {}
|
||||
|
||||
/** 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);
|
||||
/** 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.
|
||||
* This function can only be used when a multiple of 8 bytes have been written so far.
|
||||
*/
|
||||
@@ -48,17 +54,18 @@ public:
|
||||
*/
|
||||
class PresaltedSipHasher
|
||||
{
|
||||
uint64_t v[4];
|
||||
const SipHashState m_state;
|
||||
|
||||
public:
|
||||
explicit PresaltedSipHasher(uint64_t k0, uint64_t k1) noexcept {
|
||||
v[0] = CSipHasher::C0 ^ k0;
|
||||
v[1] = CSipHasher::C1 ^ k1;
|
||||
v[2] = CSipHasher::C2 ^ k0;
|
||||
v[3] = CSipHasher::C3 ^ k1;
|
||||
}
|
||||
explicit PresaltedSipHasher(uint64_t k0, uint64_t k1) noexcept : m_state{k0, k1} {}
|
||||
|
||||
/** Equivalent to CSipHasher(k0, k1).Write(val).Finalize(). */
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user