Coverage Report

Created: 2022-08-24 06:37

/src/cryptofuzz-disable-fastmath/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
18.7k
#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
24.7k
#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
392
    static std::optional<int> isPowerOf2(Bignum& A, Datasource& ds) {
61
392
        std::optional<int> ret = std::nullopt;
62
392
        wolfCrypt_bignum::Bignum tmp(ds);
63
64
392
        auto numBits = mp_count_bits(A.GetPtr());
65
392
        CF_CHECK_GTE(numBits, 1);
66
347
        numBits--;
67
347
        MP_CHECK_EQ(mp_copy(A.GetPtr(), tmp.GetPtr()), MP_OKAY);
68
347
        CF_NORET(mp_rshb(tmp.GetPtr(), numBits));
69
347
        MP_CHECK_EQ(mp_mul_2d(tmp.GetPtr(), numBits, tmp.GetPtr()), MP_OKAY);
70
71
344
        {
72
            /* Use the nearest exponent of 2 as a hint for the mutator */
73
344
            const auto s = tmp.ToDecString();
74
75
344
            util::HintBignumOpt(s);
76
344
        }
77
78
344
        CF_CHECK_EQ(compare(A, tmp, ds), MP_EQ);
79
80
185
        ret = numBits;
81
392
end:
82
392
        return ret;
83
185
    }
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
1.11k
bool Mul::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
152
1.11k
    bool ret = false;
153
154
1.11k
    GET_WHICH(3);
155
1.11k
    switch ( which ) {
156
518
        case    0:
157
518
            MP_CHECK_EQ(mp_mul(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
158
492
            ret = true;
159
492
            break;
160
455
        case    1:
161
455
            {
162
455
                const auto op = bn[1].AsUnsigned<mp_digit>();
163
455
                CF_CHECK_NE(op, std::nullopt);
164
357
                MP_CHECK_EQ(mp_mul_d(bn[0].GetPtr(), *op, res.GetPtr()), MP_OKAY);
165
357
                ret = true;
166
357
            }
167
0
            break;
168
0
#if !defined(USE_FAST_MATH) && !defined(WOLFSSL_SP_MATH)
169
52
        case    2:
170
52
            util::HintBignum("2");
171
52
            CF_CHECK_EQ(mp_cmp_d(bn[1].GetPtr(), 2), MP_EQ);
172
4
            MP_CHECK_EQ(mp_mul_2(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
173
4
            ret = true;
174
4
            break;
175
0
#endif
176
91
        case    3:
177
91
            {
178
91
                const auto numBits = mp_cnt_lsb(bn[1].GetPtr());
179
91
                CF_CHECK_GTE(numBits, DIGIT_BIT);
180
38
                CF_CHECK_EQ(numBits % DIGIT_BIT, 0);
181
182
27
                wolfCrypt_bignum::Bignum multiplier(ds);
183
27
                MP_CHECK_EQ(mp_2expt(multiplier.GetPtr(), numBits), MP_OKAY);
184
27
                CF_CHECK_EQ(wolfCrypt_bignum_detail::compare(bn[1], multiplier, ds), MP_EQ);
185
186
7
                MP_CHECK_EQ(mp_lshd(bn.GetDestPtr(0), numBits / DIGIT_BIT), MP_OKAY);
187
7
                MP_CHECK_EQ(mp_copy(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
188
7
                ret = true;
189
7
            }
190
0
            break;
191
1.11k
    }
192
193
1.11k
end:
194
1.11k
    return ret;
195
1.11k
}
196
197
704
bool Div::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
198
704
    (void)ds;
199
704
    bool ret = false;
200
201
#if defined(WOLFSSL_SP_MATH)
202
    (void)res;
203
    (void)bn;
204
#else
205
206
704
    GET_WHICH(3);
207
704
    switch ( which ) {
208
272
        case    0:
209
272
            MP_CHECK_EQ(mp_div(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr(), GET_OPTIONAL_BN()), MP_OKAY);
210
246
            break;
211
87
        case    1:
212
87
            util::HintBignum("2");
213
87
            CF_CHECK_EQ(mp_cmp_d(bn[1].GetPtr(), 2), MP_EQ);
214
50
            MP_CHECK_EQ(mp_div_2(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
215
50
            break;
216
0
#if !defined(USE_FAST_MATH)
217
60
        case    2:
218
60
            {
219
60
                mp_digit remainder;
220
60
                util::HintBignum("3");
221
60
                CF_CHECK_EQ(mp_cmp_d(bn[1].GetPtr(), 3), MP_EQ);
222
28
                MP_CHECK_EQ(mp_div_3(bn[0].GetPtr(), res.GetPtr(), ds.Get<bool>() ? &remainder : nullptr), MP_OKAY);
223
28
            }
224
0
            break;
225
0
#endif
226
0
#if defined(WOLFSSL_SP_MATH_ALL)
227
285
        case    3:
228
285
            {
229
285
                const auto divisor = bn[1].AsUnsigned<mp_digit>();
230
285
                mp_digit remainder;
231
285
                CF_CHECK_NE(divisor, std::nullopt);
232
265
                MP_CHECK_EQ(mp_div_d(bn[0].GetPtr(), *divisor, res.GetPtr(), ds.Get<bool>() ? &remainder : nullptr), MP_OKAY);
233
244
            }
234
0
#endif
235
244
        default:
236
244
            goto end;
237
704
    }
238
239
    /* wolfCrypt uses different rounding logic with negative divisior.
240
     * The result is still computed, but don't return it
241
     */
242
127
    CF_CHECK_EQ(mp_isneg(bn[0].GetPtr()), 0);
243
244
127
    ret = true;
245
246
499
end:
247
499
#endif
248
499
    return ret;
249
127
}
250
251
2.25k
bool ExpMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
252
2.25k
    bool ret = false;
253
254
2.25k
    try {
255
2.25k
        switch ( ds.Get<uint8_t>() % 5 ) {
256
223
            case    0:
257
223
            {
258
223
                auto data = ds.GetData(0, 1024 / 8, 1024 / 8);
259
                /* Odd */
260
223
                data[1024 / 8 - 1] |= 1;
261
223
                util::HintBignum(util::BinToDec(data));
262
223
            }
263
223
            break;
264
472
            case    1:
265
472
            {
266
472
                auto data = ds.GetData(0, 1536 / 8, 1536 / 8);
267
472
                data[1536 / 8 - 1] |= 1;
268
472
                util::HintBignum(util::BinToDec(data));
269
472
            }
270
472
            break;
271
194
            case    2:
272
194
            {
273
194
                auto data = ds.GetData(0, 2048 / 8, 2048 / 8);
274
194
                data[2048 / 8 - 1] |= 1;
275
194
                util::HintBignum(util::BinToDec(data));
276
194
            }
277
194
            break;
278
75
            case    3:
279
75
            {
280
75
                auto data = ds.GetData(0, 3072 / 8, 3072 / 8);
281
75
                data[3072 / 8 - 1] |= 1;
282
75
                util::HintBignum(util::BinToDec(data));
283
75
            }
284
75
            break;
285
129
            case    4:
286
129
            {
287
129
                auto data = ds.GetData(0, 4096 / 8, 4096 / 8);
288
129
                data[4096 / 8 - 1] |= 1;
289
129
                util::HintBignum(util::BinToDec(data));
290
129
            }
291
129
            break;
292
2.25k
        }
293
2.25k
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
294
2.09k
    }
295
296
2.25k
    GET_WHICH(9);
297
2.25k
    switch ( which ) {
298
1.32k
        case    0:
299
1.32k
            MP_CHECK_EQ(mp_exptmod(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
300
1.16k
            break;
301
0
#if defined(WOLFSSL_SP_MATH_ALL)
302
684
        case    1:
303
684
            MP_CHECK_EQ(mp_exptmod_nct(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
304
548
            break;
305
0
#endif
306
86
        case    2:
307
86
            MP_CHECK_EQ(mp_exptmod_ex(bn[0].GetPtr(), bn[1].GetPtr(), bn[1].GetPtr()->used, bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
308
41
            break;
309
#if defined(WOLFSSL_SP_MATH)
310
        case    3:
311
            MP_CHECK_EQ(sp_ModExp_1024(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
312
            break;
313
        case    4:
314
            MP_CHECK_EQ(sp_ModExp_1536(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
315
            break;
316
        case    5:
317
            MP_CHECK_EQ(sp_ModExp_2048(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
318
            break;
319
        case    6:
320
            MP_CHECK_EQ(sp_ModExp_3072(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
321
            break;
322
#if !defined(__i386__)
323
        case    7:
324
            MP_CHECK_EQ(sp_ModExp_4096(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
325
            break;
326
#endif
327
#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
165
        default:
343
165
            goto end;
344
2.25k
    }
345
346
#if defined(WOLFSSL_SP_MATH)
347
    ret = true;
348
#else
349
1.75k
    if (
350
1.75k
            !mp_iszero(bn[1].GetPtr()) &&
351
1.75k
            !mp_isneg(bn[0].GetPtr()) &&
352
1.75k
            !mp_isneg(bn[1].GetPtr()) &&
353
1.75k
            !mp_isneg(bn[2].GetPtr()) ) {
354
1.64k
            ret = true;
355
1.64k
    }
356
1.75k
#endif
357
358
2.25k
end:
359
2.25k
    return ret;
360
1.75k
}
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
0
#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
0
#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
1.78k
bool RShift::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
494
1.78k
    bool ret = false;
495
496
1.78k
    std::optional<uint64_t> _numBits;
497
1.78k
    int numBits;
498
499
1.78k
    GET_WHICH(2);
500
1.78k
    CF_CHECK_NE(_numBits = bn[1].AsUint64(), std::nullopt);
501
1.74k
    CF_CHECK_LTE(_numBits, 2147483647);
502
503
1.48k
    numBits = *_numBits;
504
505
1.48k
    switch ( which ) {
506
672
        case    0:
507
672
            MP_CHECK_EQ(mp_copy(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
508
672
            CF_NORET(mp_rshb(res.GetPtr(), numBits));
509
672
            ret = true;
510
672
            break;
511
0
#if !defined(WOLFSSL_SP_MATH)
512
644
        case    1:
513
644
            MP_CHECK_EQ(mp_div_2d(bn[0].GetPtr(), numBits, res.GetPtr(), GET_OPTIONAL_BN()), MP_OKAY);
514
644
            ret = true;
515
644
            break;
516
0
#endif
517
172
        case    2:
518
172
            {
519
                /* Check if number of bits to shift is a multiple of a full digit */
520
172
                CF_CHECK_EQ(numBits % (sizeof(mp_digit) * 8), 0);
521
522
148
                MP_CHECK_EQ(mp_copy(bn[0].GetPtr(), res.GetPtr()), MP_OKAY);
523
524
148
                const auto numDigits = numBits / (sizeof(mp_digit) * 8);
525
148
                CF_NORET(mp_rshd(res.GetPtr(), numDigits));
526
527
148
                ret = true;
528
148
            }
529
0
            break;
530
1.48k
    }
531
532
1.73k
end:
533
534
1.73k
    return ret;
535
1.48k
}
536
537
298
bool LShift1::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
538
298
    (void)ds;
539
540
298
    bool ret = false;
541
542
#if defined(WOLFSSL_SP_MATH)
543
    (void)res;
544
    (void)bn;
545
#else
546
298
    MP_CHECK_EQ(mp_mul_2d(bn[0].GetPtr(), 1, res.GetPtr()), MP_OKAY);
547
548
298
    ret = true;
549
550
298
end:
551
298
#endif
552
553
298
    return ret;
554
298
}
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
484
bool AddMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
626
484
    bool ret = false;
627
628
#if defined(WOLFSSL_SP_MATH)
629
    (void)ds;
630
    (void)res;
631
    (void)bn;
632
#else
633
484
    GET_WHICH(1);
634
484
    switch ( which ) {
635
268
        case    0:
636
268
            MP_CHECK_EQ(mp_addmod(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
637
146
            break;
638
216
        case    1:
639
            /* mp_addmod_ct does not support negative numbers */
640
216
            CF_CHECK_NE(mp_cmp_d(bn[0].GetPtr(), 0), MP_LT);
641
204
            CF_CHECK_NE(mp_cmp_d(bn[1].GetPtr(), 0), MP_LT);
642
188
            CF_CHECK_NE(mp_cmp_d(bn[2].GetPtr(), 0), MP_LT);
643
644
168
            CF_CHECK_EQ(wolfCrypt_bignum_detail::compare(bn[0], bn[1], ds), MP_LT)
645
114
            CF_CHECK_EQ(wolfCrypt_bignum_detail::compare(bn[1], bn[2], ds), MP_LT)
646
114
            MP_CHECK_EQ(mp_addmod_ct(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
647
65
            break;
648
0
        default:
649
0
            goto end;
650
484
    }
651
652
211
    ret = true;
653
654
484
end:
655
484
#endif
656
484
    return ret;
657
211
}
658
659
1.23k
bool SubMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
660
1.23k
    bool ret = false;
661
662
#if defined(WOLFSSL_SP_MATH)
663
    (void)ds;
664
    (void)res;
665
    (void)bn;
666
#else
667
1.23k
    GET_WHICH(1);
668
1.23k
    switch ( which ) {
669
896
        case    0:
670
896
            MP_CHECK_EQ(mp_submod(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
671
814
            break;
672
342
        case    1:
673
            /* mp_submod_ct does not support negative numbers */
674
342
            CF_CHECK_NE(mp_cmp_d(bn[0].GetPtr(), 0), MP_LT);
675
326
            CF_CHECK_NE(mp_cmp_d(bn[1].GetPtr(), 0), MP_LT);
676
306
            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
286
            CF_CHECK_EQ(wolfCrypt_bignum_detail::compare(bn[0], bn[2], ds), MP_LT)
684
233
            CF_CHECK_EQ(wolfCrypt_bignum_detail::compare(bn[1], bn[2], ds), MP_LT)
685
686
233
            MP_CHECK_EQ(mp_submod_ct(bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr(), res.GetPtr()), MP_OKAY);
687
182
            break;
688
0
        default:
689
0
            goto end;
690
1.23k
    }
691
692
996
    ret = true;
693
694
1.23k
end:
695
1.23k
#endif
696
1.23k
    return ret;
697
996
}
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
518
bool Bit::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
713
518
    (void)ds;
714
518
    bool ret = false;
715
716
#if defined(WOLFSSL_SP_MATH)
717
    (void)res;
718
    (void)bn;
719
#else
720
518
    std::optional<uint64_t> _bitPos;
721
518
#if defined(WOLFSSL_SP_MATH_ALL)
722
518
    unsigned int bitPos;
723
#else
724
    mp_digit bitPos;
725
#endif
726
518
    int isBitSet;
727
728
518
    CF_CHECK_NE(_bitPos = bn[1].AsUint64(), std::nullopt);
729
730
456
    bitPos = *_bitPos;
731
    /* Ensure no truncation has occurred */
732
456
    CF_CHECK_EQ(bitPos, *_bitPos);
733
734
278
    CF_CHECK_GTE(isBitSet = mp_is_bit_set(bn[0].GetPtr(), bitPos), 0);
735
278
    CF_CHECK_EQ( res.Set(isBitSet ? "1" : "0"), true);
736
737
278
    ret = true;
738
739
518
end:
740
518
#endif
741
518
    return ret;
742
278
}
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
1.51k
bool Mod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
807
1.51k
    bool ret = false;
808
809
1.51k
    GET_WHICH(4);
810
1.51k
    switch ( which ) {
811
460
        case    0:
812
460
            MP_CHECK_EQ(mp_mod(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
813
361
            break;
814
0
#if !defined(WOLFSSL_SP_MATH)
815
319
        case    1:
816
319
            {
817
                /* Input must not be negative */
818
319
                CF_CHECK_NE(mp_cmp_d(bn[0].GetPtr(), 0), MP_LT);
819
820
308
                const auto op = bn[1].AsUnsigned<mp_digit>();
821
308
                CF_CHECK_NE(op, std::nullopt);
822
226
                mp_digit modResult;
823
226
                MP_CHECK_EQ(mp_mod_d(bn[0].GetPtr(), *op, &modResult), MP_OKAY);
824
184
                CF_CHECK_EQ(res.Set(std::to_string(modResult)), true);
825
184
            }
826
0
            break;
827
168
        case    2:
828
168
            {
829
                /* mp_div_2_mod_ct does not support negative numbers */
830
168
                CF_CHECK_NE(mp_cmp_d(bn[0].GetPtr(), 0), MP_LT);
831
148
                CF_CHECK_NE(mp_cmp_d(bn[0].GetPtr(), 0), MP_LT);
832
833
                /* bn[0] *= 2 */
834
148
                MP_CHECK_EQ(mp_mul_d(bn[0].GetPtr(), 2, bn.GetDestPtr(0)), MP_OKAY);
835
836
144
                CF_CHECK_EQ(wolfCrypt_bignum_detail::compare(bn[0], bn[1], ds), MP_LT)
837
144
                MP_CHECK_EQ(mp_div_2_mod_ct(bn[0].GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
838
82
            }
839
0
            break;
840
160
        case    3:
841
160
            {
842
160
                mp_digit mp;
843
160
                wolfCrypt_bignum::Bignum tmp(ds);
844
845
160
                MP_CHECK_EQ(mp_montgomery_setup(bn[1].GetPtr(), &mp), MP_OKAY);
846
70
                MP_CHECK_EQ(mp_montgomery_calc_normalization(tmp.GetPtr(), bn[1].GetPtr()), MP_OKAY);
847
70
                MP_CHECK_EQ(mp_mulmod(bn[0].GetPtr(), tmp.GetPtr(), bn[1].GetPtr(), res.GetPtr()), MP_OKAY);
848
64
                MP_CHECK_EQ(mp_montgomery_reduce(res.GetPtr(), bn[1].GetPtr(), mp), MP_OKAY);
849
53
            }
850
0
            break;
851
0
#endif
852
0
#if !defined(WOLFSSL_SP_MATH) && (!defined(USE_FAST_MATH) || defined(WOLFSSL_SP_MATH_ALL))
853
404
        case    4:
854
404
            {
855
404
                std::optional<int> exponent = std::nullopt;
856
857
                /* Negative modulo not supported */
858
404
                CF_CHECK_NE(mp_cmp_d(bn[1].GetPtr(), 0), MP_LT);
859
860
392
                CF_CHECK_NE(exponent = wolfCrypt_bignum_detail::isPowerOf2(bn[1], ds), std::nullopt);
861
862
185
                MP_CHECK_EQ(mp_mod_2d(bn[0].GetPtr(), *exponent, res.GetPtr()), MP_OKAY);
863
185
            }
864
0
            break;
865
0
#endif
866
0
        default:
867
0
            goto end;
868
1.51k
    }
869
870
865
    ret = true;
871
872
1.51k
end:
873
1.51k
    return ret;
874
865
}
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
1.67k
bool Jacobi::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
994
1.67k
    bool ret = false;
995
996
1.67k
    (void)ds;
997
998
#if !defined(HAVE_MP_JACOBI)
999
    (void)res;
1000
    (void)bn;
1001
#else
1002
1.67k
    if ( mp_isodd(bn[1].GetPtr()) ) {
1003
1.58k
        int jacobi;
1004
1.58k
        MP_CHECK_EQ(mp_jacobi(bn[0].GetPtr(), bn[1].GetPtr(), &jacobi), MP_OKAY);
1005
1006
1.29k
        switch ( jacobi ) {
1007
432
            case    1:
1008
432
                CF_CHECK_EQ( res.Set("1"), true);
1009
432
                break;
1010
401
            case    -1:
1011
401
                CF_CHECK_EQ( res.Set("-1"), true);
1012
207
                break;
1013
458
            case    0:
1014
458
                CF_CHECK_EQ( res.Set("0"), true);
1015
458
                break;
1016
0
            default:
1017
0
                CF_ASSERT(0, "mp_jacobi result is not one of (-1, 0, 1)");
1018
1.29k
        }
1019
1020
1.09k
        ret = true;
1021
1.09k
    }
1022
1023
1.67k
end:
1024
1.67k
#endif
1025
1026
1.67k
    return ret;
1027
1.67k
}
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 */