2323
2424#include " tscore/Hash.h"
2525#include < cstdint>
26+ #include < cstring>
2627
2728/*
28- Siphash is a Hash Message Authentication Code and can take a key.
29+ SipHash is a Hash Message Authentication Code and can take a key.
2930
3031 If you don't care about MAC use the void constructor and it will use
3132 a zero key for you.
32- */
3333
34- struct ATSHash64Sip24 : ATSHash64 {
35- ATSHash64Sip24 ();
36- ATSHash64Sip24 (const unsigned char key[16 ]);
37- ATSHash64Sip24 (std::uint64_t key0, std::uint64_t key1);
38- void update (const void *data, std::size_t len) override ;
39- void final () override ;
40- std::uint64_t get () const override ;
41- void clear () override ;
34+ Template parameters:
35+ - c_rounds: number of compression rounds per message block
36+ - d_rounds: number of finalization rounds
37+ */
38+
39+ #define SIP_BLOCK_SIZE 8
40+
41+ #define ROTL64 (a, b ) (((a) << (b)) | ((a) >> (64 - b)))
42+
43+ static inline std::uint64_t
44+ U8TO64_LE (const std::uint8_t *p)
45+ {
46+ std::uint64_t result;
47+ std::memcpy (&result, p, sizeof (result));
48+ return result;
49+ }
50+
51+ #define SIPCOMPRESS (x0, x1, x2, x3 ) \
52+ x0 += x1; \
53+ x2 += x3; \
54+ x1 = ROTL64(x1, 13 ); \
55+ x3 = ROTL64(x3, 16 ); \
56+ x1 ^= x0; \
57+ x3 ^= x2; \
58+ x0 = ROTL64(x0, 32 ); \
59+ x2 += x1; \
60+ x0 += x3; \
61+ x1 = ROTL64(x1, 17 ); \
62+ x3 = ROTL64(x3, 21 ); \
63+ x1 ^= x2; \
64+ x3 ^= x0; \
65+ x2 = ROTL64(x2, 32 );
66+
67+ template <int c_rounds, int d_rounds> struct ATSHashSip : ATSHash64 {
68+ ATSHashSip () { this ->clear (); }
69+
70+ ATSHashSip (const unsigned char key[16 ]) : k0(U8TO64_LE(key)), k1(U8TO64_LE(key + sizeof (k0))) { this ->clear (); }
71+
72+ ATSHashSip (std::uint64_t key0, std::uint64_t key1) : k0(key0), k1(key1) { this ->clear (); }
73+
74+ void
75+ update (const void *data, std::size_t len) override
76+ {
77+ std::size_t i, blocks;
78+ unsigned char *m;
79+ std::uint64_t mi;
80+ std::uint8_t block_off = 0 ;
81+
82+ if (!finalized) {
83+ m = (unsigned char *)data;
84+ total_len += len;
85+
86+ if (len + block_buffer_len < SIP_BLOCK_SIZE) {
87+ std::memcpy (block_buffer + block_buffer_len, m, len);
88+ block_buffer_len += len;
89+ } else {
90+ if (block_buffer_len > 0 ) {
91+ block_off = SIP_BLOCK_SIZE - block_buffer_len;
92+ std::memcpy (block_buffer + block_buffer_len, m, block_off);
93+
94+ mi = U8TO64_LE (block_buffer);
95+ v3 ^= mi;
96+ for (int r = 0 ; r < c_rounds; r++) {
97+ SIPCOMPRESS (v0, v1, v2, v3);
98+ }
99+ v0 ^= mi;
100+ }
101+
102+ for (i = block_off, blocks = ((len - block_off) & ~(SIP_BLOCK_SIZE - 1 )); i < blocks; i += SIP_BLOCK_SIZE) {
103+ mi = U8TO64_LE (m + i);
104+ v3 ^= mi;
105+ for (int r = 0 ; r < c_rounds; r++) {
106+ SIPCOMPRESS (v0, v1, v2, v3);
107+ }
108+ v0 ^= mi;
109+ }
110+
111+ block_buffer_len = (len - block_off) & (SIP_BLOCK_SIZE - 1 );
112+ std::memcpy (block_buffer, m + block_off + blocks, block_buffer_len);
113+ }
114+ }
115+ }
116+
117+ void
118+ final () override
119+ {
120+ std::uint64_t last7;
121+ int i;
122+
123+ if (!finalized) {
124+ last7 = static_cast <std::uint64_t >(total_len & 0xff ) << 56 ;
125+
126+ for (i = block_buffer_len - 1 ; i >= 0 ; i--) {
127+ last7 |= static_cast <std::uint64_t >(block_buffer[i]) << (i * 8 );
128+ }
129+
130+ v3 ^= last7;
131+ for (int r = 0 ; r < c_rounds; r++) {
132+ SIPCOMPRESS (v0, v1, v2, v3);
133+ }
134+ v0 ^= last7;
135+ v2 ^= 0xff ;
136+ for (int r = 0 ; r < d_rounds; r++) {
137+ SIPCOMPRESS (v0, v1, v2, v3);
138+ }
139+ hfinal = v0 ^ v1 ^ v2 ^ v3;
140+ finalized = true ;
141+ }
142+ }
143+
144+ std::uint64_t
145+ get () const override
146+ {
147+ if (finalized) {
148+ return hfinal;
149+ } else {
150+ return 0 ;
151+ }
152+ }
153+
154+ void
155+ clear () override
156+ {
157+ v0 = k0 ^ 0x736f6d6570736575ull ;
158+ v1 = k1 ^ 0x646f72616e646f6dull ;
159+ v2 = k0 ^ 0x6c7967656e657261ull ;
160+ v3 = k1 ^ 0x7465646279746573ull ;
161+ finalized = false ;
162+ total_len = 0 ;
163+ block_buffer_len = 0 ;
164+ }
42165
43166private:
44167 unsigned char block_buffer[8 ] = {0 };
@@ -53,3 +176,7 @@ struct ATSHash64Sip24 : ATSHash64 {
53176 std::size_t total_len = 0 ;
54177 bool finalized = false ;
55178};
179+
180+ // Standard SipHash variants
181+ using ATSHash64Sip24 = ATSHashSip<2 , 4 >;
182+ using ATSHash64Sip13 = ATSHashSip<1 , 3 >;
0 commit comments