1 |
#include <assert.h> |
2 |
#include <stdint.h> |
3 |
#include <sys/types.h> |
4 |
|
5 |
struct spritz |
6 |
{ |
7 |
enum { N = 256 }; |
8 |
|
9 |
uint8_t a, i, j, k, z, w; |
10 |
uint8_t S[N]; |
11 |
|
12 |
spritz () |
13 |
{ |
14 |
a = |
15 |
i = |
16 |
j = |
17 |
k = |
18 |
z = 0; |
19 |
w = 1; |
20 |
|
21 |
uint_fast8_t v = N - 1; |
22 |
do |
23 |
S[v] = v; |
24 |
while (v--); |
25 |
} |
26 |
|
27 |
void update () |
28 |
{ |
29 |
i += w; |
30 |
j = k + S[j + S[i]]; |
31 |
k = k + i + S[j]; |
32 |
swap (S[i], S[j]); |
33 |
} |
34 |
|
35 |
void whip (uint_fast16_t r) |
36 |
{ |
37 |
while (r--) |
38 |
update (); |
39 |
|
40 |
w += 2; |
41 |
} |
42 |
|
43 |
static void swap (uint8_t &a, uint8_t &b) |
44 |
{ |
45 |
uint8_t c = a; |
46 |
a = b; |
47 |
b = c; |
48 |
} |
49 |
|
50 |
void crush () |
51 |
{ |
52 |
for (uint_fast16_t v = 0; v < (N >> 1); ++v) |
53 |
if (S[v] > S[N - 1 - v]) |
54 |
swap (S[v], S[N - 1 - v]); |
55 |
} |
56 |
|
57 |
void shuffle () |
58 |
{ |
59 |
whip (2 * N); crush (); |
60 |
whip (2 * N); crush (); |
61 |
whip (2 * N); |
62 |
|
63 |
a = 0; |
64 |
} |
65 |
|
66 |
void shuffle_absorb () |
67 |
{ |
68 |
if (a == (N >> 1)) |
69 |
shuffle (); |
70 |
} |
71 |
|
72 |
void absorb_nibble (uint8_t x) |
73 |
{ |
74 |
shuffle_absorb (); |
75 |
|
76 |
swap (S[a], S[(N >> 1) + x]); |
77 |
++a; |
78 |
} |
79 |
|
80 |
void absorb_byte (uint8_t b) |
81 |
{ |
82 |
absorb_nibble (b & 15); |
83 |
absorb_nibble (b >> 4); |
84 |
} |
85 |
|
86 |
void absorb (const void *I, size_t I_len) |
87 |
{ |
88 |
uint8_t *i = (uint8_t *)I; |
89 |
|
90 |
while (I_len--) |
91 |
absorb_byte (*i++); |
92 |
} |
93 |
|
94 |
void absorb_stop () |
95 |
{ |
96 |
shuffle_absorb (); |
97 |
|
98 |
++a; |
99 |
} |
100 |
|
101 |
// commonly used helper function |
102 |
void absorb_stop (const void *I, size_t I_len) |
103 |
{ |
104 |
absorb (I, I_len); |
105 |
absorb_stop (); |
106 |
} |
107 |
|
108 |
void shuffle_squeeze () |
109 |
{ |
110 |
if (a) |
111 |
shuffle (); |
112 |
} |
113 |
|
114 |
uint8_t output () |
115 |
{ |
116 |
return S[j + S[i + S[z + k]]]; |
117 |
} |
118 |
|
119 |
// slightly faster internal helper, drip without squeeze preparation |
120 |
uint8_t drip_nosqueeze () |
121 |
{ |
122 |
update (); |
123 |
return output (); |
124 |
} |
125 |
|
126 |
void squeeze (void *P, size_t P_len) |
127 |
{ |
128 |
shuffle_squeeze (); |
129 |
|
130 |
uint8_t *p = (uint8_t *)P; |
131 |
|
132 |
while (P_len--) |
133 |
*p++ = drip_nosqueeze (); |
134 |
} |
135 |
|
136 |
uint8_t drip () |
137 |
{ |
138 |
shuffle_squeeze (); |
139 |
|
140 |
return drip_nosqueeze (); |
141 |
} |
142 |
}; |
143 |
|
144 |
// what follows is wrappers that make using spritz easier and less error-prone |
145 |
|
146 |
// spritz-xor variant of cipher |
147 |
struct spritz_xor : protected spritz |
148 |
{ |
149 |
// key K required, IV optional |
150 |
spritz_xor (const void *K, size_t K_len, const void *IV = 0, size_t IV_len = 0) |
151 |
{ |
152 |
absorb (K, K_len); |
153 |
|
154 |
if (IV) |
155 |
{ |
156 |
absorb_stop (); |
157 |
absorb (IV, IV_len); |
158 |
} |
159 |
|
160 |
shuffle_squeeze (); |
161 |
} |
162 |
|
163 |
// can be called multiple times/incrementally |
164 |
// can work inplace |
165 |
// works for both encryption and decryption |
166 |
void crypt (const void *I, void *O, size_t len) |
167 |
{ |
168 |
const uint8_t *i = (const uint8_t *)I; |
169 |
uint8_t *o = ( uint8_t *)O; |
170 |
|
171 |
while (len--) |
172 |
*o++ = *i++ ^ drip_nosqueeze (); |
173 |
} |
174 |
}; |
175 |
|
176 |
struct spritz_hash : protected spritz |
177 |
{ |
178 |
spritz_hash () |
179 |
{ |
180 |
} |
181 |
|
182 |
// can be called multiple times/incrementally |
183 |
void add (const void *M, size_t M_len) |
184 |
{ |
185 |
absorb (M, M_len); |
186 |
} |
187 |
|
188 |
// must be called at most once at the end |
189 |
void hash (void *H, size_t H_len) |
190 |
{ |
191 |
absorb_stop (); |
192 |
assert (H_len <= 0xff); |
193 |
absorb_byte (H_len); |
194 |
|
195 |
squeeze (H, H_len); |
196 |
} |
197 |
}; |
198 |
|
199 |
struct spritz_mac : protected spritz_hash |
200 |
{ |
201 |
spritz_mac (const void *K, size_t K_len) |
202 |
{ |
203 |
absorb_stop (K, K_len); |
204 |
} |
205 |
|
206 |
// use add to incrementally add data |
207 |
using spritz_hash::add; |
208 |
|
209 |
// must be called at most once at the end |
210 |
void mac (void *H, size_t H_len) |
211 |
{ |
212 |
hash (H, H_len); |
213 |
} |
214 |
}; |
215 |
|
216 |
struct spritz_aead : protected spritz_mac |
217 |
{ |
218 |
spritz_aead (const void *K, size_t K_len) |
219 |
: spritz_mac (K, K_len) |
220 |
{ |
221 |
} |
222 |
|
223 |
// must be called after construction, before data |
224 |
void nonce (const void *N, size_t N_len) |
225 |
{ |
226 |
absorb_stop (N, N_len); |
227 |
} |
228 |
|
229 |
// must be called after nonce, before crypt |
230 |
void associated_data (const void *D, size_t D_len) |
231 |
{ |
232 |
absorb_stop (D, D_len); |
233 |
} |
234 |
|
235 |
// must be called after data, only once, before mac |
236 |
// works for both encryption and decryption |
237 |
void crypt (const void *I, void *O, size_t len) |
238 |
{ |
239 |
const uint8_t *i = (const uint8_t *)I; |
240 |
uint8_t *o = ( uint8_t *)O; |
241 |
|
242 |
uint8_t x[N >> 2]; |
243 |
|
244 |
while (len) |
245 |
{ |
246 |
uint8_t l = len > sizeof (x) ? sizeof (x) : len; |
247 |
len -= l; |
248 |
|
249 |
squeeze (x, l); |
250 |
|
251 |
for (uint_fast8_t j = 0; j < l; ++j) |
252 |
absorb_byte (*o++ = *i++ ^ x[j]); |
253 |
} |
254 |
} |
255 |
|
256 |
// call mac() at most once at the end |
257 |
using spritz_mac::mac; |
258 |
}; |
259 |
|
260 |
struct spritz_drbg : protected spritz |
261 |
{ |
262 |
// seed optional, can be done via put |
263 |
spritz_drbg (const void *S = 0, size_t S_len = 0) |
264 |
{ |
265 |
absorb (S, S_len); |
266 |
} |
267 |
|
268 |
// add additional entropy |
269 |
void put (const void *S, size_t S_len) |
270 |
{ |
271 |
absorb (S, S_len); |
272 |
} |
273 |
|
274 |
// get random bytes |
275 |
void get (void *R, size_t R_len) |
276 |
{ |
277 |
squeeze (R, R_len); |
278 |
} |
279 |
}; |
280 |
|