xref: /trafficserver/src/tscore/HashSip.cc (revision 4cfd5a73)
1 /**
2 
3 Algorithm Info:
4 https://131002.net/siphash/
5 
6 Based off of implementation:
7 https://github.com/floodyberry/siphash
8 
9  */
10 
11 #include "tscore/HashSip.h"
12 #include <cstring>
13 
14 using namespace std;
15 
16 #define SIP_BLOCK_SIZE 8
17 
18 #define ROTL64(a, b) (((a) << (b)) | ((a) >> (64 - b)))
19 
20 #define U8TO64_LE(p) *(const uint64_t *)(p)
21 
22 #define SIPCOMPRESS(x0, x1, x2, x3) \
23   x0 += x1;                         \
24   x2 += x3;                         \
25   x1 = ROTL64(x1, 13);              \
26   x3 = ROTL64(x3, 16);              \
27   x1 ^= x0;                         \
28   x3 ^= x2;                         \
29   x0 = ROTL64(x0, 32);              \
30   x2 += x1;                         \
31   x0 += x3;                         \
32   x1 = ROTL64(x1, 17);              \
33   x3 = ROTL64(x3, 21);              \
34   x1 ^= x2;                         \
35   x3 ^= x0;                         \
36   x2 = ROTL64(x2, 32);
37 
ATSHash64Sip24()38 ATSHash64Sip24::ATSHash64Sip24()
39 {
40   this->clear();
41 }
42 
ATSHash64Sip24(const unsigned char key[16])43 ATSHash64Sip24::ATSHash64Sip24(const unsigned char key[16]) : k0(U8TO64_LE(key)), k1(U8TO64_LE(key + sizeof(k0)))
44 {
45   this->clear();
46 }
47 
ATSHash64Sip24(uint64_t key0,uint64_t key1)48 ATSHash64Sip24::ATSHash64Sip24(uint64_t key0, uint64_t key1) : k0(key0), k1(key1)
49 {
50   this->clear();
51 }
52 
53 void
update(const void * data,size_t len)54 ATSHash64Sip24::update(const void *data, size_t len)
55 {
56   size_t i, blocks;
57   unsigned char *m;
58   uint64_t mi;
59   uint8_t block_off = 0;
60 
61   if (!finalized) {
62     m = (unsigned char *)data;
63     total_len += len;
64 
65     if (len + block_buffer_len < SIP_BLOCK_SIZE) {
66       memcpy(block_buffer + block_buffer_len, m, len);
67       block_buffer_len += len;
68     } else {
69       if (block_buffer_len > 0) {
70         block_off = SIP_BLOCK_SIZE - block_buffer_len;
71         memcpy(block_buffer + block_buffer_len, m, block_off);
72 
73         mi = U8TO64_LE(block_buffer);
74         v3 ^= mi;
75         SIPCOMPRESS(v0, v1, v2, v3);
76         SIPCOMPRESS(v0, v1, v2, v3);
77         v0 ^= mi;
78       }
79 
80       for (i = block_off, blocks = ((len - block_off) & ~(SIP_BLOCK_SIZE - 1)); i < blocks; i += SIP_BLOCK_SIZE) {
81         mi = U8TO64_LE(m + i);
82         v3 ^= mi;
83         SIPCOMPRESS(v0, v1, v2, v3);
84         SIPCOMPRESS(v0, v1, v2, v3);
85         v0 ^= mi;
86       }
87 
88       block_buffer_len = (len - block_off) & (SIP_BLOCK_SIZE - 1);
89       memcpy(block_buffer, m + block_off + blocks, block_buffer_len);
90     }
91   }
92 }
93 
94 void
final()95 ATSHash64Sip24::final()
96 {
97   uint64_t last7;
98   int i;
99 
100   if (!finalized) {
101     last7 = static_cast<uint64_t>(total_len & 0xff) << 56;
102 
103     for (i = block_buffer_len - 1; i >= 0; i--) {
104       last7 |= static_cast<uint64_t>(block_buffer[i]) << (i * 8);
105     }
106 
107     v3 ^= last7;
108     SIPCOMPRESS(v0, v1, v2, v3);
109     SIPCOMPRESS(v0, v1, v2, v3);
110     v0 ^= last7;
111     v2 ^= 0xff;
112     SIPCOMPRESS(v0, v1, v2, v3);
113     SIPCOMPRESS(v0, v1, v2, v3);
114     SIPCOMPRESS(v0, v1, v2, v3);
115     SIPCOMPRESS(v0, v1, v2, v3);
116     hfinal    = v0 ^ v1 ^ v2 ^ v3;
117     finalized = true;
118   }
119 }
120 
121 uint64_t
get() const122 ATSHash64Sip24::get() const
123 {
124   if (finalized) {
125     return hfinal;
126   } else {
127     return 0;
128   }
129 }
130 
131 void
clear()132 ATSHash64Sip24::clear()
133 {
134   v0               = k0 ^ 0x736f6d6570736575ull;
135   v1               = k1 ^ 0x646f72616e646f6dull;
136   v2               = k0 ^ 0x6c7967656e657261ull;
137   v3               = k1 ^ 0x7465646279746573ull;
138   finalized        = false;
139   total_len        = 0;
140   block_buffer_len = 0;
141 }
142