xref: /third_party/mbedtls/library/chacha20.c (revision a8e1175b)
1/**
2 * \file chacha20.c
3 *
4 * \brief ChaCha20 cipher.
5 *
6 * \author Daniel King <damaki.gh@gmail.com>
7 *
8 *  Copyright The Mbed TLS Contributors
9 *  SPDX-License-Identifier: Apache-2.0
10 *
11 *  Licensed under the Apache License, Version 2.0 (the "License"); you may
12 *  not use this file except in compliance with the License.
13 *  You may obtain a copy of the License at
14 *
15 *  http://www.apache.org/licenses/LICENSE-2.0
16 *
17 *  Unless required by applicable law or agreed to in writing, software
18 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
19 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 *  See the License for the specific language governing permissions and
21 *  limitations under the License.
22 */
23
24#include "common.h"
25
26#if defined(MBEDTLS_CHACHA20_C)
27
28#include "mbedtls/chacha20.h"
29#include "mbedtls/platform_util.h"
30#include "mbedtls/error.h"
31
32#include <stddef.h>
33#include <string.h>
34
35#include "mbedtls/platform.h"
36
37#if !defined(MBEDTLS_CHACHA20_ALT)
38
39#define ROTL32(value, amount) \
40    ((uint32_t) ((value) << (amount)) | ((value) >> (32 - (amount))))
41
42#define CHACHA20_CTR_INDEX (12U)
43
44#define CHACHA20_BLOCK_SIZE_BYTES (4U * 16U)
45
46/**
47 * \brief           ChaCha20 quarter round operation.
48 *
49 *                  The quarter round is defined as follows (from RFC 7539):
50 *                      1.  a += b; d ^= a; d <<<= 16;
51 *                      2.  c += d; b ^= c; b <<<= 12;
52 *                      3.  a += b; d ^= a; d <<<= 8;
53 *                      4.  c += d; b ^= c; b <<<= 7;
54 *
55 * \param state     ChaCha20 state to modify.
56 * \param a         The index of 'a' in the state.
57 * \param b         The index of 'b' in the state.
58 * \param c         The index of 'c' in the state.
59 * \param d         The index of 'd' in the state.
60 */
61static inline void chacha20_quarter_round(uint32_t state[16],
62                                          size_t a,
63                                          size_t b,
64                                          size_t c,
65                                          size_t d)
66{
67    /* a += b; d ^= a; d <<<= 16; */
68    state[a] += state[b];
69    state[d] ^= state[a];
70    state[d] = ROTL32(state[d], 16);
71
72    /* c += d; b ^= c; b <<<= 12 */
73    state[c] += state[d];
74    state[b] ^= state[c];
75    state[b] = ROTL32(state[b], 12);
76
77    /* a += b; d ^= a; d <<<= 8; */
78    state[a] += state[b];
79    state[d] ^= state[a];
80    state[d] = ROTL32(state[d], 8);
81
82    /* c += d; b ^= c; b <<<= 7; */
83    state[c] += state[d];
84    state[b] ^= state[c];
85    state[b] = ROTL32(state[b], 7);
86}
87
88/**
89 * \brief           Perform the ChaCha20 inner block operation.
90 *
91 *                  This function performs two rounds: the column round and the
92 *                  diagonal round.
93 *
94 * \param state     The ChaCha20 state to update.
95 */
96static void chacha20_inner_block(uint32_t state[16])
97{
98    chacha20_quarter_round(state, 0, 4, 8,  12);
99    chacha20_quarter_round(state, 1, 5, 9,  13);
100    chacha20_quarter_round(state, 2, 6, 10, 14);
101    chacha20_quarter_round(state, 3, 7, 11, 15);
102
103    chacha20_quarter_round(state, 0, 5, 10, 15);
104    chacha20_quarter_round(state, 1, 6, 11, 12);
105    chacha20_quarter_round(state, 2, 7, 8,  13);
106    chacha20_quarter_round(state, 3, 4, 9,  14);
107}
108
109/**
110 * \brief               Generates a keystream block.
111 *
112 * \param initial_state The initial ChaCha20 state (key, nonce, counter).
113 * \param keystream     Generated keystream bytes are written to this buffer.
114 */
115static void chacha20_block(const uint32_t initial_state[16],
116                           unsigned char keystream[64])
117{
118    uint32_t working_state[16];
119    size_t i;
120
121    memcpy(working_state,
122           initial_state,
123           CHACHA20_BLOCK_SIZE_BYTES);
124
125    for (i = 0U; i < 10U; i++) {
126        chacha20_inner_block(working_state);
127    }
128
129    working_state[0] += initial_state[0];
130    working_state[1] += initial_state[1];
131    working_state[2] += initial_state[2];
132    working_state[3] += initial_state[3];
133    working_state[4] += initial_state[4];
134    working_state[5] += initial_state[5];
135    working_state[6] += initial_state[6];
136    working_state[7] += initial_state[7];
137    working_state[8] += initial_state[8];
138    working_state[9] += initial_state[9];
139    working_state[10] += initial_state[10];
140    working_state[11] += initial_state[11];
141    working_state[12] += initial_state[12];
142    working_state[13] += initial_state[13];
143    working_state[14] += initial_state[14];
144    working_state[15] += initial_state[15];
145
146    for (i = 0U; i < 16; i++) {
147        size_t offset = i * 4U;
148
149        MBEDTLS_PUT_UINT32_LE(working_state[i], keystream, offset);
150    }
151
152    mbedtls_platform_zeroize(working_state, sizeof(working_state));
153}
154
155void mbedtls_chacha20_init(mbedtls_chacha20_context *ctx)
156{
157    mbedtls_platform_zeroize(ctx->state, sizeof(ctx->state));
158    mbedtls_platform_zeroize(ctx->keystream8, sizeof(ctx->keystream8));
159
160    /* Initially, there's no keystream bytes available */
161    ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES;
162}
163
164void mbedtls_chacha20_free(mbedtls_chacha20_context *ctx)
165{
166    if (ctx != NULL) {
167        mbedtls_platform_zeroize(ctx, sizeof(mbedtls_chacha20_context));
168    }
169}
170
171int mbedtls_chacha20_setkey(mbedtls_chacha20_context *ctx,
172                            const unsigned char key[32])
173{
174    /* ChaCha20 constants - the string "expand 32-byte k" */
175    ctx->state[0] = 0x61707865;
176    ctx->state[1] = 0x3320646e;
177    ctx->state[2] = 0x79622d32;
178    ctx->state[3] = 0x6b206574;
179
180    /* Set key */
181    ctx->state[4]  = MBEDTLS_GET_UINT32_LE(key, 0);
182    ctx->state[5]  = MBEDTLS_GET_UINT32_LE(key, 4);
183    ctx->state[6]  = MBEDTLS_GET_UINT32_LE(key, 8);
184    ctx->state[7]  = MBEDTLS_GET_UINT32_LE(key, 12);
185    ctx->state[8]  = MBEDTLS_GET_UINT32_LE(key, 16);
186    ctx->state[9]  = MBEDTLS_GET_UINT32_LE(key, 20);
187    ctx->state[10] = MBEDTLS_GET_UINT32_LE(key, 24);
188    ctx->state[11] = MBEDTLS_GET_UINT32_LE(key, 28);
189
190    return 0;
191}
192
193int mbedtls_chacha20_starts(mbedtls_chacha20_context *ctx,
194                            const unsigned char nonce[12],
195                            uint32_t counter)
196{
197    /* Counter */
198    ctx->state[12] = counter;
199
200    /* Nonce */
201    ctx->state[13] = MBEDTLS_GET_UINT32_LE(nonce, 0);
202    ctx->state[14] = MBEDTLS_GET_UINT32_LE(nonce, 4);
203    ctx->state[15] = MBEDTLS_GET_UINT32_LE(nonce, 8);
204
205    mbedtls_platform_zeroize(ctx->keystream8, sizeof(ctx->keystream8));
206
207    /* Initially, there's no keystream bytes available */
208    ctx->keystream_bytes_used = CHACHA20_BLOCK_SIZE_BYTES;
209
210    return 0;
211}
212
213int mbedtls_chacha20_update(mbedtls_chacha20_context *ctx,
214                            size_t size,
215                            const unsigned char *input,
216                            unsigned char *output)
217{
218    size_t offset = 0U;
219
220    /* Use leftover keystream bytes, if available */
221    while (size > 0U && ctx->keystream_bytes_used < CHACHA20_BLOCK_SIZE_BYTES) {
222        output[offset] = input[offset]
223                         ^ ctx->keystream8[ctx->keystream_bytes_used];
224
225        ctx->keystream_bytes_used++;
226        offset++;
227        size--;
228    }
229
230    /* Process full blocks */
231    while (size >= CHACHA20_BLOCK_SIZE_BYTES) {
232        /* Generate new keystream block and increment counter */
233        chacha20_block(ctx->state, ctx->keystream8);
234        ctx->state[CHACHA20_CTR_INDEX]++;
235
236        mbedtls_xor(output + offset, input + offset, ctx->keystream8, 64U);
237
238        offset += CHACHA20_BLOCK_SIZE_BYTES;
239        size   -= CHACHA20_BLOCK_SIZE_BYTES;
240    }
241
242    /* Last (partial) block */
243    if (size > 0U) {
244        /* Generate new keystream block and increment counter */
245        chacha20_block(ctx->state, ctx->keystream8);
246        ctx->state[CHACHA20_CTR_INDEX]++;
247
248        mbedtls_xor(output + offset, input + offset, ctx->keystream8, size);
249
250        ctx->keystream_bytes_used = size;
251
252    }
253
254    return 0;
255}
256
257int mbedtls_chacha20_crypt(const unsigned char key[32],
258                           const unsigned char nonce[12],
259                           uint32_t counter,
260                           size_t data_len,
261                           const unsigned char *input,
262                           unsigned char *output)
263{
264    mbedtls_chacha20_context ctx;
265    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
266
267    mbedtls_chacha20_init(&ctx);
268
269    ret = mbedtls_chacha20_setkey(&ctx, key);
270    if (ret != 0) {
271        goto cleanup;
272    }
273
274    ret = mbedtls_chacha20_starts(&ctx, nonce, counter);
275    if (ret != 0) {
276        goto cleanup;
277    }
278
279    ret = mbedtls_chacha20_update(&ctx, data_len, input, output);
280
281cleanup:
282    mbedtls_chacha20_free(&ctx);
283    return ret;
284}
285
286#endif /* !MBEDTLS_CHACHA20_ALT */
287
288#if defined(MBEDTLS_SELF_TEST)
289
290static const unsigned char test_keys[2][32] =
291{
292    {
293        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
294        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
297    },
298    {
299        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
302        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
303    }
304};
305
306static const unsigned char test_nonces[2][12] =
307{
308    {
309        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
310        0x00, 0x00, 0x00, 0x00
311    },
312    {
313        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314        0x00, 0x00, 0x00, 0x02
315    }
316};
317
318static const uint32_t test_counters[2] =
319{
320    0U,
321    1U
322};
323
324static const unsigned char test_input[2][375] =
325{
326    {
327        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
329        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
330        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
331        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
334        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
335    },
336    {
337        0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d,
338        0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74,
339        0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45,
340        0x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e,
341        0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74,
342        0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72,
343        0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66,
344        0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69,
345        0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61,
346        0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72,
347        0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66,
348        0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46,
349        0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
350        0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20,
351        0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61,
352        0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73,
353        0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74,
354        0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69,
355        0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65,
356        0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
357        0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49,
358        0x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69,
359        0x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20,
360        0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72,
361        0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49,
362        0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74,
363        0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e,
364        0x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20,
365        0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
366        0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75,
367        0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20,
368        0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e,
369        0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45,
370        0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69,
371        0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20,
372        0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20,
373        0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20,
374        0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63,
375        0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63,
376        0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61,
377        0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61,
378        0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e,
379        0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f,
380        0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c,
381        0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61,
382        0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65,
383        0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f
384    }
385};
386
387static const unsigned char test_output[2][375] =
388{
389    {
390        0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
391        0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
392        0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
393        0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
394        0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
395        0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
396        0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
397        0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86
398    },
399    {
400        0xa3, 0xfb, 0xf0, 0x7d, 0xf3, 0xfa, 0x2f, 0xde,
401        0x4f, 0x37, 0x6c, 0xa2, 0x3e, 0x82, 0x73, 0x70,
402        0x41, 0x60, 0x5d, 0x9f, 0x4f, 0x4f, 0x57, 0xbd,
403        0x8c, 0xff, 0x2c, 0x1d, 0x4b, 0x79, 0x55, 0xec,
404        0x2a, 0x97, 0x94, 0x8b, 0xd3, 0x72, 0x29, 0x15,
405        0xc8, 0xf3, 0xd3, 0x37, 0xf7, 0xd3, 0x70, 0x05,
406        0x0e, 0x9e, 0x96, 0xd6, 0x47, 0xb7, 0xc3, 0x9f,
407        0x56, 0xe0, 0x31, 0xca, 0x5e, 0xb6, 0x25, 0x0d,
408        0x40, 0x42, 0xe0, 0x27, 0x85, 0xec, 0xec, 0xfa,
409        0x4b, 0x4b, 0xb5, 0xe8, 0xea, 0xd0, 0x44, 0x0e,
410        0x20, 0xb6, 0xe8, 0xdb, 0x09, 0xd8, 0x81, 0xa7,
411        0xc6, 0x13, 0x2f, 0x42, 0x0e, 0x52, 0x79, 0x50,
412        0x42, 0xbd, 0xfa, 0x77, 0x73, 0xd8, 0xa9, 0x05,
413        0x14, 0x47, 0xb3, 0x29, 0x1c, 0xe1, 0x41, 0x1c,
414        0x68, 0x04, 0x65, 0x55, 0x2a, 0xa6, 0xc4, 0x05,
415        0xb7, 0x76, 0x4d, 0x5e, 0x87, 0xbe, 0xa8, 0x5a,
416        0xd0, 0x0f, 0x84, 0x49, 0xed, 0x8f, 0x72, 0xd0,
417        0xd6, 0x62, 0xab, 0x05, 0x26, 0x91, 0xca, 0x66,
418        0x42, 0x4b, 0xc8, 0x6d, 0x2d, 0xf8, 0x0e, 0xa4,
419        0x1f, 0x43, 0xab, 0xf9, 0x37, 0xd3, 0x25, 0x9d,
420        0xc4, 0xb2, 0xd0, 0xdf, 0xb4, 0x8a, 0x6c, 0x91,
421        0x39, 0xdd, 0xd7, 0xf7, 0x69, 0x66, 0xe9, 0x28,
422        0xe6, 0x35, 0x55, 0x3b, 0xa7, 0x6c, 0x5c, 0x87,
423        0x9d, 0x7b, 0x35, 0xd4, 0x9e, 0xb2, 0xe6, 0x2b,
424        0x08, 0x71, 0xcd, 0xac, 0x63, 0x89, 0x39, 0xe2,
425        0x5e, 0x8a, 0x1e, 0x0e, 0xf9, 0xd5, 0x28, 0x0f,
426        0xa8, 0xca, 0x32, 0x8b, 0x35, 0x1c, 0x3c, 0x76,
427        0x59, 0x89, 0xcb, 0xcf, 0x3d, 0xaa, 0x8b, 0x6c,
428        0xcc, 0x3a, 0xaf, 0x9f, 0x39, 0x79, 0xc9, 0x2b,
429        0x37, 0x20, 0xfc, 0x88, 0xdc, 0x95, 0xed, 0x84,
430        0xa1, 0xbe, 0x05, 0x9c, 0x64, 0x99, 0xb9, 0xfd,
431        0xa2, 0x36, 0xe7, 0xe8, 0x18, 0xb0, 0x4b, 0x0b,
432        0xc3, 0x9c, 0x1e, 0x87, 0x6b, 0x19, 0x3b, 0xfe,
433        0x55, 0x69, 0x75, 0x3f, 0x88, 0x12, 0x8c, 0xc0,
434        0x8a, 0xaa, 0x9b, 0x63, 0xd1, 0xa1, 0x6f, 0x80,
435        0xef, 0x25, 0x54, 0xd7, 0x18, 0x9c, 0x41, 0x1f,
436        0x58, 0x69, 0xca, 0x52, 0xc5, 0xb8, 0x3f, 0xa3,
437        0x6f, 0xf2, 0x16, 0xb9, 0xc1, 0xd3, 0x00, 0x62,
438        0xbe, 0xbc, 0xfd, 0x2d, 0xc5, 0xbc, 0xe0, 0x91,
439        0x19, 0x34, 0xfd, 0xa7, 0x9a, 0x86, 0xf6, 0xe6,
440        0x98, 0xce, 0xd7, 0x59, 0xc3, 0xff, 0x9b, 0x64,
441        0x77, 0x33, 0x8f, 0x3d, 0xa4, 0xf9, 0xcd, 0x85,
442        0x14, 0xea, 0x99, 0x82, 0xcc, 0xaf, 0xb3, 0x41,
443        0xb2, 0x38, 0x4d, 0xd9, 0x02, 0xf3, 0xd1, 0xab,
444        0x7a, 0xc6, 0x1d, 0xd2, 0x9c, 0x6f, 0x21, 0xba,
445        0x5b, 0x86, 0x2f, 0x37, 0x30, 0xe3, 0x7c, 0xfd,
446        0xc4, 0xfd, 0x80, 0x6c, 0x22, 0xf2, 0x21
447    }
448};
449
450static const size_t test_lengths[2] =
451{
452    64U,
453    375U
454};
455
456/* Make sure no other definition is already present. */
457#undef ASSERT
458
459#define ASSERT(cond, args)            \
460    do                                  \
461    {                                   \
462        if (!(cond))                \
463        {                               \
464            if (verbose != 0)          \
465            mbedtls_printf args;    \
466                                        \
467            return -1;               \
468        }                               \
469    }                                   \
470    while (0)
471
472int mbedtls_chacha20_self_test(int verbose)
473{
474    unsigned char output[381];
475    unsigned i;
476    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
477
478    for (i = 0U; i < 2U; i++) {
479        if (verbose != 0) {
480            mbedtls_printf("  ChaCha20 test %u ", i);
481        }
482
483        ret = mbedtls_chacha20_crypt(test_keys[i],
484                                     test_nonces[i],
485                                     test_counters[i],
486                                     test_lengths[i],
487                                     test_input[i],
488                                     output);
489
490        ASSERT(0 == ret, ("error code: %i\n", ret));
491
492        ASSERT(0 == memcmp(output, test_output[i], test_lengths[i]),
493               ("failed (output)\n"));
494
495        if (verbose != 0) {
496            mbedtls_printf("passed\n");
497        }
498    }
499
500    if (verbose != 0) {
501        mbedtls_printf("\n");
502    }
503
504    return 0;
505}
506
507#endif /* MBEDTLS_SELF_TEST */
508
509#endif /* !MBEDTLS_CHACHA20_C */
510