Coverage Report

Created: 2022-08-24 06:37

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