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