File Coverage

chacha.c
Criterion Covered Total %
statement 129 133 96.9
branch 51 64 79.6
condition n/a
subroutine n/a
pod n/a
total 180 197 91.3


line stmt bran cond sub pod time code
1             /*
2             * The ChaCha(20) CSPRNG interface.
3             * New simple core, 10 Apr 2017, Dana Jacobsen
4             * Follows RFC 7539, including test vectors.
5             * Uses 64-bit counter, 64-bit nonce.
6             *
7             * TODO: update to RFC 8439 (June 2018).
8             */
9              
10             /* Some benchmarks, repeatedly calling random_bytes(32768). Time is
11             * shown as nanoseconds per 32-bit word.
12             *
13             * 3700 ns/word ChaCha20 in Perl
14             * 760 ns/word ISAAC in Perl
15             *
16             * 16.89 ns/word ChaCha20 (simple from insane coding)
17             * 11.20 ns/word ChaCha20 (openbsd)
18             * 10.31 ns/word ChaCha20 (dj)
19             * 3.26 ns/word ISAAC
20             * 2.23 ns/word ChaCha20 (AVX2 Neves)
21             * 1.95 ns/word PCG64
22             * 1.84 ns/word ChaCha20 (AVX2 chacha-opt)
23             * 1.48 ns/word Xoroshiro128+
24             * 1.16 ns/word SplitMix64
25             */
26              
27             #include
28             #include
29             #include
30             #include "ptypes.h"
31             #include "chacha.h"
32              
33             #define CHACHA_ROUNDS 20
34             #define RUN_INTERNAL_TESTS 1
35             #define RESEED_ON_REFILL 0
36              
37             /*****************************************************************************/
38             /* Chacha routines: init, quarter round, core, keystream */
39             /*****************************************************************************/
40              
41             /* On UltraSparc, Perl's versions of these macros will crash. */
42             #if !defined(__x86_64__)
43             #undef U8TO32_LE
44             #undef U32TO8_LE
45             #endif
46              
47             #ifndef U8TO32_LE
48             #define U8TO32_LE(p) \
49             ((uint32_t)(p)[0] | \
50             (uint32_t)(p)[1] << 8 | \
51             (uint32_t)(p)[2] << 16 | \
52             (uint32_t)(p)[3] << 24)
53             #endif
54             #ifndef U32TO8_LE
55             #define U32TO8_LE(p, v) \
56             do { uint32_t _v = v; \
57             (p)[0] = _v & 0xFF; \
58             (p)[1] = _v >> 8 & 0xFF; \
59             (p)[2] = _v >> 16 & 0xFF; \
60             (p)[3] = _v >> 24 & 0xFF; \
61             } while (0)
62             #endif
63              
64 1096           static void init_context(chacha_context_t *ctx, const unsigned char *seed, bool init_buffer)
65             {
66 1096           uint32_t *x = ctx->state;
67              
68 1096           x[ 0] = 0x61707865; /* "expa" */
69 1096           x[ 1] = 0x3320646e; /* "nd 3" */
70 1096           x[ 2] = 0x79622d32; /* "2-by" */
71 1096           x[ 3] = 0x6b206574; /* "te k" */
72             #if __LITTLE_ENDIAN__ || (defined(BYTEORDER) && (BYTEORDER == 0x1234 || BYTEORDER == 0x12345678))
73 1096           memcpy(x+4, seed, 32);
74 1096           x[12] = 0;
75 1096           x[13] = 0;
76 1096           memcpy(x+14, seed+32, 8);
77             #else
78             x[ 4] = U8TO32_LE(seed + 0);
79             x[ 5] = U8TO32_LE(seed + 4);
80             x[ 6] = U8TO32_LE(seed + 8);
81             x[ 7] = U8TO32_LE(seed + 12);
82             x[ 8] = U8TO32_LE(seed + 16);
83             x[ 9] = U8TO32_LE(seed + 20);
84             x[10] = U8TO32_LE(seed + 24);
85             x[11] = U8TO32_LE(seed + 28);
86             x[12] = 0;
87             x[13] = 0;
88             x[14] = U8TO32_LE(seed + 32);
89             x[15] = U8TO32_LE(seed + 36);
90             #endif
91              
92 1096 50         if (init_buffer) {
93 1096           memset(ctx->buf, 0, BUFSZ);
94 1096           ctx->have = 0;
95             }
96 1096           }
97              
98 4294080           static INLINE uint32_t rotl32(uint32_t x, const unsigned int n) {
99 4294080           return (x << n) | (x >> (-n & 31));
100             }
101             #define QUARTERROUND(a,b,c,d) \
102             a += b; d = rotl32(d ^ a, 16); \
103             c += d; b = rotl32(b ^ c, 12); \
104             a += b; d = rotl32(d ^ a, 8); \
105             c += d; b = rotl32(b ^ c, 7); \
106              
107             /* Produces buffer from state, does not change state */
108 13416           static void chacha_core(unsigned char buf[64], const uint32_t s[16]) {
109             uint32_t i, x[16];
110              
111 13416           memcpy(x, s, 16*sizeof(uint32_t));
112              
113 147576 100         for (i = 0; i < CHACHA_ROUNDS; i += 2) {
114 134160           QUARTERROUND( x[ 0], x[ 4], x[ 8], x[12] );
115 134160           QUARTERROUND( x[ 1], x[ 5], x[ 9], x[13] );
116 134160           QUARTERROUND( x[ 2], x[ 6], x[10], x[14] );
117 134160           QUARTERROUND( x[ 3], x[ 7], x[11], x[15] );
118 134160           QUARTERROUND( x[ 0], x[ 5], x[10], x[15] );
119 134160           QUARTERROUND( x[ 1], x[ 6], x[11], x[12] );
120 134160           QUARTERROUND( x[ 2], x[ 7], x[ 8], x[13] );
121 134160           QUARTERROUND( x[ 3], x[ 4], x[ 9], x[14] );
122             }
123              
124 228072 100         for (i = 0; i < 16; i++)
125 214656           x[i] += s[i];
126              
127             #if __LITTLE_ENDIAN__ || (defined(BYTEORDER) && (BYTEORDER == 0x1234 || BYTEORDER == 0x12345678))
128 13416           memcpy(buf, x, 16*sizeof(uint32_t));
129             #else
130             for (i = 0; i < 16; i++)
131             U32TO8_LE(buf+4*i, x[i]);
132             #endif
133 13416           }
134              
135 12696           static INLINE void increment_chacha_counter(chacha_context_t *ctx) {
136             /* Use the original 64-bit counter. */
137 12696 50         if (++ctx->state[12] == 0)
138 0           ctx->state[13]++;
139 12696           }
140              
141 981           static uint32_t chacha_keystream(unsigned char* buf, uint32_t n, chacha_context_t *ctx) {
142 981           uint32_t r = n;
143 13557 100         while (r >= CORESZ) {
144 12576           chacha_core(buf, ctx->state);
145 12576           increment_chacha_counter(ctx);
146 12576           buf += CORESZ;
147 12576           r -= CORESZ;
148             }
149 981 100         if (r > 0) {
150             unsigned char sbuf[CORESZ];
151 120           chacha_core(sbuf, ctx->state);
152 120           increment_chacha_counter(ctx);
153 120           memcpy(buf, sbuf, r);
154             }
155 981           return n;
156             }
157              
158             /* The method for refilling our buffer. This includes reseeding policy.
159             */
160 741           static uint32_t _refill_buffer(chacha_context_t *ctx) {
161             #if RESEED_ON_REFILL
162             ctx->have = (uint16_t) chacha_keystream(ctx->buf, BUFSZ, ctx);
163             init_context(ctx, ctx->buf, FALSE);
164             memset(ctx->buf, 0, KEYSZ);
165             ctx->have = BUFSZ - KEYSZ;
166             #else
167 741           ctx->have = (uint16_t) chacha_keystream(ctx->buf, BUFSZ, ctx);
168             #endif
169 741           return ctx->have;
170             }
171              
172              
173             /*****************************************************************************/
174             /* Test vectors */
175             /*****************************************************************************/
176             #if RUN_INTERNAL_TESTS
177 120           static bool _test_qr(void) {
178             uint32_t i;
179 120           uint32_t tv1i[4] = {0x11111111, 0x01020304, 0x9b8d6f43, 0x01234567};
180 120           const uint32_t tv1o[4] = {0xea2a92f4, 0xcb1cf8ce, 0x4581472e, 0x5881c4bb};
181 120           uint32_t tv2i[4] = {0x516461b1, 0x2a5f714c, 0x53372767, 0x3d631689};
182 120           const uint32_t tv2o[4] = {0xbdb886dc, 0xcfacafd2, 0xe46bea80, 0xccc07c79};
183              
184 120           QUARTERROUND(tv1i[0],tv1i[1],tv1i[2],tv1i[3]);
185 120           QUARTERROUND(tv2i[0],tv2i[1],tv2i[2],tv2i[3]);
186 600 100         for (i = 0; i < 4; i++) {
187 480 50         if (tv1i[i] != tv1o[i]) croak("QR test 2.1.1 fail %u\n",i);
188 480 50         if (tv2i[i] != tv2o[i]) croak("QR test 2.2.1 fail %u\n",i);
189             }
190 120           return TRUE;
191             }
192             /* Test 5 is RFC7539 2.3.2 */
193 120           static bool _test_core(void) {
194             uint32_t test, i;
195 120           unsigned char keys[6][40] = { {0},{0},{0},{0},{0} };
196 120           char ebuf[6][129] = {
197             "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586",
198             "4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d792b1c43fea817e9ad275ae546963",
199             "de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df137821031e85a050278a7084527214f73efc7fa5b5277062eb7a0433e445f41e31afab757",
200             "ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd138e50d32111e4caf237ee53ca8ad6426194a88545ddc497a0b466e7d6bbdb0041b2f586b",
201             "f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f15916155c2be8241a",
202             "10f1e7e4d13b5915500fdd1fa32071c4c7d1f4c733c068030422aa9ac3d46c4ed2826446079faa0914c2d705d98b02a2b5129cd1de164eb9cbd083e8a2503c4e",
203             };
204 120           keys[1][31] = 1;
205 120           keys[2][39] = 1;
206 120           keys[3][32] = 1;
207 4920 100         for (i = 0; i < 40; i++) keys[4][i] = (unsigned char) i % 32;
208 3960 100         for (i = 0; i < 32; i++) keys[5][i] = (unsigned char) i;
209 120           keys[5][35] = 0x4a;
210              
211             if (CHACHA_ROUNDS != 20) return FALSE;
212             { /* Ensure the "have" variable is large enough to store a buffer */
213             chacha_context_t ctx;
214             if (BUFSZ >> (8*sizeof(ctx.have)) != 0)
215             croak("BUFSZ is set too large for context");
216             }
217              
218 840 100         for (test = 0; test < 6; test++) {
219 720           unsigned char* key = keys[test];
220 720           const char* expout = ebuf[test];
221             char got[129];
222             chacha_context_t ctx;
223 720           init_context(&ctx, key, TRUE);
224 720 100         if (test == 5) { ctx.state[12]=1; ctx.state[13]=0x09000000; }
225 720           chacha_core(ctx.buf, ctx.state);
226 720 100         if (test == 0) {
227 1560 100         for (i = 4; i < 16; i++)
228 1440 50         if (ctx.state[i] != 0)
229 0           croak("core modified state");
230             }
231 46800 100         for (i = 0; i < 64; i++)
232 46080           sprintf(got+2*i, "%02x", ctx.buf[i]);
233 720           got[128] = '\0';
234 720 50         if (memcmp(got, expout, 128))
235 0           croak("fail core test vector %u:\n exp %s\n got %s\n",test,expout,got);
236             }
237 120           return TRUE;
238             }
239 120           static bool _test_keystream(void) {
240             uint32_t test, i;
241 120           unsigned char keys[2][40] = { {0},{0} };
242             static const char ebuf[2][1024+1] = {
243             "f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f15916155c2be8241a38008b9a26bc35941e2444177c8ade6689de95264986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a475032b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c507b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f76dad3979e5c5360c3317166a1c894c94a371876a94df7628fe4eaaf2ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab78fab78c9",
244             "af051e40bba0354981329a806a140eafd258a22a6dcb4bb9f6569cb3efe2deaf837bd87ca20b5ba12081a306af0eb35c41a239d20dfc74c81771560d9c9c1e4b224f51f3401bd9e12fde276fb8631ded8c131f823d2c06e27e4fcaec9ef3cf788a3b0aa372600a92b57974cded2b9334794cba40c63e34cdea212c4cf07d41b769a6749f3f630f4122cafe28ec4dc47e26d4346d70b98c73f3e9c53ac40c5945398b6eda1a832c89c167eacd901d7e2bf363",
245             };
246 4920 100         for (i = 0; i < 40; i++) keys[0][i] = (unsigned char) i % 32;
247 3960 100         for (i = 0; i < 32; i++) keys[1][i] = (unsigned char) i;
248 120           keys[1][35] = 0x4a;
249              
250             if (CHACHA_ROUNDS != 20) return FALSE;
251              
252 360 100         for (test = 0; test < 2; test++) {
253 240           unsigned char* key = keys[test];
254 240           const char* expout = ebuf[test];
255             unsigned char kbuf[512];
256             char got[1024+1];
257 240           uint32_t gen, len = strlen(expout) / 2;
258             chacha_context_t ctx;
259              
260 240 50         if (len > 512) croak("Test vector too large");
261 240           init_context(&ctx, key, TRUE);
262 240           gen = chacha_keystream(kbuf, len, &ctx);
263 240 50         if (gen < len) croak("short keystream");
264             /* Check state block counter */
265 52320 100         for (i = 0; i < len; i++)
266 52080           sprintf(got+2*i, "%02x", kbuf[i]);
267 240           got[2*len] = '\0';
268 240 50         if (memcmp(got, expout, 2*len))
269 0           croak("fail keystream test vector %u:\n exp %s\n got %s\n",test,expout,got);
270             }
271 120           return TRUE;
272             }
273              
274 120           bool chacha_selftest(void) {
275 120 50         return _test_qr() && _test_core() && _test_keystream();
    50          
    50          
276             }
277             #else
278             bool chacha_selftest(void) { return TRUE; }
279             #endif
280              
281             /*****************************************************************************/
282             /* API */
283             /*****************************************************************************/
284              
285 136           void chacha_seed(chacha_context_t *cs, uint32_t bytes, const unsigned char* data, bool good)
286             {
287 136 50         if (bytes < 40) croak("Not enough seed bytes given to ChaCha\n");
288 136           init_context(cs, data, TRUE);
289 136           cs->goodseed = good;
290 136           }
291 33           void chacha_rand_bytes(chacha_context_t *cs, uint32_t bytes, unsigned char* data)
292             {
293 65 100         while (bytes > 0) {
294             uint32_t copybytes;
295 32 100         if (cs->have == 0)
296 8           _refill_buffer(cs);
297 32           copybytes = (bytes > cs->have) ? cs->have : bytes;
298 32           memcpy(data, cs->buf + BUFSZ - cs->have, copybytes);
299 32           data += copybytes;
300 32           cs->have -= copybytes;
301 32           bytes -= copybytes;
302             }
303 33           }
304 184981           uint32_t chacha_irand32(chacha_context_t *cs)
305             {
306             uint32_t a;
307             unsigned char* ptr;
308 184981 100         if (cs->have < 4)
309 733           _refill_buffer(cs);
310 184981           ptr = cs->buf + BUFSZ - cs->have;
311 184981           cs->have -= 4;
312 184981           a = U8TO32_LE(ptr);
313 184981           return a;
314             }
315             #if BITS_PER_WORD == 64
316 17277           UV chacha_irand64(chacha_context_t *cs)
317             {
318 17277           uint32_t a = chacha_irand32(cs);
319 17277           uint32_t b = chacha_irand32(cs);
320 17277           return (UV)a << 32 | b;
321             }
322             #else
323             UV chacha_irand64(chacha_context_t *cs) { return chacha_irand32(cs); }
324             #endif