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