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