PIVX Core  5.6.99
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/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 static const unsigned char sigma[] = "expand 32-byte k";
22 static const unsigned char tau[] = "expand 16-byte k";
23 
24 void ChaCha20::SetKey(const unsigned char* k, size_t keylen)
25 {
26  const unsigned char *constants;
27 
28  input[4] = ReadLE32(k + 0);
29  input[5] = ReadLE32(k + 4);
30  input[6] = ReadLE32(k + 8);
31  input[7] = ReadLE32(k + 12);
32  if (keylen == 32) { /* recommended */
33  k += 16;
34  constants = sigma;
35  } else { /* keylen == 16 */
36  constants = tau;
37  }
38  input[8] = ReadLE32(k + 0);
39  input[9] = ReadLE32(k + 4);
40  input[10] = ReadLE32(k + 8);
41  input[11] = ReadLE32(k + 12);
42  input[0] = ReadLE32(constants + 0);
43  input[1] = ReadLE32(constants + 4);
44  input[2] = ReadLE32(constants + 8);
45  input[3] = ReadLE32(constants + 12);
46  input[12] = 0;
47  input[13] = 0;
48  input[14] = 0;
49  input[15] = 0;
50 }
51 
53 {
54  memset(input, 0, sizeof(input));
55 }
56 
57 ChaCha20::ChaCha20(const unsigned char* k, size_t keylen)
58 {
59  SetKey(k, keylen);
60 }
61 
62 void ChaCha20::SetIV(uint64_t iv)
63 {
64  input[14] = iv;
65  input[15] = iv >> 32;
66 }
67 
68 void ChaCha20::Seek(uint64_t pos)
69 {
70  input[12] = pos;
71  input[13] = pos >> 32;
72 }
73 
74 void ChaCha20::Keystream(unsigned char* c, size_t bytes)
75 {
76  uint32_t x[16];
77  uint32_t j[16];
78  unsigned char *ctarget = nullptr;
79  unsigned char tmp[64];
80  unsigned int i;
81 
82  if (!bytes) return;
83 
84  for (uint32_t i=0; i<16; i++) {
85  j[i] = input[i];
86  }
87 
88  for (;;) {
89  if (bytes < 64) {
90  ctarget = c;
91  c = tmp;
92  }
93  for (uint32_t i=0; i<16; i++) {
94  x[i] = j[i];
95  }
96  for (i = 20;i > 0;i -= 2) {
97  QUARTERROUND( x[0], x[4], x[8],x[12])
98  QUARTERROUND( x[1], x[5], x[9],x[13])
99  QUARTERROUND( x[2], x[6],x[10],x[14])
100  QUARTERROUND( x[3], x[7],x[11],x[15])
101  QUARTERROUND( x[0], x[5],x[10],x[15])
102  QUARTERROUND( x[1], x[6],x[11],x[12])
103  QUARTERROUND( x[2], x[7], x[8],x[13])
104  QUARTERROUND( x[3], x[4], x[9],x[14])
105  }
106  for (uint32_t i=0; i<16; i++) {
107  x[i] += j[i];
108  }
109 
110  ++j[12];
111  if (!j[12]) ++j[13];
112 
113  for (uint32_t i=0; i<16; i++) {
114  WriteLE32(c + 4*i, x[i]);
115  }
116 
117  if (bytes <= 64) {
118  if (bytes < 64) {
119  for (i = 0;i < bytes;++i) ctarget[i] = c[i];
120  }
121  input[12] = j[12];
122  input[13] = j[13];
123  return;
124  }
125  bytes -= 64;
126  c += 64;
127  }
128 }
129 
130 void ChaCha20::Crypt(const unsigned char* m, unsigned char* c, size_t bytes)
131 {
132  uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
133  uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
134  unsigned char *ctarget = nullptr;
135  unsigned char tmp[64];
136  unsigned int i;
137 
138  if (!bytes) return;
139 
140  j0 = input[0];
141  j1 = input[1];
142  j2 = input[2];
143  j3 = input[3];
144  j4 = input[4];
145  j5 = input[5];
146  j6 = input[6];
147  j7 = input[7];
148  j8 = input[8];
149  j9 = input[9];
150  j10 = input[10];
151  j11 = input[11];
152  j12 = input[12];
153  j13 = input[13];
154  j14 = input[14];
155  j15 = input[15];
156 
157  for (;;) {
158  if (bytes < 64) {
159  // if m has fewer than 64 bytes available, copy m to tmp and
160  // read from tmp instead
161  for (i = 0;i < bytes;++i) tmp[i] = m[i];
162  m = tmp;
163  ctarget = c;
164  c = tmp;
165  }
166  x0 = j0;
167  x1 = j1;
168  x2 = j2;
169  x3 = j3;
170  x4 = j4;
171  x5 = j5;
172  x6 = j6;
173  x7 = j7;
174  x8 = j8;
175  x9 = j9;
176  x10 = j10;
177  x11 = j11;
178  x12 = j12;
179  x13 = j13;
180  x14 = j14;
181  x15 = j15;
182  for (i = 20;i > 0;i -= 2) {
183  QUARTERROUND( x0, x4, x8,x12)
184  QUARTERROUND( x1, x5, x9,x13)
185  QUARTERROUND( x2, x6,x10,x14)
186  QUARTERROUND( x3, x7,x11,x15)
187  QUARTERROUND( x0, x5,x10,x15)
188  QUARTERROUND( x1, x6,x11,x12)
189  QUARTERROUND( x2, x7, x8,x13)
190  QUARTERROUND( x3, x4, x9,x14)
191  }
192  x0 += j0;
193  x1 += j1;
194  x2 += j2;
195  x3 += j3;
196  x4 += j4;
197  x5 += j5;
198  x6 += j6;
199  x7 += j7;
200  x8 += j8;
201  x9 += j9;
202  x10 += j10;
203  x11 += j11;
204  x12 += j12;
205  x13 += j13;
206  x14 += j14;
207  x15 += j15;
208 
209  x0 ^= ReadLE32(m + 0);
210  x1 ^= ReadLE32(m + 4);
211  x2 ^= ReadLE32(m + 8);
212  x3 ^= ReadLE32(m + 12);
213  x4 ^= ReadLE32(m + 16);
214  x5 ^= ReadLE32(m + 20);
215  x6 ^= ReadLE32(m + 24);
216  x7 ^= ReadLE32(m + 28);
217  x8 ^= ReadLE32(m + 32);
218  x9 ^= ReadLE32(m + 36);
219  x10 ^= ReadLE32(m + 40);
220  x11 ^= ReadLE32(m + 44);
221  x12 ^= ReadLE32(m + 48);
222  x13 ^= ReadLE32(m + 52);
223  x14 ^= ReadLE32(m + 56);
224  x15 ^= ReadLE32(m + 60);
225 
226  ++j12;
227  if (!j12) ++j13;
228 
229  WriteLE32(c + 0, x0);
230  WriteLE32(c + 4, x1);
231  WriteLE32(c + 8, x2);
232  WriteLE32(c + 12, x3);
233  WriteLE32(c + 16, x4);
234  WriteLE32(c + 20, x5);
235  WriteLE32(c + 24, x6);
236  WriteLE32(c + 28, x7);
237  WriteLE32(c + 32, x8);
238  WriteLE32(c + 36, x9);
239  WriteLE32(c + 40, x10);
240  WriteLE32(c + 44, x11);
241  WriteLE32(c + 48, x12);
242  WriteLE32(c + 52, x13);
243  WriteLE32(c + 56, x14);
244  WriteLE32(c + 60, x15);
245 
246  if (bytes <= 64) {
247  if (bytes < 64) {
248  for (i = 0;i < bytes;++i) ctarget[i] = c[i];
249  }
250  input[12] = j12;
251  input[13] = j13;
252  return;
253  }
254  bytes -= 64;
255  c += 64;
256  m += 64;
257  }
258 }
void Keystream(unsigned char *c, size_t bytes)
outputs the keystream of size <bytes> into
Definition: chacha20.cpp:74
uint32_t input[16]
Definition: chacha20.h:16
void SetIV(uint64_t iv)
Definition: chacha20.cpp:62
ChaCha20()
Definition: chacha20.cpp:52
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:130
void Seek(uint64_t pos)
Definition: chacha20.cpp:68
void SetKey(const unsigned char *key, size_t keylen)
set key with flexible keylength; 256bit recommended *‍/
Definition: chacha20.cpp:24
#define QUARTERROUND(a, b, c, d)
Definition: chacha20.cpp:15