Skip to content

Commit

Permalink
Optimized siphash implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
elichai committed Mar 19, 2021
1 parent 3fb1f51 commit 4431644
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 17 deletions.
62 changes: 47 additions & 15 deletions src/crypto/siphash.cpp
Expand Up @@ -2,8 +2,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <crypto/common.h>
#include <crypto/siphash.h>

#include <algorithm>

#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))

#define SIPROUND do { \
Expand All @@ -22,14 +25,14 @@ CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
v[2] = 0x6c7967656e657261ULL ^ k0;
v[3] = 0x7465646279746573ULL ^ k1;
count = 0;
tmp = 0;
tail = 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);
assert((count & 0x07) == 0);

v3 ^= data;
SIPROUND;
Expand All @@ -45,30 +48,57 @@ CSipHasher& CSipHasher::Write(uint64_t data)
return *this;
}


/// Load a uint64_t from 0 to 7 bytes.
inline uint64_t ReadU64ByLenLE(const unsigned char* data, size_t len)
{
assert(len < 8);
uint64_t out = 0;
for (size_t i = 0; i < len; ++i) {
out |= (uint64_t)data[i] << (i * 8);
}
return out;
}

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;
uint8_t c = count;

while (size--) {
t |= ((uint64_t)(*(data++))) << (8 * (c % 8));
c++;
if ((c & 7) == 0) {
v3 ^= t;
auto ntail = count & 0x07;
count += size;

size_t needed = 0;

if (ntail != 0) {
needed = 8 - ntail;
tail |= ReadU64ByLenLE(data, std::min(size, needed)) << 8 * ntail;
if (size < needed) {
return *this;
} else {
v3 ^= tail;
SIPROUND;
SIPROUND;
v0 ^= t;
t = 0;
v0 ^= tail;
}
}

size_t len = size - needed;
auto left = len & 0x07;

auto i = needed;
while (i < len - left) {
uint64_t mi = ReadLE64(data + i);
v3 ^= mi;
SIPROUND;
SIPROUND;
v0 ^= mi;
i += 8;
}

v[0] = v0;
v[1] = v1;
v[2] = v2;
v[3] = v3;
count = c;
tmp = t;
tail = ReadU64ByLenLE(data + i, left);

return *this;
}
Expand All @@ -77,12 +107,14 @@ uint64_t CSipHasher::Finalize() const
{
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];

uint64_t t = tmp | (((uint64_t)count) << 56);

uint64_t t = tail | (((uint64_t)count) << 56);

v3 ^= t;
SIPROUND;
SIPROUND;
v0 ^= t;

v2 ^= 0xFF;
SIPROUND;
SIPROUND;
Expand Down
4 changes: 2 additions & 2 deletions src/crypto/siphash.h
Expand Up @@ -14,8 +14,8 @@ class CSipHasher
{
private:
uint64_t v[4];
uint64_t tmp;
uint8_t count; // Only the low 8 bits of the input size matter.
uint64_t tail; // bytes that weren't processed yet.
uint8_t count; // total amount of bytes inputted.

public:
/** Construct a SipHash calculator initialized with 128-bit key (k0, k1) */
Expand Down

0 comments on commit 4431644

Please sign in to comment.