/src/systemd/src/basic/siphash24.c
Line | Count | Source |
1 | | /* SPDX-License-Identifier: CC0-1.0 */ |
2 | | |
3 | | /* |
4 | | SipHash reference C implementation |
5 | | |
6 | | Written in 2012 by |
7 | | Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com> |
8 | | Daniel J. Bernstein <djb@cr.yp.to> |
9 | | |
10 | | To the extent possible under law, the author(s) have dedicated all copyright |
11 | | and related and neighboring rights to this software to the public domain |
12 | | worldwide. This software is distributed without any warranty. |
13 | | |
14 | | You should have received a copy of the CC0 Public Domain Dedication along with |
15 | | this software. If not, see <https://creativecommons.org/publicdomain/zero/1.0/>. |
16 | | |
17 | | (Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd) |
18 | | (Refactored by Tom Gundersen to split up in several functions and follow systemd |
19 | | coding style) |
20 | | */ |
21 | | |
22 | | #include <stdio.h> |
23 | | |
24 | | #include "siphash24.h" |
25 | | #include "string-util.h" |
26 | | #include "unaligned.h" |
27 | | |
28 | 5.30G | static uint64_t rotate_left(uint64_t x, uint8_t b) { |
29 | 5.30G | assert(b < 64); |
30 | | |
31 | 5.30G | return (x << b) | (x >> (64 - b)); |
32 | 5.30G | } |
33 | | |
34 | 884M | static void sipround(struct siphash *state) { |
35 | 884M | assert(state); |
36 | | |
37 | 884M | state->v0 += state->v1; |
38 | 884M | state->v1 = rotate_left(state->v1, 13); |
39 | 884M | state->v1 ^= state->v0; |
40 | 884M | state->v0 = rotate_left(state->v0, 32); |
41 | 884M | state->v2 += state->v3; |
42 | 884M | state->v3 = rotate_left(state->v3, 16); |
43 | 884M | state->v3 ^= state->v2; |
44 | 884M | state->v0 += state->v3; |
45 | 884M | state->v3 = rotate_left(state->v3, 21); |
46 | 884M | state->v3 ^= state->v0; |
47 | 884M | state->v2 += state->v1; |
48 | 884M | state->v1 = rotate_left(state->v1, 17); |
49 | 884M | state->v1 ^= state->v2; |
50 | 884M | state->v2 = rotate_left(state->v2, 32); |
51 | 884M | } |
52 | | |
53 | 101M | void siphash24_init(struct siphash *state, const uint8_t k[static 16]) { |
54 | 101M | uint64_t k0, k1; |
55 | | |
56 | 101M | assert(state); |
57 | 101M | assert(k); |
58 | | |
59 | 101M | k0 = unaligned_read_le64(k); |
60 | 101M | k1 = unaligned_read_le64(k + 8); |
61 | | |
62 | 101M | *state = (struct siphash) { |
63 | | /* "somepseudorandomlygeneratedbytes" */ |
64 | 101M | .v0 = 0x736f6d6570736575ULL ^ k0, |
65 | 101M | .v1 = 0x646f72616e646f6dULL ^ k1, |
66 | 101M | .v2 = 0x6c7967656e657261ULL ^ k0, |
67 | 101M | .v3 = 0x7465646279746573ULL ^ k1, |
68 | 101M | .padding = 0, |
69 | 101M | .inlen = 0, |
70 | 101M | }; |
71 | 101M | } |
72 | | |
73 | 156M | void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) { |
74 | | |
75 | 156M | const uint8_t *in = ASSERT_PTR(_in); |
76 | 156M | const uint8_t *end = in + inlen; |
77 | 156M | size_t left = state->inlen & 7; |
78 | 156M | uint64_t m; |
79 | | |
80 | 156M | assert(state); |
81 | | |
82 | | /* Update total length */ |
83 | 156M | state->inlen += inlen; |
84 | | |
85 | | /* If padding exists, fill it out */ |
86 | 156M | if (left > 0) { |
87 | 147M | for ( ; in < end && left < 8; in ++, left ++) |
88 | 96.4M | state->padding |= ((uint64_t) *in) << (left * 8); |
89 | | |
90 | 50.6M | if (in == end && left < 8) |
91 | | /* We did not have enough input to fill out the padding completely */ |
92 | 36.5M | return; |
93 | | |
94 | | #if ENABLE_DEBUG_SIPHASH |
95 | | printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); |
96 | | printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); |
97 | | printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); |
98 | | printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); |
99 | | printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding); |
100 | | #endif |
101 | | |
102 | 14.1M | state->v3 ^= state->padding; |
103 | 14.1M | sipround(state); |
104 | 14.1M | sipround(state); |
105 | 14.1M | state->v0 ^= state->padding; |
106 | | |
107 | 14.1M | state->padding = 0; |
108 | 14.1M | } |
109 | | |
110 | 120M | end -= (state->inlen % sizeof(uint64_t)); |
111 | | |
112 | 245M | for ( ; in < end; in += 8) { |
113 | 125M | m = unaligned_read_le64(in); |
114 | | #if ENABLE_DEBUG_SIPHASH |
115 | | printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); |
116 | | printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); |
117 | | printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); |
118 | | printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); |
119 | | printf("(%3zu) compress %08x %08x\n", state->inlen, (uint32_t) (m >> 32), (uint32_t) m); |
120 | | #endif |
121 | 125M | state->v3 ^= m; |
122 | 125M | sipround(state); |
123 | 125M | sipround(state); |
124 | 125M | state->v0 ^= m; |
125 | 125M | } |
126 | | |
127 | 120M | left = state->inlen & 7; |
128 | 120M | switch (left) { |
129 | 1.00M | case 7: |
130 | 1.00M | state->padding |= ((uint64_t) in[6]) << 48; |
131 | 1.00M | _fallthrough_; |
132 | 7.53M | case 6: |
133 | 7.53M | state->padding |= ((uint64_t) in[5]) << 40; |
134 | 7.53M | _fallthrough_; |
135 | 14.2M | case 5: |
136 | 14.2M | state->padding |= ((uint64_t) in[4]) << 32; |
137 | 14.2M | _fallthrough_; |
138 | 22.6M | case 4: |
139 | 22.6M | state->padding |= ((uint64_t) in[3]) << 24; |
140 | 22.6M | _fallthrough_; |
141 | 27.4M | case 3: |
142 | 27.4M | state->padding |= ((uint64_t) in[2]) << 16; |
143 | 27.4M | _fallthrough_; |
144 | 36.1M | case 2: |
145 | 36.1M | state->padding |= ((uint64_t) in[1]) << 8; |
146 | 36.1M | _fallthrough_; |
147 | 60.9M | case 1: |
148 | 60.9M | state->padding |= ((uint64_t) in[0]); |
149 | 60.9M | _fallthrough_; |
150 | 120M | case 0: |
151 | 120M | break; |
152 | 120M | } |
153 | 120M | } |
154 | | |
155 | 2.86M | void siphash24_compress_string(const char *in, struct siphash *state) { |
156 | 2.86M | siphash24_compress_safe(in, strlen_ptr(in), state); |
157 | 2.86M | } |
158 | | |
159 | 101M | uint64_t siphash24_finalize(struct siphash *state) { |
160 | 101M | uint64_t b; |
161 | | |
162 | 101M | assert(state); |
163 | | |
164 | 101M | b = state->padding | (((uint64_t) state->inlen) << 56); |
165 | | |
166 | | #if ENABLE_DEBUG_SIPHASH |
167 | | printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); |
168 | | printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); |
169 | | printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); |
170 | | printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); |
171 | | printf("(%3zu) padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding); |
172 | | #endif |
173 | | |
174 | 101M | state->v3 ^= b; |
175 | 101M | sipround(state); |
176 | 101M | sipround(state); |
177 | 101M | state->v0 ^= b; |
178 | | |
179 | | #if ENABLE_DEBUG_SIPHASH |
180 | | printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); |
181 | | printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); |
182 | | printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); |
183 | | printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); |
184 | | #endif |
185 | 101M | state->v2 ^= 0xff; |
186 | | |
187 | 101M | sipround(state); |
188 | 101M | sipround(state); |
189 | 101M | sipround(state); |
190 | 101M | sipround(state); |
191 | | |
192 | 101M | return state->v0 ^ state->v1 ^ state->v2 ^ state->v3; |
193 | 101M | } |
194 | | |
195 | 614k | uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[static 16]) { |
196 | 614k | struct siphash state; |
197 | | |
198 | 614k | assert(in); |
199 | 614k | assert(k); |
200 | | |
201 | 614k | siphash24_init(&state, k); |
202 | 614k | siphash24_compress(in, inlen, &state); |
203 | | |
204 | 614k | return siphash24_finalize(&state); |
205 | 614k | } |
206 | | |
207 | 0 | uint64_t siphash24_string(const char *s, const uint8_t k[static 16]) { |
208 | 0 | return siphash24(s, strlen(s) + 1, k); |
209 | 0 | } |