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