Skip to content

Commit 409c2e3

Browse files
committed
Optimized siphash implementation
1 parent 169a439 commit 409c2e3

File tree

2 files changed

+49
-17
lines changed

2 files changed

+49
-17
lines changed

src/crypto/siphash.cpp

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
// Distributed under the MIT software license, see the accompanying
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

5+
#include <crypto/common.h>
56
#include <crypto/siphash.h>
67

8+
#include <algorithm>
9+
710
#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
811

912
#define SIPROUND do { \
@@ -22,14 +25,14 @@ CSipHasher::CSipHasher(uint64_t k0, uint64_t k1)
2225
v[2] = 0x6c7967656e657261ULL ^ k0;
2326
v[3] = 0x7465646279746573ULL ^ k1;
2427
count = 0;
25-
tmp = 0;
28+
tail = 0;
2629
}
2730

2831
CSipHasher& CSipHasher::Write(uint64_t data)
2932
{
3033
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
3134

32-
assert(count % 8 == 0);
35+
assert((count & 0x07) == 0);
3336

3437
v3 ^= data;
3538
SIPROUND;
@@ -45,30 +48,57 @@ CSipHasher& CSipHasher::Write(uint64_t data)
4548
return *this;
4649
}
4750

51+
52+
/// Load a uint64_t from 0 to 7 bytes.
53+
inline uint64_t ReadU64ByLenLE(const unsigned char* data, size_t len)
54+
{
55+
assert(len < 8);
56+
uint64_t out = 0;
57+
for (size_t i = 0; i < len; ++i) {
58+
out |= (uint64_t)data[i] << (i * 8);
59+
}
60+
return out;
61+
}
62+
4863
CSipHasher& CSipHasher::Write(const unsigned char* data, size_t size)
4964
{
5065
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
51-
uint64_t t = tmp;
52-
uint8_t c = count;
53-
54-
while (size--) {
55-
t |= ((uint64_t)(*(data++))) << (8 * (c % 8));
56-
c++;
57-
if ((c & 7) == 0) {
58-
v3 ^= t;
66+
auto ntail = count & 0x07;
67+
count += size;
68+
69+
size_t needed = 0;
70+
71+
if (ntail != 0) {
72+
needed = 8 - ntail;
73+
tail |= ReadU64ByLenLE(data, std::min(size, needed)) << 8 * ntail;
74+
if (size < needed) {
75+
return *this;
76+
} else {
77+
v3 ^= tail;
5978
SIPROUND;
6079
SIPROUND;
61-
v0 ^= t;
62-
t = 0;
80+
v0 ^= tail;
6381
}
6482
}
6583

84+
size_t len = size - needed;
85+
auto left = len & 0x07;
86+
87+
auto i = needed;
88+
while (i < len - left) {
89+
uint64_t mi = ReadLE64(data + i);
90+
v3 ^= mi;
91+
SIPROUND;
92+
SIPROUND;
93+
v0 ^= mi;
94+
i += 8;
95+
}
96+
6697
v[0] = v0;
6798
v[1] = v1;
6899
v[2] = v2;
69100
v[3] = v3;
70-
count = c;
71-
tmp = t;
101+
tail = ReadU64ByLenLE(data + i, left);
72102

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

80-
uint64_t t = tmp | (((uint64_t)count) << 56);
110+
111+
uint64_t t = tail | (((uint64_t)count) << 56);
81112

82113
v3 ^= t;
83114
SIPROUND;
84115
SIPROUND;
85116
v0 ^= t;
117+
86118
v2 ^= 0xFF;
87119
SIPROUND;
88120
SIPROUND;

src/crypto/siphash.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ class CSipHasher
1414
{
1515
private:
1616
uint64_t v[4];
17-
uint64_t tmp;
18-
uint8_t count; // Only the low 8 bits of the input size matter.
17+
uint64_t tail; // bytes that weren't processed yet.
18+
uint8_t count; // total amount of bytes inputted.
1919

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

0 commit comments

Comments
 (0)