More optimized CRC implementations
[libgcrypt.git] / cipher / chacha20.c
1 /* chacha20.c  -  Bernstein's ChaCha20 cipher
2  * Copyright (C) 2014 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 /* The code is based on salsa20.c and public-domain ChaCha implementations:
24  *  chacha-ref.c version 20080118
25  *  D. J. Bernstein
26  *  Public domain.
27  * and
28  *  Andrew Moon
29  *  https://github.com/floodyberry/chacha-opt
30  */
31
32
33 #include <config.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include "types.h"
38 #include "g10lib.h"
39 #include "cipher.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 #define CHACHA20_INPUT_LENGTH (CHACHA20_BLOCK_SIZE / 4)
50
51 /* USE_SSE2 indicates whether to compile with Intel SSE2 code. */
52 #undef USE_SSE2
53 #if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS)
54 # define USE_SSE2 1
55 #endif
56
57 /* USE_SSSE3 indicates whether to compile with Intel SSSE3 code. */
58 #undef USE_SSSE3
59 #if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) && \
60     defined(HAVE_GCC_INLINE_ASM_SSSE3)
61 # define USE_SSSE3 1
62 #endif
63
64 /* USE_AVX2 indicates whether to compile with Intel AVX2 code. */
65 #undef USE_AVX2
66 #if defined(__x86_64__) && defined(HAVE_COMPATIBLE_GCC_AMD64_PLATFORM_AS) && \
67     defined(ENABLE_AVX2_SUPPORT)
68 # define USE_AVX2 1
69 #endif
70
71 /* USE_NEON indicates whether to enable ARM NEON assembly code. */
72 #undef USE_NEON
73 #ifdef ENABLE_NEON_SUPPORT
74 # if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__) \
75      && defined(HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS) \
76      && defined(HAVE_GCC_INLINE_ASM_NEON)
77 #  define USE_NEON 1
78 # endif
79 #endif /*ENABLE_NEON_SUPPORT*/
80
81
82 struct CHACHA20_context_s;
83
84
85 typedef unsigned int (* chacha20_blocks_t)(u32 *state, const byte *src,
86                                            byte *dst, size_t bytes);
87
88 typedef struct CHACHA20_context_s
89 {
90   u32 input[CHACHA20_INPUT_LENGTH];
91   u32 pad[CHACHA20_INPUT_LENGTH];
92   chacha20_blocks_t blocks;
93   unsigned int unused; /* bytes in the pad.  */
94 } CHACHA20_context_t;
95
96
97 #ifdef USE_SSE2
98
99 unsigned int _gcry_chacha20_amd64_sse2_blocks(u32 *state, const byte *in,
100                                               byte *out, size_t bytes);
101
102 #endif /* USE_SSE2 */
103
104 #ifdef USE_SSSE3
105
106 unsigned int _gcry_chacha20_amd64_ssse3_blocks(u32 *state, const byte *in,
107                                                byte *out, size_t bytes);
108
109 #endif /* USE_SSSE3 */
110
111 #ifdef USE_AVX2
112
113 unsigned int _gcry_chacha20_amd64_avx2_blocks(u32 *state, const byte *in,
114                                               byte *out, size_t bytes);
115
116 #endif /* USE_AVX2 */
117
118 #ifdef USE_NEON
119
120 unsigned int _gcry_chacha20_armv7_neon_blocks(u32 *state, const byte *in,
121                                               byte *out, size_t bytes);
122
123 #endif /* USE_NEON */
124
125
126 static void chacha20_setiv (void *context, const byte * iv, size_t ivlen);
127 static const char *selftest (void);
128 \f
129
130
131 #define QROUND(a,b,c,d)         \
132   do {                          \
133     a += b; d = rol(d ^ a, 16); \
134     c += d; b = rol(b ^ c, 12); \
135     a += b; d = rol(d ^ a, 8);  \
136     c += d; b = rol(b ^ c, 7);  \
137   } while (0)
138
139 #define QOUT(ai, bi, ci, di) \
140   DO_OUT(ai); DO_OUT(bi); DO_OUT(ci); DO_OUT(di)
141
142
143 #ifndef USE_SSE2
144 static unsigned int
145 chacha20_blocks (u32 *state, const byte *src, byte *dst, size_t bytes)
146 {
147   u32 pad[CHACHA20_INPUT_LENGTH];
148   u32 inp[CHACHA20_INPUT_LENGTH];
149   unsigned int i;
150
151   /* Note: 'bytes' must be multiple of 64 and not zero. */
152
153   inp[0] = state[0];
154   inp[1] = state[1];
155   inp[2] = state[2];
156   inp[3] = state[3];
157   inp[4] = state[4];
158   inp[5] = state[5];
159   inp[6] = state[6];
160   inp[7] = state[7];
161   inp[8] = state[8];
162   inp[9] = state[9];
163   inp[10] = state[10];
164   inp[11] = state[11];
165   inp[12] = state[12];
166   inp[13] = state[13];
167   inp[14] = state[14];
168   inp[15] = state[15];
169
170   do
171     {
172       /* First round. */
173       pad[0] = inp[0];
174       pad[4] = inp[4];
175       pad[8] = inp[8];
176       pad[12] = inp[12];
177       QROUND (pad[0], pad[4], pad[8], pad[12]);
178       pad[1] = inp[1];
179       pad[5] = inp[5];
180       pad[9] = inp[9];
181       pad[13] = inp[13];
182       QROUND (pad[1], pad[5], pad[9], pad[13]);
183       pad[2] = inp[2];
184       pad[6] = inp[6];
185       pad[10] = inp[10];
186       pad[14] = inp[14];
187       QROUND (pad[2], pad[6], pad[10], pad[14]);
188       pad[3] = inp[3];
189       pad[7] = inp[7];
190       pad[11] = inp[11];
191       pad[15] = inp[15];
192       QROUND (pad[3], pad[7], pad[11], pad[15]);
193
194       QROUND (pad[0], pad[5], pad[10], pad[15]);
195       QROUND (pad[1], pad[6], pad[11], pad[12]);
196       QROUND (pad[2], pad[7], pad[8], pad[13]);
197       QROUND (pad[3], pad[4], pad[9], pad[14]);
198
199       for (i = 2; i < 20 - 2; i += 2)
200       {
201         QROUND (pad[0], pad[4], pad[8], pad[12]);
202         QROUND (pad[1], pad[5], pad[9], pad[13]);
203         QROUND (pad[2], pad[6], pad[10], pad[14]);
204         QROUND (pad[3], pad[7], pad[11], pad[15]);
205
206         QROUND (pad[0], pad[5], pad[10], pad[15]);
207         QROUND (pad[1], pad[6], pad[11], pad[12]);
208         QROUND (pad[2], pad[7], pad[8], pad[13]);
209         QROUND (pad[3], pad[4], pad[9], pad[14]);
210       }
211
212       QROUND (pad[0], pad[4], pad[8], pad[12]);
213       QROUND (pad[1], pad[5], pad[9], pad[13]);
214       QROUND (pad[2], pad[6], pad[10], pad[14]);
215       QROUND (pad[3], pad[7], pad[11], pad[15]);
216
217       if (src)
218         {
219 #define DO_OUT(idx) buf_put_le32(dst + (idx) * 4, \
220                                  (pad[idx] + inp[idx]) ^ \
221                                   buf_get_le32(src + (idx) * 4))
222           /* Last round. */
223           QROUND (pad[0], pad[5], pad[10], pad[15]);
224           QOUT(0, 5, 10, 15);
225           QROUND (pad[1], pad[6], pad[11], pad[12]);
226           QOUT(1, 6, 11, 12);
227           QROUND (pad[2], pad[7], pad[8], pad[13]);
228           QOUT(2, 7, 8, 13);
229           QROUND (pad[3], pad[4], pad[9], pad[14]);
230           QOUT(3, 4, 9, 14);
231 #undef DO_OUT
232         }
233       else
234         {
235 #define DO_OUT(idx) buf_put_le32(dst + (idx) * 4, pad[idx] + inp[idx])
236           /* Last round. */
237           QROUND (pad[0], pad[5], pad[10], pad[15]);
238           QOUT(0, 5, 10, 15);
239           QROUND (pad[1], pad[6], pad[11], pad[12]);
240           QOUT(1, 6, 11, 12);
241           QROUND (pad[2], pad[7], pad[8], pad[13]);
242           QOUT(2, 7, 8, 13);
243           QROUND (pad[3], pad[4], pad[9], pad[14]);
244           QOUT(3, 4, 9, 14);
245 #undef DO_OUT
246         }
247
248       /* Update counter. */
249       inp[13] += (!++inp[12]);
250
251       bytes -= CHACHA20_BLOCK_SIZE;
252       dst += CHACHA20_BLOCK_SIZE;
253       src += (src) ? CHACHA20_BLOCK_SIZE : 0;
254     }
255   while (bytes >= CHACHA20_BLOCK_SIZE);
256
257   state[12] = inp[12];
258   state[13] = inp[13];
259
260   /* burn_stack */
261   return (2 * CHACHA20_INPUT_LENGTH * sizeof(u32) + 6 * sizeof(void *));
262 }
263 #endif /*!USE_SSE2*/
264
265 #undef QROUND
266 #undef QOUT
267
268
269 static unsigned int
270 chacha20_core(u32 *dst, struct CHACHA20_context_s *ctx)
271 {
272   return ctx->blocks(ctx->input, NULL, (byte *)dst, CHACHA20_BLOCK_SIZE);
273 }
274
275
276 static void
277 chacha20_keysetup (CHACHA20_context_t * ctx, const byte * key,
278                    unsigned int keylen)
279 {
280   /* These constants are the little endian encoding of the string
281      "expand 32-byte k".  For the 128 bit variant, the "32" in that
282      string will be fixed up to "16".  */
283   ctx->input[0] = 0x61707865;        /* "apxe"  */
284   ctx->input[1] = 0x3320646e;        /* "3 dn"  */
285   ctx->input[2] = 0x79622d32;        /* "yb-2"  */
286   ctx->input[3] = 0x6b206574;        /* "k et"  */
287
288   ctx->input[4] = buf_get_le32 (key + 0);
289   ctx->input[5] = buf_get_le32 (key + 4);
290   ctx->input[6] = buf_get_le32 (key + 8);
291   ctx->input[7] = buf_get_le32 (key + 12);
292
293   if (keylen == CHACHA20_MAX_KEY_SIZE) /* 256 bits */
294     {
295       ctx->input[8] = buf_get_le32 (key + 16);
296       ctx->input[9] = buf_get_le32 (key + 20);
297       ctx->input[10] = buf_get_le32 (key + 24);
298       ctx->input[11] = buf_get_le32 (key + 28);
299     }
300   else /* 128 bits */
301     {
302       ctx->input[8] = ctx->input[4];
303       ctx->input[9] = ctx->input[5];
304       ctx->input[10] = ctx->input[6];
305       ctx->input[11] = ctx->input[7];
306
307       ctx->input[1] -= 0x02000000;        /* Change to "1 dn".  */
308       ctx->input[2] += 0x00000004;        /* Change to "yb-6".  */
309     }
310 }
311
312
313 static void
314 chacha20_ivsetup (CHACHA20_context_t * ctx, const byte * iv, size_t ivlen)
315 {
316   if (ivlen == CHACHA20_CTR_SIZE)
317     {
318       ctx->input[12] = buf_get_le32 (iv + 0);
319       ctx->input[13] = buf_get_le32 (iv + 4);
320       ctx->input[14] = buf_get_le32 (iv + 8);
321       ctx->input[15] = buf_get_le32 (iv + 12);
322     }
323   else if (ivlen == CHACHA20_MAX_IV_SIZE)
324     {
325       ctx->input[12] = 0;
326       ctx->input[13] = buf_get_le32 (iv + 0);
327       ctx->input[14] = buf_get_le32 (iv + 4);
328       ctx->input[15] = buf_get_le32 (iv + 8);
329     }
330   else if (ivlen == CHACHA20_MIN_IV_SIZE)
331     {
332       ctx->input[12] = 0;
333       ctx->input[13] = 0;
334       ctx->input[14] = buf_get_le32 (iv + 0);
335       ctx->input[15] = buf_get_le32 (iv + 4);
336     }
337   else
338     {
339       ctx->input[12] = 0;
340       ctx->input[13] = 0;
341       ctx->input[14] = 0;
342       ctx->input[15] = 0;
343     }
344 }
345
346
347 static gcry_err_code_t
348 chacha20_do_setkey (CHACHA20_context_t * ctx,
349                     const byte * key, unsigned int keylen)
350 {
351   static int initialized;
352   static const char *selftest_failed;
353   unsigned int features = _gcry_get_hw_features ();
354
355   if (!initialized)
356     {
357       initialized = 1;
358       selftest_failed = selftest ();
359       if (selftest_failed)
360         log_error ("CHACHA20 selftest failed (%s)\n", selftest_failed);
361     }
362   if (selftest_failed)
363     return GPG_ERR_SELFTEST_FAILED;
364
365   if (keylen != CHACHA20_MAX_KEY_SIZE && keylen != CHACHA20_MIN_KEY_SIZE)
366     return GPG_ERR_INV_KEYLEN;
367
368 #ifdef USE_SSE2
369   ctx->blocks = _gcry_chacha20_amd64_sse2_blocks;
370 #else
371   ctx->blocks = chacha20_blocks;
372 #endif
373
374 #ifdef USE_SSSE3
375   if (features & HWF_INTEL_SSSE3)
376     ctx->blocks = _gcry_chacha20_amd64_ssse3_blocks;
377 #endif
378 #ifdef USE_AVX2
379   if (features & HWF_INTEL_AVX2)
380     ctx->blocks = _gcry_chacha20_amd64_avx2_blocks;
381 #endif
382 #ifdef USE_NEON
383   if (features & HWF_ARM_NEON)
384     ctx->blocks = _gcry_chacha20_armv7_neon_blocks;
385 #endif
386
387   (void)features;
388
389   chacha20_keysetup (ctx, key, keylen);
390
391   /* We default to a zero nonce.  */
392   chacha20_setiv (ctx, NULL, 0);
393
394   return 0;
395 }
396
397
398 static gcry_err_code_t
399 chacha20_setkey (void *context, const byte * key, unsigned int keylen)
400 {
401   CHACHA20_context_t *ctx = (CHACHA20_context_t *) context;
402   gcry_err_code_t rc = chacha20_do_setkey (ctx, key, keylen);
403   _gcry_burn_stack (4 + sizeof (void *) + 4 * sizeof (void *));
404   return rc;
405 }
406
407
408 static void
409 chacha20_setiv (void *context, const byte * iv, size_t ivlen)
410 {
411   CHACHA20_context_t *ctx = (CHACHA20_context_t *) context;
412
413   /* draft-nir-cfrg-chacha20-poly1305-02 defines 96-bit and 64-bit nonce. */
414   if (iv && ivlen != CHACHA20_MAX_IV_SIZE && ivlen != CHACHA20_MIN_IV_SIZE
415       && ivlen != CHACHA20_CTR_SIZE)
416     log_info ("WARNING: chacha20_setiv: bad ivlen=%u\n", (u32) ivlen);
417
418   if (iv && (ivlen == CHACHA20_MAX_IV_SIZE || ivlen == CHACHA20_MIN_IV_SIZE
419              || ivlen == CHACHA20_CTR_SIZE))
420     chacha20_ivsetup (ctx, iv, ivlen);
421   else
422     chacha20_ivsetup (ctx, NULL, 0);
423
424   /* Reset the unused pad bytes counter.  */
425   ctx->unused = 0;
426 }
427 \f
428
429
430 /* Note: This function requires LENGTH > 0.  */
431 static void
432 chacha20_do_encrypt_stream (CHACHA20_context_t * ctx,
433                             byte * outbuf, const byte * inbuf, size_t length)
434 {
435   unsigned int nburn, burn = 0;
436
437   if (ctx->unused)
438     {
439       unsigned char *p = (void *) ctx->pad;
440       size_t n;
441
442       gcry_assert (ctx->unused < CHACHA20_BLOCK_SIZE);
443
444       n = ctx->unused;
445       if (n > length)
446         n = length;
447       buf_xor (outbuf, inbuf, p + CHACHA20_BLOCK_SIZE - ctx->unused, n);
448       length -= n;
449       outbuf += n;
450       inbuf += n;
451       ctx->unused -= n;
452       if (!length)
453         return;
454       gcry_assert (!ctx->unused);
455     }
456
457   if (length >= CHACHA20_BLOCK_SIZE)
458     {
459       size_t nblocks = length / CHACHA20_BLOCK_SIZE;
460       size_t bytes = nblocks * CHACHA20_BLOCK_SIZE;
461       burn = ctx->blocks(ctx->input, inbuf, outbuf, bytes);
462       length -= bytes;
463       outbuf += bytes;
464       inbuf  += bytes;
465     }
466
467   if (length > 0)
468     {
469       nburn = chacha20_core (ctx->pad, ctx);
470       burn = nburn > burn ? nburn : burn;
471
472       buf_xor (outbuf, inbuf, ctx->pad, length);
473       ctx->unused = CHACHA20_BLOCK_SIZE - length;
474     }
475
476   _gcry_burn_stack (burn);
477 }
478
479
480 static void
481 chacha20_encrypt_stream (void *context, byte * outbuf, const byte * inbuf,
482                          size_t length)
483 {
484   CHACHA20_context_t *ctx = (CHACHA20_context_t *) context;
485
486   if (length)
487     chacha20_do_encrypt_stream (ctx, outbuf, inbuf, length);
488 }
489
490
491 static const char *
492 selftest (void)
493 {
494   CHACHA20_context_t ctx;
495   byte scratch[127 + 1];
496   byte buf[512 + 64 + 4];
497   int i;
498
499   /* From draft-strombergson-chacha-test-vectors */
500   static byte key_1[] = {
501     0xc4, 0x6e, 0xc1, 0xb1, 0x8c, 0xe8, 0xa8, 0x78,
502     0x72, 0x5a, 0x37, 0xe7, 0x80, 0xdf, 0xb7, 0x35,
503     0x1f, 0x68, 0xed, 0x2e, 0x19, 0x4c, 0x79, 0xfb,
504     0xc6, 0xae, 0xbe, 0xe1, 0xa6, 0x67, 0x97, 0x5d
505   };
506   static const byte nonce_1[] =
507     { 0x1a, 0xda, 0x31, 0xd5, 0xcf, 0x68, 0x82, 0x21 };
508   static const byte plaintext_1[127] = {
509     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
511     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
512     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
513     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
514     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
515     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
516     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
518     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
519     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
520     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
521     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
522     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
523     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
524     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
525   };
526   static const byte ciphertext_1[127] = {
527     0xf6, 0x3a, 0x89, 0xb7, 0x5c, 0x22, 0x71, 0xf9,
528     0x36, 0x88, 0x16, 0x54, 0x2b, 0xa5, 0x2f, 0x06,
529     0xed, 0x49, 0x24, 0x17, 0x92, 0x30, 0x2b, 0x00,
530     0xb5, 0xe8, 0xf8, 0x0a, 0xe9, 0xa4, 0x73, 0xaf,
531     0xc2, 0x5b, 0x21, 0x8f, 0x51, 0x9a, 0xf0, 0xfd,
532     0xd4, 0x06, 0x36, 0x2e, 0x8d, 0x69, 0xde, 0x7f,
533     0x54, 0xc6, 0x04, 0xa6, 0xe0, 0x0f, 0x35, 0x3f,
534     0x11, 0x0f, 0x77, 0x1b, 0xdc, 0xa8, 0xab, 0x92,
535     0xe5, 0xfb, 0xc3, 0x4e, 0x60, 0xa1, 0xd9, 0xa9,
536     0xdb, 0x17, 0x34, 0x5b, 0x0a, 0x40, 0x27, 0x36,
537     0x85, 0x3b, 0xf9, 0x10, 0xb0, 0x60, 0xbd, 0xf1,
538     0xf8, 0x97, 0xb6, 0x29, 0x0f, 0x01, 0xd1, 0x38,
539     0xae, 0x2c, 0x4c, 0x90, 0x22, 0x5b, 0xa9, 0xea,
540     0x14, 0xd5, 0x18, 0xf5, 0x59, 0x29, 0xde, 0xa0,
541     0x98, 0xca, 0x7a, 0x6c, 0xcf, 0xe6, 0x12, 0x27,
542     0x05, 0x3c, 0x84, 0xe4, 0x9a, 0x4a, 0x33
543   };
544
545   chacha20_setkey (&ctx, key_1, sizeof key_1);
546   chacha20_setiv (&ctx, nonce_1, sizeof nonce_1);
547   scratch[sizeof (scratch) - 1] = 0;
548   chacha20_encrypt_stream (&ctx, scratch, plaintext_1, sizeof plaintext_1);
549   if (memcmp (scratch, ciphertext_1, sizeof ciphertext_1))
550     return "ChaCha20 encryption test 1 failed.";
551   if (scratch[sizeof (scratch) - 1])
552     return "ChaCha20 wrote too much.";
553   chacha20_setkey (&ctx, key_1, sizeof (key_1));
554   chacha20_setiv (&ctx, nonce_1, sizeof nonce_1);
555   chacha20_encrypt_stream (&ctx, scratch, scratch, sizeof plaintext_1);
556   if (memcmp (scratch, plaintext_1, sizeof plaintext_1))
557     return "ChaCha20 decryption test 1 failed.";
558
559   for (i = 0; i < sizeof buf; i++)
560     buf[i] = i;
561   chacha20_setkey (&ctx, key_1, sizeof key_1);
562   chacha20_setiv (&ctx, nonce_1, sizeof nonce_1);
563   /*encrypt */
564   chacha20_encrypt_stream (&ctx, buf, buf, sizeof buf);
565   /*decrypt */
566   chacha20_setkey (&ctx, key_1, sizeof key_1);
567   chacha20_setiv (&ctx, nonce_1, sizeof nonce_1);
568   chacha20_encrypt_stream (&ctx, buf, buf, 1);
569   chacha20_encrypt_stream (&ctx, buf + 1, buf + 1, (sizeof buf) - 1 - 1);
570   chacha20_encrypt_stream (&ctx, buf + (sizeof buf) - 1,
571                            buf + (sizeof buf) - 1, 1);
572   for (i = 0; i < sizeof buf; i++)
573     if (buf[i] != (byte) i)
574       return "ChaCha20 encryption test 2 failed.";
575
576   chacha20_setkey (&ctx, key_1, sizeof key_1);
577   chacha20_setiv (&ctx, nonce_1, sizeof nonce_1);
578   /* encrypt */
579   for (i = 0; i < sizeof buf; i++)
580     chacha20_encrypt_stream (&ctx, &buf[i], &buf[i], 1);
581   /* decrypt */
582   chacha20_setkey (&ctx, key_1, sizeof key_1);
583   chacha20_setiv (&ctx, nonce_1, sizeof nonce_1);
584   chacha20_encrypt_stream (&ctx, buf, buf, sizeof buf);
585   for (i = 0; i < sizeof buf; i++)
586     if (buf[i] != (byte) i)
587       return "ChaCha20 encryption test 3 failed.";
588
589   return NULL;
590 }
591
592
593 gcry_cipher_spec_t _gcry_cipher_spec_chacha20 = {
594   GCRY_CIPHER_CHACHA20,
595   {0, 0},                       /* flags */
596   "CHACHA20",                   /* name */
597   NULL,                         /* aliases */
598   NULL,                         /* oids */
599   1,                            /* blocksize in bytes. */
600   CHACHA20_MAX_KEY_SIZE * 8,    /* standard key length in bits. */
601   sizeof (CHACHA20_context_t),
602   chacha20_setkey,
603   NULL,
604   NULL,
605   chacha20_encrypt_stream,
606   chacha20_encrypt_stream,
607   NULL,
608   NULL,
609   chacha20_setiv
610 };