xref: /netbsd-src/external/bsd/nsd/dist/siphash.c (revision ee75899804fc815b722d4dff05164c608f88c7d5)
1*ee758998Schristos /*
2*ee758998Schristos    SipHash reference C implementation
3*ee758998Schristos 
4*ee758998Schristos    Copyright (c) 2012-2016 Jean-Philippe Aumasson
5*ee758998Schristos    <jeanphilippe.aumasson@gmail.com>
6*ee758998Schristos    Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
7*ee758998Schristos 
8*ee758998Schristos    To the extent possible under law, the author(s) have dedicated all copyright
9*ee758998Schristos    and related and neighboring rights to this software to the public domain
10*ee758998Schristos    worldwide. This software is distributed without any warranty.
11*ee758998Schristos 
12*ee758998Schristos    You should have received a copy of the CC0 Public Domain Dedication along
13*ee758998Schristos    with
14*ee758998Schristos    this software. If not, see
15*ee758998Schristos    <http://creativecommons.org/publicdomain/zero/1.0/>.
16*ee758998Schristos  */
17*ee758998Schristos #include <assert.h>
18*ee758998Schristos #include <stdint.h>
19*ee758998Schristos #include <stdio.h>
20*ee758998Schristos #include <string.h>
21*ee758998Schristos 
22*ee758998Schristos /* default: SipHash-2-4 */
23*ee758998Schristos #define cROUNDS 2
24*ee758998Schristos #define dROUNDS 4
25*ee758998Schristos 
26*ee758998Schristos #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
27*ee758998Schristos 
28*ee758998Schristos #define U32TO8_LE(p, v)                                                        \
29*ee758998Schristos     (p)[0] = (uint8_t)((v));                                                   \
30*ee758998Schristos     (p)[1] = (uint8_t)((v) >> 8);                                              \
31*ee758998Schristos     (p)[2] = (uint8_t)((v) >> 16);                                             \
32*ee758998Schristos     (p)[3] = (uint8_t)((v) >> 24);
33*ee758998Schristos 
34*ee758998Schristos #define U64TO8_LE(p, v)                                                        \
35*ee758998Schristos     U32TO8_LE((p), (uint32_t)((v)));                                           \
36*ee758998Schristos     U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
37*ee758998Schristos 
38*ee758998Schristos #define U8TO64_LE(p)                                                           \
39*ee758998Schristos     (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) |                        \
40*ee758998Schristos      ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) |                 \
41*ee758998Schristos      ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) |                 \
42*ee758998Schristos      ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
43*ee758998Schristos 
44*ee758998Schristos #define SIPROUND                                                               \
45*ee758998Schristos     do {                                                                       \
46*ee758998Schristos         v0 += v1;                                                              \
47*ee758998Schristos         v1 = ROTL(v1, 13);                                                     \
48*ee758998Schristos         v1 ^= v0;                                                              \
49*ee758998Schristos         v0 = ROTL(v0, 32);                                                     \
50*ee758998Schristos         v2 += v3;                                                              \
51*ee758998Schristos         v3 = ROTL(v3, 16);                                                     \
52*ee758998Schristos         v3 ^= v2;                                                              \
53*ee758998Schristos         v0 += v3;                                                              \
54*ee758998Schristos         v3 = ROTL(v3, 21);                                                     \
55*ee758998Schristos         v3 ^= v0;                                                              \
56*ee758998Schristos         v2 += v1;                                                              \
57*ee758998Schristos         v1 = ROTL(v1, 17);                                                     \
58*ee758998Schristos         v1 ^= v2;                                                              \
59*ee758998Schristos         v2 = ROTL(v2, 32);                                                     \
60*ee758998Schristos     } while (0)
61*ee758998Schristos 
62*ee758998Schristos #ifdef DEBUG
63*ee758998Schristos #define TRACE                                                                  \
64*ee758998Schristos     do {                                                                       \
65*ee758998Schristos         printf("(%3d) v0 %08x %08x\n", (int)inlen, (uint32_t)(v0 >> 32),       \
66*ee758998Schristos                (uint32_t)v0);                                                  \
67*ee758998Schristos         printf("(%3d) v1 %08x %08x\n", (int)inlen, (uint32_t)(v1 >> 32),       \
68*ee758998Schristos                (uint32_t)v1);                                                  \
69*ee758998Schristos         printf("(%3d) v2 %08x %08x\n", (int)inlen, (uint32_t)(v2 >> 32),       \
70*ee758998Schristos                (uint32_t)v2);                                                  \
71*ee758998Schristos         printf("(%3d) v3 %08x %08x\n", (int)inlen, (uint32_t)(v3 >> 32),       \
72*ee758998Schristos                (uint32_t)v3);                                                  \
73*ee758998Schristos     } while (0)
74*ee758998Schristos #else
75*ee758998Schristos #define TRACE
76*ee758998Schristos #endif
77*ee758998Schristos 
siphash(const uint8_t * in,const size_t inlen,const uint8_t * k,uint8_t * out,const size_t outlen)78*ee758998Schristos int siphash(const uint8_t *in, const size_t inlen, const uint8_t *k,
79*ee758998Schristos             uint8_t *out, const size_t outlen) {
80*ee758998Schristos     uint64_t v0 = 0x736f6d6570736575ULL;
81*ee758998Schristos     uint64_t v1 = 0x646f72616e646f6dULL;
82*ee758998Schristos     uint64_t v2 = 0x6c7967656e657261ULL;
83*ee758998Schristos     uint64_t v3 = 0x7465646279746573ULL;
84*ee758998Schristos     uint64_t k0 = U8TO64_LE(k);
85*ee758998Schristos     uint64_t k1 = U8TO64_LE(k + 8);
86*ee758998Schristos     uint64_t m;
87*ee758998Schristos     int i;
88*ee758998Schristos     const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t));
89*ee758998Schristos     const int left = inlen & 7;
90*ee758998Schristos     uint64_t b = ((uint64_t)inlen) << 56;
91*ee758998Schristos     v3 ^= k1;
92*ee758998Schristos     v2 ^= k0;
93*ee758998Schristos     v1 ^= k1;
94*ee758998Schristos     v0 ^= k0;
95*ee758998Schristos 
96*ee758998Schristos     assert((outlen == 8) || (outlen == 16));
97*ee758998Schristos     if (outlen == 16)
98*ee758998Schristos         v1 ^= 0xee;
99*ee758998Schristos 
100*ee758998Schristos     for (; in != end; in += 8) {
101*ee758998Schristos         m = U8TO64_LE(in);
102*ee758998Schristos         v3 ^= m;
103*ee758998Schristos 
104*ee758998Schristos         TRACE;
105*ee758998Schristos         for (i = 0; i < cROUNDS; ++i)
106*ee758998Schristos             SIPROUND;
107*ee758998Schristos 
108*ee758998Schristos         v0 ^= m;
109*ee758998Schristos     }
110*ee758998Schristos 
111*ee758998Schristos     switch (left) {
112*ee758998Schristos     case 7:
113*ee758998Schristos         b |= ((uint64_t)in[6]) << 48;
114*ee758998Schristos 	/* fallthrough */
115*ee758998Schristos     case 6:
116*ee758998Schristos         b |= ((uint64_t)in[5]) << 40;
117*ee758998Schristos 	/* fallthrough */
118*ee758998Schristos     case 5:
119*ee758998Schristos         b |= ((uint64_t)in[4]) << 32;
120*ee758998Schristos 	/* fallthrough */
121*ee758998Schristos     case 4:
122*ee758998Schristos         b |= ((uint64_t)in[3]) << 24;
123*ee758998Schristos 	/* fallthrough */
124*ee758998Schristos     case 3:
125*ee758998Schristos         b |= ((uint64_t)in[2]) << 16;
126*ee758998Schristos 	/* fallthrough */
127*ee758998Schristos     case 2:
128*ee758998Schristos         b |= ((uint64_t)in[1]) << 8;
129*ee758998Schristos 	/* fallthrough */
130*ee758998Schristos     case 1:
131*ee758998Schristos         b |= ((uint64_t)in[0]);
132*ee758998Schristos         break;
133*ee758998Schristos     case 0:
134*ee758998Schristos         break;
135*ee758998Schristos     }
136*ee758998Schristos 
137*ee758998Schristos     v3 ^= b;
138*ee758998Schristos 
139*ee758998Schristos     TRACE;
140*ee758998Schristos     for (i = 0; i < cROUNDS; ++i)
141*ee758998Schristos         SIPROUND;
142*ee758998Schristos 
143*ee758998Schristos     v0 ^= b;
144*ee758998Schristos 
145*ee758998Schristos     if (outlen == 16)
146*ee758998Schristos         v2 ^= 0xee;
147*ee758998Schristos     else
148*ee758998Schristos         v2 ^= 0xff;
149*ee758998Schristos 
150*ee758998Schristos     TRACE;
151*ee758998Schristos     for (i = 0; i < dROUNDS; ++i)
152*ee758998Schristos         SIPROUND;
153*ee758998Schristos 
154*ee758998Schristos     b = v0 ^ v1 ^ v2 ^ v3;
155*ee758998Schristos     U64TO8_LE(out, b);
156*ee758998Schristos 
157*ee758998Schristos     if (outlen == 8)
158*ee758998Schristos         return 0;
159*ee758998Schristos 
160*ee758998Schristos     v1 ^= 0xdd;
161*ee758998Schristos 
162*ee758998Schristos     TRACE;
163*ee758998Schristos     for (i = 0; i < dROUNDS; ++i)
164*ee758998Schristos         SIPROUND;
165*ee758998Schristos 
166*ee758998Schristos     b = v0 ^ v1 ^ v2 ^ v3;
167*ee758998Schristos     U64TO8_LE(out + 8, b);
168*ee758998Schristos 
169*ee758998Schristos     return 0;
170*ee758998Schristos }
171