Coverage Report

Created: 2023-02-22 06:39

/src/cryptofuzz/modules/wolfcrypt/bn_ops.cpp
Line
Count
Source (jump to first uncovered line)
1
#include <cryptofuzz/util.h>
2
#include <cryptofuzz/repository.h>
3
#include <fuzzing/datasource/id.hpp>
4
#include <type_traits>
5
6
#include "bn_ops.h"
7
8
2.18k
#define GET_WHICH(max) uint8_t which = 0; try { which = ds.Get<uint8_t>(); which %= ((max)+1); } catch ( ... ) { }
9
#define GET_OPTIONAL_BN() (ds.Get<bool>() ? bn.GetDestPtr(3) : nullptr)
10
11
namespace cryptofuzz {
12
namespace module {
13
14
namespace wolfCrypt_detail {
15
    WC_RNG* GetRNG(void);
16
}
17
18
namespace wolfCrypt_bignum {
19
20
namespace wolfCrypt_bignum_detail {
21
22
    template <class ReturnType>
23
3.32k
    static ReturnType assertRet(const ReturnType ret) {
24
3.32k
        static_assert(std::is_same<ReturnType, int>());
25
26
3.32k
        if ( ret > 0 ) {
27
0
            CF_ASSERT(0, "Result of mp_* function is not negative or zero");
28
0
        }
29
30
3.32k
        return ret;
31
3.32k
    }
32
3.33k
#define MP_CHECK_EQ(expr, res) CF_CHECK_EQ(::cryptofuzz::module::wolfCrypt_bignum::wolfCrypt_bignum_detail::assertRet(expr), res);
33
34
311
    static int compare(Bignum& A, Bignum& B, Datasource& ds) {
35
311
        util::HintBignumOpt(A.ToDecString());
36
311
        util::HintBignumOpt(B.ToDecString());
37
38
311
        bool swap = false;
39
311
        try {
40
311
            swap = ds.Get<bool>();
41
311
        } catch ( ... ) { }
42
43
311
        if ( swap == false ) {
44
230
            return mp_cmp(A.GetPtr(), B.GetPtr());
45
230
        } else {
46
81
            const auto ret = mp_cmp(B.GetPtr(), A.GetPtr());
47
48
            /* Because the operands were swapped, invert the result */
49
81
            if ( ret == MP_LT ) {
50
37
                return MP_GT;
51
44
            } else if ( ret == MP_GT ) {
52
42
                return MP_LT;
53
42
            } else {
54
2
                return ret;
55
2
            }
56
81
        }
57
311
    }
58
59
#if !defined(WOLFSSL_SP_MATH) && (!defined(USE_FAST_MATH) || defined(WOLFSSL_SP_MATH_ALL))
60
21
    static std::optional<int> isPowerOf2(Bignum& A, Datasource& ds) {
61
21
        std::optional<int> ret = std::nullopt;
62
21
        wolfCrypt_bignum::Bignum tmp(ds);
63
64
21
        auto numBits = mp_count_bits(A.GetPtr());
65
21
        CF_CHECK_GTE(numBits, 1);
66
20
        numBits--;
67
20
        MP_CHECK_EQ(mp_copy(A.GetPtr(), tmp.GetPtr()), MP_OKAY);
68
#if defined(USE_FAST_MATH) || defined(USE_INTEGER_HEAP_MATH)
69
        CF_NORET(mp_rshb(tmp.GetPtr(), numBits));
70
#else
71
20
        MP_CHECK_EQ(mp_rshb(tmp.GetPtr(), numBits), MP_OKAY);
72
20
#endif
73
20
        MP_CHECK_EQ(mp_mul_2d(tmp.GetPtr(), numBits, tmp.GetPtr()), MP_OKAY);
74
75
19
        {
76
            /* Use the nearest exponent of 2 as a hint for the mutator */
77
19
            const auto s = tmp.ToDecString();
78
79
19
            util::HintBignumOpt(s);
80
19
        }
81
82
19
        CF_CHECK_EQ(compare(A, tmp, ds), MP_EQ);
83
84
3
        ret = numBits;
85
21
end:
86
21
        return ret;
87
3
    }
88
#endif
89
}
90
91
63
bool Add::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
92
63
    bool ret = false;
93
94
63
    GET_WHICH(1);
95
63
    switch ( which ) {
96
38
        case    0:
97
38
            MP_CHECK_EQ(mp_add(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
98
37
            ret = true;
99
37
            break;
100
25
        case    1:
101
25
            {
102
25
                const auto op = bn[1].AsUnsigned<mp_digit>();
103
25
                CF_CHECK_NE(op, std::nullopt);
104
21
                MP_CHECK_EQ(mp_add_d(bn[0].GetPtr(), *op, res.GetPtr()), MP_OKAY);
105
21
                ret = true;
106
21
            }
107
0
            break;
108
63
    }
109
110
63
end:
111
63
    return ret;
112
63
}
113
114
152
bool Sub::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
115
152
    bool ret = false;
116
117
152
#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)
118
    /* SP math cannot represent negative numbers, so ensure the result
119
     * of the subtracton is always >= 0.
120
     *
121
     * Still run the subtraction operation to see if this can cause
122
     * memory errors, but don't return the result.
123
     */
124
152
    bool negative = false;
125
152
    if ( wolfCrypt_bignum_detail::compare(bn[0], bn[1], ds) == MP_LT) {
126
47
        negative = true;
127
47
    }
128
152
#endif
129
130
152
    GET_WHICH(1);
131
152
    switch ( which ) {
132
97
        case    0:
133
97
            MP_CHECK_EQ(mp_sub(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
134
89
            ret = true;
135
89
            break;
136
55
        case    1:
137
55
            {
138
55
                const auto op = bn[1].AsUnsigned<mp_digit>();
139
55
                CF_CHECK_NE(op, std::nullopt);
140
45
                MP_CHECK_EQ(mp_sub_d(bn[0].GetPtr(), *op, res.GetPtr()), MP_OKAY);
141
44
                ret = true;
142
44
            }
143
0
            break;
144
152
    }
145
146
152
end:
147
152
#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)
148
152
    if ( negative == true ) {
149
47
        return false;
150
47
    }
151
105
#endif
152
105
    return ret;
153
152
}
154
155
101
bool Mul::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
156
101
    bool ret = false;
157
158
101
    GET_WHICH(3);
159
101
    switch ( which ) {
160
43
        case    0:
161
43
            MP_CHECK_EQ(mp_mul(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
162
36
            ret = true;
163
36
            break;
164
25
        case    1:
165
25
            {
166
25
                const auto op = bn[1].AsUnsigned<mp_digit>();
167
25
                CF_CHECK_NE(op, std::nullopt);
168
22
                MP_CHECK_EQ(mp_mul_d(bn[0].GetPtr(), *op, res.GetPtr()), MP_OKAY);
169
22
                ret = true;
170
22
            }
171
0
            break;
172
0
#if !defined(USE_FAST_MATH) && !defined(WOLFSSL_SP_MATH)
173
9
        case    2:
174
9
            util::HintBignum("2");
175
9
            CF_CHECK_EQ(mp_cmp_d(bn[1].GetPtr(), 2), MP_EQ);
176
0
            MP_CHECK_EQ(mp_mul_2(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
177
0
            ret = true;
178
0
            break;
179
0
#endif
180
24
        case    3:
181
24
            {
182
24
                const auto numBits = mp_cnt_lsb(bn[1].GetPtr());
183
24
                CF_CHECK_GTE(numBits, DIGIT_BIT);
184
9
                CF_CHECK_EQ(numBits % DIGIT_BIT, 0);
185
186
1
                wolfCrypt_bignum::Bignum multiplier(ds);
187
1
                MP_CHECK_EQ(mp_2expt(multiplier.GetPtr(), numBits), MP_OKAY);
188
1
                CF_CHECK_EQ(wolfCrypt_bignum_detail::compare(bn[1], multiplier, ds), MP_EQ);
189
190
1
                MP_CHECK_EQ(mp_lshd(bn.GetDestPtr(0), numBits / DIGIT_BIT), MP_OKAY);
191
1
                MP_CHECK_EQ(mp_copy(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
192
1
                ret = true;
193
1
            }
194
0
            break;
195
101
    }
196
197
101
end:
198
101
    return ret;
199
101
}
200
201
0
bool Div::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
202
0
    (void)ds;
203
0
    bool ret = false;
204
205
#if defined(WOLFSSL_SP_MATH)
206
    (void)res;
207
    (void)bn;
208
#else
209
210
0
    GET_WHICH(3);
211
0
    switch ( which ) {
212
0
        case    0:
213
0
            MP_CHECK_EQ(mp_div(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr(), GET_OPTIONAL_BN()), MP_OKAY);
214
0
            break;
215
0
        case    1:
216
0
            util::HintBignum("2");
217
0
            CF_CHECK_EQ(mp_cmp_d(bn[1].GetPtr(), 2), MP_EQ);
218
0
            MP_CHECK_EQ(mp_div_2(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
219
0
            break;
220
0
#if !defined(USE_FAST_MATH)
221
0
        case    2:
222
0
            {
223
0
                mp_digit remainder;
224
0
                util::HintBignum("3");
225
0
                CF_CHECK_EQ(mp_cmp_d(bn[1].GetPtr(), 3), MP_EQ);
226
0
                MP_CHECK_EQ(mp_div_3(bn[0].GetPtr(), res.GetPtr(), ds.Get<bool>() ? &remainder : nullptr), MP_OKAY);
227
0
            }
228
0
            break;
229
0
#endif
230
0
#if defined(WOLFSSL_SP_MATH_ALL)
231
0
        case    3:
232
0
            {
233
0
                const auto divisor = bn[1].AsUnsigned<mp_digit>();
234
0
                mp_digit remainder;
235
0
                CF_CHECK_NE(divisor, std::nullopt);
236
0
                MP_CHECK_EQ(mp_div_d(bn[0].GetPtr(), *divisor, res.GetPtr(), ds.Get<bool>() ? &remainder : nullptr), MP_OKAY);
237
0
            }
238
0
#endif
239
0
        default:
240
0
            goto end;
241
0
    }
242
243
    /* wolfCrypt uses different rounding logic with negative divisior.
244
     * The result is still computed, but don't return it
245
     */
246
0
    CF_CHECK_EQ(mp_isneg(bn[0].GetPtr()), 0);
247
248
0
    ret = true;
249
250
0
end:
251
0
#endif
252
0
    return ret;
253
0
}
254
255
0
bool ExpMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
256
0
    bool ret = false;
257
258
0
    try {
259
0
        switch ( ds.Get<uint8_t>() % 5 ) {
260
0
            case    0:
261
0
            {
262
0
                auto data = ds.GetData(0, 1024 / 8, 1024 / 8);
263
                /* Odd */
264
0
                data[1024 / 8 - 1] |= 1;
265
0
                util::HintBignum(util::BinToDec(data));
266
0
            }
267
0
            break;
268
0
            case    1:
269
0
            {
270
0
                auto data = ds.GetData(0, 1536 / 8, 1536 / 8);
271
0
                data[1536 / 8 - 1] |= 1;
272
0
                util::HintBignum(util::BinToDec(data));
273
0
            }
274
0
            break;
275
0
            case    2:
276
0
            {
277
0
                auto data = ds.GetData(0, 2048 / 8, 2048 / 8);
278
0
                data[2048 / 8 - 1] |= 1;
279
0
                util::HintBignum(util::BinToDec(data));
280
0
            }
281
0
            break;
282
0
            case    3:
283
0
            {
284
0
                auto data = ds.GetData(0, 3072 / 8, 3072 / 8);
285
0
                data[3072 / 8 - 1] |= 1;
286
0
                util::HintBignum(util::BinToDec(data));
287
0
            }
288
0
            break;
289
0
            case    4:
290
0
            {
291
0
                auto data = ds.GetData(0, 4096 / 8, 4096 / 8);
292
0
                data[4096 / 8 - 1] |= 1;
293
0
                util::HintBignum(util::BinToDec(data));
294
0
            }
295
0
            break;
296
0
        }
297
0
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
298
0
    }
299
300
0
    GET_WHICH(9);
301
0
    switch ( which ) {
302
0
        case    0:
303
0
            MP_CHECK_EQ(mp_exptmod(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
304
0
            break;
305
0
#if defined(WOLFSSL_SP_MATH_ALL)
306
0
        case    1:
307
0
            MP_CHECK_EQ(mp_exptmod_nct(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
308
0
            break;
309
0
#endif
310
0
        case    2:
311
0
            MP_CHECK_EQ(mp_exptmod_ex(bn[0].GetPtr(), bn[1].GetPtr(), bn[1].GetPtr()->used, bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
312
0
            break;
313
#if defined(WOLFSSL_SP_MATH)
314
            /* ZD 15548 */
315
#if !defined(__aarch64__)
316
        case    3:
317
            MP_CHECK_EQ(sp_ModExp_1024(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
318
            break;
319
#endif
320
        case    4:
321
            MP_CHECK_EQ(sp_ModExp_1536(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
322
            break;
323
        case    5:
324
            MP_CHECK_EQ(sp_ModExp_2048(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
325
            break;
326
        case    6:
327
            MP_CHECK_EQ(sp_ModExp_3072(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
328
            break;
329
#if !defined(__i386__)
330
        case    7:
331
            MP_CHECK_EQ(sp_ModExp_4096(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
332
            break;
333
#endif
334
#endif
335
#if !defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_SP_MATH_ALL) && !defined(USE_FAST_MATH)
336
        case    8:
337
            MP_CHECK_EQ(mp_exptmod_fast(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr(), 0), MP_OKAY);
338
            break;
339
#endif
340
#if !defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_SP_MATH_ALL) && !defined(USE_FAST_MATH)
341
        case    9:
342
            {
343
                util::HintBignum("2");
344
                CF_CHECK_EQ(mp_cmp_d(bn[0].GetPtr(), 2), MP_EQ);
345
                MP_CHECK_EQ(mp_exptmod_base_2(bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
346
            }
347
            break;
348
#endif
349
0
        default:
350
0
            goto end;
351
0
    }
352
353
#if defined(WOLFSSL_SP_MATH)
354
    ret = true;
355
#else
356
0
    if (
357
0
            !mp_iszero(bn[1].GetPtr()) &&
358
0
            !mp_isneg(bn[0].GetPtr()) &&
359
0
            !mp_isneg(bn[1].GetPtr()) &&
360
0
            !mp_isneg(bn[2].GetPtr()) ) {
361
0
            ret = true;
362
0
    }
363
0
#endif
364
365
0
end:
366
0
    return ret;
367
0
}
368
369
121
bool Sqr::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
370
121
    (void)ds;
371
372
121
    bool ret = false;
373
374
121
    MP_CHECK_EQ(mp_sqr(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
375
376
77
    ret = true;
377
378
121
end:
379
121
    return ret;
380
77
}
381
382
697
bool GCD::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
383
697
    (void)ds;
384
697
    (void)res;
385
697
    (void)bn;
386
387
697
    bool ret = false;
388
389
    /* mp_gcd does not support negative numbers */
390
697
    CF_CHECK_NE(mp_cmp_d(bn[0].GetPtr(), 0), MP_LT);
391
697
    CF_CHECK_NE(mp_cmp_d(bn[1].GetPtr(), 0), MP_LT);
392
393
697
    MP_CHECK_EQ(mp_gcd(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
394
395
664
    ret = true;
396
397
697
end:
398
697
    return ret;
399
664
}
400
401
1.08k
bool InvMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
402
1.08k
    (void)ds;
403
404
1.08k
    bool ret = false;
405
406
1.08k
    GET_WHICH(0);
407
1.08k
    switch ( which ) {
408
1.08k
        case    0:
409
1.08k
            MP_CHECK_EQ(mp_invmod(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
410
520
            break;
411
0
#if !defined(USE_FAST_MATH) && !defined(WOLFSSL_SP_MATH)
412
#if 0
413
        case    1:
414
            MP_CHECK_EQ(mp_invmod_slow(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
415
            break;
416
#endif
417
0
#endif
418
0
        default:
419
0
            goto end;
420
1.08k
    }
421
422
520
    ret = true;
423
424
1.08k
end:
425
1.08k
    return ret;
426
520
}
427
428
0
bool Cmp::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
429
0
    bool ret = false;
430
431
0
    int cmpRes = 0;
432
0
    GET_WHICH(1);
433
0
    switch ( which ) {
434
0
        case    0:
435
0
            cmpRes = wolfCrypt_bignum_detail::compare(bn[0], bn[1], ds);
436
0
            break;
437
0
        case    1:
438
0
            {
439
0
                const auto op = bn[1].AsUnsigned<mp_digit>();
440
0
                CF_CHECK_NE(op, std::nullopt);
441
0
                cmpRes = mp_cmp_d(bn[0].GetPtr(), *op);
442
0
            }
443
0
            break;
444
0
        default:
445
0
            goto end;
446
0
    }
447
448
0
    switch ( cmpRes ) {
449
0
        case    MP_GT:
450
0
            CF_CHECK_EQ( res.Set("1"), true);
451
0
            break;
452
0
        case    MP_LT:
453
0
            CF_CHECK_EQ( res.Set("-1"), true);
454
0
            break;
455
0
        case    MP_EQ:
456
0
            CF_CHECK_EQ( res.Set("0"), true);
457
0
            break;
458
0
        default:
459
0
            CF_ASSERT(0, "Compare result is not one of (MP_GT, MP_LT, MP_EQ)");
460
0
    }
461
462
0
    ret = true;
463
464
0
end:
465
0
    return ret;
466
0
}
467
468
0
bool Abs::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
469
0
    (void)ds;
470
471
0
    bool ret = false;
472
473
0
    MP_CHECK_EQ(mp_abs(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
474
475
0
    ret = true;
476
477
0
end:
478
0
    return ret;
479
0
}
480
481
0
bool Neg::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
482
0
    (void)ds;
483
0
    bool ret = false;
484
485
0
#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)
486
0
    (void)res;
487
0
    (void)bn;
488
#else
489
    CF_CHECK_EQ(res.Set("0"), true);
490
    MP_CHECK_EQ(mp_sub(res.GetPtr(), bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
491
492
    ret = true;
493
494
end:
495
#endif
496
497
0
    return ret;
498
0
}
499
500
118
bool RShift::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
501
118
    bool ret = false;
502
503
118
    std::optional<uint64_t> _numBits;
504
118
    int numBits;
505
506
118
    GET_WHICH(2);
507
118
    CF_CHECK_NE(_numBits = bn[1].AsUint64(), std::nullopt);
508
114
    CF_CHECK_LTE(_numBits, 2147483647);
509
510
97
    numBits = *_numBits;
511
512
97
    switch ( which ) {
513
51
        case    0:
514
51
            MP_CHECK_EQ(mp_copy(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
515
#if defined(USE_FAST_MATH) || defined(USE_INTEGER_HEAP_MATH)
516
            CF_NORET(mp_rshb(res.GetPtr(), numBits));
517
#else
518
50
            MP_CHECK_EQ(mp_rshb(res.GetPtr(), numBits), MP_OKAY);
519
50
#endif
520
50
            ret = true;
521
50
            break;
522
0
#if !defined(WOLFSSL_SP_MATH)
523
36
        case    1:
524
36
            MP_CHECK_EQ(mp_div_2d(bn[0].GetPtr(), numBits, res.GetPtr(), GET_OPTIONAL_BN()), MP_OKAY);
525
34
            ret = true;
526
34
            break;
527
0
#endif
528
0
#if !defined(WOLFSSL_SP_MATH)
529
10
        case    2:
530
10
            {
531
                /* Check if number of bits to shift is a multiple of a full digit */
532
10
                CF_CHECK_EQ(numBits % (sizeof(mp_digit) * 8), 0);
533
534
9
                MP_CHECK_EQ(mp_copy(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
535
536
9
                const auto numDigits = numBits / (sizeof(mp_digit) * 8);
537
9
                CF_NORET(mp_rshd(res.GetPtr(), numDigits));
538
539
9
                ret = true;
540
9
            }
541
0
            break;
542
97
#endif
543
97
    }
544
545
115
end:
546
547
115
    return ret;
548
97
}
549
550
91
bool LShift1::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
551
91
    (void)ds;
552
553
91
    bool ret = false;
554
555
#if defined(WOLFSSL_SP_MATH)
556
    (void)res;
557
    (void)bn;
558
#else
559
91
    MP_CHECK_EQ(mp_mul_2d(bn[0].GetPtr(), 1, res.GetPtr()), MP_OKAY);
560
561
83
    ret = true;
562
563
91
end:
564
91
#endif
565
566
91
    return ret;
567
83
}
568
569
0
bool IsNeg::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
570
0
    (void)ds;
571
572
0
    bool ret = false;
573
574
0
#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)
575
0
    (void)res;
576
0
    (void)bn;
577
#else
578
    CF_CHECK_EQ( res.Set( std::to_string(mp_isneg(bn[0].GetPtr()) ? 1 : 0) ), true);
579
580
    ret = true;
581
582
end:
583
#endif
584
0
    return ret;
585
0
}
586
587
0
bool IsEq::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
588
0
    bool ret = false;
589
590
0
    const bool isEq = wolfCrypt_bignum_detail::compare(bn[0], bn[1], ds) == MP_EQ;
591
0
    CF_CHECK_EQ( res.Set( std::to_string(isEq ? 1 : 0) ), true);
592
593
0
    ret = true;
594
595
0
end:
596
0
    return ret;
597
0
}
598
599
4
bool IsZero::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
600
4
    (void)ds;
601
602
4
    bool ret = false;
603
604
4
    CF_CHECK_EQ( res.Set( std::to_string(mp_iszero(bn[0].GetPtr()) ? 1 : 0) ), true);
605
606
4
    ret = true;
607
608
4
end:
609
4
    return ret;
610
4
}
611
612
62
bool IsOne::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
613
62
    (void)ds;
614
615
62
    bool ret = false;
616
617
62
    CF_CHECK_EQ( res.Set( std::to_string(mp_isone(bn[0].GetPtr()) ? 1 : 0) ), true);
618
619
62
    ret = true;
620
621
62
end:
622
62
    return ret;
623
62
}
624
625
77
bool MulMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
626
77
    (void)ds;
627
628
77
    bool ret = false;
629
630
77
    MP_CHECK_EQ(mp_mulmod(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
631
632
56
    ret = true;
633
634
77
end:
635
77
    return ret;
636
56
}
637
638
188
bool AddMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
639
188
    bool ret = false;
640
641
#if defined(WOLFSSL_SP_MATH)
642
    (void)ds;
643
    (void)res;
644
    (void)bn;
645
#else
646
188
    GET_WHICH(1);
647
188
    switch ( which ) {
648
155
        case    0:
649
155
            MP_CHECK_EQ(mp_addmod(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
650
150
            break;
651
33
        case    1:
652
            /* mp_addmod_ct does not support negative numbers */
653
33
            CF_CHECK_NE(mp_cmp_d(bn[0].GetPtr(), 0), MP_LT);
654
33
            CF_CHECK_NE(mp_cmp_d(bn[1].GetPtr(), 0), MP_LT);
655
33
            CF_CHECK_NE(mp_cmp_d(bn[2].GetPtr(), 0), MP_LT);
656
657
33
            CF_CHECK_EQ(wolfCrypt_bignum_detail::compare(bn[0], bn[1], ds), MP_LT)
658
24
            CF_CHECK_EQ(wolfCrypt_bignum_detail::compare(bn[1], bn[2], ds), MP_LT)
659
24
            MP_CHECK_EQ(mp_addmod_ct(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
660
7
            break;
661
0
        default:
662
0
            goto end;
663
188
    }
664
665
157
    ret = true;
666
667
188
end:
668
188
#endif
669
188
    return ret;
670
157
}
671
672
212
bool SubMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
673
212
    bool ret = false;
674
675
#if defined(WOLFSSL_SP_MATH)
676
    (void)ds;
677
    (void)res;
678
    (void)bn;
679
#else
680
212
    GET_WHICH(1);
681
212
    switch ( which ) {
682
168
        case    0:
683
168
            MP_CHECK_EQ(mp_submod(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
684
157
            break;
685
44
        case    1:
686
            /* mp_submod_ct does not support negative numbers */
687
44
            CF_CHECK_NE(mp_cmp_d(bn[0].GetPtr(), 0), MP_LT);
688
44
            CF_CHECK_NE(mp_cmp_d(bn[1].GetPtr(), 0), MP_LT);
689
44
            CF_CHECK_NE(mp_cmp_d(bn[2].GetPtr(), 0), MP_LT);
690
691
            /* mp_submod_ct documentation states that:
692
             *
693
             * A < modulo
694
             * B < modulo
695
             */
696
44
            CF_CHECK_EQ(wolfCrypt_bignum_detail::compare(bn[0], bn[2], ds), MP_LT)
697
28
            CF_CHECK_EQ(wolfCrypt_bignum_detail::compare(bn[1], bn[2], ds), MP_LT)
698
699
28
            MP_CHECK_EQ(mp_submod_ct(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
700
17
            break;
701
0
        default:
702
0
            goto end;
703
212
    }
704
705
174
    ret = true;
706
707
212
end:
708
212
#endif
709
212
    return ret;
710
174
}
711
712
0
bool SqrMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
713
0
    (void)ds;
714
715
0
    bool ret = false;
716
717
0
    MP_CHECK_EQ(mp_sqrmod(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
718
719
0
    ret = true;
720
721
0
end:
722
0
    return ret;
723
0
}
724
725
73
bool Bit::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
726
73
    (void)ds;
727
73
    bool ret = false;
728
729
#if defined(WOLFSSL_SP_MATH)
730
    (void)res;
731
    (void)bn;
732
#else
733
73
    std::optional<uint64_t> _bitPos;
734
73
#if defined(WOLFSSL_SP_MATH_ALL)
735
73
    unsigned int bitPos;
736
#else
737
    mp_digit bitPos;
738
#endif
739
73
    int isBitSet;
740
741
73
    CF_CHECK_NE(_bitPos = bn[1].AsUint64(), std::nullopt);
742
743
69
    bitPos = *_bitPos;
744
    /* Ensure no truncation has occurred */
745
69
    CF_CHECK_EQ(bitPos, *_bitPos);
746
747
28
    CF_CHECK_GTE(isBitSet = mp_is_bit_set(bn[0].GetPtr(), bitPos), 0);
748
28
    CF_CHECK_EQ( res.Set(isBitSet ? "1" : "0"), true);
749
750
28
    ret = true;
751
752
73
end:
753
73
#endif
754
73
    return ret;
755
28
}
756
757
0
bool CmpAbs::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
758
0
    (void)ds;
759
0
    (void)res;
760
0
    (void)bn;
761
762
    /* TODO */
763
764
0
    bool ret = false;
765
766
0
    return ret;
767
0
}
768
769
0
bool SetBit::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
770
0
    (void)ds;
771
0
    bool ret = false;
772
773
0
    std::optional<uint64_t> _bitPos;
774
0
    mp_digit bitPos;
775
776
0
    CF_CHECK_NE(_bitPos = bn[1].AsUint64(), std::nullopt);
777
778
0
    bitPos = *_bitPos;
779
    /* Ensure no truncation has occurred */
780
0
    CF_CHECK_EQ(bitPos, *_bitPos);
781
782
0
    MP_CHECK_EQ(mp_copy(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
783
0
    MP_CHECK_EQ(mp_set_bit(res.GetPtr(), bitPos), MP_OKAY);
784
785
0
    ret = true;
786
787
0
end:
788
0
    return ret;
789
0
}
790
791
0
bool LCM::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
792
0
#if \
793
0
    defined(WOLFSSL_SP_MATH) || \
794
0
    (defined(WOLFSSL_SP_MATH_ALL) && \
795
0
        !(!defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && !defined(WC_RSA_BLINDING)) \
796
0
    )
797
0
    (void)ds;
798
0
    (void)res;
799
0
    (void)bn;
800
0
    return false;
801
#else
802
    (void)ds;
803
804
    bool ret = false;
805
806
    /* mp_lcm does not support negative numbers */
807
    CF_CHECK_NE(mp_cmp_d(bn[0].GetPtr(), 0), MP_LT);
808
    CF_CHECK_NE(mp_cmp_d(bn[1].GetPtr(), 0), MP_LT);
809
810
    MP_CHECK_EQ(mp_lcm(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
811
812
    ret = true;
813
814
end:
815
    return ret;
816
#endif
817
0
}
818
819
271
bool Mod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
820
271
    bool ret = false;
821
822
271
    GET_WHICH(4);
823
271
    switch ( which ) {
824
158
        case    0:
825
158
            MP_CHECK_EQ(mp_mod(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
826
153
            break;
827
0
#if !defined(WOLFSSL_SP_MATH)
828
15
        case    1:
829
15
            {
830
                /* Input must not be negative */
831
15
                CF_CHECK_NE(mp_cmp_d(bn[0].GetPtr(), 0), MP_LT);
832
833
15
                const auto op = bn[1].AsUnsigned<mp_digit>();
834
15
                CF_CHECK_NE(op, std::nullopt);
835
13
                mp_digit modResult;
836
13
                MP_CHECK_EQ(mp_mod_d(bn[0].GetPtr(), *op, &modResult), MP_OKAY);
837
13
                CF_CHECK_EQ(res.Set(std::to_string(modResult)), true);
838
13
            }
839
0
            break;
840
10
        case    2:
841
10
            {
842
                /* mp_div_2_mod_ct does not support negative numbers */
843
10
                CF_CHECK_NE(mp_cmp_d(bn[0].GetPtr(), 0), MP_LT);
844
10
                CF_CHECK_NE(mp_cmp_d(bn[0].GetPtr(), 0), MP_LT);
845
846
                /* bn[0] *= 2 */
847
10
                MP_CHECK_EQ(mp_mul_d(bn[0].GetPtr(), 2, bn.GetDestPtr(0)), MP_OKAY);
848
849
10
                CF_CHECK_EQ(wolfCrypt_bignum_detail::compare(bn[0], bn[1], ds), MP_LT)
850
10
                MP_CHECK_EQ(mp_div_2_mod_ct(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
851
6
            }
852
0
            break;
853
67
        case    3:
854
67
            {
855
67
                mp_digit mp;
856
67
                wolfCrypt_bignum::Bignum tmp(ds);
857
858
67
                MP_CHECK_EQ(mp_montgomery_setup(bn[1].GetPtr(), &mp), MP_OKAY);
859
65
                MP_CHECK_EQ(mp_montgomery_calc_normalization(tmp.GetPtr(), bn[1].GetPtr()), MP_OKAY);
860
63
                MP_CHECK_EQ(mp_mulmod(bn[0].GetPtr(), tmp.GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
861
50
                MP_CHECK_EQ(mp_montgomery_reduce(res.GetPtr(), bn[1].GetPtr(), mp), MP_OKAY);
862
48
            }
863
0
            break;
864
0
#endif
865
0
#if !defined(WOLFSSL_SP_MATH) && (!defined(USE_FAST_MATH) || defined(WOLFSSL_SP_MATH_ALL))
866
21
        case    4:
867
21
            {
868
21
                std::optional<int> exponent = std::nullopt;
869
870
                /* Negative modulo not supported */
871
21
                CF_CHECK_NE(mp_cmp_d(bn[1].GetPtr(), 0), MP_LT);
872
873
21
                CF_CHECK_NE(exponent = wolfCrypt_bignum_detail::isPowerOf2(bn[1], ds), std::nullopt);
874
875
3
                MP_CHECK_EQ(mp_mod_2d(bn[0].GetPtr(), *exponent, res.GetPtr()), MP_OKAY);
876
3
            }
877
0
            break;
878
0
#endif
879
0
        default:
880
0
            goto end;
881
271
    }
882
883
223
    ret = true;
884
885
271
end:
886
271
    return ret;
887
223
}
888
889
0
bool IsEven::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
890
0
    (void)ds;
891
892
0
    bool ret = false;
893
894
0
    CF_CHECK_EQ(mp_iszero(bn[0].GetPtr()), false);
895
896
0
    CF_CHECK_EQ( res.Set( std::to_string(mp_iseven(bn[0].GetPtr()) ? 1 : 0) ), true);
897
898
0
    ret = true;
899
900
0
end:
901
902
0
    return ret;
903
0
}
904
905
10
bool IsOdd::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
906
10
    (void)ds;
907
908
10
    bool ret = false;
909
910
10
    CF_CHECK_EQ( res.Set( std::to_string(mp_isodd(bn[0].GetPtr()) ? 1 : 0) ), true);
911
912
10
    ret = true;
913
914
10
end:
915
916
10
    return ret;
917
10
}
918
919
0
bool MSB::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
920
0
    (void)ds;
921
922
0
    bool ret = false;
923
924
0
    const int bit = mp_leading_bit(bn[0].GetPtr());
925
926
0
    CF_ASSERT(bit == 0 || bit == 1, "mp_leading_bit result is not one of (0, 1)");
927
928
0
    CF_CHECK_EQ( res.Set( std::to_string(bit) ), true);
929
930
0
    ret = true;
931
932
0
end:
933
934
0
    return ret;
935
0
}
936
937
13
bool NumBits::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
938
13
    (void)ds;
939
940
13
    bool ret = false;
941
942
13
    const auto numBits = mp_count_bits(bn[0].GetPtr());
943
944
13
    CF_ASSERT(numBits >= 0, "mp_count_bits result is negative");
945
946
13
    CF_CHECK_EQ( res.Set( std::to_string(numBits) ), true);
947
948
13
    ret = true;
949
950
13
end:
951
13
    return ret;
952
13
}
953
954
0
bool Set::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
955
0
    bool ret = false;
956
957
0
    GET_WHICH(3);
958
0
    switch ( which ) {
959
0
        case    0:
960
0
            MP_CHECK_EQ(mp_copy(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
961
0
            ret = true;
962
0
            break;
963
0
        case    1:
964
0
            {
965
0
                const auto op = bn[0].AsUnsigned<mp_digit>();
966
0
                CF_CHECK_NE(op, std::nullopt);
967
0
                MP_CHECK_EQ(mp_set(res.GetPtr(), *op), MP_OKAY);
968
0
                ret = true;
969
0
            }
970
0
            break;
971
0
        case    2:
972
0
            {
973
                /* mp_exch alters the value of bn[0], so invalidate the cache. */
974
0
                bn.InvalidateCache();
975
976
                /* mp_exch always returns a value */
977
0
                MP_CHECK_EQ(mp_exch(res.GetPtr(), bn[0].GetPtr()), MP_OKAY);
978
979
0
                ret = true;
980
0
            }
981
0
            break;
982
0
        case    3:
983
0
            {
984
0
                const auto op = bn[0].AsUnsigned<unsigned long>();
985
0
                CF_CHECK_NE(op, std::nullopt);
986
0
                MP_CHECK_EQ(mp_set_int(res.GetPtr(), *op), MP_OKAY);
987
0
                ret = true;
988
0
            }
989
0
            break;
990
0
    }
991
992
0
end:
993
0
    return ret;
994
0
}
995
996
#if defined(HAVE_COMP_KEY) && !defined(WOLFSSL_SP_MATH)
997
  #define HAVE_MP_JACOBI 1
998
#endif
999
1000
#if defined(HAVE_MP_JACOBI)
1001
extern "C" {
1002
int mp_jacobi(mp_int* a, mp_int* n, int* c);
1003
}
1004
#endif
1005
1006
0
bool Jacobi::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1007
0
    bool ret = false;
1008
1009
0
    (void)ds;
1010
1011
#if !defined(HAVE_MP_JACOBI)
1012
    (void)res;
1013
    (void)bn;
1014
#else
1015
0
    if ( mp_isodd(bn[1].GetPtr()) ) {
1016
0
        int jacobi;
1017
0
        MP_CHECK_EQ(mp_jacobi(bn[0].GetPtr(), bn[1].GetPtr(), &jacobi), MP_OKAY);
1018
1019
0
        switch ( jacobi ) {
1020
0
            case    1:
1021
0
                CF_CHECK_EQ( res.Set("1"), true);
1022
0
                break;
1023
0
            case    -1:
1024
0
                CF_CHECK_EQ( res.Set("-1"), true);
1025
0
                break;
1026
0
            case    0:
1027
0
                CF_CHECK_EQ( res.Set("0"), true);
1028
0
                break;
1029
0
            default:
1030
0
                CF_ASSERT(0, "mp_jacobi result is not one of (-1, 0, 1)");
1031
0
        }
1032
1033
0
        ret = true;
1034
0
    }
1035
1036
0
end:
1037
0
#endif
1038
1039
0
    return ret;
1040
0
}
1041
1042
0
bool Exp2::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1043
0
    (void)ds;
1044
1045
0
    bool ret = false;
1046
1047
0
    const auto exponent = bn[0].AsUnsigned<unsigned int>();
1048
0
    CF_CHECK_NE(exponent, std::nullopt);
1049
#if defined(USE_FAST_MATH) && !defined(WOLFSSL_SP_MATH) && !defined(WOLFSSL_SP_MATH_ALL)
1050
    CF_CHECK_LT(*exponent / DIGIT_BIT, FP_SIZE);
1051
#endif
1052
0
    MP_CHECK_EQ(mp_2expt(res.GetPtr(), *exponent), MP_OKAY);
1053
1054
0
    ret = true;
1055
1056
0
end:
1057
1058
0
    return ret;
1059
0
}
1060
1061
0
bool NumLSZeroBits::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1062
0
    (void)ds;
1063
1064
0
    bool ret = false;
1065
1066
#if (defined(USE_FAST_MATH) && !defined(HAVE_COMP_KEY))
1067
    (void)res;
1068
    (void)bn;
1069
#else
1070
0
    const auto numBits = mp_cnt_lsb(bn[0].GetPtr());
1071
1072
0
    CF_ASSERT(numBits >= 0, "mp_cnt_lsb result is negative");
1073
1074
0
    CF_CHECK_EQ( res.Set( std::to_string(numBits) ), true);
1075
1076
0
    ret = true;
1077
1078
0
end:
1079
0
#endif
1080
1081
0
    return ret;
1082
0
}
1083
1084
0
bool MulAdd::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1085
0
    bool ret = false;
1086
1087
0
    std::optional<std::string> mulRes, toAdd;
1088
1089
0
    auto mul = std::make_unique<Mul>();
1090
0
    auto add = std::make_unique<Add>();
1091
1092
0
    CF_CHECK_NE(toAdd = bn[2].ToDecString(), std::nullopt);
1093
1094
0
    CF_CHECK_EQ(mul->Run(ds, res, bn), true);
1095
1096
0
    CF_CHECK_NE(mulRes = res.ToDecString(), std::nullopt);
1097
1098
    /* bn[0] and bn[1] are altered, so invalidate the cache. */
1099
0
    bn.InvalidateCache();
1100
1101
0
    CF_CHECK_EQ(bn.Set(0, *mulRes), true);
1102
1103
0
    CF_CHECK_EQ(bn.Set(1, *toAdd), true);
1104
0
    CF_CHECK_EQ(add->Run(ds, res, bn), true);
1105
1106
0
    ret = true;
1107
1108
0
end:
1109
0
    return ret;
1110
0
}
1111
1112
0
bool CondSet::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1113
0
    (void)ds;
1114
1115
0
    bool ret = false;
1116
1117
0
    const int doCopy = mp_iszero(bn[1].GetPtr()) ? 0 : 1;
1118
0
    CF_CHECK_EQ(res.Set("0"), true);
1119
0
    MP_CHECK_EQ(mp_cond_copy(bn[0].GetPtr(), doCopy, res.GetPtr()), MP_OKAY);
1120
1121
0
    ret = true;
1122
1123
0
end:
1124
0
    return ret;
1125
0
}
1126
1127
0
bool Rand::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1128
0
    (void)ds;
1129
0
    (void)bn;
1130
1131
0
    bool ret = false;
1132
1133
0
    GET_WHICH(1);
1134
0
    switch ( which ) {
1135
0
        case    0:
1136
0
            {
1137
0
                const auto len = ds.Get<uint16_t>() % 512;
1138
0
                MP_CHECK_EQ(mp_rand(res.GetPtr(), len, wolfCrypt_detail::GetRNG()), MP_OKAY);
1139
0
                ret = true;
1140
0
            }
1141
0
            break;
1142
0
        case    1:
1143
0
            {
1144
0
                const auto len = ds.Get<uint16_t>() % 100;
1145
0
                MP_CHECK_EQ(mp_rand_prime(res.GetPtr(), len, wolfCrypt_detail::GetRNG(), nullptr), MP_OKAY);
1146
0
                ret = true;
1147
0
            }
1148
0
            break;
1149
0
    }
1150
1151
0
end:
1152
0
    return ret;
1153
0
}
1154
1155
0
bool Zero::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1156
0
    (void)bn;
1157
1158
0
    GET_WHICH(1);
1159
0
    switch ( which ) {
1160
0
        case    0:
1161
0
            CF_NORET(mp_zero(res.GetPtr()));
1162
0
            break;
1163
0
        case    1:
1164
0
            CF_NORET(mp_forcezero(res.GetPtr()));
1165
0
            break;
1166
0
    }
1167
1168
0
    return true;
1169
0
}
1170
1171
} /* namespace wolfCrypt_bignum */
1172
} /* namespace module */
1173
} /* namespace cryptofuzz */