Coverage Report

Created: 2026-07-16 06:50

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