Bitcoin ABC  0.24.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 
13 constexpr 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 
29 static const uint8_t sigma[] = "expand 32-byte k";
30 static const uint8_t tau[] = "expand 16-byte k";
31 
32 void 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 
65 ChaCha20::ChaCha20(const uint8_t *k, size_t keylen) {
66  SetKey(k, keylen);
67 }
68 
69 void ChaCha20::SetIV(uint64_t iv) {
70  input[14] = iv;
71  input[15] = iv >> 32;
72 }
73 
74 void ChaCha20::Seek(uint64_t pos) {
75  input[12] = pos;
76  input[13] = pos >> 32;
77 }
78 
79 void 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 
194 void 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 }
ChaCha20::Keystream
void Keystream(uint8_t *c, size_t bytes)
outputs the keystream of size <bytes> into
Definition: chacha20.cpp:79
WriteLE32
static void WriteLE32(uint8_t *ptr, uint32_t x)
Definition: common.h:40
ReadLE32
static uint32_t ReadLE32(const uint8_t *ptr)
Definition: common.h:23
chacha20.h
ChaCha20::Seek
void Seek(uint64_t pos)
Definition: chacha20.cpp:74
ChaCha20::input
uint32_t input[16]
Definition: chacha20.h:17
ChaCha20::Crypt
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
rotl32
constexpr static uint32_t rotl32(uint32_t v, int c)
Definition: chacha20.cpp:13
ChaCha20::ChaCha20
ChaCha20()
Definition: chacha20.cpp:61
ChaCha20::SetKey
void SetKey(const uint8_t *key, size_t keylen)
set key with flexible keylength; 256bit recommended
Definition: chacha20.cpp:32
tau
static const uint8_t tau[]
Definition: chacha20.cpp:30
ChaCha20::SetIV
void SetIV(uint64_t iv)
Definition: chacha20.cpp:69
common.h
QUARTERROUND
#define QUARTERROUND(a, b, c, d)
Definition: chacha20.cpp:17
sigma
static const uint8_t sigma[]
Definition: chacha20.cpp:29