Bitcoin ABC 0.30.7
P2P Digital Currency
chacha20.cpp
Go to the documentation of this file.
1// Copyright (c) 2017 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5// Based on the public domain implementation 'merged' by D. J. Bernstein
6// See https://cr.yp.to/chacha.html.
7
8#include <crypto/chacha20.h>
9#include <crypto/common.h>
10
11#include <cstring>
12
13constexpr static inline uint32_t rotl32(uint32_t v, int c) {
14 return (v << c) | (v >> (32 - c));
15}
16
17#define QUARTERROUND(a, b, c, d) \
18 do { \
19 a += b; \
20 d = rotl32(d ^ a, 16); \
21 c += d; \
22 b = rotl32(b ^ c, 12); \
23 a += b; \
24 d = rotl32(d ^ a, 8); \
25 c += d; \
26 b = rotl32(b ^ c, 7); \
27 } while (0)
28
29static const uint8_t sigma[] = "expand 32-byte k";
30static const uint8_t tau[] = "expand 16-byte k";
31
32void ChaCha20::SetKey(const uint8_t *k, size_t keylen) {
33 const uint8_t *constants;
34
35 input[4] = ReadLE32(k + 0);
36 input[5] = ReadLE32(k + 4);
37 input[6] = ReadLE32(k + 8);
38 input[7] = ReadLE32(k + 12);
39 if (keylen == 32) {
40 // recommended
41 k += 16;
42 constants = sigma;
43 } else {
44 // keylen == 16
45 constants = tau;
46 }
47 input[8] = ReadLE32(k + 0);
48 input[9] = ReadLE32(k + 4);
49 input[10] = ReadLE32(k + 8);
50 input[11] = ReadLE32(k + 12);
51 input[0] = ReadLE32(constants + 0);
52 input[1] = ReadLE32(constants + 4);
53 input[2] = ReadLE32(constants + 8);
54 input[3] = ReadLE32(constants + 12);
55 input[12] = 0;
56 input[13] = 0;
57 input[14] = 0;
58 input[15] = 0;
59}
60
62 memset(input, 0, sizeof(input));
63}
64
65ChaCha20::ChaCha20(const uint8_t *k, size_t keylen) {
66 SetKey(k, keylen);
67}
68
69void ChaCha20::SetIV(uint64_t iv) {
70 input[14] = iv;
71 input[15] = iv >> 32;
72}
73
74void ChaCha20::Seek(uint64_t pos) {
75 input[12] = pos;
76 input[13] = pos >> 32;
77}
78
79void ChaCha20::Keystream(uint8_t *c, size_t bytes) {
80 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14,
81 x15;
82 uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14,
83 j15;
84 uint8_t *ctarget = nullptr;
85 uint8_t tmp[64];
86 unsigned int i;
87
88 if (!bytes) {
89 return;
90 }
91
92 j0 = input[0];
93 j1 = input[1];
94 j2 = input[2];
95 j3 = input[3];
96 j4 = input[4];
97 j5 = input[5];
98 j6 = input[6];
99 j7 = input[7];
100 j8 = input[8];
101 j9 = input[9];
102 j10 = input[10];
103 j11 = input[11];
104 j12 = input[12];
105 j13 = input[13];
106 j14 = input[14];
107 j15 = input[15];
108
109 for (;;) {
110 if (bytes < 64) {
111 ctarget = c;
112 c = tmp;
113 }
114 x0 = j0;
115 x1 = j1;
116 x2 = j2;
117 x3 = j3;
118 x4 = j4;
119 x5 = j5;
120 x6 = j6;
121 x7 = j7;
122 x8 = j8;
123 x9 = j9;
124 x10 = j10;
125 x11 = j11;
126 x12 = j12;
127 x13 = j13;
128 x14 = j14;
129 x15 = j15;
130 for (i = 20; i > 0; i -= 2) {
131 QUARTERROUND(x0, x4, x8, x12);
132 QUARTERROUND(x1, x5, x9, x13);
133 QUARTERROUND(x2, x6, x10, x14);
134 QUARTERROUND(x3, x7, x11, x15);
135 QUARTERROUND(x0, x5, x10, x15);
136 QUARTERROUND(x1, x6, x11, x12);
137 QUARTERROUND(x2, x7, x8, x13);
138 QUARTERROUND(x3, x4, x9, x14);
139 }
140 x0 += j0;
141 x1 += j1;
142 x2 += j2;
143 x3 += j3;
144 x4 += j4;
145 x5 += j5;
146 x6 += j6;
147 x7 += j7;
148 x8 += j8;
149 x9 += j9;
150 x10 += j10;
151 x11 += j11;
152 x12 += j12;
153 x13 += j13;
154 x14 += j14;
155 x15 += j15;
156
157 ++j12;
158 if (!j12) {
159 ++j13;
160 }
161
162 WriteLE32(c + 0, x0);
163 WriteLE32(c + 4, x1);
164 WriteLE32(c + 8, x2);
165 WriteLE32(c + 12, x3);
166 WriteLE32(c + 16, x4);
167 WriteLE32(c + 20, x5);
168 WriteLE32(c + 24, x6);
169 WriteLE32(c + 28, x7);
170 WriteLE32(c + 32, x8);
171 WriteLE32(c + 36, x9);
172 WriteLE32(c + 40, x10);
173 WriteLE32(c + 44, x11);
174 WriteLE32(c + 48, x12);
175 WriteLE32(c + 52, x13);
176 WriteLE32(c + 56, x14);
177 WriteLE32(c + 60, x15);
178
179 if (bytes <= 64) {
180 if (bytes < 64) {
181 for (i = 0; i < bytes; ++i) {
182 ctarget[i] = c[i];
183 }
184 }
185 input[12] = j12;
186 input[13] = j13;
187 return;
188 }
189 bytes -= 64;
190 c += 64;
191 }
192}
193
194void ChaCha20::Crypt(const uint8_t *m, uint8_t *c, size_t bytes) {
195 uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14,
196 x15;
197 uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14,
198 j15;
199 uint8_t *ctarget = nullptr;
200 uint8_t tmp[64];
201 unsigned int i;
202
203 if (!bytes) {
204 return;
205 }
206
207 j0 = input[0];
208 j1 = input[1];
209 j2 = input[2];
210 j3 = input[3];
211 j4 = input[4];
212 j5 = input[5];
213 j6 = input[6];
214 j7 = input[7];
215 j8 = input[8];
216 j9 = input[9];
217 j10 = input[10];
218 j11 = input[11];
219 j12 = input[12];
220 j13 = input[13];
221 j14 = input[14];
222 j15 = input[15];
223
224 for (;;) {
225 if (bytes < 64) {
226 // if m has fewer than 64 bytes available, copy m to tmp and
227 // read from tmp instead
228 for (i = 0; i < bytes; ++i) {
229 tmp[i] = m[i];
230 }
231 m = tmp;
232 ctarget = c;
233 c = tmp;
234 }
235 x0 = j0;
236 x1 = j1;
237 x2 = j2;
238 x3 = j3;
239 x4 = j4;
240 x5 = j5;
241 x6 = j6;
242 x7 = j7;
243 x8 = j8;
244 x9 = j9;
245 x10 = j10;
246 x11 = j11;
247 x12 = j12;
248 x13 = j13;
249 x14 = j14;
250 x15 = j15;
251 for (i = 20; i > 0; i -= 2) {
252 QUARTERROUND(x0, x4, x8, x12);
253 QUARTERROUND(x1, x5, x9, x13);
254 QUARTERROUND(x2, x6, x10, x14);
255 QUARTERROUND(x3, x7, x11, x15);
256 QUARTERROUND(x0, x5, x10, x15);
257 QUARTERROUND(x1, x6, x11, x12);
258 QUARTERROUND(x2, x7, x8, x13);
259 QUARTERROUND(x3, x4, x9, x14);
260 }
261 x0 += j0;
262 x1 += j1;
263 x2 += j2;
264 x3 += j3;
265 x4 += j4;
266 x5 += j5;
267 x6 += j6;
268 x7 += j7;
269 x8 += j8;
270 x9 += j9;
271 x10 += j10;
272 x11 += j11;
273 x12 += j12;
274 x13 += j13;
275 x14 += j14;
276 x15 += j15;
277
278 x0 ^= ReadLE32(m + 0);
279 x1 ^= ReadLE32(m + 4);
280 x2 ^= ReadLE32(m + 8);
281 x3 ^= ReadLE32(m + 12);
282 x4 ^= ReadLE32(m + 16);
283 x5 ^= ReadLE32(m + 20);
284 x6 ^= ReadLE32(m + 24);
285 x7 ^= ReadLE32(m + 28);
286 x8 ^= ReadLE32(m + 32);
287 x9 ^= ReadLE32(m + 36);
288 x10 ^= ReadLE32(m + 40);
289 x11 ^= ReadLE32(m + 44);
290 x12 ^= ReadLE32(m + 48);
291 x13 ^= ReadLE32(m + 52);
292 x14 ^= ReadLE32(m + 56);
293 x15 ^= ReadLE32(m + 60);
294
295 ++j12;
296 if (!j12) {
297 ++j13;
298 }
299
300 WriteLE32(c + 0, x0);
301 WriteLE32(c + 4, x1);
302 WriteLE32(c + 8, x2);
303 WriteLE32(c + 12, x3);
304 WriteLE32(c + 16, x4);
305 WriteLE32(c + 20, x5);
306 WriteLE32(c + 24, x6);
307 WriteLE32(c + 28, x7);
308 WriteLE32(c + 32, x8);
309 WriteLE32(c + 36, x9);
310 WriteLE32(c + 40, x10);
311 WriteLE32(c + 44, x11);
312 WriteLE32(c + 48, x12);
313 WriteLE32(c + 52, x13);
314 WriteLE32(c + 56, x14);
315 WriteLE32(c + 60, x15);
316
317 if (bytes <= 64) {
318 if (bytes < 64) {
319 for (i = 0; i < bytes; ++i) {
320 ctarget[i] = c[i];
321 }
322 }
323 input[12] = j12;
324 input[13] = j13;
325 return;
326 }
327 bytes -= 64;
328 c += 64;
329 m += 64;
330 }
331}
void SetKey(const uint8_t *key, size_t keylen)
set key with flexible keylength; 256bit recommended
Definition: chacha20.cpp:32
void Keystream(uint8_t *c, size_t bytes)
outputs the keystream of size <bytes> into
Definition: chacha20.cpp:79
void Crypt(const uint8_t *input, uint8_t *output, size_t bytes)
enciphers the message <input> of length <bytes> and write the enciphered representation into <output>...
Definition: chacha20.cpp:194
uint32_t input[16]
Definition: chacha20.h:17
void SetIV(uint64_t iv)
Definition: chacha20.cpp:69
ChaCha20()
Definition: chacha20.cpp:61
void Seek(uint64_t pos)
Definition: chacha20.cpp:74
static const uint8_t tau[]
Definition: chacha20.cpp:30
static constexpr uint32_t rotl32(uint32_t v, int c)
Definition: chacha20.cpp:13
static const uint8_t sigma[]
Definition: chacha20.cpp:29
#define QUARTERROUND(a, b, c, d)
Definition: chacha20.cpp:17
static void WriteLE32(uint8_t *ptr, uint32_t x)
Definition: common.h:40
static uint32_t ReadLE32(const uint8_t *ptr)
Definition: common.h:23