Line data Source code
1 : /*
2 : SipHash reference C implementation
3 :
4 : Written in 2012 by
5 : Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
6 : 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 with
13 : this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
14 :
15 : (Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd)
16 : (Refactored by Tom Gundersen to split up in several functions and follow systemd
17 : coding style)
18 : */
19 :
20 : #include <stdio.h>
21 :
22 : #include "macro.h"
23 : #include "siphash24.h"
24 : #include "unaligned.h"
25 :
26 34282572 : static uint64_t rotate_left(uint64_t x, uint8_t b) {
27 34282572 : assert(b < 64);
28 :
29 34282572 : return (x << b) | (x >> (64 - b));
30 : }
31 :
32 5713762 : static void sipround(struct siphash *state) {
33 5713762 : assert(state);
34 :
35 5713762 : state->v0 += state->v1;
36 5713762 : state->v1 = rotate_left(state->v1, 13);
37 5713762 : state->v1 ^= state->v0;
38 5713762 : state->v0 = rotate_left(state->v0, 32);
39 5713762 : state->v2 += state->v3;
40 5713762 : state->v3 = rotate_left(state->v3, 16);
41 5713762 : state->v3 ^= state->v2;
42 5713762 : state->v0 += state->v3;
43 5713762 : state->v3 = rotate_left(state->v3, 21);
44 5713762 : state->v3 ^= state->v0;
45 5713762 : state->v2 += state->v1;
46 5713762 : state->v1 = rotate_left(state->v1, 17);
47 5713762 : state->v1 ^= state->v2;
48 5713762 : state->v2 = rotate_left(state->v2, 32);
49 5713762 : }
50 :
51 490111 : void siphash24_init(struct siphash *state, const uint8_t k[static 16]) {
52 : uint64_t k0, k1;
53 :
54 490111 : assert(state);
55 490111 : assert(k);
56 :
57 490111 : k0 = unaligned_read_le64(k);
58 490111 : k1 = unaligned_read_le64(k + 8);
59 :
60 490111 : *state = (struct siphash) {
61 : /* "somepseudorandomlygeneratedbytes" */
62 490111 : .v0 = 0x736f6d6570736575ULL ^ k0,
63 490111 : .v1 = 0x646f72616e646f6dULL ^ k1,
64 490111 : .v2 = 0x6c7967656e657261ULL ^ k0,
65 490111 : .v3 = 0x7465646279746573ULL ^ k1,
66 : .padding = 0,
67 : .inlen = 0,
68 : };
69 490111 : }
70 :
71 1230467 : void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
72 :
73 1230467 : const uint8_t *in = _in;
74 1230467 : const uint8_t *end = in + inlen;
75 1230467 : size_t left = state->inlen & 7;
76 : uint64_t m;
77 :
78 1230467 : assert(in);
79 1230467 : assert(state);
80 :
81 : /* Update total length */
82 1230467 : state->inlen += inlen;
83 :
84 : /* If padding exists, fill it out */
85 1230467 : if (left > 0) {
86 2613545 : for ( ; in < end && left < 8; in ++, left ++)
87 1977519 : state->padding |= ((uint64_t) *in) << (left * 8);
88 :
89 636026 : if (in == end && left < 8)
90 : /* We did not have enough input to fill out the padding completely */
91 312627 : return;
92 :
93 : #if ENABLE_DEBUG_SIPHASH
94 : printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
95 : printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
96 : printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
97 : printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
98 : printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding);
99 : #endif
100 :
101 323399 : state->v3 ^= state->padding;
102 323399 : sipround(state);
103 323399 : sipround(state);
104 323399 : state->v0 ^= state->padding;
105 :
106 323399 : state->padding = 0;
107 : }
108 :
109 917840 : end -= (state->inlen % sizeof(uint64_t));
110 :
111 1980995 : for ( ; in < end; in += 8) {
112 1063155 : m = unaligned_read_le64(in);
113 : #if ENABLE_DEBUG_SIPHASH
114 : printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
115 : printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
116 : printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
117 : printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
118 : printf("(%3zu) compress %08x %08x\n", state->inlen, (uint32_t) (m >> 32), (uint32_t) m);
119 : #endif
120 1063155 : state->v3 ^= m;
121 1063155 : sipround(state);
122 1063155 : sipround(state);
123 1063155 : state->v0 ^= m;
124 : }
125 :
126 917840 : left = state->inlen & 7;
127 917840 : switch (left) {
128 26595 : case 7:
129 26595 : state->padding |= ((uint64_t) in[6]) << 48;
130 : _fallthrough_;
131 80022 : case 6:
132 80022 : state->padding |= ((uint64_t) in[5]) << 40;
133 : _fallthrough_;
134 132330 : case 5:
135 132330 : state->padding |= ((uint64_t) in[4]) << 32;
136 : _fallthrough_;
137 173049 : case 4:
138 173049 : state->padding |= ((uint64_t) in[3]) << 24;
139 : _fallthrough_;
140 268702 : case 3:
141 268702 : state->padding |= ((uint64_t) in[2]) << 16;
142 : _fallthrough_;
143 338521 : case 2:
144 338521 : state->padding |= ((uint64_t) in[1]) << 8;
145 : _fallthrough_;
146 579191 : case 1:
147 579191 : state->padding |= ((uint64_t) in[0]);
148 : _fallthrough_;
149 917840 : case 0:
150 917840 : break;
151 : }
152 : }
153 :
154 7 : void siphash24_compress_boolean(bool in, struct siphash *state) {
155 7 : int i = in;
156 :
157 7 : siphash24_compress(&i, sizeof i, state);
158 7 : }
159 :
160 490109 : uint64_t siphash24_finalize(struct siphash *state) {
161 : uint64_t b;
162 :
163 490109 : assert(state);
164 :
165 490109 : b = state->padding | (((uint64_t) state->inlen) << 56);
166 :
167 : #if ENABLE_DEBUG_SIPHASH
168 : printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
169 : printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
170 : printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
171 : printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
172 : printf("(%3zu) padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding);
173 : #endif
174 :
175 490109 : state->v3 ^= b;
176 490109 : sipround(state);
177 490109 : sipround(state);
178 490109 : state->v0 ^= b;
179 :
180 : #if ENABLE_DEBUG_SIPHASH
181 : printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
182 : printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
183 : printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
184 : printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
185 : #endif
186 490109 : state->v2 ^= 0xff;
187 :
188 490109 : sipround(state);
189 490109 : sipround(state);
190 490109 : sipround(state);
191 490109 : sipround(state);
192 :
193 490109 : return state->v0 ^ state->v1 ^ state->v2 ^ state->v3;
194 : }
195 :
196 24 : uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[static 16]) {
197 : struct siphash state;
198 :
199 24 : assert(in);
200 24 : assert(k);
201 :
202 24 : siphash24_init(&state, k);
203 24 : siphash24_compress(in, inlen, &state);
204 :
205 24 : return siphash24_finalize(&state);
206 : }
|