Coverage Report

Created: 2026-08-15 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wolfssl-heapmath/wolfcrypt/src/chacha.c
Line
Count
Source
1
/* chacha.c
2
 *
3
 * Copyright (C) 2006-2026 wolfSSL Inc.
4
 *
5
 * This file is part of wolfSSL.
6
 *
7
 * wolfSSL is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * wolfSSL is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20
 */
21
/*
22
23
DESCRIPTION
24
This library contains implementation for the ChaCha20 stream cipher.
25
26
Based from chacha-ref.c version 20080118
27
D. J. Bernstein
28
Public domain.
29
30
*/
31
32
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
33
34
#ifdef HAVE_CHACHA
35
    #include <wolfssl/wolfcrypt/chacha.h>
36
37
    #ifdef NO_INLINE
38
        #include <wolfssl/wolfcrypt/misc.h>
39
    #else
40
        #define WOLFSSL_MISC_INCLUDED
41
        #include <wolfcrypt/src/misc.c>
42
    #endif
43
44
    #ifdef BIG_ENDIAN_ORDER
45
        #define LITTLE32(x) ByteReverseWord32(x)
46
    #else
47
5.57k
        #define LITTLE32(x) (x)
48
    #endif
49
50
    /* Number of rounds */
51
5.76k
    #define ROUNDS  20
52
53
1.94M
    #define U32C(v) (v##U)
54
1.94M
    #define U32V(v) ((word32)(v) & U32C(0xFFFFFFFF))
55
2.60k
    #define U8TO32_LITTLE(p) LITTLE32(readUnalignedWord32(p))
56
57
1.84M
    #define ROTATE(v,c) rotlFixed(v, c)
58
    #define XOR(v,w)    ((v) ^ (w))
59
1.94M
    #define PLUS(v,w)   (U32V((v) + (w)))
60
4.79k
    #define PLUSONE(v)  (PLUS((v),1))
61
62
    #define QUARTERROUND(a,b,c,d) \
63
461k
        x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
64
461k
        x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
65
461k
        x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
66
461k
        x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);
67
#endif /* HAVE_CHACHA */
68
69
70
/* BEGIN ChaCha C implementation */
71
#if defined(HAVE_CHACHA)
72
73
#include <wolfssl/wolfcrypt/cpuid.h>
74
75
#ifdef CHACHA_AEAD_TEST
76
    #include <stdio.h>
77
#endif
78
79
#ifdef USE_INTEL_CHACHA_SPEEDUP
80
    #include <emmintrin.h>
81
    #include <immintrin.h>
82
83
    #if defined(__GNUC__) && ((__GNUC__ < 4) || \
84
                              (__GNUC__ == 4 && __GNUC_MINOR__ <= 8))
85
        #undef  NO_AVX2_SUPPORT
86
        #define NO_AVX2_SUPPORT
87
    #endif
88
    #if defined(__clang__) && ((__clang_major__ < 3) || \
89
                               (__clang_major__ == 3 && __clang_minor__ <= 5))
90
        #undef  NO_AVX2_SUPPORT
91
        #define NO_AVX2_SUPPORT
92
    #elif defined(__clang__) && defined(NO_AVX2_SUPPORT)
93
        #undef NO_AVX2_SUPPORT
94
    #endif
95
    #if defined(_MSC_VER) && (_MSC_VER <= 1900)
96
        #undef  NO_AVX2_SUPPORT
97
        #define NO_AVX2_SUPPORT
98
    #endif
99
100
    #ifndef NO_AVX2_SUPPORT
101
        #define HAVE_INTEL_AVX2
102
    #endif
103
    #if !defined(NO_AVX512_SUPPORT) && !defined(HAVE_INTEL_AVX512)
104
        #define HAVE_INTEL_AVX512
105
    #endif
106
    /* SSSE3 is the baseline SIMD path, used on CPUs that lack AVX. */
107
    #ifndef HAVE_INTEL_SSSE3
108
        #define HAVE_INTEL_SSSE3
109
    #endif
110
111
    static cpuid_flags_t cpuidFlags = WC_CPUID_INITIALIZER;
112
#endif
113
114
/* The aarch64 ChaCha assembly is NEON-only. When NEON might be absent, also
115
 * build the C implementation: dispatch on ASIMD at runtime when NEON is
116
 * compiled in, or use only the C path when NEON is disabled at build time. */
117
#if defined(USE_ARM_CHACHA_SPEEDUP) && defined(__aarch64__)
118
    #ifdef WOLFSSL_ARMASM_NO_NEON
119
        #define WOLFSSL_ARM_CHACHA_C_ONLY
120
    #else
121
        #define WOLFSSL_ARM_CHACHA_NEON_FALLBACK
122
    #endif
123
#endif
124
#if defined(WOLFSSL_ARM_CHACHA_NEON_FALLBACK) || \
125
    defined(WOLFSSL_ARM_CHACHA_C_ONLY)
126
    #define WOLFSSL_ARM_CHACHA_NEED_C
127
#endif
128
129
#ifdef WOLFSSL_ARM_CHACHA_NEON_FALLBACK
130
    static cpuid_flags_t chacha_cpuid_flags = WC_CPUID_INITIALIZER;
131
    /* Return non-zero when NEON/ASIMD is present and the asm path should run. */
132
    static WC_INLINE int chacha_use_neon(void)
133
    {
134
        cpuid_get_flags_ex(&chacha_cpuid_flags);
135
        return IS_AARCH64_ASIMD(chacha_cpuid_flags);
136
    }
137
#endif
138
139
/**
140
  * Set up iv(nonce). Earlier versions used 64 bits instead of 96, this version
141
  * uses the typical AEAD 96 bit nonce and can do record sizes of 256 GB.
142
  */
143
int wc_Chacha_SetIV(ChaCha* ctx, const byte* inIv, word32 counter)
144
988
{
145
988
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
146
988
    !defined(USE_RISCV_CHACHA_SPEEDUP) && !defined(WOLFSSL_WIDE_BYTE)
147
988
    word32 temp[CHACHA_IV_WORDS];/* used for alignment of memory */
148
988
#endif
149
150
988
    if (ctx == NULL || inIv == NULL)
151
0
        return BAD_FUNC_ARG;
152
153
988
    ctx->left = 0; /* resets state */
154
155
#ifdef WOLFSSL_ARM_CHACHA_NEON_FALLBACK
156
    if (chacha_use_neon())
157
        wc_chacha_setiv(ctx->X, inIv, counter);
158
    else
159
#elif (defined(USE_ARM_CHACHA_SPEEDUP) && !defined(WOLFSSL_ARM_CHACHA_C_ONLY)) || \
160
    defined(USE_RISCV_CHACHA_SPEEDUP)
161
    wc_chacha_setiv(ctx->X, inIv, counter);
162
#endif
163
988
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
164
988
    !defined(USE_RISCV_CHACHA_SPEEDUP)
165
988
    {
166
#ifdef WOLFSSL_WIDE_BYTE
167
        /* inIv holds one octet per cell, so XMEMCPY into a word32[] would
168
         * overflow; load the three little-endian nonce/counter words
169
         * octet-wise instead. */
170
        ctx->X[CHACHA_MATRIX_CNT_IV+0] = counter;
171
        ctx->X[CHACHA_MATRIX_CNT_IV+1] = U8TO32_LITTLE(inIv + 0);
172
        ctx->X[CHACHA_MATRIX_CNT_IV+2] = U8TO32_LITTLE(inIv + 4);
173
        ctx->X[CHACHA_MATRIX_CNT_IV+3] = U8TO32_LITTLE(inIv + 8);
174
#else
175
988
        XMEMCPY(temp, inIv, CHACHA_IV_BYTES);
176
        /* block counter */
177
988
        ctx->X[CHACHA_MATRIX_CNT_IV+0] = counter;
178
        /* fixed variable from nonce */
179
988
        ctx->X[CHACHA_MATRIX_CNT_IV+1] = LITTLE32(temp[0]);
180
        /* counter from nonce */
181
988
        ctx->X[CHACHA_MATRIX_CNT_IV+2] = LITTLE32(temp[1]);
182
        /* counter from nonce */
183
988
        ctx->X[CHACHA_MATRIX_CNT_IV+3] = LITTLE32(temp[2]);
184
988
#endif
185
988
    }
186
988
#endif
187
188
988
    return 0;
189
988
}
190
191
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
192
    !defined(USE_RISCV_CHACHA_SPEEDUP)
193
/* "expand 32-byte k" as unsigned 32 byte */
194
static const word32 sigma[4] = {0x61707865, 0x3320646e, 0x79622d32, 0x6b206574};
195
/* "expand 16-byte k" as unsigned 16 byte */
196
static const word32 tau[4] = {0x61707865, 0x3120646e, 0x79622d36, 0x6b206574};
197
#endif
198
199
/**
200
  * Key setup. 8 word iv (nonce)
201
  */
202
int wc_Chacha_SetKey(ChaCha* ctx, const byte* key, word32 keySz)
203
326
{
204
326
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
205
326
    !defined(USE_RISCV_CHACHA_SPEEDUP)
206
326
    const word32* constants;
207
326
    const byte*   k;
208
#ifdef XSTREAM_ALIGN
209
    word32 alignKey[8];
210
#endif
211
326
#endif
212
213
326
    if (ctx == NULL || key == NULL)
214
0
        return BAD_FUNC_ARG;
215
216
326
    if (keySz != (CHACHA_MAX_KEY_SZ/2) && keySz != CHACHA_MAX_KEY_SZ)
217
0
        return BAD_FUNC_ARG;
218
219
#ifdef WOLFSSL_ARM_CHACHA_NEON_FALLBACK
220
    if (chacha_use_neon())
221
        wc_chacha_setkey(ctx->X, key, keySz);
222
    else
223
#elif (defined(USE_ARM_CHACHA_SPEEDUP) && !defined(WOLFSSL_ARM_CHACHA_C_ONLY)) || \
224
    defined(USE_RISCV_CHACHA_SPEEDUP)
225
    wc_chacha_setkey(ctx->X, key, keySz);
226
#endif
227
326
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
228
326
    !defined(USE_RISCV_CHACHA_SPEEDUP)
229
326
    {
230
#ifdef XSTREAM_ALIGN
231
    if ((wc_ptr_t)key % 4) {
232
        WOLFSSL_MSG("wc_ChachaSetKey unaligned key");
233
        XMEMCPY(alignKey, key, keySz);
234
        k = (byte*)alignKey;
235
    }
236
    else {
237
        k = key;
238
    }
239
#else
240
326
    k = key;
241
326
#endif /* XSTREAM_ALIGN */
242
243
#ifdef CHACHA_AEAD_TEST
244
    word32 i;
245
    printf("ChaCha key used :\n");
246
    for (i = 0; i < keySz; i++) {
247
        printf("%02x", key[i]);
248
        if ((i + 1) % 8 == 0)
249
           printf("\n");
250
    }
251
    printf("\n\n");
252
#endif
253
254
326
    ctx->X[4] = U8TO32_LITTLE(k +  0);
255
326
    ctx->X[5] = U8TO32_LITTLE(k +  4);
256
326
    ctx->X[6] = U8TO32_LITTLE(k +  8);
257
326
    ctx->X[7] = U8TO32_LITTLE(k + 12);
258
326
    if (keySz == CHACHA_MAX_KEY_SZ) {
259
326
        k += 16;
260
326
        constants = sigma;
261
326
    }
262
0
    else {
263
0
        constants = tau;
264
0
    }
265
326
    ctx->X[ 8] = U8TO32_LITTLE(k +  0);
266
326
    ctx->X[ 9] = U8TO32_LITTLE(k +  4);
267
326
    ctx->X[10] = U8TO32_LITTLE(k +  8);
268
326
    ctx->X[11] = U8TO32_LITTLE(k + 12);
269
326
    ctx->X[ 0] = constants[0];
270
326
    ctx->X[ 1] = constants[1];
271
326
    ctx->X[ 2] = constants[2];
272
326
    ctx->X[ 3] = constants[3];
273
326
    }
274
326
#endif
275
276
326
    ctx->left = 0; /* resets state */
277
326
    ctx->keySet = 1;
278
279
326
    return 0;
280
326
}
281
282
#if (!defined(USE_INTEL_CHACHA_SPEEDUP) && !defined(USE_ARM_CHACHA_SPEEDUP) && \
283
    !defined(USE_RISCV_CHACHA_SPEEDUP)) || defined(WOLFSSL_ARM_CHACHA_NEED_C)
284
/**
285
  * Converts word into bytes with rotations having been done.
286
  */
287
static WC_INLINE void wc_Chacha_wordtobyte(word32 x[CHACHA_CHUNK_WORDS],
288
        word32 state[CHACHA_CHUNK_WORDS])
289
5.76k
{
290
5.76k
    word32 i;
291
292
    /* Copy the word32[] state array by its cell size, not CHACHA_CHUNK_BYTES:
293
     * that macro is an octet count (=64) for serialized keystream buffers, and
294
     * XMEMCPY works in CHAR_BIT-sized cells, so using it here would over-copy
295
     * (2x) on CHAR_BIT == 16 targets. See chacha.h CHACHA_CHUNK_BYTES note. */
296
5.76k
    XMEMCPY(x, state, CHACHA_CHUNK_WORDS * sizeof(word32));
297
298
63.4k
    for (i = (ROUNDS); i > 0; i -= 2) {
299
57.6k
        QUARTERROUND(0, 4,  8, 12)
300
57.6k
        QUARTERROUND(1, 5,  9, 13)
301
57.6k
        QUARTERROUND(2, 6, 10, 14)
302
57.6k
        QUARTERROUND(3, 7, 11, 15)
303
57.6k
        QUARTERROUND(0, 5, 10, 15)
304
57.6k
        QUARTERROUND(1, 6, 11, 12)
305
57.6k
        QUARTERROUND(2, 7,  8, 13)
306
57.6k
        QUARTERROUND(3, 4,  9, 14)
307
57.6k
    }
308
309
98.0k
    for (i = 0; i < CHACHA_CHUNK_WORDS; i++) {
310
92.2k
        x[i] = PLUS(x[i], state[i]);
311
#ifdef BIG_ENDIAN_ORDER
312
        x[i] = LITTLE32(x[i]);
313
#endif
314
92.2k
    }
315
5.76k
}
316
#endif /* !USE_INTEL_CHACHA_SPEEDUP */
317
318
#ifdef __cplusplus
319
    extern "C" {
320
#endif
321
322
extern void chacha_encrypt_x64(ChaCha* ctx, const byte* m, byte* c,
323
                               word32 bytes);
324
extern void chacha_encrypt_avx1(ChaCha* ctx, const byte* m, byte* c,
325
                                word32 bytes);
326
extern void chacha_encrypt_avx2(ChaCha* ctx, const byte* m, byte* c,
327
                                word32 bytes);
328
extern void chacha_encrypt_avx512(ChaCha* ctx, const byte* m, byte* c,
329
                                  word32 bytes);
330
extern void chacha_encrypt_avx512vl(ChaCha* ctx, const byte* m, byte* c,
331
                                    word32 bytes);
332
extern void chacha_encrypt_sse3(ChaCha* ctx, const byte* m, byte* c,
333
                                word32 bytes);
334
335
#ifdef __cplusplus
336
    }  /* extern "C" */
337
#endif
338
339
#if defined(USE_INTEL_CHACHA_SPEEDUP) && defined(HAVE_INTEL_AVX512)
340
/* Decide whether to use the 512-bit (zmm) ChaCha path for this CPU.
341
 *
342
 * The zmm path processes 16 blocks at a time and is the fastest option on
343
 * microarchitectures that run 512-bit code at full clock: AMD Zen 4/5 (no
344
 * AVX-512 license) and Intel Ice Lake and later.  On Intel Skylake-SP /
345
 * Cascade Lake-class parts, sustained 512-bit instructions trip the AVX-512
346
 * frequency license and downclock the core - enough that the 256-bit AVX2 path
347
 * is faster in practice (this matches OpenSSL, which suppresses its 16x zmm
348
 * ChaCha there, and the Linux kernel, which uses only 256-bit AVX-512VL).
349
 *
350
 * There is no direct "does this core downclock" CPUID bit, so VAES presence is
351
 * used as a generational proxy: the throttling parts (Skylake-SP / Skylake-X /
352
 * Cascade Lake) predate VAES, whereas every microarchitecture that runs 512-bit
353
 * without penalty (AMD Zen 4/5, Intel Ice Lake+) implements it.  A missing VAES
354
 * only costs a little throughput (fall back to AVX2), never correctness.
355
 *
356
 * Override the heuristic with:
357
 *   WOLFSSL_CHACHA20_AVX512_ALWAYS - use zmm whenever AVX-512 is present
358
 *   WOLFSSL_CHACHA20_AVX512_NEVER  - never use zmm (always AVX2 or below)
359
 */
360
static WC_INLINE int chacha_avx512_beneficial(cpuid_flags_t flags)
361
{
362
#if defined(WOLFSSL_CHACHA20_AVX512_NEVER)
363
    (void)flags;
364
    return 0;
365
#elif defined(WOLFSSL_CHACHA20_AVX512_ALWAYS)
366
    return IS_INTEL_AVX512(flags) != 0;
367
#else
368
    return (IS_INTEL_AVX512(flags) != 0) && (IS_INTEL_VAES(flags) != 0);
369
#endif
370
}
371
#endif /* USE_INTEL_CHACHA_SPEEDUP && HAVE_INTEL_AVX512 */
372
373
374
#if (!defined(USE_INTEL_CHACHA_SPEEDUP) && !defined(USE_ARM_CHACHA_SPEEDUP) && \
375
    !defined(USE_RISCV_CHACHA_SPEEDUP)) || defined(WOLFSSL_ARM_CHACHA_NEED_C)
376
/**
377
  * Encrypt a stream of bytes
378
  */
379
static void wc_Chacha_encrypt_bytes(ChaCha* ctx, const byte* m, byte* c,
380
                                    word32 bytes)
381
978
{
382
#ifdef WOLFSSL_WIDE_BYTE
383
    /* A C byte is wider than an octet here, so the keystream cannot be aliased
384
     * as both word32 and byte through a union; generate the 16 state words and
385
     * serialize them little-endian into a one-octet-per-cell byte buffer. */
386
    word32 ks32[CHACHA_CHUNK_WORDS];
387
    byte   sbuf[CHACHA_CHUNK_BYTES];
388
    byte*  state = sbuf;
389
    #define WC_CHACHA_GEN_STREAM()                                  \
390
        do {                                                        \
391
            wc_Chacha_wordtobyte(ks32, ctx->X);                     \
392
            BytesFromWordsLE32(sbuf, ks32, CHACHA_CHUNK_BYTES);     \
393
        } while (0)
394
#else
395
978
    union {
396
978
        byte state[CHACHA_CHUNK_BYTES];
397
978
        word32 state32[CHACHA_CHUNK_WORDS];
398
978
        wolfssl_word align_word; /* align for xorbufout */
399
978
    } tmp;
400
978
    byte* state = tmp.state;
401
5.76k
    #define WC_CHACHA_GEN_STREAM() wc_Chacha_wordtobyte(tmp.state32, ctx->X)
402
978
#endif
403
404
    /* handle left overs */
405
978
    if (bytes > 0 && ctx->left > 0) {
406
0
        word32 processed = min(bytes, ctx->left);
407
0
        WC_CHACHA_GEN_STREAM(); /* recreate the stream */
408
0
        xorbufout(c, m, state + CHACHA_CHUNK_BYTES - ctx->left, processed);
409
0
        ctx->left -= processed;
410
411
        /* Used up all of the stream that was left, increment the counter */
412
0
        if (ctx->left == 0) {
413
0
            ctx->X[CHACHA_MATRIX_CNT_IV] =
414
0
                                          PLUSONE(ctx->X[CHACHA_MATRIX_CNT_IV]);
415
0
        }
416
0
        bytes -= processed;
417
0
        c += processed;
418
0
        m += processed;
419
0
    }
420
421
5.76k
    while (bytes >= CHACHA_CHUNK_BYTES) {
422
4.79k
        WC_CHACHA_GEN_STREAM();
423
4.79k
        ctx->X[CHACHA_MATRIX_CNT_IV] = PLUSONE(ctx->X[CHACHA_MATRIX_CNT_IV]);
424
4.79k
        xorbufout(c, m, state, CHACHA_CHUNK_BYTES);
425
4.79k
        bytes -= CHACHA_CHUNK_BYTES;
426
4.79k
        c += CHACHA_CHUNK_BYTES;
427
4.79k
        m += CHACHA_CHUNK_BYTES;
428
4.79k
    }
429
430
978
    if (bytes) {
431
        /* in this case there will always be some left over since bytes is less
432
         * than CHACHA_CHUNK_BYTES, so do not increment counter after getting
433
         * stream in order for the stream to be recreated on next call */
434
976
        WC_CHACHA_GEN_STREAM();
435
976
        xorbufout(c, m, state, bytes);
436
976
        ctx->left = CHACHA_CHUNK_BYTES - bytes;
437
976
    }
438
978
    #undef WC_CHACHA_GEN_STREAM
439
978
}
440
#endif /* !USE_INTEL_CHACHA_SPEEDUP */
441
442
443
/**
444
  * API to encrypt/decrypt a message of any size.
445
  */
446
int wc_Chacha_Process(ChaCha* ctx, byte* output, const byte* input,
447
                      word32 msglen)
448
978
{
449
978
    if (ctx == NULL || input == NULL || output == NULL)
450
0
        return BAD_FUNC_ARG;
451
452
978
    if (!ctx->keySet)
453
0
        return MISSING_KEY;
454
455
#ifdef USE_INTEL_CHACHA_SPEEDUP
456
    /* handle left overs */
457
    if (msglen > 0 && ctx->left > 0) {
458
        byte*  out;
459
        word32 processed = min(msglen, ctx->left);
460
461
        out = (byte*)ctx->over + CHACHA_CHUNK_BYTES - ctx->left;
462
        xorbufout(output, input, out, processed);
463
        ctx->left -= processed;
464
        msglen -= processed;
465
        output += processed;
466
        input += processed;
467
    }
468
469
    if (msglen == 0) {
470
        return 0;
471
    }
472
473
    cpuid_get_flags_ex(&cpuidFlags);
474
475
    /* One block or less. */
476
#if defined(HAVE_INTEL_AVX1) && !defined(WOLFSSL_LINUXKM)
477
    /* In userspace SAVE_VECTOR_REGISTERS is free, so a single AVX block (~285
478
     * cyc) beats the scalar block (~435) - e.g. the per-record Poly1305 key
479
     * derivation (a 32-byte ChaCha) in the ChaCha20-Poly1305 two-pass path.
480
     * The AVX-512VL path already uses SIMD for one block; match that here. */
481
    if (msglen <= CHACHA_CHUNK_BYTES && IS_INTEL_AVX512_VL(cpuidFlags) == 0 &&
482
            IS_INTEL_AVX1(cpuidFlags)) {
483
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
484
        chacha_encrypt_avx1(ctx, input, output, msglen);
485
        RESTORE_VECTOR_REGISTERS();
486
        return 0;
487
    }
488
#endif
489
    /* At most one block: the scalar path avoids the SIMD broadcast/transpose
490
     * setup and (in the Linux kernel module) the costly vector-register
491
     * save/restore. */
492
    if (msglen <= CHACHA_CHUNK_BYTES) {
493
        chacha_encrypt_x64(ctx, input, output, msglen);
494
        return 0;
495
    }
496
497
    /* 65..255 bytes without AVX-512VL: use the SSSE3 128-bit exact-block path.
498
     * It is ~1.8x the scalar path and beats the 8-block AVX2 kernel (which
499
     * always emits a full 512-byte key stream) below 256 bytes - e.g. a
500
     * 192-byte key stream is 735 vs 1335 (scalar) vs 836 (AVX2) cycles on
501
     * Coffee Lake.  This is the ChaCha20-Poly1305 short-record hot path (poly
502
     * key + <=2 data blocks).  At >=256 bytes the four-block AVX2/AVX1 kernels
503
     * take over below. */
504
#ifdef HAVE_INTEL_SSSE3
505
    if (IS_INTEL_AVX512_VL(cpuidFlags) == 0 &&
506
            msglen < 4 * CHACHA_CHUNK_BYTES &&
507
            IS_INTEL_SSSE3(cpuidFlags)) {
508
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
509
        chacha_encrypt_sse3(ctx, input, output, msglen);
510
        RESTORE_VECTOR_REGISTERS();
511
        return 0;
512
    }
513
#endif
514
    if (IS_INTEL_AVX512_VL(cpuidFlags) == 0 &&
515
            msglen < 4 * CHACHA_CHUNK_BYTES) {
516
        chacha_encrypt_x64(ctx, input, output, msglen);
517
        return 0;
518
    }
519
520
    #ifdef HAVE_INTEL_AVX512
521
    /* Below one 16-block chunk (1024 bytes) the zmm path does no work and
522
     * just tail-calls AVX2, so dispatch straight to AVX2 for smaller input. */
523
    if (chacha_avx512_beneficial(cpuidFlags) &&
524
            msglen >= 16 * CHACHA_CHUNK_BYTES) {
525
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
526
        chacha_encrypt_avx512(ctx, input, output, msglen);
527
        RESTORE_VECTOR_REGISTERS();
528
        return 0;
529
    }
530
    /* Everything below the AVX2 512-byte minimum (1..511 bytes) is handled by
531
     * the AVX-512VL path itself - whole 256-byte four-block chunks plus a
532
     * partial four-block tail - using single-instruction vprold rotations on
533
     * 128-bit registers (no AVX-512 frequency penalty).  It does not fall back
534
     * to any other implementation. */
535
    if (IS_INTEL_AVX512_VL(cpuidFlags) && msglen < 8 * CHACHA_CHUNK_BYTES) {
536
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
537
        chacha_encrypt_avx512vl(ctx, input, output, msglen);
538
        RESTORE_VECTOR_REGISTERS();
539
        return 0;
540
    }
541
    #endif
542
    #ifdef HAVE_INTEL_AVX2
543
    if (IS_INTEL_AVX2(cpuidFlags)) {
544
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
545
        chacha_encrypt_avx2(ctx, input, output, msglen);
546
        RESTORE_VECTOR_REGISTERS();
547
        return 0;
548
    }
549
    #endif
550
    if (IS_INTEL_AVX1(cpuidFlags)) {
551
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
552
        chacha_encrypt_avx1(ctx, input, output, msglen);
553
        RESTORE_VECTOR_REGISTERS();
554
        return 0;
555
    }
556
    #ifdef HAVE_INTEL_SSSE3
557
    else if (IS_INTEL_SSSE3(cpuidFlags)) {
558
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
559
        chacha_encrypt_sse3(ctx, input, output, msglen);
560
        RESTORE_VECTOR_REGISTERS();
561
        return 0;
562
    }
563
    #endif
564
    else {
565
        chacha_encrypt_x64(ctx, input, output, msglen);
566
        return 0;
567
    }
568
#elif defined(USE_ARM_CHACHA_SPEEDUP) || defined(USE_RISCV_CHACHA_SPEEDUP)
569
#ifdef WOLFSSL_ARM_CHACHA_NEON_FALLBACK
570
    if (chacha_use_neon())
571
#endif
572
#ifndef WOLFSSL_ARM_CHACHA_C_ONLY
573
    {
574
        /* Handle left over bytes from last block. */
575
        if ((msglen > 0) && (ctx->left > 0)) {
576
            byte* over = ((byte*)ctx->over) + CHACHA_CHUNK_BYTES - ctx->left;
577
            word32 l = min(msglen, ctx->left);
578
579
            wc_chacha_use_over(over, output, input, l);
580
581
            ctx->left -= l;
582
            input += l;
583
            output += l;
584
            msglen -= l;
585
        }
586
587
        if (msglen != 0) {
588
            wc_chacha_crypt_bytes(ctx, output, input, msglen);
589
        }
590
        return 0;
591
    }
592
#endif
593
#ifdef WOLFSSL_ARM_CHACHA_NEED_C
594
#ifdef WOLFSSL_ARM_CHACHA_NEON_FALLBACK
595
    else
596
#endif
597
    {
598
        wc_Chacha_encrypt_bytes(ctx, input, output, msglen);
599
        return 0;
600
    }
601
#endif
602
#else
603
978
    wc_Chacha_encrypt_bytes(ctx, input, output, msglen);
604
978
    return 0;
605
978
#endif
606
978
}
607
#endif /* HAVE_CHACHA */
608
/* END ChaCha C implementation */
609
610
#if defined(HAVE_CHACHA) && defined(HAVE_XCHACHA)
611
612
void wc_Chacha_purge_current_block(ChaCha* ctx)
613
0
{
614
0
    if (ctx->left > 0) {
615
0
        byte scratch[CHACHA_CHUNK_BYTES];
616
0
        XMEMSET(scratch, 0, sizeof(scratch));
617
0
        (void)wc_Chacha_Process(ctx, scratch, scratch, CHACHA_CHUNK_BYTES - ctx->left);
618
0
    }
619
0
}
620
621
/*
622
 * wc_HChacha_block - half a ChaCha block, for XChaCha
623
 *
624
 * see https://tools.ietf.org/html/draft-arciszewski-xchacha-03
625
 */
626
static WC_INLINE void wc_HChacha_block(ChaCha* ctx,
627
    word32 stream[CHACHA_CHUNK_WORDS/2], word32 nrounds)
628
0
{
629
0
    word32 x[CHACHA_CHUNK_WORDS];
630
0
    word32 i;
631
632
0
    for (i = 0; i < CHACHA_CHUNK_WORDS; i++) {
633
0
        x[i] = ctx->X[i];
634
0
    }
635
636
0
    for (i = nrounds; i > 0; i -= 2) {
637
0
        QUARTERROUND(0, 4,  8, 12)
638
0
        QUARTERROUND(1, 5,  9, 13)
639
0
        QUARTERROUND(2, 6, 10, 14)
640
0
        QUARTERROUND(3, 7, 11, 15)
641
0
        QUARTERROUND(0, 5, 10, 15)
642
0
        QUARTERROUND(1, 6, 11, 12)
643
0
        QUARTERROUND(2, 7,  8, 13)
644
0
        QUARTERROUND(3, 4,  9, 14)
645
0
    }
646
647
0
    for (i = 0; i < CHACHA_CHUNK_WORDS/4; ++i)
648
0
        stream[i] = x[i];
649
0
    for (i = CHACHA_CHUNK_WORDS/4; i < CHACHA_CHUNK_WORDS/2; ++i)
650
0
        stream[i] = x[i + CHACHA_CHUNK_WORDS/2];
651
0
}
652
653
/* XChaCha -- https://tools.ietf.org/html/draft-arciszewski-xchacha-03 */
654
int wc_XChacha_SetKey(ChaCha *ctx,
655
                      const byte *key, word32 keySz,
656
                      const byte *nonce, word32 nonceSz,
657
                      word32 counter)
658
0
{
659
0
    int ret;
660
0
    word32 k[CHACHA_MAX_KEY_SZ];
661
0
    byte   iv[CHACHA_IV_BYTES];
662
663
    /* k will hold the HChacha-derived subkey and iv the derived IV. Register
664
     * from the top with a zero baseline so every exit (including the arg/setup
665
     * error returns below, where the buffers are still zero) is covered. */
666
#ifdef WOLFSSL_CHECK_MEM_ZERO
667
    XMEMSET(k, 0, sizeof k);
668
    XMEMSET(iv, 0, sizeof iv);
669
    wc_MemZero_Add("wc_XChacha_SetKey k", k, sizeof k);
670
    wc_MemZero_Add("wc_XChacha_SetKey iv", iv, sizeof iv);
671
#endif
672
673
0
    if (nonceSz != XCHACHA_NONCE_BYTES) {
674
    #ifdef WOLFSSL_CHECK_MEM_ZERO
675
        wc_MemZero_Check(k, sizeof k);
676
        wc_MemZero_Check(iv, sizeof iv);
677
    #endif
678
0
        return BAD_FUNC_ARG;
679
0
    }
680
681
0
    if ((ret = wc_Chacha_SetKey(ctx, key, keySz)) < 0) {
682
    #ifdef WOLFSSL_CHECK_MEM_ZERO
683
        wc_MemZero_Check(k, sizeof k);
684
        wc_MemZero_Check(iv, sizeof iv);
685
    #endif
686
0
        return ret;
687
0
    }
688
689
    /* form a first chacha IV from the first 16 bytes of the nonce.
690
     * the first word is supplied in the "counter" arg, and
691
     * the result is a full 128 bit nonceful IV for the one-time block
692
     * crypto op that follows.
693
     */
694
0
    if ((ret = wc_Chacha_SetIV(ctx, nonce + 4, U8TO32_LITTLE(nonce))) < 0) {
695
    #ifdef WOLFSSL_CHECK_MEM_ZERO
696
        wc_MemZero_Check(k, sizeof k);
697
        wc_MemZero_Check(iv, sizeof iv);
698
    #endif
699
0
        return ret;
700
0
    }
701
702
0
    wc_HChacha_block(ctx, k, 20); /* 20 rounds, but keeping half the output. */
703
704
    /* the HChacha output is used as a 256 bit key for the main cipher. */
705
0
    XMEMCPY(&ctx->X[4], k, 8 * sizeof(word32));
706
707
    /* use 8 bytes from the end of the 24 byte nonce, padded up to 12 bytes,
708
     * to form the IV for the main cipher.
709
     */
710
0
    XMEMSET(iv, 0, 4);
711
0
    XMEMCPY(iv + 4, nonce + 16, 8);
712
713
0
    if ((ret = wc_Chacha_SetIV(ctx, iv, counter)) < 0) {
714
        /* k and iv hold derived key material - wipe before erroring out. */
715
0
        ForceZero(k, sizeof k);
716
0
        ForceZero(iv, sizeof iv);
717
    #ifdef WOLFSSL_CHECK_MEM_ZERO
718
        wc_MemZero_Check(k, sizeof k);
719
        wc_MemZero_Check(iv, sizeof iv);
720
    #endif
721
0
        return ret;
722
0
    }
723
724
0
    ForceZero(k, sizeof k);
725
0
    ForceZero(iv, sizeof iv);
726
#ifdef WOLFSSL_CHECK_MEM_ZERO
727
    wc_MemZero_Check(k, sizeof k);
728
    wc_MemZero_Check(iv, sizeof iv);
729
#endif
730
731
0
    return 0;
732
0
}
733
734
#endif /* HAVE_CHACHA && HAVE_XCHACHA */