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 "macro.h"
25 #include "siphash24.h"
26 #include "unaligned.h"
27 
rotate_left(uint64_t x,uint8_t b)28 static uint64_t rotate_left(uint64_t x, uint8_t b) {
29         assert(b < 64);
30 
31         return (x << b) | (x >> (64 - b));
32 }
33 
sipround(struct siphash * state)34 static void sipround(struct siphash *state) {
35         assert(state);
36 
37         state->v0 += state->v1;
38         state->v1 = rotate_left(state->v1, 13);
39         state->v1 ^= state->v0;
40         state->v0 = rotate_left(state->v0, 32);
41         state->v2 += state->v3;
42         state->v3 = rotate_left(state->v3, 16);
43         state->v3 ^= state->v2;
44         state->v0 += state->v3;
45         state->v3 = rotate_left(state->v3, 21);
46         state->v3 ^= state->v0;
47         state->v2 += state->v1;
48         state->v1 = rotate_left(state->v1, 17);
49         state->v1 ^= state->v2;
50         state->v2 = rotate_left(state->v2, 32);
51 }
52 
siphash24_init(struct siphash * state,const uint8_t k[static16])53 void siphash24_init(struct siphash *state, const uint8_t k[static 16]) {
54         uint64_t k0, k1;
55 
56         assert(state);
57         assert(k);
58 
59         k0 = unaligned_read_le64(k);
60         k1 = unaligned_read_le64(k + 8);
61 
62         *state = (struct siphash) {
63                 /* "somepseudorandomlygeneratedbytes" */
64                 .v0 = 0x736f6d6570736575ULL ^ k0,
65                 .v1 = 0x646f72616e646f6dULL ^ k1,
66                 .v2 = 0x6c7967656e657261ULL ^ k0,
67                 .v3 = 0x7465646279746573ULL ^ k1,
68                 .padding = 0,
69                 .inlen = 0,
70         };
71 }
72 
siphash24_compress(const void * _in,size_t inlen,struct siphash * state)73 void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
74 
75         const uint8_t *in = _in;
76         const uint8_t *end = in + inlen;
77         size_t left = state->inlen & 7;
78         uint64_t m;
79 
80         assert(in);
81         assert(state);
82 
83         /* Update total length */
84         state->inlen += inlen;
85 
86         /* If padding exists, fill it out */
87         if (left > 0) {
88                 for ( ; in < end && left < 8; in ++, left ++)
89                         state->padding |= ((uint64_t) *in) << (left * 8);
90 
91                 if (in == end && left < 8)
92                         /* We did not have enough input to fill out the padding completely */
93                         return;
94 
95 #if ENABLE_DEBUG_SIPHASH
96                 printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
97                 printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
98                 printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
99                 printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
100                 printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding);
101 #endif
102 
103                 state->v3 ^= state->padding;
104                 sipround(state);
105                 sipround(state);
106                 state->v0 ^= state->padding;
107 
108                 state->padding = 0;
109         }
110 
111         end -= (state->inlen % sizeof(uint64_t));
112 
113         for ( ; in < end; in += 8) {
114                 m = unaligned_read_le64(in);
115 #if ENABLE_DEBUG_SIPHASH
116                 printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
117                 printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
118                 printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
119                 printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
120                 printf("(%3zu) compress %08x %08x\n", state->inlen, (uint32_t) (m >> 32), (uint32_t) m);
121 #endif
122                 state->v3 ^= m;
123                 sipround(state);
124                 sipround(state);
125                 state->v0 ^= m;
126         }
127 
128         left = state->inlen & 7;
129         switch (left) {
130                 case 7:
131                         state->padding |= ((uint64_t) in[6]) << 48;
132                         _fallthrough_;
133                 case 6:
134                         state->padding |= ((uint64_t) in[5]) << 40;
135                         _fallthrough_;
136                 case 5:
137                         state->padding |= ((uint64_t) in[4]) << 32;
138                         _fallthrough_;
139                 case 4:
140                         state->padding |= ((uint64_t) in[3]) << 24;
141                         _fallthrough_;
142                 case 3:
143                         state->padding |= ((uint64_t) in[2]) << 16;
144                         _fallthrough_;
145                 case 2:
146                         state->padding |= ((uint64_t) in[1]) <<  8;
147                         _fallthrough_;
148                 case 1:
149                         state->padding |= ((uint64_t) in[0]);
150                         _fallthrough_;
151                 case 0:
152                         break;
153         }
154 }
155 
siphash24_finalize(struct siphash * state)156 uint64_t siphash24_finalize(struct siphash *state) {
157         uint64_t b;
158 
159         assert(state);
160 
161         b = state->padding | (((uint64_t) state->inlen) << 56);
162 
163 #if ENABLE_DEBUG_SIPHASH
164         printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
165         printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
166         printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
167         printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
168         printf("(%3zu) padding   %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding);
169 #endif
170 
171         state->v3 ^= b;
172         sipround(state);
173         sipround(state);
174         state->v0 ^= b;
175 
176 #if ENABLE_DEBUG_SIPHASH
177         printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
178         printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
179         printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
180         printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
181 #endif
182         state->v2 ^= 0xff;
183 
184         sipround(state);
185         sipround(state);
186         sipround(state);
187         sipround(state);
188 
189         return state->v0 ^ state->v1 ^ state->v2  ^ state->v3;
190 }
191 
siphash24(const void * in,size_t inlen,const uint8_t k[static16])192 uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[static 16]) {
193         struct siphash state;
194 
195         assert(in);
196         assert(k);
197 
198         siphash24_init(&state, k);
199         siphash24_compress(in, inlen, &state);
200 
201         return siphash24_finalize(&state);
202 }
203