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