blob: 700f5f4f4953ff5520b39ad4022bafe7bc529251 [file] [log] [blame]
/**
Algorithm Info:
https://131002.net/siphash/
Based off of implementation:
https://github.com/floodyberry/siphash
*/
#include "tscore/HashSip.h"
#include <cstring>
using namespace std;
#define SIP_BLOCK_SIZE 8
#define ROTL64(a, b) (((a) << (b)) | ((a) >> (64 - b)))
#define U8TO64_LE(p) *(const uint64_t *)(p)
#define SIPCOMPRESS(x0, x1, x2, x3) \
x0 += x1; \
x2 += x3; \
x1 = ROTL64(x1, 13); \
x3 = ROTL64(x3, 16); \
x1 ^= x0; \
x3 ^= x2; \
x0 = ROTL64(x0, 32); \
x2 += x1; \
x0 += x3; \
x1 = ROTL64(x1, 17); \
x3 = ROTL64(x3, 21); \
x1 ^= x2; \
x3 ^= x0; \
x2 = ROTL64(x2, 32);
ATSHash64Sip24::ATSHash64Sip24()
{
this->clear();
}
ATSHash64Sip24::ATSHash64Sip24(const unsigned char key[16]) : k0(U8TO64_LE(key)), k1(U8TO64_LE(key + sizeof(k0)))
{
this->clear();
}
ATSHash64Sip24::ATSHash64Sip24(uint64_t key0, uint64_t key1) : k0(key0), k1(key1)
{
this->clear();
}
void
ATSHash64Sip24::update(const void *data, size_t len)
{
size_t i, blocks;
unsigned char *m;
uint64_t mi;
uint8_t block_off = 0;
if (!finalized) {
m = (unsigned char *)data;
total_len += len;
if (len + block_buffer_len < SIP_BLOCK_SIZE) {
memcpy(block_buffer + block_buffer_len, m, len);
block_buffer_len += len;
} else {
if (block_buffer_len > 0) {
block_off = SIP_BLOCK_SIZE - block_buffer_len;
memcpy(block_buffer + block_buffer_len, m, block_off);
mi = U8TO64_LE(block_buffer);
v3 ^= mi;
SIPCOMPRESS(v0, v1, v2, v3);
SIPCOMPRESS(v0, v1, v2, v3);
v0 ^= mi;
}
for (i = block_off, blocks = ((len - block_off) & ~(SIP_BLOCK_SIZE - 1)); i < blocks; i += SIP_BLOCK_SIZE) {
mi = U8TO64_LE(m + i);
v3 ^= mi;
SIPCOMPRESS(v0, v1, v2, v3);
SIPCOMPRESS(v0, v1, v2, v3);
v0 ^= mi;
}
block_buffer_len = (len - block_off) & (SIP_BLOCK_SIZE - 1);
memcpy(block_buffer, m + block_off + blocks, block_buffer_len);
}
}
}
void
ATSHash64Sip24::final()
{
uint64_t last7;
int i;
if (!finalized) {
last7 = static_cast<uint64_t>(total_len & 0xff) << 56;
for (i = block_buffer_len - 1; i >= 0; i--) {
last7 |= static_cast<uint64_t>(block_buffer[i]) << (i * 8);
}
v3 ^= last7;
SIPCOMPRESS(v0, v1, v2, v3);
SIPCOMPRESS(v0, v1, v2, v3);
v0 ^= last7;
v2 ^= 0xff;
SIPCOMPRESS(v0, v1, v2, v3);
SIPCOMPRESS(v0, v1, v2, v3);
SIPCOMPRESS(v0, v1, v2, v3);
SIPCOMPRESS(v0, v1, v2, v3);
hfinal = v0 ^ v1 ^ v2 ^ v3;
finalized = true;
}
}
uint64_t
ATSHash64Sip24::get() const
{
if (finalized) {
return hfinal;
} else {
return 0;
}
}
void
ATSHash64Sip24::clear()
{
v0 = k0 ^ 0x736f6d6570736575ull;
v1 = k1 ^ 0x646f72616e646f6dull;
v2 = k0 ^ 0x6c7967656e657261ull;
v3 = k1 ^ 0x7465646279746573ull;
finalized = false;
total_len = 0;
block_buffer_len = 0;
}