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