libclod
C library for interacting with NBTs, region files, LOD data and other things.
Loading...
Searching...
No Matches
siphash.c
1#include <clod/hash.h>
2#include <stddef.h>
3#include <stdint.h>
4#include <string.h>
5
6/*
7 * I thank those who have researched and developed SipHash,
8 * and the original designers Jean-Philippe Aumasson and Daniel J. Bernstein.
9 * https://www.aumasson.jp/siphash/siphash.pdf
10 *
11 * This implementation is my own and is designed to support streaming.
12 * Surprisingly, this streaming variant outperforms the SIMD-optimised SipHash 2-4 implementation found in SMHasher3.
13 */
14
15#define data_size(state) ((state)._size >> 3)
16#define remaining(state) ((state)._size & 0b00000111)
17#define set_data_size(state, size) ((state)._size = (uint8_t)(((state)._size & 0b00000111) | ((uint8_t)(size) << 3)))
18#define set_remaining(state, size) ((state)._size = (uint8_t)(((state)._size & 0b11111000) | ((uint8_t)(size) & 0b00000111)))
19
20static void sip_round(clod_sip64_state *state) {
21 state->_v0 += state->_v1;
22 state->_v1 = state->_v1 << 13 | state->_v1 >> 51;
23 state->_v1 ^= state->_v0;
24 state->_v0 = state->_v0 << 32 | state->_v0 >> 32;
25 state->_v2 += state->_v3;
26 state->_v3 = state->_v3 << 16 | state->_v3 >> 48;
27 state->_v3 ^= state->_v2;
28 state->_v0 += state->_v3;
29 state->_v3 = state->_v3 << 21 | state->_v3 >> 43;
30 state->_v3 ^= state->_v0;
31 state->_v2 += state->_v1;
32 state->_v1 = state->_v1 << 17 | state->_v1 >> 47;
33 state->_v1 ^= state->_v2;
34 state->_v2 = state->_v2 << 32 | state->_v2 >> 32;
35}
36static uint64_t read_uint64(const uint8_t *restrict bytes, const size_t data_size) {
37 uint64_t r = 0;
38 switch (data_size) {
39 default: r |= (uint64_t)bytes[7] << 7 * 8; __attribute__((fallthrough));
40 case 7: r |= (uint64_t)bytes[6] << 6 * 8; __attribute__((fallthrough));
41 case 6: r |= (uint64_t)bytes[5] << 5 * 8; __attribute__((fallthrough));
42 case 5: r |= (uint64_t)bytes[4] << 4 * 8; __attribute__((fallthrough));
43 case 4: r |= (uint64_t)bytes[3] << 3 * 8; __attribute__((fallthrough));
44 case 3: r |= (uint64_t)bytes[2] << 2 * 8; __attribute__((fallthrough));
45 case 2: r |= (uint64_t)bytes[1] << 1 * 8; __attribute__((fallthrough));
46 case 1: r |= (uint64_t)bytes[0] << 0 * 8; __attribute__((fallthrough));
47 case 0: return r;
48 }
49}
50clod_sip64_state clod_sip64_add(clod_sip64_state state, const void *restrict data, const size_t size) {
51 const uint8_t *restrict bytes = data;
52 if (size == 0) return state;
53 set_data_size(state, data_size(state) + size);
54
55 if (remaining(state) + size < 8) {
56 memcpy(state._buf + remaining(state), bytes, size);
57 set_remaining(state, remaining(state) + size);
58 return state;
59 }
60
61 uint64_t d, off = 0;
62 if (remaining(state) > 0) {
63 d = read_uint64(state._buf, remaining(state));
64 d |= read_uint64(bytes, 8 - remaining(state)) << remaining(state) * 8;
65 off = 8 - remaining(state);
66 set_remaining(state, 0);
67 } else {
68 d = read_uint64(bytes, 8);
69 off = 8;
70 }
71
72 state._v3 ^= d;
73 sip_round(&state);
74 sip_round(&state);
75 state._v0 ^= d;
76
77 while (off + 8 <= size) {
78 d = read_uint64(bytes + off, 8);
79 off += 8;
80
81 state._v3 ^= d;
82 sip_round(&state);
83 sip_round(&state);
84 state._v0 ^= d;
85 }
86
87 if (off < size) {
88 memcpy(state._buf, bytes + off, size - off);
89 set_remaining(state, size - off);
90 }
91
92 return state;
93}
95 uint64_t d = read_uint64(state._buf, remaining(state));
96 d |= (uint64_t)(data_size(state)) << 56;
97 state._v3 ^= d;
98 sip_round(&state);
99 sip_round(&state);
100 state._v0 ^= d;
101 state._v2 ^= 0xee;
102 sip_round(&state);
103 sip_round(&state);
104 sip_round(&state);
105 sip_round(&state);
106 return state._v0 ^ state._v1 ^ state._v2 ^ state._v3;
107}
uint64_t clod_sip64_finalise(clod_sip64_state state)
Definition siphash.c:94
clod_sip64_state clod_sip64_add(clod_sip64_state state, const void *data, size_t size)
Sized string helpers.