Coverage Report

Created: 2025-11-16 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wolfssl-fastmath/wolfcrypt/src/wolfmath.c
Line
Count
Source
1
/* wolfmath.c
2
 *
3
 * Copyright (C) 2006-2025 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
/* common functions between all math libraries */
23
24
/* HAVE_WOLF_BIGINT: Used with asynchronous crypto hardware where "raw" math
25
 *                   buffers are required.
26
 * NO_BIG_INT: Disable support for all multi-precision math libraries
27
 */
28
29
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
30
31
#include <wolfssl/wolfcrypt/wolfmath.h>
32
33
#ifdef WOLFSSL_ASYNC_CRYPT
34
    #include <wolfssl/wolfcrypt/async.h>
35
#endif
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
#if !defined(NO_BIG_INT) || defined(WOLFSSL_SP_MATH)
45
46
#if !defined(WC_NO_CACHE_RESISTANT) && \
47
    ((defined(HAVE_ECC) && defined(ECC_TIMING_RESISTANT)) || \
48
     (defined(USE_FAST_MATH) && defined(TFM_TIMING_RESISTANT)))
49
50
    /* all off / all on pointer addresses for constant calculations */
51
    /* ecc.c uses same table */
52
    const wc_ptr_t wc_off_on_addr[2] =
53
    {
54
    #if defined(WC_64BIT_CPU)
55
        W64LIT(0x0000000000000000),
56
        W64LIT(0xffffffffffffffff)
57
    #elif defined(WC_16BIT_CPU)
58
        0x0000U,
59
        0xffffU
60
    #else
61
        /* 32 bit */
62
        0x00000000U,
63
        0xffffffffU
64
    #endif
65
    };
66
#endif
67
68
69
/* reverse an array, used for radix code */
70
void mp_reverse(unsigned char *s, int len)
71
12.3k
{
72
12.3k
    int ix, iy;
73
74
12.3k
    if (s == NULL)
75
10
        return;
76
77
12.3k
    ix = 0;
78
12.3k
    iy = len - 1;
79
557k
    while (ix < iy) {
80
545k
        unsigned char t = s[ix];
81
545k
        s[ix] = s[iy];
82
545k
        s[iy] = t;
83
545k
        ++ix;
84
545k
        --iy;
85
545k
    }
86
12.3k
}
87
88
int mp_get_digit_count(const mp_int* a)
89
22.5k
{
90
22.5k
    if (a == NULL)
91
0
        return 0;
92
93
22.5k
    return (int)a->used;
94
22.5k
}
95
96
mp_digit mp_get_digit(const mp_int* a, int n)
97
800k
{
98
800k
    if (a == NULL)
99
0
        return 0;
100
101
800k
    return (n < 0 || (unsigned int)n >= (unsigned int)a->used) ? 0 : a->dp[n];
102
800k
}
103
104
#if defined(HAVE_ECC) || defined(WOLFSSL_MP_COND_COPY)
105
/* Conditionally copy a into b. Performed in constant time.
106
 *
107
 * a     MP integer to copy.
108
 * copy  On 1, copy a into b. on 0 leave b unchanged.
109
 * b     MP integer to copy into.
110
 * returns BAD_FUNC_ARG when a or b is NULL, MEMORY_E when growing b fails and
111
 *         MP_OKAY otherwise.
112
 */
113
int mp_cond_copy(mp_int* a, int copy, mp_int* b)
114
63.5k
{
115
63.5k
    int err = MP_OKAY;
116
#if defined(SP_WORD_SIZE) && SP_WORD_SIZE == 8
117
    unsigned int mask = (unsigned int)0 - copy;
118
#else
119
63.5k
    mp_digit mask = (mp_digit)0 - (mp_digit)copy;
120
63.5k
#endif
121
122
63.5k
    if (a == NULL || b == NULL)
123
0
        err = BAD_FUNC_ARG;
124
125
    /* Ensure b has enough space to copy a into */
126
63.5k
    if (err == MP_OKAY)
127
63.5k
        err = mp_grow(b, (int)a->used + 1);
128
63.5k
    if (err == MP_OKAY) {
129
    #if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)
130
        unsigned int i;
131
    #else
132
63.5k
        int i;
133
63.5k
    #endif
134
        /* When mask 0, b is unchanged2
135
         * When mask all set, b ^ b ^ a = a
136
         */
137
        /* Conditionally copy all digits and then number of used digits.
138
         * mp_get_digit() returns 0 when index greater than available digit.
139
         */
140
423k
        for (i = 0; i < a->used; i++) {
141
359k
            b->dp[i] ^= (mp_get_digit(a, (int)i) ^ mp_get_digit(b, (int)i)) & mask;
142
359k
        }
143
104k
        for (; i < b->used; i++) {
144
40.8k
            b->dp[i] ^= (mp_get_digit(a, (int)i) ^ mp_get_digit(b, (int)i)) & mask;
145
40.8k
        }
146
63.5k
        b->used ^= (a->used ^ b->used) & (wc_mp_size_t)mask;
147
63.5k
#if (!defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_SP_MATH_ALL)) || \
148
63.5k
    defined(WOLFSSL_SP_INT_NEGATIVE)
149
63.5k
        b->sign ^= (wc_mp_sign_t)(a->sign ^ b->sign) & (wc_mp_sign_t)mask;
150
63.5k
#endif
151
63.5k
    }
152
153
63.5k
    return err;
154
63.5k
}
155
#endif /* HAVE_ECC || WOLFSSL_MP_COND_COPY */
156
157
158
#ifndef WC_NO_RNG
159
int mp_get_rand_digit(WC_RNG* rng, mp_digit* d)
160
1.31k
{
161
1.31k
    return wc_RNG_GenerateBlock(rng, (byte*)d, sizeof(mp_digit));
162
1.31k
}
163
164
int mp_rand(mp_int* a, int digits, WC_RNG* rng)
165
9.37k
{
166
9.37k
    int ret = 0;
167
9.37k
    int cnt = digits * (int)sizeof(mp_digit);
168
169
9.37k
    if (rng == NULL) {
170
0
        ret = MISSING_RNG_E;
171
0
    }
172
9.37k
    else if (a == NULL || digits <= 0) {
173
32
        ret = BAD_FUNC_ARG;
174
32
    }
175
176
#ifdef USE_INTEGER_HEAP_MATH
177
    /* allocate space for digits */
178
    if (ret == MP_OKAY) {
179
        ret = mp_set_bit(a, digits * DIGIT_BIT - 1);
180
    }
181
#else
182
#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)
183
    if ((ret == MP_OKAY) && ((unsigned int)digits > a->size))
184
#else
185
9.37k
    if ((ret == MP_OKAY) && (digits > FP_SIZE))
186
58
#endif
187
58
    {
188
58
        ret = BAD_FUNC_ARG;
189
58
    }
190
9.37k
    if (ret == MP_OKAY) {
191
9.28k
        a->used = (wc_mp_size_t)digits;
192
9.28k
    }
193
9.37k
#endif
194
    /* fill the data with random bytes */
195
9.37k
    if (ret == MP_OKAY) {
196
9.28k
        ret = wc_RNG_GenerateBlock(rng, (byte*)a->dp, (word32)cnt);
197
9.28k
    }
198
9.37k
    if (ret == MP_OKAY) {
199
#ifdef USE_INTEGER_HEAP_MATH
200
        int i;
201
        /* Mask down each digit to only bits used */
202
        for (i = 0; i < a->used; i++) {
203
            a->dp[i] &= MP_MASK;
204
        }
205
#endif
206
        /* ensure top digit is not zero */
207
10.3k
        while ((ret == MP_OKAY) && (a->dp[a->used - 1] == 0)) {
208
1.18k
            ret = mp_get_rand_digit(rng, &a->dp[a->used - 1]);
209
#ifdef USE_INTEGER_HEAP_MATH
210
            a->dp[a->used - 1] &= MP_MASK;
211
#endif
212
1.18k
        }
213
9.17k
    }
214
215
9.37k
    return ret;
216
9.37k
}
217
#endif /* !WC_NO_RNG */
218
219
#if defined(HAVE_ECC) || defined(WOLFSSL_EXPORT_INT)
220
/* export an mp_int as unsigned char or hex string
221
 * encType is WC_TYPE_UNSIGNED_BIN or WC_TYPE_HEX_STR
222
 * return MP_OKAY on success */
223
int wc_export_int(mp_int* mp, byte* buf, word32* len, word32 keySz,
224
    int encType)
225
0
{
226
0
    int err;
227
228
0
    if (mp == NULL || buf == NULL || len == NULL)
229
0
        return BAD_FUNC_ARG;
230
231
0
    if (encType == WC_TYPE_HEX_STR) {
232
        /* for WC_TYPE_HEX_STR the keySz is not used.
233
         * The size is computed via mp_radix_size and checked with len input */
234
0
    #ifdef WC_MP_TO_RADIX
235
0
        int size = 0;
236
0
        err = mp_radix_size(mp, MP_RADIX_HEX, &size);
237
0
        if (err == MP_OKAY) {
238
            /* make sure we can fit result */
239
0
            if (*len < (word32)size) {
240
0
                *len = (word32)size;
241
0
                return BUFFER_E;
242
0
            }
243
0
            *len = (word32)size;
244
0
            err = mp_tohex(mp, (char*)buf);
245
0
        }
246
    #else
247
        err = NOT_COMPILED_IN;
248
    #endif
249
0
    }
250
0
    else {
251
        /* for WC_TYPE_UNSIGNED_BIN keySz is used to zero pad.
252
         * The key size is always returned as the size */
253
0
        if (*len < keySz) {
254
0
            *len = keySz;
255
0
            return BUFFER_E;
256
0
        }
257
0
        *len = keySz;
258
0
        XMEMSET(buf, 0, *len);
259
0
        err = mp_to_unsigned_bin(mp, buf +
260
0
            (keySz - (word32)mp_unsigned_bin_size(mp)));
261
0
    }
262
263
0
    return err;
264
0
}
265
#endif
266
267
#ifdef HAVE_WOLF_BIGINT
268
void wc_bigint_init(WC_BIGINT* a)
269
{
270
    if (a != NULL) {
271
        a->buf = NULL;
272
        a->len = 0;
273
        a->heap = NULL;
274
    }
275
}
276
277
int wc_bigint_alloc(WC_BIGINT* a, word32 sz)
278
{
279
    int err = MP_OKAY;
280
281
    if (a == NULL)
282
        return BAD_FUNC_ARG;
283
284
    if (sz > 0) {
285
        if (a->buf && sz > a->len) {
286
            wc_bigint_free(a);
287
        }
288
        if (a->buf == NULL) {
289
            a->buf = (byte*)XMALLOC(sz, a->heap, DYNAMIC_TYPE_WOLF_BIGINT);
290
            if (a->buf == NULL) {
291
                err = MP_MEM;
292
            }
293
        }
294
        else {
295
            XMEMSET(a->buf, 0, sz);
296
        }
297
    }
298
    a->len = sz;
299
300
    return err;
301
}
302
303
/* assumes input is big endian format */
304
int wc_bigint_from_unsigned_bin(WC_BIGINT* a, const byte* in, word32 inlen)
305
{
306
    int err;
307
308
    if (a == NULL || in == NULL || inlen == 0)
309
        return BAD_FUNC_ARG;
310
311
    err = wc_bigint_alloc(a, inlen);
312
    if (err == 0) {
313
        XMEMCPY(a->buf, in, inlen);
314
    }
315
316
    return err;
317
}
318
319
int wc_bigint_to_unsigned_bin(WC_BIGINT* a, byte* out, word32* outlen)
320
{
321
    word32 sz;
322
323
    if (a == NULL || out == NULL || outlen == NULL || *outlen == 0)
324
        return BAD_FUNC_ARG;
325
326
    /* trim to fit into output buffer */
327
    sz = a->len;
328
    if (a->len > *outlen) {
329
        WOLFSSL_MSG("wc_bigint_export: Truncating output");
330
        sz = *outlen;
331
    }
332
333
    if (a->buf) {
334
        XMEMCPY(out, a->buf, sz);
335
    }
336
337
    *outlen = sz;
338
339
    return MP_OKAY;
340
}
341
342
void wc_bigint_zero(WC_BIGINT* a)
343
{
344
    if (a && a->buf) {
345
        ForceZero(a->buf, a->len);
346
    }
347
}
348
349
void wc_bigint_free(WC_BIGINT* a)
350
{
351
    if (a) {
352
        XFREE(a->buf, a->heap, DYNAMIC_TYPE_WOLF_BIGINT);
353
        a->buf = NULL;
354
        a->len = 0;
355
    }
356
}
357
358
/* sz: make sure the buffer is at least that size and zero padded.
359
 *     A `sz == 0` will use the size of `src`.
360
 *     The calculated sz is stored into dst->len in `wc_bigint_alloc`.
361
 */
362
int wc_mp_to_bigint_sz(mp_int* src, WC_BIGINT* dst, word32 sz)
363
{
364
    int err;
365
    word32 x;
366
367
    if (src == NULL || dst == NULL)
368
        return BAD_FUNC_ARG;
369
370
    /* get size of source */
371
    x = mp_unsigned_bin_size(src);
372
    if (sz < x)
373
        sz = x;
374
375
    /* make sure destination is allocated and large enough */
376
    err = wc_bigint_alloc(dst, sz);
377
    if (err == MP_OKAY && sz > 0) {
378
        /* leading zero pad */
379
        word32 y = sz - x;
380
        XMEMSET(dst->buf, 0, y);
381
382
        /* export src as unsigned bin to destination buf */
383
        err = mp_to_unsigned_bin(src, dst->buf + y);
384
    }
385
386
    return err;
387
}
388
389
int wc_mp_to_bigint(mp_int* src, WC_BIGINT* dst)
390
{
391
    if (src == NULL || dst == NULL)
392
        return BAD_FUNC_ARG;
393
394
    return wc_mp_to_bigint_sz(src, dst, 0);
395
}
396
397
int wc_bigint_to_mp(WC_BIGINT* src, mp_int* dst)
398
{
399
    int err;
400
401
    if (src == NULL || dst == NULL)
402
        return BAD_FUNC_ARG;
403
404
    if (src->buf == NULL)
405
        return BAD_FUNC_ARG;
406
407
    err = mp_read_unsigned_bin(dst, src->buf, src->len);
408
    wc_bigint_free(src);
409
410
    return err;
411
}
412
#endif /* HAVE_WOLF_BIGINT */
413
414
#endif /* !NO_BIG_INT || WOLFSSL_SP_MATH */
415
416
#ifdef HAVE_WC_INTROSPECTION
417
const char *wc_GetMathInfo(void)
418
0
{
419
0
    return
420
0
        "\tMulti-Precision: "
421
    #ifdef WOLFSSL_SP_MATH_ALL
422
        "Wolf(SP)"
423
        #ifdef WOLFSSL_SP_NO_DYN_STACK
424
            " no-dyn-stack"
425
        #endif
426
        " word-size=" WC_STRINGIFY(SP_WORD_SIZE)
427
        " bits=" WC_STRINGIFY(SP_INT_BITS)
428
        " sp_int.c"
429
    #elif defined(USE_FAST_MATH)
430
        "Fast"
431
0
        " max-bits=" WC_STRINGIFY(FP_MAX_BITS)
432
        #ifndef TFM_TIMING_RESISTANT
433
        " not-constant-time"
434
        #endif
435
0
        " tfm.c"
436
    #elif defined(USE_INTEGER_HEAP_MATH)
437
        "Heap"
438
        " not-constant-time"
439
        " integer.c"
440
    #elif defined(NO_BIG_INT) || defined(WOLFSSL_SP_MATH)
441
        "Disabled"
442
    #else
443
        "Unknown"
444
    #endif
445
446
    #if defined(WOLFSSL_HAVE_SP_ECC) || defined(WOLFSSL_HAVE_SP_DH) || \
447
        defined(WOLFSSL_HAVE_SP_RSA)
448
         "\n\tSingle Precision:"
449
        #ifdef WOLFSSL_HAVE_SP_ECC
450
            " ecc"
451
            #ifndef WOLFSSL_SP_NO_256
452
                " 256"
453
            #endif
454
            #ifdef WOLFSSL_SP_384
455
                " 384"
456
            #endif
457
            #ifdef WOLFSSL_SP_521
458
                " 521"
459
            #endif
460
        #endif
461
        #if defined(WOLFSSL_HAVE_SP_RSA) && defined(WOLFSSL_HAVE_SP_DH)
462
            " rsa/dh"
463
        #elif defined(WOLFSSL_HAVE_SP_RSA)
464
            " rsa"
465
        #elif defined(WOLFSSL_HAVE_SP_DH)
466
            " dh"
467
        #endif
468
        #if defined(WOLFSSL_HAVE_SP_RSA) || defined(WOLFSSL_HAVE_SP_DH)
469
            #ifndef WOLFSSL_SP_NO_2048
470
                " 2048"
471
            #endif
472
            #ifndef WOLFSSL_SP_NO_3072
473
                " 3072"
474
            #endif
475
            #ifdef WOLFSSL_SP_4096
476
                " 4096"
477
            #endif
478
        #endif
479
        #ifdef WOLFSSL_SP_ASM
480
            " asm"
481
        #endif
482
483
        #if !defined(WOLFSSL_SP_ASM)
484
            #if defined(SP_WORD_SIZE) && SP_WORD_SIZE == 32
485
            " sp_c32.c"
486
            #else
487
            " sp_c64.c"
488
            #endif
489
        #elif defined(WOLFSSL_SP_ARM32_ASM)
490
            " sp_arm32.c"
491
        #elif defined(WOLFSSL_SP_ARM64_ASM)
492
            " sp_arm64.c"
493
        #elif defined(WOLFSSL_SP_ARM_THUMB_ASM)
494
            " sp_armthumb.c"
495
        #elif defined(WOLFSSL_SP_ARM_CORTEX_M_ASM)
496
            " sp_cortexm.c"
497
        #elif defined(WOLFSSL_SP_X86_64_ASM)
498
            " sp_x86_64.c"
499
        #else
500
            " sp_[arch].c"
501
        #endif
502
    #endif
503
504
    /* other SP math options */
505
    #if defined(WOLFSSL_SP_MATH_ALL) || defined(WOLFSSL_HAVE_SP_ECC) || \
506
        defined(WOLFSSL_HAVE_SP_DH) || defined(WOLFSSL_HAVE_SP_RSA)
507
        #ifdef WOLFSSL_SP_SMALL
508
            " small"
509
        #endif
510
        #ifdef WOLFSSL_SP_NO_MALLOC
511
            " no-malloc"
512
        #endif
513
    #endif
514
515
    /* ARM Assembly speedups */
516
    #if defined(WOLFSSL_ARMASM) || defined(USE_INTEL_SPEEDUP) || \
517
        defined(WOLFSSL_RISCV_ASM) || defined(WOLFSSL_PPC32_ASM)
518
        "\n\tAssembly Speedups:"
519
520
        #ifdef WOLFSSL_ARMASM
521
            " ARMASM"
522
            #ifdef WOLFSSL_ARMASM_THUMB2
523
                " THUMB2"
524
            #endif
525
            #ifdef WOLFSSL_ARMASM_INLINE
526
                " INLINE"
527
            #endif
528
            #ifdef WOLFSSL_ARMASM_NO_HW_CRYPTO
529
                " NO_HW_CRYPTO"
530
            #endif
531
            #ifdef WOLFSSL_ARMASM_NO_NEON
532
                " NO_NEON"
533
            #endif
534
            #ifdef WOLFSSL_ARM_ARCH
535
                " ARM ARCH=" WC_STRINGIFY(WOLFSSL_ARM_ARCH)
536
            #endif
537
        #endif /* WOLFSSL_ARMASM */
538
539
        #ifdef USE_INTEL_SPEEDUP
540
            " INTELASM"
541
            #ifdef USE_INTEL_SPEEDUP_FOR_AES
542
                " AES"
543
            #endif
544
        #endif
545
546
        #ifdef WOLFSSL_RISCV_ASM
547
            " RISCVASM"
548
            #ifdef WOLFSSL_RISCV_BASE_BIT_MANIPULATION
549
                " REV8"
550
            #endif
551
            #ifdef WOLFSSL_RISCV_CARRYLESS
552
                " CLMUL CLMULH"
553
            #endif
554
            #ifdef WOLFSSL_RISCV_BIT_MANIPULATION
555
                " PACK"
556
            #endif
557
            #ifdef WOLFSSL_RISCV_BIT_MANIPULATION_TERNARY
558
                " FSL FSR FSRI CMOV CMIX"
559
            #endif
560
            #ifdef WOLFSSL_RISCV_VECTOR_BASE_BIT_MANIPULATION
561
                " VBREV8"
562
            #endif
563
            #ifdef WOLFSSL_RISCV_VECTOR_CARRYLESS
564
                " VCLMUL VCLMULH"
565
            #endif
566
            #ifdef WOLFSSL_RISCV_VECTOR_GCM
567
                " VGMUL VHHSH"
568
            #endif
569
            #ifdef WOLFSSL_RISCV_VECTOR_CRYPTO_ASM
570
                " Vector AES SHA-2"
571
            #endif
572
            #ifdef WOLFSSL_RISCV_SCALAR_CRYPTO_ASM
573
                " AES encrypt/decrpyt SHA-2"
574
            #endif
575
        #endif /* WOLFSSL_RISCV_ASM */
576
577
        #ifdef WOLFSSL_PPC32_ASM
578
            " PPC32ASM"
579
            #ifdef WOLFSSL_PPC32_ASM_INLINE
580
                " INLINE"
581
            #endif
582
            #ifdef WOLFSSL_PPC32_ASM_SMALL
583
                " SMALL"
584
            #endif
585
            #ifdef WOLFSSL_PPC32_ASM_SPE
586
                " SPE"
587
            #endif
588
        #endif /* WOLFSSL_PPC32_ASM */
589
590
        #ifdef WOLFSSL_USE_ALIGN
591
            " ALIGN"
592
        #endif
593
        #ifdef HAVE_INTEL_RDRAND
594
            " INTEL_RDRAND"
595
        #endif
596
        #ifdef HAVE_AMD_RDSEED
597
            " AMD_RDSEED"
598
        #endif
599
        #ifdef WOLFSSL_X86_64_BUILD
600
            " X86_64_BUILD"
601
        #endif
602
        #ifdef WOLFSSL_X86_BUILD
603
            " X86_BUILD"
604
        #endif
605
    #endif
606
607
0
    ;
608
0
}
609
#endif /* HAVE_WC_INTROSPECTION */