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