]>
Commit | Line | Data |
---|---|---|
60f067b4 JS |
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) | |
6300502b MP |
16 | (Refactored by Tom Gundersen to split up in several functions and follow systemd |
17 | coding style) | |
60f067b4 | 18 | */ |
6300502b MP |
19 | |
20 | #include "sparse-endian.h" | |
60f067b4 JS |
21 | |
22 | #include "siphash24.h" | |
6300502b | 23 | #include "util.h" |
60f067b4 | 24 | |
6300502b MP |
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; | |
60f067b4 | 88 | |
60f067b4 | 89 | #ifdef DEBUG |
6300502b MP |
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); | |
60f067b4 | 95 | #endif |
6300502b MP |
96 | state->v3 ^= state->padding; |
97 | sipround(state); | |
98 | sipround(state); | |
99 | state->v0 ^= state->padding; | |
60f067b4 | 100 | |
6300502b MP |
101 | state->padding = 0; |
102 | } | |
60f067b4 | 103 | |
6300502b | 104 | end -= ( state->inlen % sizeof (uint64_t) ); |
60f067b4 | 105 | |
6300502b MP |
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; | |
60f067b4 | 126 | |
6300502b | 127 | case 6: state->padding |= ((uint64_t) in[5]) << 40; |
60f067b4 | 128 | |
6300502b | 129 | case 5: state->padding |= ((uint64_t) in[4]) << 32; |
60f067b4 | 130 | |
6300502b | 131 | case 4: state->padding |= ((uint64_t) in[3]) << 24; |
60f067b4 | 132 | |
6300502b MP |
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 | } | |
60f067b4 | 142 | |
6300502b MP |
143 | void siphash24_finalize(uint8_t out[8], struct siphash *state) { |
144 | uint64_t b; | |
60f067b4 | 145 | |
6300502b | 146 | b = state->padding | (( ( uint64_t )state->inlen ) << 56); |
60f067b4 | 147 | #ifdef DEBUG |
6300502b MP |
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); | |
60f067b4 | 153 | #endif |
6300502b MP |
154 | state->v3 ^= b; |
155 | sipround(state); | |
156 | sipround(state); | |
157 | state->v0 ^= b; | |
158 | ||
60f067b4 | 159 | #ifdef DEBUG |
6300502b MP |
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); | |
60f067b4 | 164 | #endif |
6300502b MP |
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); | |
60f067b4 | 182 | } |