Branch data 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 : 4255244748 : static uint64_t rotate_left(uint64_t x, uint8_t b) {
27 [ - + ]: 4255244748 : assert(b < 64);
28 : :
29 : 4255244748 : return (x << b) | (x >> (64 - b));
30 : : }
31 : :
32 : 709207458 : static void sipround(struct siphash *state) {
33 [ - + ]: 709207458 : assert(state);
34 : :
35 : 709207458 : state->v0 += state->v1;
36 : 709207458 : state->v1 = rotate_left(state->v1, 13);
37 : 709207458 : state->v1 ^= state->v0;
38 : 709207458 : state->v0 = rotate_left(state->v0, 32);
39 : 709207458 : state->v2 += state->v3;
40 : 709207458 : state->v3 = rotate_left(state->v3, 16);
41 : 709207458 : state->v3 ^= state->v2;
42 : 709207458 : state->v0 += state->v3;
43 : 709207458 : state->v3 = rotate_left(state->v3, 21);
44 : 709207458 : state->v3 ^= state->v0;
45 : 709207458 : state->v2 += state->v1;
46 : 709207458 : state->v1 = rotate_left(state->v1, 17);
47 : 709207458 : state->v1 ^= state->v2;
48 : 709207458 : state->v2 = rotate_left(state->v2, 32);
49 : 709207458 : }
50 : :
51 : 94727969 : void siphash24_init(struct siphash *state, const uint8_t k[static 16]) {
52 : : uint64_t k0, k1;
53 : :
54 [ - + ]: 94727969 : assert(state);
55 [ - + ]: 94727969 : assert(k);
56 : :
57 : 94727969 : k0 = unaligned_read_le64(k);
58 : 94727969 : k1 = unaligned_read_le64(k + 8);
59 : :
60 : 94727969 : *state = (struct siphash) {
61 : : /* "somepseudorandomlygeneratedbytes" */
62 : 94727969 : .v0 = 0x736f6d6570736575ULL ^ k0,
63 : 94727969 : .v1 = 0x646f72616e646f6dULL ^ k1,
64 : 94727969 : .v2 = 0x6c7967656e657261ULL ^ k0,
65 : 94727969 : .v3 = 0x7465646279746573ULL ^ k1,
66 : : .padding = 0,
67 : : .inlen = 0,
68 : : };
69 : 94727969 : }
70 : :
71 : 97712272 : void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
72 : :
73 : 97712272 : const uint8_t *in = _in;
74 : 97712272 : const uint8_t *end = in + inlen;
75 : 97712272 : size_t left = state->inlen & 7;
76 : : uint64_t m;
77 : :
78 [ - + ]: 97712272 : assert(in);
79 [ - + ]: 97712272 : assert(state);
80 : :
81 : : /* Update total length */
82 : 97712272 : state->inlen += inlen;
83 : :
84 : : /* If padding exists, fill it out */
85 [ + + ]: 97712272 : if (left > 0) {
86 [ + + + + ]: 10531005 : for ( ; in < end && left < 8; in ++, left ++)
87 : 7965996 : state->padding |= ((uint64_t) *in) << (left * 8);
88 : :
89 [ + + + + ]: 2565009 : if (in == end && left < 8)
90 : : /* We did not have enough input to fill out the padding completely */
91 : 1261359 : 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 : 1303650 : state->v3 ^= state->padding;
102 : 1303650 : sipround(state);
103 : 1303650 : sipround(state);
104 : 1303650 : state->v0 ^= state->padding;
105 : :
106 : 1303650 : state->padding = 0;
107 : : }
108 : :
109 : 96450913 : end -= (state->inlen % sizeof(uint64_t));
110 : :
111 [ + + ]: 165567109 : for ( ; in < end; in += 8) {
112 : 69116196 : 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 : 69116196 : state->v3 ^= m;
121 : 69116196 : sipround(state);
122 : 69116196 : sipround(state);
123 : 69116196 : state->v0 ^= m;
124 : : }
125 : :
126 : 96450913 : left = state->inlen & 7;
127 [ + + + + : 96450913 : switch (left) {
+ + + +
- ]
128 : 21229785 : case 7:
129 : 21229785 : state->padding |= ((uint64_t) in[6]) << 48;
130 : : _fallthrough_;
131 : 27155787 : case 6:
132 : 27155787 : state->padding |= ((uint64_t) in[5]) << 40;
133 : : _fallthrough_;
134 : 28288449 : case 5:
135 : 28288449 : state->padding |= ((uint64_t) in[4]) << 32;
136 : : _fallthrough_;
137 : 28574064 : case 4:
138 : 28574064 : state->padding |= ((uint64_t) in[3]) << 24;
139 : : _fallthrough_;
140 : 28970118 : case 3:
141 : 28970118 : state->padding |= ((uint64_t) in[2]) << 16;
142 : : _fallthrough_;
143 : 29246262 : case 2:
144 : 29246262 : state->padding |= ((uint64_t) in[1]) << 8;
145 : : _fallthrough_;
146 : 30209667 : case 1:
147 : 30209667 : state->padding |= ((uint64_t) in[0]);
148 : : _fallthrough_;
149 : 96450913 : case 0:
150 : 96450913 : break;
151 : : }
152 : : }
153 : :
154 : 28 : void siphash24_compress_boolean(bool in, struct siphash *state) {
155 : 28 : int i = in;
156 : :
157 : 28 : siphash24_compress(&i, sizeof i, state);
158 : 28 : }
159 : :
160 : 94727961 : uint64_t siphash24_finalize(struct siphash *state) {
161 : : uint64_t b;
162 : :
163 [ - + ]: 94727961 : assert(state);
164 : :
165 : 94727961 : 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 : 94727961 : state->v3 ^= b;
176 : 94727961 : sipround(state);
177 : 94727961 : sipround(state);
178 : 94727961 : 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 : 94727961 : state->v2 ^= 0xff;
187 : :
188 : 94727961 : sipround(state);
189 : 94727961 : sipround(state);
190 : 94727961 : sipround(state);
191 : 94727961 : sipround(state);
192 : :
193 : 94727961 : return state->v0 ^ state->v1 ^ state->v2 ^ state->v3;
194 : : }
195 : :
196 : 96 : uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[static 16]) {
197 : : struct siphash state;
198 : :
199 [ - + ]: 96 : assert(in);
200 [ - + ]: 96 : assert(k);
201 : :
202 : 96 : siphash24_init(&state, k);
203 : 96 : siphash24_compress(in, inlen, &state);
204 : :
205 : 96 : return siphash24_finalize(&state);
206 : : }
|