build: Fix build with !HAVE_PTHREAD
[libgcrypt.git] / cipher / chacha20.c
1 /* chacha20.c  -  Bernstein's ChaCha20 cipher
2  * Copyright (C) 2014,2017-2019 Jussi Kivilinna <jussi.kivilinna@iki.fi>
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser general Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  *
19  * For a description of the algorithm, see:
20  *   http://cr.yp.to/chacha.html
21  */
22
23 /*
24  * Based on D. J. Bernstein reference implementation at
25  * http://cr.yp.to/chacha.html:
26  *
27  * chacha-regs.c version 20080118
28  * D. J. Bernstein
29  * Public domain.
30  */
31
32 #include <config.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include "types.h"
37 #include "g10lib.h"
38 #include "cipher.h"
39 #include "cipher-internal.h"
40 #include "bufhelp.h"
41
42
43 #define CHACHA20_MIN_KEY_SIZE 16        /* Bytes.  */
44 #define CHACHA20_MAX_KEY_SIZE 32        /* Bytes.  */
45 #define CHACHA20_BLOCK_SIZE   64        /* Bytes.  */
46 #define CHACHA20_MIN_IV_SIZE   8        /* Bytes.  */
47 #define CHACHA20_MAX_IV_SIZE  12        /* Bytes.  */
48 #define CHACHA20_CTR_SIZE     16        /* Bytes.  */
49
50
51 /* USE_SSSE3 indicates whether to compile with Intel SSSE3 code. */
52 #undef USE_SSSE3
53 #if defined(__x86_64__) && defined(HAVE_GCC_INLINE_ASM_SSSE3) && \
54    (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
55     defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS))
56 # define USE_SSSE3 1
57 #endif
58
59 /* USE_AVX2 indicates whether to compile with Intel AVX2 code. */
60 #undef USE_AVX2
61 #if defined(__x86_64__) && defined(HAVE_GCC_INLINE_ASM_AVX2) && \
62     (defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) || \
63      defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS))
64 # define USE_AVX2 1
65 #endif
66
67 /* USE_ARMV7_NEON indicates whether to enable ARMv7 NEON assembly code. */
68 #undef USE_ARMV7_NEON
69 #ifdef ENABLE_NEON_SUPPORT
70 # if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) \
71      && defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) \
72      && defined(HAVE_GCC_INLINE_ASM_NEON)
73 #  define USE_ARMV7_NEON 1
74 # endif
75 #endif
76
77 /* USE_AARCH64_SIMD indicates whether to enable ARMv8 SIMD assembly
78  * code. */
79 #undef USE_AARCH64_SIMD
80 #ifdef ENABLE_NEON_SUPPORT
81 # if defined(__AARCH64EL__) \
82        && defined(HAVE_COMPATIBLE_GCC_AARCH64_PLATFORM_AS) \
83        && defined(HAVE_GCC_INLINE_ASM_AARCH64_NEON)
84 #  define USE_AARCH64_SIMD 1
85 # endif
86 #endif
87
88 /* Assembly implementations use SystemV ABI, ABI conversion and additional
89  * stack to store XMM6-XMM15 needed on Win64. */
90 #undef ASM_FUNC_ABI
91 #undef ASM_EXTRA_STACK
92 #if defined(HAVE_COMPATIBLE_GCC_WIN64_PLATFORM_AS)
93 # define ASM_FUNC_ABI __attribute__((sysv_abi))
94 #else
95 # define ASM_FUNC_ABI
96 #endif
97
98
99 typedef struct CHACHA20_context_s
100 {
101   u32 input[16];
102   unsigned char pad[CHACHA20_BLOCK_SIZE];
103   unsigned int unused; /* bytes in the pad.  */
104   int use_ssse3:1;
105   int use_avx2:1;
106   int use_neon:1;
107 } CHACHA20_context_t;
108
109
110 #ifdef USE_SSSE3
111
112 unsigned int _gcry_chacha20_amd64_ssse3_blocks4(u32 *state, byte *dst,
113                                                 const byte *src,
114                                                 size_t nblks) ASM_FUNC_ABI;
115
116 unsigned int _gcry_chacha20_amd64_ssse3_blocks1(u32 *state, byte *dst,
117                                                 const byte *src,
118                                                 size_t nblks) ASM_FUNC_ABI;
119
120 unsigned int _gcry_chacha20_poly1305_amd64_ssse3_blocks4(
121                 u32 *state, byte *dst, const byte *src, size_t nblks,
122                 void *poly1305_state, const byte *poly1305_src) ASM_FUNC_ABI;
123
124 unsigned int _gcry_chacha20_poly1305_amd64_ssse3_blocks1(
125                 u32 *state, byte *dst, const byte *src, size_t nblks,
126                 void *poly1305_state, const byte *poly1305_src) ASM_FUNC_ABI;
127
128 #endif /* USE_SSSE3 */
129
130 #ifdef USE_AVX2
131
132 unsigned int _gcry_chacha20_amd64_avx2_blocks8(u32 *state, byte *dst,
133                                                const byte *src,
134                                                size_t nblks) ASM_FUNC_ABI;
135
136 unsigned int _gcry_chacha20_poly1305_amd64_avx2_blocks8(
137                 u32 *state, byte *dst, const byte *src, size_t nblks,
138                 void *poly1305_state, const byte *poly1305_src) ASM_FUNC_ABI;
139
140 #endif /* USE_AVX2 */
141
142 #ifdef USE_ARMV7_NEON
143
144 unsigned int _gcry_chacha20_armv7_neon_blocks4(u32 *state, byte *dst,
145                                                const byte *src,
146                                                size_t nblks);
147
148 #endif /* USE_ARMV7_NEON */
149
150 #ifdef USE_AARCH64_SIMD
151
152 unsigned int _gcry_chacha20_aarch64_blocks4(u32 *state, byte *dst,
153                                             const byte *src, size_t nblks);
154
155 #endif /* USE_AARCH64_SIMD */
156
157
158 static const char *selftest (void);
159 \f
160
161 #define ROTATE(v,c)     (rol(v,c))
162 #define XOR(v,w)        ((v) ^ (w))
163 #define PLUS(v,w)       ((u32)((v) + (w)))
164 #define PLUSONE(v)      (PLUS((v),1))
165
166 #define QUARTERROUND(a,b,c,d) \
167   a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
168   c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
169   a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
170   c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
171
172 #define BUF_XOR_LE32(dst, src, offset, x) \
173   buf_put_le32((dst) + (offset), buf_get_le32((src) + (offset)) ^ (x))
174
175 static unsigned int
176 do_chacha20_blocks (u32 *input, byte *dst, const byte *src, size_t nblks)
177 {
178   u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
179   unsigned int i;
180
181   while (nblks)
182     {
183       x0 = input[0];
184       x1 = input[1];
185       x2 = input[2];
186       x3 = input[3];
187       x4 = input[4];
188       x5 = input[5];
189       x6 = input[6];
190       x7 = input[7];
191       x8 = input[8];
192       x9 = input[9];
193       x10 = input[10];
194       x11 = input[11];
195       x12 = input[12];
196       x13 = input[13];
197       x14 = input[14];
198       x15 = input[15];
199
200       for (i = 20; i > 0; i -= 2)
201         {
202           QUARTERROUND(x0, x4,  x8, x12)
203           QUARTERROUND(x1, x5,  x9, x13)
204           QUARTERROUND(x2, x6, x10, x14)
205           QUARTERROUND(x3, x7, x11, x15)
206           QUARTERROUND(x0, x5, x10, x15)
207           QUARTERROUND(x1, x6, x11, x12)
208           QUARTERROUND(x2, x7,  x8, x13)
209           QUARTERROUND(x3, x4,  x9, x14)
210         }
211
212       x0 = PLUS(x0, input[0]);
213       x1 = PLUS(x1, input[1]);
214       x2 = PLUS(x2, input[2]);
215       x3 = PLUS(x3, input[3]);
216       x4 = PLUS(x4, input[4]);
217       x5 = PLUS(x5, input[5]);
218       x6 = PLUS(x6, input[6]);
219       x7 = PLUS(x7, input[7]);
220       x8 = PLUS(x8, input[8]);
221       x9 = PLUS(x9, input[9]);
222       x10 = PLUS(x10, input[10]);
223       x11 = PLUS(x11, input[11]);
224       x12 = PLUS(x12, input[12]);
225       x13 = PLUS(x13, input[13]);
226       x14 = PLUS(x14, input[14]);
227       x15 = PLUS(x15, input[15]);
228
229       input[12] = PLUSONE(input[12]);
230       input[13] = PLUS(input[13], !input[12]);
231
232       BUF_XOR_LE32(dst, src, 0, x0);
233       BUF_XOR_LE32(dst, src, 4, x1);
234       BUF_XOR_LE32(dst, src, 8, x2);
235       BUF_XOR_LE32(dst, src, 12, x3);
236       BUF_XOR_LE32(dst, src, 16, x4);
237       BUF_XOR_LE32(dst, src, 20, x5);
238       BUF_XOR_LE32(dst, src, 24, x6);
239       BUF_XOR_LE32(dst, src, 28, x7);
240       BUF_XOR_LE32(dst, src, 32, x8);
241       BUF_XOR_LE32(dst, src, 36, x9);
242       BUF_XOR_LE32(dst, src, 40, x10);
243       BUF_XOR_LE32(dst, src, 44, x11);
244       BUF_XOR_LE32(dst, src, 48, x12);
245       BUF_XOR_LE32(dst, src, 52, x13);
246       BUF_XOR_LE32(dst, src, 56, x14);
247       BUF_XOR_LE32(dst, src, 60, x15);
248
249       src += CHACHA20_BLOCK_SIZE;
250       dst += CHACHA20_BLOCK_SIZE;
251       nblks--;
252     }
253
254   /* burn_stack */
255   return (17 * sizeof(u32) + 6 * sizeof(void *));
256 }
257
258
259 static unsigned int
260 chacha20_blocks (CHACHA20_context_t *ctx, byte *dst, const byte *src,
261                  size_t nblks)
262 {
263 #ifdef USE_SSSE3
264   if (ctx->use_ssse3)
265     {
266       return _gcry_chacha20_amd64_ssse3_blocks1(ctx->input, dst, src, nblks);
267     }
268 #endif
269
270   return do_chacha20_blocks (ctx->input, dst, src, nblks);
271 }
272
273
274 static void
275 chacha20_keysetup (CHACHA20_context_t *ctx, const byte *key,
276                    unsigned int keylen)
277 {
278   static const char sigma[16] = "expand 32-byte k";
279   static const char tau[16] = "expand 16-byte k";
280   const char *constants;
281
282   ctx->input[4] = buf_get_le32(key + 0);
283   ctx->input[5] = buf_get_le32(key + 4);
284   ctx->input[6] = buf_get_le32(key + 8);
285   ctx->input[7] = buf_get_le32(key + 12);
286   if (keylen == CHACHA20_MAX_KEY_SIZE) /* 256 bits */
287     {
288       key += 16;
289       constants = sigma;
290     }
291   else /* 128 bits */
292     {
293       constants = tau;
294     }
295   ctx->input[8] = buf_get_le32(key + 0);
296   ctx->input[9] = buf_get_le32(key + 4);
297   ctx->input[10] = buf_get_le32(key + 8);
298   ctx->input[11] = buf_get_le32(key + 12);
299   ctx->input[0] = buf_get_le32(constants + 0);
300   ctx->input[1] = buf_get_le32(constants + 4);
301   ctx->input[2] = buf_get_le32(constants + 8);
302   ctx->input[3] = buf_get_le32(constants + 12);
303 }
304
305
306 static void
307 chacha20_ivsetup (CHACHA20_context_t * ctx, const byte *iv, size_t ivlen)
308 {
309   if (ivlen == CHACHA20_CTR_SIZE)
310     {
311       ctx->input[12] = buf_get_le32 (iv + 0);
312       ctx->input[13] = buf_get_le32 (iv + 4);
313       ctx->input[14] = buf_get_le32 (iv + 8);
314       ctx->input[15] = buf_get_le32 (iv + 12);
315     }
316   else if (ivlen == CHACHA20_MAX_IV_SIZE)
317     {
318       ctx->input[12] = 0;
319       ctx->input[13] = buf_get_le32 (iv + 0);
320       ctx->input[14] = buf_get_le32 (iv + 4);
321       ctx->input[15] = buf_get_le32 (iv + 8);
322     }
323   else if (ivlen == CHACHA20_MIN_IV_SIZE)
324     {
325       ctx->input[12] = 0;
326       ctx->input[13] = 0;
327       ctx->input[14] = buf_get_le32 (iv + 0);
328       ctx->input[15] = buf_get_le32 (iv + 4);
329     }
330   else
331     {
332       ctx->input[12] = 0;
333       ctx->input[13] = 0;
334       ctx->input[14] = 0;
335       ctx->input[15] = 0;
336     }
337 }
338
339
340 static void
341 chacha20_setiv (void *context, const byte *iv, size_t ivlen)
342 {
343   CHACHA20_context_t *ctx = (CHACHA20_context_t *) context;
344
345   /* draft-nir-cfrg-chacha20-poly1305-02 defines 96-bit and 64-bit nonce. */
346   if (iv && ivlen != CHACHA20_MAX_IV_SIZE && ivlen != CHACHA20_MIN_IV_SIZE
347       && ivlen != CHACHA20_CTR_SIZE)
348     log_info ("WARNING: chacha20_setiv: bad ivlen=%u\n", (u32) ivlen);
349
350   if (iv && (ivlen == CHACHA20_MAX_IV_SIZE || ivlen == CHACHA20_MIN_IV_SIZE
351              || ivlen == CHACHA20_CTR_SIZE))
352     chacha20_ivsetup (ctx, iv, ivlen);
353   else
354     chacha20_ivsetup (ctx, NULL, 0);
355
356   /* Reset the unused pad bytes counter.  */
357   ctx->unused = 0;
358 }
359
360
361 static gcry_err_code_t
362 chacha20_do_setkey (CHACHA20_context_t *ctx,
363                     const byte *key, unsigned int keylen)
364 {
365   static int initialized;
366   static const char *selftest_failed;
367   unsigned int features = _gcry_get_hw_features ();
368
369   if (!initialized)
370     {
371       initialized = 1;
372       selftest_failed = selftest ();
373       if (selftest_failed)
374         log_error ("CHACHA20 selftest failed (%s)\n", selftest_failed);
375     }
376   if (selftest_failed)
377     return GPG_ERR_SELFTEST_FAILED;
378
379   if (keylen != CHACHA20_MAX_KEY_SIZE && keylen != CHACHA20_MIN_KEY_SIZE)
380     return GPG_ERR_INV_KEYLEN;
381
382 #ifdef USE_SSSE3
383   ctx->use_ssse3 = (features & HWF_INTEL_SSSE3) != 0;
384 #endif
385 #ifdef USE_AVX2
386   ctx->use_avx2 = (features & HWF_INTEL_AVX2) != 0;
387 #endif
388 #ifdef USE_ARMV7_NEON
389   ctx->use_neon = (features & HWF_ARM_NEON) != 0;
390 #endif
391 #ifdef USE_AARCH64_SIMD
392   ctx->use_neon = (features & HWF_ARM_NEON) != 0;
393 #endif
394
395   (void)features;
396
397   chacha20_keysetup (ctx, key, keylen);
398
399   /* We default to a zero nonce.  */
400   chacha20_setiv (ctx, NULL, 0);
401
402   return 0;
403 }
404
405
406 static gcry_err_code_t
407 chacha20_setkey (void *context, const byte *key, unsigned int keylen,
408                  gcry_cipher_hd_t hd)
409 {
410   CHACHA20_context_t *ctx = (CHACHA20_context_t *) context;
411   gcry_err_code_t rc = chacha20_do_setkey (ctx, key, keylen);
412   (void)hd;
413   _gcry_burn_stack (4 + sizeof (void *) + 4 * sizeof (void *));
414   return rc;
415 }
416
417
418 static unsigned int
419 do_chacha20_encrypt_stream_tail (CHACHA20_context_t *ctx, byte *outbuf,
420                                  const byte *inbuf, size_t length)
421 {
422   static const unsigned char zero_pad[CHACHA20_BLOCK_SIZE] = { 0, };
423   unsigned int nburn, burn = 0;
424
425 #ifdef USE_AVX2
426   if (ctx->use_avx2 && length >= CHACHA20_BLOCK_SIZE * 8)
427     {
428       size_t nblocks = length / CHACHA20_BLOCK_SIZE;
429       nblocks -= nblocks % 8;
430       nburn = _gcry_chacha20_amd64_avx2_blocks8(ctx->input, outbuf, inbuf,
431                                                 nblocks);
432       burn = nburn > burn ? nburn : burn;
433       length -= nblocks * CHACHA20_BLOCK_SIZE;
434       outbuf += nblocks * CHACHA20_BLOCK_SIZE;
435       inbuf  += nblocks * CHACHA20_BLOCK_SIZE;
436     }
437 #endif
438
439 #ifdef USE_SSSE3
440   if (ctx->use_ssse3 && length >= CHACHA20_BLOCK_SIZE * 4)
441     {
442       size_t nblocks = length / CHACHA20_BLOCK_SIZE;
443       nblocks -= nblocks % 4;
444       nburn = _gcry_chacha20_amd64_ssse3_blocks4(ctx->input, outbuf, inbuf,
445                                                  nblocks);
446       burn = nburn > burn ? nburn : burn;
447       length -= nblocks * CHACHA20_BLOCK_SIZE;
448       outbuf += nblocks * CHACHA20_BLOCK_SIZE;
449       inbuf  += nblocks * CHACHA20_BLOCK_SIZE;
450     }
451 #endif
452
453 #ifdef USE_ARMV7_NEON
454   if (ctx->use_neon && length >= CHACHA20_BLOCK_SIZE * 4)
455     {
456       size_t nblocks = length / CHACHA20_BLOCK_SIZE;
457       nblocks -= nblocks % 4;
458       nburn = _gcry_chacha20_armv7_neon_blocks4(ctx->input, outbuf, inbuf,
459                                                 nblocks);
460       burn = nburn > burn ? nburn : burn;
461       length -= nblocks * CHACHA20_BLOCK_SIZE;
462       outbuf += nblocks * CHACHA20_BLOCK_SIZE;
463       inbuf  += nblocks * CHACHA20_BLOCK_SIZE;
464     }
465 #endif
466
467 #ifdef USE_AARCH64_SIMD
468   if (ctx->use_neon && length >= CHACHA20_BLOCK_SIZE * 4)
469     {
470       size_t nblocks = length / CHACHA20_BLOCK_SIZE;
471       nblocks -= nblocks % 4;
472       nburn = _gcry_chacha20_aarch64_blocks4(ctx->input, outbuf, inbuf,
473                                              nblocks);
474       burn = nburn > burn ? nburn : burn;
475       length -= nblocks * CHACHA20_BLOCK_SIZE;
476       outbuf += nblocks * CHACHA20_BLOCK_SIZE;
477       inbuf  += nblocks * CHACHA20_BLOCK_SIZE;
478     }
479 #endif
480
481   if (length >= CHACHA20_BLOCK_SIZE)
482     {
483       size_t nblocks = length / CHACHA20_BLOCK_SIZE;
484       nburn = chacha20_blocks(ctx, outbuf, inbuf, nblocks);
485       burn = nburn > burn ? nburn : burn;
486       length -= nblocks * CHACHA20_BLOCK_SIZE;
487       outbuf += nblocks * CHACHA20_BLOCK_SIZE;
488       inbuf  += nblocks * CHACHA20_BLOCK_SIZE;
489     }
490
491   if (length > 0)
492     {
493       nburn = chacha20_blocks(ctx, ctx->pad, zero_pad, 1);
494       burn = nburn > burn ? nburn : burn;
495
496       buf_xor (outbuf, inbuf, ctx->pad, length);
497       ctx->unused = CHACHA20_BLOCK_SIZE - length;
498     }
499
500   if (burn)
501     burn += 5 * sizeof(void *);
502
503   return burn;
504 }
505
506
507 static void
508 chacha20_encrypt_stream (void *context, byte *outbuf, const byte *inbuf,
509                          size_t length)
510 {
511   CHACHA20_context_t *ctx = (CHACHA20_context_t *) context;
512   unsigned int nburn, burn = 0;
513
514   if (!length)
515     return;
516
517   if (ctx->unused)
518     {
519       unsigned char *p = ctx->pad;
520       size_t n;
521
522       gcry_assert (ctx->unused < CHACHA20_BLOCK_SIZE);
523
524       n = ctx->unused;
525       if (n > length)
526         n = length;
527
528       buf_xor (outbuf, inbuf, p + CHACHA20_BLOCK_SIZE - ctx->unused, n);
529       length -= n;
530       outbuf += n;
531       inbuf += n;
532       ctx->unused -= n;
533
534       if (!length)
535         return;
536       gcry_assert (!ctx->unused);
537     }
538
539   nburn = do_chacha20_encrypt_stream_tail (ctx, outbuf, inbuf, length);
540   burn = nburn > burn ? nburn : burn;
541
542   if (burn)
543     _gcry_burn_stack (burn);
544 }
545
546
547 gcry_err_code_t
548 _gcry_chacha20_poly1305_encrypt(gcry_cipher_hd_t c, byte *outbuf,
549                                 const byte *inbuf, size_t length)
550 {
551   CHACHA20_context_t *ctx = (void *) &c->context.c;
552   unsigned int nburn, burn = 0;
553   byte *authptr = NULL;
554
555   if (!length)
556     return 0;
557
558   if (ctx->unused)
559     {
560       unsigned char *p = ctx->pad;
561       size_t n;
562
563       gcry_assert (ctx->unused < CHACHA20_BLOCK_SIZE);
564
565       n = ctx->unused;
566       if (n > length)
567         n = length;
568
569       buf_xor (outbuf, inbuf, p + CHACHA20_BLOCK_SIZE - ctx->unused, n);
570       nburn = _gcry_poly1305_update_burn (&c->u_mode.poly1305.ctx, outbuf, n);
571       burn = nburn > burn ? nburn : burn;
572       length -= n;
573       outbuf += n;
574       inbuf += n;
575       ctx->unused -= n;
576
577       if (!length)
578         {
579           if (burn)
580             _gcry_burn_stack (burn);
581
582           return 0;
583         }
584       gcry_assert (!ctx->unused);
585     }
586
587   gcry_assert (c->u_mode.poly1305.ctx.leftover == 0);
588
589   if (0)
590     { }
591 #ifdef USE_AVX2
592   else if (ctx->use_avx2 && length >= CHACHA20_BLOCK_SIZE * 8)
593     {
594       nburn = _gcry_chacha20_amd64_avx2_blocks8(ctx->input, outbuf, inbuf, 8);
595       burn = nburn > burn ? nburn : burn;
596
597       authptr = outbuf;
598       length -= 8 * CHACHA20_BLOCK_SIZE;
599       outbuf += 8 * CHACHA20_BLOCK_SIZE;
600       inbuf  += 8 * CHACHA20_BLOCK_SIZE;
601     }
602 #endif
603 #ifdef USE_SSSE3
604   else if (ctx->use_ssse3 && length >= CHACHA20_BLOCK_SIZE * 4)
605     {
606       nburn = _gcry_chacha20_amd64_ssse3_blocks4(ctx->input, outbuf, inbuf, 4);
607       burn = nburn > burn ? nburn : burn;
608
609       authptr = outbuf;
610       length -= 4 * CHACHA20_BLOCK_SIZE;
611       outbuf += 4 * CHACHA20_BLOCK_SIZE;
612       inbuf  += 4 * CHACHA20_BLOCK_SIZE;
613     }
614   else if (ctx->use_ssse3 && length >= CHACHA20_BLOCK_SIZE * 2)
615     {
616       nburn = _gcry_chacha20_amd64_ssse3_blocks1(ctx->input, outbuf, inbuf, 2);
617       burn = nburn > burn ? nburn : burn;
618
619       authptr = outbuf;
620       length -= 2 * CHACHA20_BLOCK_SIZE;
621       outbuf += 2 * CHACHA20_BLOCK_SIZE;
622       inbuf  += 2 * CHACHA20_BLOCK_SIZE;
623     }
624   else if (ctx->use_ssse3 && length >= CHACHA20_BLOCK_SIZE)
625     {
626       nburn = _gcry_chacha20_amd64_ssse3_blocks1(ctx->input, outbuf, inbuf, 1);
627       burn = nburn > burn ? nburn : burn;
628
629       authptr = outbuf;
630       length -= 1 * CHACHA20_BLOCK_SIZE;
631       outbuf += 1 * CHACHA20_BLOCK_SIZE;
632       inbuf  += 1 * CHACHA20_BLOCK_SIZE;
633     }
634 #endif
635
636   if (authptr)
637     {
638       size_t authoffset = outbuf - authptr;
639
640 #ifdef USE_AVX2
641       if (ctx->use_avx2 &&
642           length >= 8 * CHACHA20_BLOCK_SIZE &&
643           authoffset >= 8 * CHACHA20_BLOCK_SIZE)
644         {
645           size_t nblocks = length / CHACHA20_BLOCK_SIZE;
646           nblocks -= nblocks % 8;
647
648           nburn = _gcry_chacha20_poly1305_amd64_avx2_blocks8(
649                       ctx->input, outbuf, inbuf, nblocks,
650                       &c->u_mode.poly1305.ctx.state, authptr);
651           burn = nburn > burn ? nburn : burn;
652
653           length  -= nblocks * CHACHA20_BLOCK_SIZE;
654           outbuf  += nblocks * CHACHA20_BLOCK_SIZE;
655           inbuf   += nblocks * CHACHA20_BLOCK_SIZE;
656           authptr += nblocks * CHACHA20_BLOCK_SIZE;
657         }
658 #endif
659
660 #ifdef USE_SSSE3
661       if (ctx->use_ssse3)
662         {
663           if (length >= 4 * CHACHA20_BLOCK_SIZE &&
664               authoffset >= 4 * CHACHA20_BLOCK_SIZE)
665             {
666               size_t nblocks = length / CHACHA20_BLOCK_SIZE;
667               nblocks -= nblocks % 4;
668
669               nburn = _gcry_chacha20_poly1305_amd64_ssse3_blocks4(
670                           ctx->input, outbuf, inbuf, nblocks,
671                           &c->u_mode.poly1305.ctx.state, authptr);
672               burn = nburn > burn ? nburn : burn;
673
674               length  -= nblocks * CHACHA20_BLOCK_SIZE;
675               outbuf  += nblocks * CHACHA20_BLOCK_SIZE;
676               inbuf   += nblocks * CHACHA20_BLOCK_SIZE;
677               authptr += nblocks * CHACHA20_BLOCK_SIZE;
678             }
679
680           if (length >= CHACHA20_BLOCK_SIZE &&
681               authoffset >= CHACHA20_BLOCK_SIZE)
682             {
683               size_t nblocks = length / CHACHA20_BLOCK_SIZE;
684
685               nburn = _gcry_chacha20_poly1305_amd64_ssse3_blocks1(
686                           ctx->input, outbuf, inbuf, nblocks,
687                           &c->u_mode.poly1305.ctx.state, authptr);
688               burn = nburn > burn ? nburn : burn;
689
690               length  -= nblocks * CHACHA20_BLOCK_SIZE;
691               outbuf  += nblocks * CHACHA20_BLOCK_SIZE;
692               inbuf   += nblocks * CHACHA20_BLOCK_SIZE;
693               authptr += nblocks * CHACHA20_BLOCK_SIZE;
694             }
695         }
696 #endif
697
698       if (authoffset > 0)
699         {
700           _gcry_poly1305_update (&c->u_mode.poly1305.ctx, authptr, authoffset);
701           authptr += authoffset;
702           authoffset = 0;
703         }
704
705       gcry_assert(authptr == outbuf);
706     }
707
708   while (length)
709     {
710       size_t currlen = length;
711
712       /* Since checksumming is done after encryption, process input in 24KiB
713        * chunks to keep data loaded in L1 cache for checksumming. */
714       if (currlen > 24 * 1024)
715         currlen = 24 * 1024;
716
717       nburn = do_chacha20_encrypt_stream_tail (ctx, outbuf, inbuf, currlen);
718       burn = nburn > burn ? nburn : burn;
719
720       nburn = _gcry_poly1305_update_burn (&c->u_mode.poly1305.ctx, outbuf,
721                                           currlen);
722       burn = nburn > burn ? nburn : burn;
723
724       outbuf += currlen;
725       inbuf += currlen;
726       length -= currlen;
727     }
728
729   if (burn)
730     _gcry_burn_stack (burn);
731
732   return 0;
733 }
734
735
736 gcry_err_code_t
737 _gcry_chacha20_poly1305_decrypt(gcry_cipher_hd_t c, byte *outbuf,
738                                 const byte *inbuf, size_t length)
739 {
740   CHACHA20_context_t *ctx = (void *) &c->context.c;
741   unsigned int nburn, burn = 0;
742
743   if (!length)
744     return 0;
745
746   if (ctx->unused)
747     {
748       unsigned char *p = ctx->pad;
749       size_t n;
750
751       gcry_assert (ctx->unused < CHACHA20_BLOCK_SIZE);
752
753       n = ctx->unused;
754       if (n > length)
755         n = length;
756
757       nburn = _gcry_poly1305_update_burn (&c->u_mode.poly1305.ctx, inbuf, n);
758       burn = nburn > burn ? nburn : burn;
759       buf_xor (outbuf, inbuf, p + CHACHA20_BLOCK_SIZE - ctx->unused, n);
760       length -= n;
761       outbuf += n;
762       inbuf += n;
763       ctx->unused -= n;
764
765       if (!length)
766         {
767           if (burn)
768             _gcry_burn_stack (burn);
769
770           return 0;
771         }
772       gcry_assert (!ctx->unused);
773     }
774
775   gcry_assert (c->u_mode.poly1305.ctx.leftover == 0);
776
777 #ifdef USE_AVX2
778   if (ctx->use_avx2 && length >= 8 * CHACHA20_BLOCK_SIZE)
779     {
780       size_t nblocks = length / CHACHA20_BLOCK_SIZE;
781       nblocks -= nblocks % 8;
782
783       nburn = _gcry_chacha20_poly1305_amd64_avx2_blocks8(
784                         ctx->input, outbuf, inbuf, nblocks,
785                         &c->u_mode.poly1305.ctx.state, inbuf);
786       burn = nburn > burn ? nburn : burn;
787
788       length -= nblocks * CHACHA20_BLOCK_SIZE;
789       outbuf += nblocks * CHACHA20_BLOCK_SIZE;
790       inbuf  += nblocks * CHACHA20_BLOCK_SIZE;
791     }
792 #endif
793
794 #ifdef USE_SSSE3
795   if (ctx->use_ssse3)
796     {
797       if (length >= 4 * CHACHA20_BLOCK_SIZE)
798         {
799           size_t nblocks = length / CHACHA20_BLOCK_SIZE;
800           nblocks -= nblocks % 4;
801
802           nburn = _gcry_chacha20_poly1305_amd64_ssse3_blocks4(
803                             ctx->input, outbuf, inbuf, nblocks,
804                             &c->u_mode.poly1305.ctx.state, inbuf);
805           burn = nburn > burn ? nburn : burn;
806
807           length -= nblocks * CHACHA20_BLOCK_SIZE;
808           outbuf += nblocks * CHACHA20_BLOCK_SIZE;
809           inbuf  += nblocks * CHACHA20_BLOCK_SIZE;
810         }
811
812       if (length >= CHACHA20_BLOCK_SIZE)
813         {
814           size_t nblocks = length / CHACHA20_BLOCK_SIZE;
815
816           nburn = _gcry_chacha20_poly1305_amd64_ssse3_blocks1(
817                             ctx->input, outbuf, inbuf, nblocks,
818                             &c->u_mode.poly1305.ctx.state, inbuf);
819           burn = nburn > burn ? nburn : burn;
820
821           length -= nblocks * CHACHA20_BLOCK_SIZE;
822           outbuf += nblocks * CHACHA20_BLOCK_SIZE;
823           inbuf  += nblocks * CHACHA20_BLOCK_SIZE;
824         }
825     }
826 #endif
827
828   while (length)
829     {
830       size_t currlen = length;
831
832       /* Since checksumming is done before decryption, process input in 24KiB
833        * chunks to keep data loaded in L1 cache for decryption. */
834       if (currlen > 24 * 1024)
835         currlen = 24 * 1024;
836
837       nburn = _gcry_poly1305_update_burn (&c->u_mode.poly1305.ctx, inbuf,
838                                           currlen);
839       burn = nburn > burn ? nburn : burn;
840
841       nburn = do_chacha20_encrypt_stream_tail (ctx, outbuf, inbuf, currlen);
842       burn = nburn > burn ? nburn : burn;
843
844       outbuf += currlen;
845       inbuf += currlen;
846       length -= currlen;
847     }
848
849   if (burn)
850     _gcry_burn_stack (burn);
851
852   return 0;
853 }
854
855
856 static const char *
857 selftest (void)
858 {
859   byte ctxbuf[sizeof(CHACHA20_context_t) + 15];
860   CHACHA20_context_t *ctx;
861   byte scratch[127 + 1];
862   byte buf[512 + 64 + 4];
863   int i;
864
865   /* From draft-strombergson-chacha-test-vectors */
866   static byte key_1[] = {
867     0xc4, 0x6e, 0xc1, 0xb1, 0x8c, 0xe8, 0xa8, 0x78,
868     0x72, 0x5a, 0x37, 0xe7, 0x80, 0xdf, 0xb7, 0x35,
869     0x1f, 0x68, 0xed, 0x2e, 0x19, 0x4c, 0x79, 0xfb,
870     0xc6, 0xae, 0xbe, 0xe1, 0xa6, 0x67, 0x97, 0x5d
871   };
872   static const byte nonce_1[] =
873     { 0x1a, 0xda, 0x31, 0xd5, 0xcf, 0x68, 0x82, 0x21 };
874   static const byte plaintext_1[127] = {
875     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
876     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
877     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
878     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
879     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
880     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
881     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
882     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
883     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
884     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
885     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
886     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
887     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
888     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
889     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
890     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
891   };
892   static const byte ciphertext_1[127] = {
893     0xf6, 0x3a, 0x89, 0xb7, 0x5c, 0x22, 0x71, 0xf9,
894     0x36, 0x88, 0x16, 0x54, 0x2b, 0xa5, 0x2f, 0x06,
895     0xed, 0x49, 0x24, 0x17, 0x92, 0x30, 0x2b, 0x00,
896     0xb5, 0xe8, 0xf8, 0x0a, 0xe9, 0xa4, 0x73, 0xaf,
897     0xc2, 0x5b, 0x21, 0x8f, 0x51, 0x9a, 0xf0, 0xfd,
898     0xd4, 0x06, 0x36, 0x2e, 0x8d, 0x69, 0xde, 0x7f,
899     0x54, 0xc6, 0x04, 0xa6, 0xe0, 0x0f, 0x35, 0x3f,
900     0x11, 0x0f, 0x77, 0x1b, 0xdc, 0xa8, 0xab, 0x92,
901     0xe5, 0xfb, 0xc3, 0x4e, 0x60, 0xa1, 0xd9, 0xa9,
902     0xdb, 0x17, 0x34, 0x5b, 0x0a, 0x40, 0x27, 0x36,
903     0x85, 0x3b, 0xf9, 0x10, 0xb0, 0x60, 0xbd, 0xf1,
904     0xf8, 0x97, 0xb6, 0x29, 0x0f, 0x01, 0xd1, 0x38,
905     0xae, 0x2c, 0x4c, 0x90, 0x22, 0x5b, 0xa9, 0xea,
906     0x14, 0xd5, 0x18, 0xf5, 0x59, 0x29, 0xde, 0xa0,
907     0x98, 0xca, 0x7a, 0x6c, 0xcf, 0xe6, 0x12, 0x27,
908     0x05, 0x3c, 0x84, 0xe4, 0x9a, 0x4a, 0x33
909   };
910
911   /* 16-byte alignment required for amd64 implementation. */
912   ctx = (CHACHA20_context_t *)((uintptr_t)(ctxbuf + 15) & ~(uintptr_t)15);
913
914   chacha20_setkey (ctx, key_1, sizeof key_1, NULL);
915   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
916   scratch[sizeof (scratch) - 1] = 0;
917   chacha20_encrypt_stream (ctx, scratch, plaintext_1, sizeof plaintext_1);
918   if (memcmp (scratch, ciphertext_1, sizeof ciphertext_1))
919     return "ChaCha20 encryption test 1 failed.";
920   if (scratch[sizeof (scratch) - 1])
921     return "ChaCha20 wrote too much.";
922   chacha20_setkey (ctx, key_1, sizeof (key_1), NULL);
923   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
924   chacha20_encrypt_stream (ctx, scratch, scratch, sizeof plaintext_1);
925   if (memcmp (scratch, plaintext_1, sizeof plaintext_1))
926     return "ChaCha20 decryption test 1 failed.";
927
928   for (i = 0; i < sizeof buf; i++)
929     buf[i] = i;
930   chacha20_setkey (ctx, key_1, sizeof key_1, NULL);
931   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
932   /*encrypt */
933   chacha20_encrypt_stream (ctx, buf, buf, sizeof buf);
934   /*decrypt */
935   chacha20_setkey (ctx, key_1, sizeof key_1, NULL);
936   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
937   chacha20_encrypt_stream (ctx, buf, buf, 1);
938   chacha20_encrypt_stream (ctx, buf + 1, buf + 1, (sizeof buf) - 1 - 1);
939   chacha20_encrypt_stream (ctx, buf + (sizeof buf) - 1,
940                            buf + (sizeof buf) - 1, 1);
941   for (i = 0; i < sizeof buf; i++)
942     if (buf[i] != (byte) i)
943       return "ChaCha20 encryption test 2 failed.";
944
945   chacha20_setkey (ctx, key_1, sizeof key_1, NULL);
946   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
947   /* encrypt */
948   for (i = 0; i < sizeof buf; i++)
949     chacha20_encrypt_stream (ctx, &buf[i], &buf[i], 1);
950   /* decrypt */
951   chacha20_setkey (ctx, key_1, sizeof key_1, NULL);
952   chacha20_setiv (ctx, nonce_1, sizeof nonce_1);
953   chacha20_encrypt_stream (ctx, buf, buf, sizeof buf);
954   for (i = 0; i < sizeof buf; i++)
955     if (buf[i] != (byte) i)
956       return "ChaCha20 encryption test 3 failed.";
957
958   return NULL;
959 }
960
961
962 gcry_cipher_spec_t _gcry_cipher_spec_chacha20 = {
963   GCRY_CIPHER_CHACHA20,
964   {0, 0},                       /* flags */
965   "CHACHA20",                   /* name */
966   NULL,                         /* aliases */
967   NULL,                         /* oids */
968   1,                            /* blocksize in bytes. */
969   CHACHA20_MAX_KEY_SIZE * 8,    /* standard key length in bits. */
970   sizeof (CHACHA20_context_t),
971   chacha20_setkey,
972   NULL,
973   NULL,
974   chacha20_encrypt_stream,
975   chacha20_encrypt_stream,
976   NULL,
977   NULL,
978   chacha20_setiv
979 };