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