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