Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wolfssl-fastmath/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
1.53k
        #define LITTLE32(x) (x)
48
    #endif
49
50
    /* Number of rounds */
51
925
    #define ROUNDS  20
52
53
311k
    #define U32C(v) (v##U)
54
311k
    #define U32V(v) ((word32)(v) & U32C(0xFFFFFFFF))
55
752
    #define U8TO32_LITTLE(p) LITTLE32(readUnalignedWord32(p))
56
57
296k
    #define ROTATE(v,c) rotlFixed(v, c)
58
    #define XOR(v,w)    ((v) ^ (w))
59
311k
    #define PLUS(v,w)   (U32V((v) + (w)))
60
676
    #define PLUSONE(v)  (PLUS((v),1))
61
62
    #define QUARTERROUND(a,b,c,d) \
63
74.0k
        x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
64
74.0k
        x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
65
74.0k
        x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
66
74.0k
        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
260
{
145
260
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
146
260
    !defined(USE_RISCV_CHACHA_SPEEDUP) && !defined(WOLFSSL_WIDE_BYTE)
147
260
    word32 temp[CHACHA_IV_WORDS];/* used for alignment of memory */
148
260
#endif
149
150
260
    if (ctx == NULL || inIv == NULL)
151
0
        return BAD_FUNC_ARG;
152
153
260
    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
260
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
164
260
    !defined(USE_RISCV_CHACHA_SPEEDUP)
165
260
    {
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
260
        XMEMCPY(temp, inIv, CHACHA_IV_BYTES);
176
        /* block counter */
177
260
        ctx->X[CHACHA_MATRIX_CNT_IV+0] = counter;
178
        /* fixed variable from nonce */
179
260
        ctx->X[CHACHA_MATRIX_CNT_IV+1] = LITTLE32(temp[0]);
180
        /* counter from nonce */
181
260
        ctx->X[CHACHA_MATRIX_CNT_IV+2] = LITTLE32(temp[1]);
182
        /* counter from nonce */
183
260
        ctx->X[CHACHA_MATRIX_CNT_IV+3] = LITTLE32(temp[2]);
184
260
#endif
185
260
    }
186
260
#endif
187
188
260
    return 0;
189
260
}
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_ex(ChaCha* ctx, const byte* key, word32 keySz,
203
    void* heap, int devId)
204
94
{
205
94
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
206
94
    !defined(USE_RISCV_CHACHA_SPEEDUP)
207
94
    const word32* constants;
208
94
    const byte*   k;
209
#ifdef XSTREAM_ALIGN
210
    word32 alignKey[8];
211
#endif
212
94
#endif
213
214
94
    if (ctx == NULL || key == NULL)
215
0
        return BAD_FUNC_ARG;
216
217
94
    if (keySz != (CHACHA_MAX_KEY_SZ/2) && keySz != CHACHA_MAX_KEY_SZ)
218
0
        return BAD_FUNC_ARG;
219
220
#ifdef WOLFSSL_ARM_CHACHA_NEON_FALLBACK
221
    if (chacha_use_neon())
222
        wc_chacha_setkey(ctx->X, key, keySz);
223
    else
224
#elif (defined(USE_ARM_CHACHA_SPEEDUP) && !defined(WOLFSSL_ARM_CHACHA_C_ONLY)) || \
225
    defined(USE_RISCV_CHACHA_SPEEDUP)
226
    wc_chacha_setkey(ctx->X, key, keySz);
227
#endif
228
94
#if (!defined(USE_ARM_CHACHA_SPEEDUP) || defined(WOLFSSL_ARM_CHACHA_NEED_C)) && \
229
94
    !defined(USE_RISCV_CHACHA_SPEEDUP)
230
94
    {
231
#ifdef XSTREAM_ALIGN
232
    if ((wc_ptr_t)key % 4) {
233
        WOLFSSL_MSG("wc_ChachaSetKey unaligned key");
234
        XMEMCPY(alignKey, key, keySz);
235
        k = (byte*)alignKey;
236
    }
237
    else {
238
        k = key;
239
    }
240
#else
241
94
    k = key;
242
94
#endif /* XSTREAM_ALIGN */
243
244
#ifdef CHACHA_AEAD_TEST
245
    word32 i;
246
    printf("ChaCha key used :\n");
247
    for (i = 0; i < keySz; i++) {
248
        printf("%02x", key[i]);
249
        if ((i + 1) % 8 == 0)
250
           printf("\n");
251
    }
252
    printf("\n\n");
253
#endif
254
255
94
    ctx->X[4] = U8TO32_LITTLE(k +  0);
256
94
    ctx->X[5] = U8TO32_LITTLE(k +  4);
257
94
    ctx->X[6] = U8TO32_LITTLE(k +  8);
258
94
    ctx->X[7] = U8TO32_LITTLE(k + 12);
259
94
    if (keySz == CHACHA_MAX_KEY_SZ) {
260
94
        k += 16;
261
94
        constants = sigma;
262
94
    }
263
0
    else {
264
0
        constants = tau;
265
0
    }
266
94
    ctx->X[ 8] = U8TO32_LITTLE(k +  0);
267
94
    ctx->X[ 9] = U8TO32_LITTLE(k +  4);
268
94
    ctx->X[10] = U8TO32_LITTLE(k +  8);
269
94
    ctx->X[11] = U8TO32_LITTLE(k + 12);
270
94
    ctx->X[ 0] = constants[0];
271
94
    ctx->X[ 1] = constants[1];
272
94
    ctx->X[ 2] = constants[2];
273
94
    ctx->X[ 3] = constants[3];
274
94
    }
275
94
#endif
276
277
94
    ctx->left = 0; /* resets state */
278
94
    ctx->keySet = 1;
279
280
94
#ifdef WOLF_CRYPTO_CB
281
    /* A device takes the plaintext key, not the expanded state above. There
282
     * is no wc_Chacha_Init(), so clear the whole buffer first rather than
283
     * leave the tail of a 16 byte key holding whatever the caller's storage
284
     * held before. */
285
94
    XMEMSET(ctx->devKey, 0, sizeof(ctx->devKey));
286
94
    XMEMCPY(ctx->devKey, key, keySz);
287
94
    ctx->devKeySz = keySz;
288
94
    ctx->devId = devId;
289
94
#endif
290
94
    (void)heap;   /* nothing on this path allocates */
291
94
    (void)devId;
292
293
94
    return 0;
294
94
}
295
296
int wc_Chacha_SetKey(ChaCha* ctx, const byte* key, word32 keySz)
297
0
{
298
0
    return wc_Chacha_SetKey_ex(ctx, key, keySz, NULL, INVALID_DEVID);
299
0
}
300
301
#if (!defined(USE_INTEL_CHACHA_SPEEDUP) && !defined(USE_ARM_CHACHA_SPEEDUP) && \
302
    !defined(USE_RISCV_CHACHA_SPEEDUP)) || defined(WOLFSSL_ARM_CHACHA_NEED_C)
303
/**
304
  * Converts word into bytes with rotations having been done.
305
  */
306
static WC_INLINE void wc_Chacha_wordtobyte(word32 x[CHACHA_CHUNK_WORDS],
307
        word32 state[CHACHA_CHUNK_WORDS])
308
925
{
309
925
    word32 i;
310
311
    /* Copy the word32[] state array by its cell size, not CHACHA_CHUNK_BYTES:
312
     * that macro is an octet count (=64) for serialized keystream buffers, and
313
     * XMEMCPY works in CHAR_BIT-sized cells, so using it here would over-copy
314
     * (2x) on CHAR_BIT == 16 targets. See chacha.h CHACHA_CHUNK_BYTES note. */
315
925
    XMEMCPY(x, state, CHACHA_CHUNK_WORDS * sizeof(word32));
316
317
10.1k
    for (i = (ROUNDS); i > 0; i -= 2) {
318
9.25k
        QUARTERROUND(0, 4,  8, 12)
319
9.25k
        QUARTERROUND(1, 5,  9, 13)
320
9.25k
        QUARTERROUND(2, 6, 10, 14)
321
9.25k
        QUARTERROUND(3, 7, 11, 15)
322
9.25k
        QUARTERROUND(0, 5, 10, 15)
323
9.25k
        QUARTERROUND(1, 6, 11, 12)
324
9.25k
        QUARTERROUND(2, 7,  8, 13)
325
9.25k
        QUARTERROUND(3, 4,  9, 14)
326
9.25k
    }
327
328
15.7k
    for (i = 0; i < CHACHA_CHUNK_WORDS; i++) {
329
14.8k
        x[i] = PLUS(x[i], state[i]);
330
#ifdef BIG_ENDIAN_ORDER
331
        x[i] = LITTLE32(x[i]);
332
#endif
333
14.8k
    }
334
925
}
335
#endif /* !USE_INTEL_CHACHA_SPEEDUP */
336
337
#ifdef __cplusplus
338
    extern "C" {
339
#endif
340
341
extern void chacha_encrypt_x64(ChaCha* ctx, const byte* m, byte* c,
342
                               word32 bytes);
343
extern void chacha_encrypt_avx1(ChaCha* ctx, const byte* m, byte* c,
344
                                word32 bytes);
345
extern void chacha_encrypt_avx2(ChaCha* ctx, const byte* m, byte* c,
346
                                word32 bytes);
347
extern void chacha_encrypt_avx512(ChaCha* ctx, const byte* m, byte* c,
348
                                  word32 bytes);
349
extern void chacha_encrypt_avx512vl(ChaCha* ctx, const byte* m, byte* c,
350
                                    word32 bytes);
351
extern void chacha_encrypt_sse3(ChaCha* ctx, const byte* m, byte* c,
352
                                word32 bytes);
353
354
#ifdef __cplusplus
355
    }  /* extern "C" */
356
#endif
357
358
#if defined(USE_INTEL_CHACHA_SPEEDUP) && defined(HAVE_INTEL_AVX512)
359
/* Decide whether to use the 512-bit (zmm) ChaCha path for this CPU.
360
 *
361
 * The zmm path processes 16 blocks at a time and is the fastest option on
362
 * microarchitectures that run 512-bit code at full clock: AMD Zen 4/5 (no
363
 * AVX-512 license) and Intel Ice Lake and later.  On Intel Skylake-SP /
364
 * Cascade Lake-class parts, sustained 512-bit instructions trip the AVX-512
365
 * frequency license and downclock the core - enough that the 256-bit AVX2 path
366
 * is faster in practice (this matches OpenSSL, which suppresses its 16x zmm
367
 * ChaCha there, and the Linux kernel, which uses only 256-bit AVX-512VL).
368
 *
369
 * There is no direct "does this core downclock" CPUID bit, so VAES presence is
370
 * used as a generational proxy: the throttling parts (Skylake-SP / Skylake-X /
371
 * Cascade Lake) predate VAES, whereas every microarchitecture that runs 512-bit
372
 * without penalty (AMD Zen 4/5, Intel Ice Lake+) implements it.  A missing VAES
373
 * only costs a little throughput (fall back to AVX2), never correctness.
374
 *
375
 * Override the heuristic with:
376
 *   WOLFSSL_CHACHA20_AVX512_ALWAYS - use zmm whenever AVX-512 is present
377
 *   WOLFSSL_CHACHA20_AVX512_NEVER  - never use zmm (always AVX2 or below)
378
 */
379
static WC_INLINE int chacha_avx512_beneficial(cpuid_flags_t flags)
380
{
381
#if defined(WOLFSSL_CHACHA20_AVX512_NEVER)
382
    (void)flags;
383
    return 0;
384
#elif defined(WOLFSSL_CHACHA20_AVX512_ALWAYS)
385
    return IS_INTEL_AVX512(flags) != 0;
386
#else
387
    return (IS_INTEL_AVX512(flags) != 0) && (IS_INTEL_VAES(flags) != 0);
388
#endif
389
}
390
#endif /* USE_INTEL_CHACHA_SPEEDUP && HAVE_INTEL_AVX512 */
391
392
393
#if (!defined(USE_INTEL_CHACHA_SPEEDUP) && !defined(USE_ARM_CHACHA_SPEEDUP) && \
394
    !defined(USE_RISCV_CHACHA_SPEEDUP)) || defined(WOLFSSL_ARM_CHACHA_NEED_C)
395
/**
396
  * Encrypt a stream of bytes
397
  */
398
static void wc_Chacha_encrypt_bytes(ChaCha* ctx, const byte* m, byte* c,
399
                                    word32 bytes)
400
250
{
401
#ifdef WOLFSSL_WIDE_BYTE
402
    /* A C byte is wider than an octet here, so the keystream cannot be aliased
403
     * as both word32 and byte through a union; generate the 16 state words and
404
     * serialize them little-endian into a one-octet-per-cell byte buffer. */
405
    word32 ks32[CHACHA_CHUNK_WORDS];
406
    byte   sbuf[CHACHA_CHUNK_BYTES];
407
    byte*  state = sbuf;
408
    #define WC_CHACHA_GEN_STREAM()                                  \
409
        do {                                                        \
410
            wc_Chacha_wordtobyte(ks32, ctx->X);                     \
411
            BytesFromWordsLE32(sbuf, ks32, CHACHA_CHUNK_BYTES);     \
412
        } while (0)
413
#else
414
250
    union {
415
250
        byte state[CHACHA_CHUNK_BYTES];
416
250
        word32 state32[CHACHA_CHUNK_WORDS];
417
250
        wolfssl_word align_word; /* align for xorbufout */
418
250
    } tmp;
419
250
    byte* state = tmp.state;
420
925
    #define WC_CHACHA_GEN_STREAM() wc_Chacha_wordtobyte(tmp.state32, ctx->X)
421
250
#endif
422
423
    /* handle left overs */
424
250
    if (bytes > 0 && ctx->left > 0) {
425
0
        word32 processed = min(bytes, ctx->left);
426
0
        WC_CHACHA_GEN_STREAM(); /* recreate the stream */
427
0
        xorbufout(c, m, state + CHACHA_CHUNK_BYTES - ctx->left, processed);
428
0
        ctx->left -= processed;
429
430
        /* Used up all of the stream that was left, increment the counter */
431
0
        if (ctx->left == 0) {
432
0
            ctx->X[CHACHA_MATRIX_CNT_IV] =
433
0
                                          PLUSONE(ctx->X[CHACHA_MATRIX_CNT_IV]);
434
0
        }
435
0
        bytes -= processed;
436
0
        c += processed;
437
0
        m += processed;
438
0
    }
439
440
926
    while (bytes >= CHACHA_CHUNK_BYTES) {
441
676
        WC_CHACHA_GEN_STREAM();
442
676
        ctx->X[CHACHA_MATRIX_CNT_IV] = PLUSONE(ctx->X[CHACHA_MATRIX_CNT_IV]);
443
676
        xorbufout(c, m, state, CHACHA_CHUNK_BYTES);
444
676
        bytes -= CHACHA_CHUNK_BYTES;
445
676
        c += CHACHA_CHUNK_BYTES;
446
676
        m += CHACHA_CHUNK_BYTES;
447
676
    }
448
449
250
    if (bytes) {
450
        /* in this case there will always be some left over since bytes is less
451
         * than CHACHA_CHUNK_BYTES, so do not increment counter after getting
452
         * stream in order for the stream to be recreated on next call */
453
249
        WC_CHACHA_GEN_STREAM();
454
249
        xorbufout(c, m, state, bytes);
455
249
        ctx->left = CHACHA_CHUNK_BYTES - bytes;
456
249
    }
457
250
    #undef WC_CHACHA_GEN_STREAM
458
250
}
459
#endif /* !USE_INTEL_CHACHA_SPEEDUP */
460
461
462
/**
463
  * API to encrypt/decrypt a message of any size.
464
  */
465
int wc_Chacha_Process(ChaCha* ctx, byte* output, const byte* input,
466
                      word32 msglen)
467
250
{
468
250
    if (ctx == NULL || input == NULL || output == NULL)
469
0
        return BAD_FUNC_ARG;
470
471
250
    if (!ctx->keySet)
472
0
        return MISSING_KEY;
473
474
#ifdef USE_INTEL_CHACHA_SPEEDUP
475
    /* handle left overs */
476
    if (msglen > 0 && ctx->left > 0) {
477
        byte*  out;
478
        word32 processed = min(msglen, ctx->left);
479
480
        out = (byte*)ctx->over + CHACHA_CHUNK_BYTES - ctx->left;
481
        xorbufout(output, input, out, processed);
482
        ctx->left -= processed;
483
        msglen -= processed;
484
        output += processed;
485
        input += processed;
486
    }
487
488
    if (msglen == 0) {
489
        return 0;
490
    }
491
492
    cpuid_get_flags_ex(&cpuidFlags);
493
494
    /* One block or less. */
495
#if defined(HAVE_INTEL_AVX1) && !defined(WOLFSSL_LINUXKM)
496
    /* In userspace SAVE_VECTOR_REGISTERS is free, so a single AVX block (~285
497
     * cyc) beats the scalar block (~435) - e.g. the per-record Poly1305 key
498
     * derivation (a 32-byte ChaCha) in the ChaCha20-Poly1305 two-pass path.
499
     * The AVX-512VL path already uses SIMD for one block; match that here. */
500
    if (msglen <= CHACHA_CHUNK_BYTES && IS_INTEL_AVX512_VL(cpuidFlags) == 0 &&
501
            IS_INTEL_AVX1(cpuidFlags)) {
502
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
503
        chacha_encrypt_avx1(ctx, input, output, msglen);
504
        RESTORE_VECTOR_REGISTERS();
505
        return 0;
506
    }
507
#endif
508
    /* At most one block: the scalar path avoids the SIMD broadcast/transpose
509
     * setup and (in the Linux kernel module) the costly vector-register
510
     * save/restore. */
511
    if (msglen <= CHACHA_CHUNK_BYTES) {
512
        chacha_encrypt_x64(ctx, input, output, msglen);
513
        return 0;
514
    }
515
516
    /* 65..255 bytes without AVX-512VL: use the SSSE3 128-bit exact-block path.
517
     * It is ~1.8x the scalar path and beats the 8-block AVX2 kernel (which
518
     * always emits a full 512-byte key stream) below 256 bytes - e.g. a
519
     * 192-byte key stream is 735 vs 1335 (scalar) vs 836 (AVX2) cycles on
520
     * Coffee Lake.  This is the ChaCha20-Poly1305 short-record hot path (poly
521
     * key + <=2 data blocks).  At >=256 bytes the four-block AVX2/AVX1 kernels
522
     * take over below. */
523
#ifdef HAVE_INTEL_SSSE3
524
    if (IS_INTEL_AVX512_VL(cpuidFlags) == 0 &&
525
            msglen < 4 * CHACHA_CHUNK_BYTES &&
526
            IS_INTEL_SSSE3(cpuidFlags)) {
527
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
528
        chacha_encrypt_sse3(ctx, input, output, msglen);
529
        RESTORE_VECTOR_REGISTERS();
530
        return 0;
531
    }
532
#endif
533
    if (IS_INTEL_AVX512_VL(cpuidFlags) == 0 &&
534
            msglen < 4 * CHACHA_CHUNK_BYTES) {
535
        chacha_encrypt_x64(ctx, input, output, msglen);
536
        return 0;
537
    }
538
539
    #ifdef HAVE_INTEL_AVX512
540
    /* Below one 16-block chunk (1024 bytes) the zmm path does no work and
541
     * just tail-calls AVX2, so dispatch straight to AVX2 for smaller input. */
542
    if (chacha_avx512_beneficial(cpuidFlags) &&
543
            msglen >= 16 * CHACHA_CHUNK_BYTES) {
544
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
545
        chacha_encrypt_avx512(ctx, input, output, msglen);
546
        RESTORE_VECTOR_REGISTERS();
547
        return 0;
548
    }
549
    /* Everything below the AVX2 512-byte minimum (1..511 bytes) is handled by
550
     * the AVX-512VL path itself - whole 256-byte four-block chunks plus a
551
     * partial four-block tail - using single-instruction vprold rotations on
552
     * 128-bit registers (no AVX-512 frequency penalty).  It does not fall back
553
     * to any other implementation. */
554
    if (IS_INTEL_AVX512_VL(cpuidFlags) && msglen < 8 * CHACHA_CHUNK_BYTES) {
555
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
556
        chacha_encrypt_avx512vl(ctx, input, output, msglen);
557
        RESTORE_VECTOR_REGISTERS();
558
        return 0;
559
    }
560
    #endif
561
    #ifdef HAVE_INTEL_AVX2
562
    if (IS_INTEL_AVX2(cpuidFlags)) {
563
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
564
        chacha_encrypt_avx2(ctx, input, output, msglen);
565
        RESTORE_VECTOR_REGISTERS();
566
        return 0;
567
    }
568
    #endif
569
    if (IS_INTEL_AVX1(cpuidFlags)) {
570
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
571
        chacha_encrypt_avx1(ctx, input, output, msglen);
572
        RESTORE_VECTOR_REGISTERS();
573
        return 0;
574
    }
575
    #ifdef HAVE_INTEL_SSSE3
576
    else if (IS_INTEL_SSSE3(cpuidFlags)) {
577
        SAVE_VECTOR_REGISTERS(return _svr_ret;);
578
        chacha_encrypt_sse3(ctx, input, output, msglen);
579
        RESTORE_VECTOR_REGISTERS();
580
        return 0;
581
    }
582
    #endif
583
    else {
584
        chacha_encrypt_x64(ctx, input, output, msglen);
585
        return 0;
586
    }
587
#elif defined(USE_ARM_CHACHA_SPEEDUP) || defined(USE_RISCV_CHACHA_SPEEDUP)
588
#ifdef WOLFSSL_ARM_CHACHA_NEON_FALLBACK
589
    if (chacha_use_neon())
590
#endif
591
#ifndef WOLFSSL_ARM_CHACHA_C_ONLY
592
    {
593
        /* Handle left over bytes from last block. */
594
        if ((msglen > 0) && (ctx->left > 0)) {
595
            byte* over = ((byte*)ctx->over) + CHACHA_CHUNK_BYTES - ctx->left;
596
            word32 l = min(msglen, ctx->left);
597
598
            wc_chacha_use_over(over, output, input, l);
599
600
            ctx->left -= l;
601
            input += l;
602
            output += l;
603
            msglen -= l;
604
        }
605
606
        if (msglen != 0) {
607
            wc_chacha_crypt_bytes(ctx, output, input, msglen);
608
        }
609
        return 0;
610
    }
611
#endif
612
#ifdef WOLFSSL_ARM_CHACHA_NEED_C
613
#ifdef WOLFSSL_ARM_CHACHA_NEON_FALLBACK
614
    else
615
#endif
616
    {
617
        wc_Chacha_encrypt_bytes(ctx, input, output, msglen);
618
        return 0;
619
    }
620
#endif
621
#else
622
250
    wc_Chacha_encrypt_bytes(ctx, input, output, msglen);
623
250
    return 0;
624
250
#endif
625
250
}
626
#endif /* HAVE_CHACHA */
627
/* END ChaCha C implementation */
628
629
#if defined(HAVE_CHACHA) && defined(HAVE_XCHACHA)
630
631
void wc_Chacha_purge_current_block(ChaCha* ctx)
632
0
{
633
0
    if (ctx->left > 0) {
634
0
        byte scratch[CHACHA_CHUNK_BYTES];
635
0
        XMEMSET(scratch, 0, sizeof(scratch));
636
0
        (void)wc_Chacha_Process(ctx, scratch, scratch, CHACHA_CHUNK_BYTES - ctx->left);
637
0
    }
638
0
}
639
640
/*
641
 * wc_HChacha_block - half a ChaCha block, for XChaCha
642
 *
643
 * see https://tools.ietf.org/html/draft-arciszewski-xchacha-03
644
 */
645
static WC_INLINE void wc_HChacha_block(ChaCha* ctx,
646
    word32 stream[CHACHA_CHUNK_WORDS/2], word32 nrounds)
647
0
{
648
0
    word32 x[CHACHA_CHUNK_WORDS];
649
0
    word32 i;
650
651
0
    for (i = 0; i < CHACHA_CHUNK_WORDS; i++) {
652
0
        x[i] = ctx->X[i];
653
0
    }
654
655
0
    for (i = nrounds; i > 0; i -= 2) {
656
0
        QUARTERROUND(0, 4,  8, 12)
657
0
        QUARTERROUND(1, 5,  9, 13)
658
0
        QUARTERROUND(2, 6, 10, 14)
659
0
        QUARTERROUND(3, 7, 11, 15)
660
0
        QUARTERROUND(0, 5, 10, 15)
661
0
        QUARTERROUND(1, 6, 11, 12)
662
0
        QUARTERROUND(2, 7,  8, 13)
663
0
        QUARTERROUND(3, 4,  9, 14)
664
0
    }
665
666
0
    for (i = 0; i < CHACHA_CHUNK_WORDS/4; ++i)
667
0
        stream[i] = x[i];
668
0
    for (i = CHACHA_CHUNK_WORDS/4; i < CHACHA_CHUNK_WORDS/2; ++i)
669
0
        stream[i] = x[i + CHACHA_CHUNK_WORDS/2];
670
0
}
671
672
/* XChaCha -- https://tools.ietf.org/html/draft-arciszewski-xchacha-03 */
673
int wc_XChacha_SetKey(ChaCha *ctx,
674
                      const byte *key, word32 keySz,
675
                      const byte *nonce, word32 nonceSz,
676
                      word32 counter)
677
0
{
678
0
    int ret;
679
0
    word32 k[CHACHA_MAX_KEY_SZ];
680
0
    byte   iv[CHACHA_IV_BYTES];
681
682
    /* k will hold the HChacha-derived subkey and iv the derived IV. Register
683
     * from the top with a zero baseline so every exit (including the arg/setup
684
     * error returns below, where the buffers are still zero) is covered. */
685
#ifdef WOLFSSL_CHECK_MEM_ZERO
686
    XMEMSET(k, 0, sizeof k);
687
    XMEMSET(iv, 0, sizeof iv);
688
    wc_MemZero_Add("wc_XChacha_SetKey k", k, sizeof k);
689
    wc_MemZero_Add("wc_XChacha_SetKey iv", iv, sizeof iv);
690
#endif
691
692
0
    if (nonceSz != XCHACHA_NONCE_BYTES) {
693
    #ifdef WOLFSSL_CHECK_MEM_ZERO
694
        wc_MemZero_Check(k, sizeof k);
695
        wc_MemZero_Check(iv, sizeof iv);
696
    #endif
697
0
        return BAD_FUNC_ARG;
698
0
    }
699
700
0
    if ((ret = wc_Chacha_SetKey(ctx, key, keySz)) < 0) {
701
    #ifdef WOLFSSL_CHECK_MEM_ZERO
702
        wc_MemZero_Check(k, sizeof k);
703
        wc_MemZero_Check(iv, sizeof iv);
704
    #endif
705
0
        return ret;
706
0
    }
707
708
    /* form a first chacha IV from the first 16 bytes of the nonce.
709
     * the first word is supplied in the "counter" arg, and
710
     * the result is a full 128 bit nonceful IV for the one-time block
711
     * crypto op that follows.
712
     */
713
0
    if ((ret = wc_Chacha_SetIV(ctx, nonce + 4, U8TO32_LITTLE(nonce))) < 0) {
714
    #ifdef WOLFSSL_CHECK_MEM_ZERO
715
        wc_MemZero_Check(k, sizeof k);
716
        wc_MemZero_Check(iv, sizeof iv);
717
    #endif
718
0
        return ret;
719
0
    }
720
721
0
    wc_HChacha_block(ctx, k, 20); /* 20 rounds, but keeping half the output. */
722
723
    /* the HChacha output is used as a 256 bit key for the main cipher. */
724
0
    XMEMCPY(&ctx->X[4], k, 8 * sizeof(word32));
725
726
    /* use 8 bytes from the end of the 24 byte nonce, padded up to 12 bytes,
727
     * to form the IV for the main cipher.
728
     */
729
0
    XMEMSET(iv, 0, 4);
730
0
    XMEMCPY(iv + 4, nonce + 16, 8);
731
732
0
    if ((ret = wc_Chacha_SetIV(ctx, iv, counter)) < 0) {
733
        /* k and iv hold derived key material - wipe before erroring out. */
734
0
        ForceZero(k, sizeof k);
735
0
        ForceZero(iv, sizeof iv);
736
    #ifdef WOLFSSL_CHECK_MEM_ZERO
737
        wc_MemZero_Check(k, sizeof k);
738
        wc_MemZero_Check(iv, sizeof iv);
739
    #endif
740
0
        return ret;
741
0
    }
742
743
0
    ForceZero(k, sizeof k);
744
0
    ForceZero(iv, sizeof iv);
745
#ifdef WOLFSSL_CHECK_MEM_ZERO
746
    wc_MemZero_Check(k, sizeof k);
747
    wc_MemZero_Check(iv, sizeof iv);
748
#endif
749
750
0
    return 0;
751
0
}
752
753
#endif /* HAVE_CHACHA && HAVE_XCHACHA */