Coverage Report

Created: 2024-06-28 06:39

/src/cryptofuzz/modules/botan/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 <botan/numthry.h>
5
#include <botan/reducer.h>
6
#include <botan/internal/divide.h>
7
#include <botan/internal/curve_nistp.h>
8
#include <botan/internal/primality.h>
9
#include <botan/system_rng.h>
10
11
#include "bn_ops.h"
12
13
namespace cryptofuzz {
14
namespace module {
15
namespace Botan_bignum {
16
17
namespace detail {
18
446
    std::optional<size_t> To_size_t(const Bignum& bn) {
19
        /* TODO use #if */
20
21
446
        if ( sizeof(size_t) == 4 ) {
22
0
            try {
23
0
                return bn.ConstRef().to_u32bit();
24
0
            } catch ( ::Botan::Encoding_Error ) {
25
0
                return std::nullopt;
26
0
            }
27
446
        } else if ( sizeof(size_t) == 8 ) {
28
446
            if( bn.ConstRef().is_negative() ) {
29
0
                return std::nullopt;
30
0
            }
31
32
446
            if( bn.ConstRef().bits() > 64 ) {
33
62
                return std::nullopt;
34
62
            }
35
36
384
            uint64_t out = 0;
37
38
3.45k
            for (size_t i = 0; i != 8; ++i) {
39
3.07k
                out = (out << 8) | bn.ConstRef().byte_at(7-i);
40
3.07k
            }
41
42
384
            return out;
43
446
        } else {
44
0
            CF_UNREACHABLE();
45
0
        }
46
446
    }
47
}
48
49
#if !defined(CRYPTOFUZZ_BOTAN_IS_ORACLE)
50
1.96k
 #define GET_UINT8_FOR_SWITCH() ds.Get<uint8_t>()
51
#else
52
 #define GET_UINT8_FOR_SWITCH() 0
53
#endif /* CRYPTOFUZZ_BOTAN_IS_ORACLE */
54
55
1.02k
#define APPLY_MODULO if (modulo != std::nullopt) res = (res.ConstRef() % modulo->ConstRef())
56
57
78
bool Add::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
58
78
    (void)ds;
59
60
78
    res = bn[0].Ref() + bn[1].Ref();
61
62
78
    APPLY_MODULO;
63
64
78
    return true;
65
78
}
66
67
88
bool Sub::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
68
88
    (void)ds;
69
70
88
    res = bn[0].Ref() - bn[1].Ref();
71
72
88
    APPLY_MODULO;
73
74
88
    return true;
75
88
}
76
77
120
bool Mul::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
78
120
    (void)ds;
79
80
120
    res = bn[0].Ref() * bn[1].Ref();
81
82
120
    APPLY_MODULO;
83
84
120
    return true;
85
120
}
86
87
318
bool Div::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
88
318
    (void)modulo;
89
318
    (void)ds;
90
91
    /* Botan handles negative division different than
92
     * other libraries.
93
     */
94
318
    CF_CHECK_TRUE(bn[0].Ref() > 0);
95
298
    CF_CHECK_TRUE(bn[1].Ref() > 0);
96
97
278
    try {
98
278
        switch ( GET_UINT8_FOR_SWITCH() ) {
99
26
            case    0:
100
                /* / operator */
101
26
                res = bn[0].Ref() / bn[1].Ref();
102
26
                return true;
103
51
            case    1:
104
51
                {
105
51
                    CF_CHECK_TRUE(bn[1].Ref() != 0);
106
51
                    Bignum dummy;
107
51
                    /* noret */ ::Botan::vartime_divide(bn[0].Ref(), bn[1].Ref(), res.Ref(), dummy.Ref());
108
51
                }
109
0
                return true;
110
34
            case    2:
111
34
                {
112
34
                    CF_CHECK_GT(bn[1].Ref(), 0);
113
34
                    CF_CHECK_TRUE(bn[1].Ref() < 256);
114
16
                    ::Botan::word dummy;
115
16
                    CF_NORET(::Botan::ct_divide_word(bn[0].Ref(), bn[1].Ref().word_at(0), res.Ref(), dummy));
116
16
                }
117
0
                return true;
118
9
            case    3:
119
9
                CF_CHECK_TRUE(bn[1].Ref() != 0);
120
9
                res = ::Botan::ct_divide(bn[0].Ref(), bn[1].Ref());
121
9
                return true;
122
56
            case    4:
123
                /* /= operator */
124
56
                res = bn[0].Ref();
125
56
                res.Ref() /= bn[1].Ref();
126
56
                return true;
127
278
        }
128
278
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
129
63
        return false;
130
63
    } catch ( ::Botan::Invalid_Argument& e ) {
131
        /* Botan is expected to throw an exception when divisor is 0 */
132
0
        if ( bn[1].Ref() == 0 ) {
133
0
            return false;
134
0
        }
135
136
        /* Rethrow */
137
0
        throw e;
138
0
    }
139
140
97
end:
141
97
    return false;
142
278
}
143
144
379
bool Mod::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
145
379
    (void)modulo;
146
379
    (void)ds;
147
148
379
    try {
149
379
        switch ( GET_UINT8_FOR_SWITCH() ) {
150
41
            case    0:
151
41
                {
152
41
                    try {
153
41
                        const Botan::Modular_Reducer reducer(bn[1].Ref());
154
41
                        res = reducer.reduce(bn[0].Ref());
155
41
                    } catch ( ::Botan::Invalid_State& e ) {
156
                        /* Modular reducer is expected to throw an exception when modulo is 0 */
157
22
                        if ( bn[1].Ref() == 0 ) {
158
22
                            return false;
159
22
                        }
160
161
                        /* Rethrow */
162
0
                        throw e;
163
22
                    }
164
41
                }
165
19
                return true;
166
43
            case    1:
167
43
                res = ct_modulo(bn[0].Ref(), bn[1].Ref());
168
43
                return true;
169
52
            case    2:
170
                /* % operator */
171
52
                res = bn[0].Ref() % bn[1].Ref();
172
52
                return true;
173
177
            case    3:
174
                /* %= operator */
175
177
                {
176
177
                    res = bn[0].Ref();
177
178
177
                    const ::Botan::word modulo = bn[1].Ref().word_at(0);
179
180
                    /* Ensure no truncation occurred */
181
177
                    if ( modulo != bn[1].Ref() ) {
182
2
                        return false;
183
2
                    }
184
185
175
                    res = bn[0].Ref() %= modulo;
186
175
                }
187
0
                return true;
188
379
        }
189
379
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
190
39
        return false;
191
58
    } catch ( ::Botan::Invalid_Argument& e ) {
192
        /* Botan is expected to throw an exception when modulo is <= 0 */
193
58
        if ( bn[1].Ref() <= 0 ) {
194
58
            return false;
195
58
        }
196
197
        /* Rethrow */
198
0
        throw e;
199
58
    }
200
201
27
    return false;
202
379
}
203
204
104
bool Exp::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
205
104
    (void)ds;
206
207
104
    if ( modulo == std::nullopt ) {
208
20
        return false;
209
20
    }
210
211
84
    res = ::Botan::power_mod(bn[0].Ref(), bn[1].Ref(), modulo->ConstRef());
212
213
84
    return true;
214
104
}
215
216
731
bool ExpMod::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
217
731
    (void)modulo;
218
731
    (void)ds;
219
220
    /* Exponent and modulus must be positive, according to the documentation */
221
731
    if ( bn[1].Ref() < 0 || bn[2].Ref() <= 0 ) {
222
20
        return false;
223
20
    }
224
225
711
    res = ::Botan::power_mod(bn[0].Ref(), bn[1].Ref(), bn[2].Ref());
226
227
711
    return true;
228
731
}
229
230
204
bool Sqr::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
231
204
    (void)ds;
232
233
204
    res = ::Botan::square(bn[0].Ref());
234
235
204
    APPLY_MODULO;
236
237
204
    return true;
238
204
}
239
240
132
bool GCD::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
241
132
    (void)modulo;
242
132
    (void)ds;
243
244
132
    res = ::Botan::gcd(bn[0].Ref(), bn[1].Ref());
245
246
132
    return true;
247
132
}
248
249
176
bool SqrMod::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
250
176
    (void)modulo;
251
176
    (void)ds;
252
253
176
    if ( bn[1].Ref().is_negative() ) {
254
0
        return false;
255
176
    } else {
256
176
        try {
257
176
            switch ( GET_UINT8_FOR_SWITCH() ) {
258
50
                case    0:
259
50
                    {
260
50
                        try {
261
50
                            ::Botan::Modular_Reducer mod(bn[1].Ref());
262
50
                            res = mod.square(bn[0].Ref());
263
50
                        } catch ( ::Botan::Invalid_State& e ) {
264
                            /* Modular reducer is expected to throw an exception when modulo is 0 */
265
16
                            if ( bn[1].Ref() == 0 ) {
266
16
                                return false;
267
16
                            }
268
269
                            /* Rethrow */
270
0
                            throw e;
271
16
                        }
272
50
                    }
273
34
                    break;
274
55
                case    1:
275
55
                    res = ::Botan::square(bn[0].Ref()) % bn[1].Ref();
276
55
                    break;
277
20
                default:
278
20
                    return false;
279
176
            }
280
176
        } catch ( fuzzing::datasource::Datasource::OutOfData ) {
281
51
            return false;
282
51
        } catch ( ::Botan::Invalid_Argument& e ) {
283
            /* Botan is expected to throw an exception when modulo is 0 */
284
22
            if ( bn[1].Ref() == 0 ) {
285
22
                return false;
286
22
            }
287
288
            /* Rethrow */
289
0
            throw e;
290
22
        }
291
176
    }
292
293
67
    return true;
294
176
}
295
296
427
bool InvMod::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
297
427
    (void)modulo;
298
427
    (void)ds;
299
300
427
    const auto mod = modulo == std::nullopt ? bn[1].ConstRef() : modulo->ConstRef();
301
302
427
    try {
303
427
        res = ::Botan::inverse_mod(bn[0].Ref(), mod);
304
427
    } catch ( ::Botan::Invalid_Argument& e ) {
305
        /* inverse_mod() is expected to throw an exception when modulo is 0 */
306
21
        if ( mod == 0 ) {
307
21
            return false;
308
21
        }
309
310
        /* inverse_mod() is expected to throw an exception when either argument is negative */
311
0
        if ( bn[0].Ref() < 0 || mod < 0 ) {
312
0
            return false;
313
0
        }
314
315
        /* Rethrow */
316
0
        throw e;
317
0
    }
318
319
406
    return true;
320
427
}
321
322
121
bool Cmp::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
323
121
    (void)modulo;
324
121
    (void)ds;
325
326
121
    if ( bn[0].Ref() < bn[1].Ref() ) {
327
33
        res = Bignum("-1");
328
88
    } else if ( bn[0].Ref() > bn[1].Ref() ) {
329
23
        res = 1;
330
65
    } else {
331
65
        res = 0;
332
65
    }
333
334
121
    return true;
335
121
}
336
337
164
bool LCM::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
338
164
    (void)modulo;
339
164
    (void)ds;
340
341
164
    try {
342
164
        res = ::Botan::lcm(bn[0].Ref(), bn[1].Ref());
343
164
    } catch ( ::Botan::Invalid_Argument& e ) {
344
        /* lcm() is expected to throw in these cases */
345
0
        if ( bn[0].Ref() == 0 || bn[1].Ref() == 0 ) {
346
0
            return false;
347
0
        }
348
349
        /* Rethrow */
350
0
        throw e;
351
0
    }
352
353
354
164
    return true;
355
164
}
356
357
30
bool Abs::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
358
30
    (void)modulo;
359
30
    (void)ds;
360
361
30
    res = ::Botan::abs(bn[0].Ref());
362
363
30
    return true;
364
30
}
365
366
146
bool Jacobi::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
367
146
    (void)modulo;
368
146
    (void)ds;
369
370
371
146
    int resInt;
372
373
146
    try {
374
146
        resInt = ::Botan::jacobi(bn[0].Ref(), bn[1].Ref());
375
146
    } catch ( ::Botan::Invalid_Argument& e ) {
376
        /* jacobi() is expected to throw in these cases */
377
42
        if ( (bn[1].Ref() % 2) == 0 || bn[1].Ref() <= 1 ) {
378
42
            return false;
379
42
        }
380
381
        /* Rethrow */
382
0
        throw e;
383
42
    }
384
385
104
    if ( resInt == -1 ) {
386
35
        res = Bignum("-1");
387
69
    } else {
388
69
        res = resInt;
389
69
    }
390
391
104
    return true;
392
146
}
393
394
49
bool Neg::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
395
49
    (void)modulo;
396
49
    (void)ds;
397
398
49
    res = -bn[0].Ref();
399
400
49
    return true;
401
49
}
402
403
312
bool IsPrime::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
404
312
    (void)modulo;
405
312
    (void)ds;
406
407
312
    if ( bn[0].Ref().is_negative() ) {
408
0
        return false;
409
0
    }
410
411
    /* Avoid time-outs */
412
312
    if ( bn[0].Ref().bytes() > 300 ) {
413
4
        return false;
414
4
    }
415
416
308
    Botan::Modular_Reducer mod_n(bn[0].Ref());
417
308
    if ( Botan::is_bailie_psw_probable_prime(bn[0].Ref(), mod_n) ) {
418
160
        res = 1;
419
160
    } else {
420
148
        res = 0;
421
148
    }
422
423
308
    return true;
424
312
}
425
426
247
bool RShift::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
427
247
    (void)ds;
428
429
247
    const auto count = detail::To_size_t(bn[1].Ref());
430
431
247
    if ( count == std::nullopt ) {
432
21
        return false;
433
21
    }
434
435
226
    Bignum toShift = bn[0];
436
226
    if ( modulo && bn[0].Ref() % 2 ) {
437
26
        toShift = toShift.Ref() + modulo->ConstRef();
438
26
    }
439
440
226
    res = toShift.Ref() >> *count;
441
442
226
    APPLY_MODULO;
443
444
226
    return true;
445
247
}
446
447
104
bool LShift1::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
448
104
    (void)ds;
449
450
104
    res = bn[0].Ref() << 1;
451
452
104
    APPLY_MODULO;
453
454
104
    return true;
455
104
}
456
457
20
bool IsNeg::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
458
20
    (void)modulo;
459
20
    (void)ds;
460
461
20
    res = bn[0].Ref() < 0 ? 1 : 0;
462
463
20
    return true;
464
20
}
465
466
105
bool IsEq::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
467
105
    (void)ds;
468
469
105
    auto A = modulo == std::nullopt ? bn[0] : bn[0].Ref() % modulo->ConstRef();
470
105
    auto B = modulo == std::nullopt ? bn[1] : bn[1].Ref() % modulo->ConstRef();
471
472
105
    res = A.Ref() == B.Ref() ? 1 : 0;
473
474
105
    return true;
475
105
}
476
477
20
bool IsGt::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
478
20
    (void)modulo;
479
20
    (void)ds;
480
481
20
    res = bn[0].Ref() > bn[1].Ref() ? 1 : 0;
482
483
20
    return true;
484
20
}
485
486
23
bool IsGte::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
487
23
    (void)modulo;
488
23
    (void)ds;
489
490
23
    res = bn[0].Ref() >= bn[1].Ref() ? 1 : 0;
491
492
23
    return true;
493
23
}
494
495
11
bool IsLt::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
496
11
    (void)modulo;
497
11
    (void)ds;
498
499
11
    res = bn[0].Ref() < bn[1].Ref() ? 1 : 0;
500
501
11
    return true;
502
11
}
503
504
20
bool IsLte::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
505
20
    (void)modulo;
506
20
    (void)ds;
507
508
20
    res = bn[0].Ref() <= bn[1].Ref() ? 1 : 0;
509
510
20
    return true;
511
20
}
512
513
48
bool IsEven::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
514
48
    (void)modulo;
515
48
    (void)ds;
516
517
48
    res = !(bn[0].Ref() % 2) ? 1 : 0;
518
519
48
    return true;
520
48
}
521
522
49
bool IsOdd::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
523
49
    (void)modulo;
524
49
    (void)ds;
525
526
49
    res = (bn[0].Ref() % 2) ? 1 : 0;
527
528
49
    return true;
529
49
}
530
531
67
bool IsZero::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
532
67
    (void)ds;
533
534
67
    auto A = modulo == std::nullopt ? bn[0] : bn[0].Ref() % modulo->ConstRef();
535
536
67
    res = A.Ref() == 0 ? 1 : 0;
537
538
67
    return true;
539
67
}
540
541
20
bool IsNotZero::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
542
20
    (void)modulo;
543
20
    (void)ds;
544
545
20
    res = bn[0].Ref() == 0 ? 0 : 1;
546
547
20
    return true;
548
20
}
549
550
89
bool IsOne::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
551
89
    (void)ds;
552
553
89
    auto A = modulo == std::nullopt ? bn[0] : bn[0].Ref() % modulo->ConstRef();
554
555
89
    res = A.Ref() == 1 ? 1 : 0;
556
557
89
    return true;
558
89
}
559
560
175
bool MulMod::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
561
175
    (void)modulo;
562
175
    (void)ds;
563
564
175
    try {
565
175
        switch ( GET_UINT8_FOR_SWITCH() ) {
566
66
            case    0:
567
66
                {
568
66
                    try {
569
66
                        ::Botan::Modular_Reducer mod(bn[2].Ref());
570
66
                        res = mod.multiply(bn[0].Ref(), bn[1].Ref());
571
66
                    } catch ( ::Botan::Invalid_State& e ) {
572
                        /* Modular reducer is expected to throw an exception when modulo is 0 */
573
21
                        if ( bn[2].Ref() == 0 ) {
574
21
                            return false;
575
21
                        }
576
577
                        /* Rethrow */
578
0
                        throw e;
579
21
                    }
580
66
                }
581
45
                break;
582
66
            case    1:
583
66
                res = (bn[0].Ref() * bn[1].Ref()) % bn[2].Ref();
584
66
                break;
585
19
            default:
586
19
                return false;
587
175
        }
588
175
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
589
24
        return false;
590
26
    } catch ( ::Botan::Invalid_Argument& e ) {
591
        /* Botan is expected to throw an exception when modulo is <= 0 */
592
26
        if ( bn[2].Ref() <= 0 ) {
593
26
            return false;
594
26
        }
595
596
        /* Rethrow */
597
0
        throw e;
598
26
    }
599
600
85
    return true;
601
175
}
602
603
77
bool Bit::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
604
77
    (void)modulo;
605
77
    (void)ds;
606
607
77
    const auto pos = detail::To_size_t(bn[1].Ref());
608
609
77
    if ( pos == std::nullopt ) {
610
21
        return false;
611
21
    }
612
613
56
    res = bn[0].Ref().get_bit(*pos) ? 1 : 0;
614
615
56
    return true;
616
77
}
617
618
97
bool CmpAbs::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
619
97
    (void)modulo;
620
97
    std::vector<Bignum> bnAbs = {bn[0].Ref().abs(), bn[1].Ref().abs()};
621
97
    auto cmp = std::make_unique<Cmp>();
622
623
97
    return cmp->Run(ds, res, bnAbs, modulo);
624
97
}
625
626
45
bool SetBit::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
627
45
    (void)modulo;
628
45
    (void)ds;
629
630
45
    res = bn[0].Ref();
631
632
45
    const auto pos = detail::To_size_t(bn[1].Ref());
633
634
45
    if ( pos == std::nullopt ) {
635
0
        return false;
636
0
    }
637
638
45
    res.Ref().set_bit(*pos);
639
640
45
    return true;
641
45
}
642
643
135
bool Mod_NIST_192::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
644
135
    (void)modulo;
645
135
    (void)ds;
646
647
135
    static const auto prime = ::Botan::prime_p192();
648
135
    static const auto limit = prime * prime;
649
650
135
    try {
651
135
        switch ( GET_UINT8_FOR_SWITCH() ) {
652
37
            case    0:
653
37
                res = bn[0].Ref() % Bignum("6277101735386680763835789423207666416083908700390324961279").Ref();
654
37
                return true;
655
26
            case    1:
656
26
                {
657
26
                    if ( bn[0].Ref() < 0 || bn[0].Ref() >= limit ) {
658
2
                        return false;
659
2
                    }
660
24
                    res = bn[0].Ref();
661
24
                    ::Botan::secure_vector<::Botan::word> ws;
662
24
                    CF_NORET(redc_p192(res.Ref(), ws));
663
24
                }
664
0
                return true;
665
14
            case    2:
666
14
                {
667
14
                    ::Botan::Modular_Reducer prime_redc(prime);
668
14
                    res = prime_redc.reduce(bn[0].Ref());
669
14
                }
670
14
                return true;
671
135
        }
672
135
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
673
33
        return false;
674
33
    }
675
676
25
    return false;
677
135
}
678
679
148
bool Mod_NIST_224::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
680
148
    (void)modulo;
681
148
    (void)ds;
682
683
148
    static const auto prime = ::Botan::prime_p224();
684
148
    static const auto limit = prime * prime;
685
686
148
    try {
687
148
        switch ( GET_UINT8_FOR_SWITCH() ) {
688
35
            case    0:
689
35
                res = bn[0].Ref() % Bignum("26959946667150639794667015087019630673557916260026308143510066298881").Ref();
690
35
                return true;
691
25
            case    1:
692
25
                {
693
25
                    if ( bn[0].Ref() < 0 || bn[0].Ref() >= limit ) {
694
1
                        return false;
695
1
                    }
696
24
                    res = bn[0].Ref();
697
24
                    ::Botan::secure_vector<::Botan::word> ws;
698
24
                    CF_NORET(redc_p224(res.Ref(), ws));
699
24
                }
700
0
                return true;
701
13
            case    2:
702
13
                {
703
13
                    ::Botan::Modular_Reducer prime_redc(prime);
704
13
                    res = prime_redc.reduce(bn[0].Ref());
705
13
                }
706
13
                return true;
707
148
        }
708
148
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
709
55
        return false;
710
55
    }
711
712
20
    return false;
713
148
}
714
715
104
bool Mod_NIST_256::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
716
104
    (void)modulo;
717
104
    (void)ds;
718
719
104
    static const auto prime = ::Botan::prime_p256();
720
104
    static const auto limit = prime * prime;
721
722
104
    try {
723
104
        switch ( GET_UINT8_FOR_SWITCH() ) {
724
32
            case    0:
725
32
                res = bn[0].Ref() % Bignum("115792089210356248762697446949407573530086143415290314195533631308867097853951").Ref();
726
32
                return true;
727
26
            case    1:
728
26
                {
729
26
                    if ( bn[0].Ref() < 0 || bn[0].Ref() >= limit ) {
730
2
                        return false;
731
2
                    }
732
24
                    res = bn[0].Ref();
733
24
                    ::Botan::secure_vector<::Botan::word> ws;
734
24
                    CF_NORET(redc_p256(res.Ref(), ws));
735
24
                }
736
0
                return true;
737
2
            case    2:
738
2
                {
739
2
                    ::Botan::Modular_Reducer prime_redc(prime);
740
2
                    res = prime_redc.reduce(bn[0].Ref());
741
2
                }
742
2
                return true;
743
104
        }
744
104
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
745
25
        return false;
746
25
    }
747
748
19
    return false;
749
104
}
750
751
118
bool Mod_NIST_384::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
752
118
    (void)modulo;
753
118
    (void)ds;
754
755
118
    static const auto prime = ::Botan::prime_p384();
756
118
    static const auto limit = prime * prime;
757
758
118
    try {
759
118
        switch ( GET_UINT8_FOR_SWITCH() ) {
760
30
            case    0:
761
30
                res = bn[0].Ref() % Bignum("39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319").Ref();
762
30
                return true;
763
19
            case    1:
764
19
                {
765
19
                    if ( bn[0].Ref() < 0 || bn[0].Ref() >= limit ) {
766
1
                        return false;
767
1
                    }
768
18
                    res = bn[0].Ref();
769
18
                    ::Botan::secure_vector<::Botan::word> ws;
770
18
                    CF_NORET(redc_p384(res.Ref(), ws));
771
18
                }
772
0
                return true;
773
16
            case    2:
774
16
                {
775
16
                    ::Botan::Modular_Reducer prime_redc(prime);
776
16
                    res = prime_redc.reduce(bn[0].Ref());
777
16
                }
778
16
                return true;
779
118
        }
780
118
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
781
29
        return false;
782
29
    }
783
784
24
    return false;
785
118
}
786
787
89
bool Mod_NIST_521::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
788
89
    (void)modulo;
789
89
    (void)ds;
790
791
89
    static const auto prime = ::Botan::prime_p521();
792
89
    static const auto limit = prime * prime;
793
794
89
    try {
795
89
        switch ( GET_UINT8_FOR_SWITCH() ) {
796
27
            case    0:
797
27
                res = bn[0].Ref() % Bignum("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151").Ref();
798
27
                return true;
799
12
            case    1:
800
12
                {
801
12
                    if ( bn[0].Ref() < 0 || bn[0].Ref() >= limit ) {
802
2
                        return false;
803
2
                    }
804
10
                    res = bn[0].Ref();
805
10
                    ::Botan::secure_vector<::Botan::word> ws;
806
10
                    CF_NORET(redc_p521(res.Ref(), ws));
807
10
                }
808
0
                return true;
809
2
            case    2:
810
2
                {
811
2
                    ::Botan::Modular_Reducer prime_redc(prime);
812
2
                    res = prime_redc.reduce(bn[0].Ref());
813
2
                }
814
2
                return true;
815
89
        }
816
89
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
817
29
        return false;
818
29
    }
819
820
19
    return false;
821
89
}
822
823
77
bool ClearBit::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
824
77
    (void)modulo;
825
77
    (void)ds;
826
827
77
    res = bn[0].Ref();
828
829
77
    const auto pos = detail::To_size_t(bn[1].Ref());
830
831
77
    if ( pos == std::nullopt ) {
832
20
        return false;
833
20
    }
834
835
57
    res.Ref().clear_bit(*pos);
836
837
57
    return true;
838
77
}
839
840
58
bool MulAdd::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
841
58
    (void)modulo;
842
58
    (void)ds;
843
844
58
    res = (bn[0].Ref()*bn[1].Ref()) + bn[2].Ref();
845
846
58
    return true;
847
58
}
848
849
41
bool MulDiv::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
850
41
    (void)modulo;
851
41
    (void)ds;
852
853
41
    if ( bn[2].Ref() == 0 ) {
854
20
        return false;
855
20
    }
856
857
21
    res = (bn[0].Ref()*bn[1].Ref()+1) / bn[2].Ref();
858
859
21
    return true;
860
41
}
861
862
134
bool MulDivCeil::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
863
134
    (void)modulo;
864
134
    (void)ds;
865
866
134
    if ( bn[2].Ref() <= 0 ) {
867
20
        return false;
868
20
    }
869
870
114
    const auto mulRes = bn[0].Ref() * bn[1].Ref();
871
114
    const auto modRes = mulRes % bn[2].Ref();
872
114
    res = mulRes / bn[2].Ref() + (modRes != 0 ? 1 : 0);
873
874
114
    return true;
875
134
}
876
877
76
bool Exp2::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
878
76
    (void)modulo;
879
76
    (void)ds;
880
881
76
    if ( bn[0].Ref() < 1 ) {
882
16
        return false;
883
16
    }
884
885
60
    const size_t exponent = bn[0].Ref().word_at(0) - 1;
886
887
60
    res = Bignum(2).Ref() << exponent;
888
889
60
    return true;
890
76
}
891
892
23
bool NumLSZeroBits::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
893
23
    (void)modulo;
894
23
    (void)ds;
895
896
23
    res = ::Botan::low_zero_bits(bn[0].Ref());
897
898
23
    return true;
899
23
}
900
901
144
bool Sqrt::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
902
144
    (void)ds;
903
904
144
    try {
905
144
        const auto res2 = ::Botan::is_perfect_square(bn[0].Ref());
906
144
        if ( res2 == 0 ) {
907
88
            return false;
908
88
        }
909
910
56
        res = res2;
911
56
    } catch ( ::Botan::Invalid_Argument& e ) {
912
        /* is_perfect_square() is expected to throw in this case */
913
24
        if ( bn[0].Ref() < 1 ) {
914
24
            return false;
915
24
        }
916
917
        /* Rethrow */
918
0
        throw e;
919
24
    }
920
921
32
    APPLY_MODULO;
922
923
32
    return true;
924
144
}
925
926
177
bool AddMod::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
927
177
    (void)modulo;
928
177
    (void)ds;
929
930
177
    try {
931
177
        switch ( GET_UINT8_FOR_SWITCH() ) {
932
54
            case    0:
933
54
                res = (bn[0].Ref() + bn[1].Ref()) % bn[2].Ref();
934
54
                break;
935
73
            case    1:
936
73
                {
937
73
                    if ( bn[0].Ref() >= bn[2].Ref() ) {
938
23
                        return false;
939
23
                    }
940
50
                    if ( bn[1].Ref() >= bn[2].Ref() ) {
941
20
                        return false;
942
20
                    }
943
944
30
                    ::Botan::secure_vector<::Botan::word> ws;
945
30
                    try {
946
30
                        res = bn[0].Ref().mod_add(bn[1].Ref(), bn[2].Ref(), ws);
947
30
                    } catch ( ::Botan::Invalid_Argument& e ) {
948
                        /* mod_add is expected to throw an exception when any argument is negative */
949
0
                        if ( bn[0].Ref() < 0 || bn[1].Ref() < 0 || bn[2].Ref() < 0) {
950
0
                            return false;
951
0
                        }
952
953
                        /* Rethrow */
954
0
                        throw e;
955
0
                    }
956
30
                }
957
30
                break;
958
24
            default:
959
24
                return false;
960
177
        }
961
177
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
962
26
        return false;
963
26
    } catch ( ::Botan::Invalid_Argument& e ) {
964
        /* Botan is expected to throw an exception when modulo is <= 0 */
965
17
        if ( bn[2].Ref() <= 0 ) {
966
17
            return false;
967
17
        }
968
969
        /* Rethrow */
970
0
        throw e;
971
17
    }
972
973
67
    return true;
974
177
}
975
976
188
bool SubMod::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
977
188
    (void)modulo;
978
188
    (void)ds;
979
980
188
    try {
981
188
        switch ( GET_UINT8_FOR_SWITCH() ) {
982
68
            case    0:
983
68
                res = (bn[0].Ref() - bn[1].Ref()) % bn[2].Ref();
984
68
                break;
985
82
            case    1:
986
82
                {
987
82
                    if ( bn[0].Ref() >= bn[2].Ref() ) {
988
20
                        return false;
989
20
                    }
990
62
                    if ( bn[1].Ref() >= bn[2].Ref() ) {
991
16
                        return false;
992
16
                    }
993
994
46
                    ::Botan::secure_vector<::Botan::word> ws;
995
46
                    try {
996
46
                        res = bn[0].Ref().mod_sub(bn[1].Ref(), bn[2].Ref(), ws);
997
46
                    } catch ( ::Botan::Invalid_Argument& e ) {
998
                        /* mod_sub is expected to throw an exception when any argument is negative */
999
0
                        if ( bn[0].Ref() < 0 || bn[1].Ref() < 0 || bn[2].Ref() < 0) {
1000
0
                            return false;
1001
0
                        }
1002
1003
                        /* Rethrow */
1004
0
                        throw e;
1005
0
                    }
1006
46
                }
1007
46
                break;
1008
18
            default:
1009
18
                return false;
1010
188
        }
1011
188
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
1012
20
        return false;
1013
20
    } catch ( ::Botan::Invalid_Argument& e ) {
1014
        /* Botan is expected to throw an exception when modulo is <= 0 */
1015
20
        if ( bn[2].Ref() <= 0 ) {
1016
20
            return false;
1017
20
        }
1018
1019
        /* Rethrow */
1020
0
        throw e;
1021
20
    }
1022
1023
94
    return true;
1024
188
}
1025
1026
54
bool NumBits::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
1027
54
    (void)ds;
1028
1029
54
    if ( modulo ) {
1030
41
        res = (bn[0].Ref() % modulo->ConstRef()).bits();
1031
41
    } else {
1032
13
        res = bn[0].Ref().bits();
1033
13
    }
1034
1035
54
    return true;
1036
54
}
1037
1038
69
bool Set::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
1039
69
    (void)modulo;
1040
69
    (void)ds;
1041
1042
69
    res = bn[0].Ref();
1043
1044
69
    APPLY_MODULO;
1045
1046
69
    return true;
1047
69
}
1048
1049
156
bool CondSet::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
1050
156
    (void)modulo;
1051
156
    (void)ds;
1052
1053
156
    res.Ref().ct_cond_assign(bn[1].Ref() != 0, bn[0].Ref());
1054
1055
156
    return true;
1056
156
}
1057
1058
227
bool Ressol::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
1059
227
    (void)ds;
1060
1061
227
    try {
1062
227
        auto mod = modulo == std::nullopt ? bn[1] : *modulo;
1063
1064
227
        const auto r = ::Botan::sqrt_modulo_prime(bn[0].Ref(), mod.Ref());
1065
1066
227
        if ( r < 1 ) {
1067
61
            if ( modulo != std::nullopt ) {
1068
61
                res = 0;
1069
61
                return true;
1070
61
            } else {
1071
0
                return false;
1072
0
            }
1073
61
        }
1074
1075
166
        if ( modulo != std::nullopt ) {
1076
129
            res = ::Botan::square(r) % mod.Ref();
1077
129
        }
1078
1079
166
        return true;
1080
227
    } catch ( ::Botan::Invalid_Argument& e ) {
1081
        /* Expected to throw if called with non-prime argument */
1082
1083
37
        return false;
1084
37
    }
1085
227
}
1086
1087
128
bool Not::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
1088
128
    (void)ds;
1089
1090
128
    Bignum max;
1091
1092
128
    if ( modulo ) {
1093
80
        max = *modulo;
1094
80
    } else {
1095
48
        const size_t numBits = bn[0].Ref().bits();
1096
1097
48
        if ( numBits == 0 ) {
1098
21
            return false;
1099
21
        }
1100
1101
27
        max = (::Botan::BigInt(1) << numBits) - 1;
1102
27
    }
1103
1104
107
    res = max.Ref() - bn[0].Ref();
1105
1106
107
    APPLY_MODULO;
1107
1108
107
    return true;
1109
128
}
1110
1111
1.20k
bool Prime::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
1112
1.20k
    (void)ds;
1113
1.20k
    (void)bn;
1114
1.20k
    (void)modulo;
1115
1116
1.20k
    ::Botan::System_RNG rng;
1117
1.20k
    res = Botan::random_prime(rng, (rand() % 512) + 2);
1118
1119
1.20k
    return true;
1120
1.20k
}
1121
1122
59
bool RandRange::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
1123
59
    (void)ds;
1124
59
    (void)modulo;
1125
1126
59
    try {
1127
59
        ::Botan::System_RNG rng;
1128
59
        res = ::Botan::BigInt::random_integer(rng, bn[0].Ref(), bn[1].Ref());
1129
59
    } catch ( ::Botan::Invalid_Argument ) {
1130
20
        return false;
1131
20
    }
1132
1133
39
    return true;
1134
59
}
1135
1136
75
bool IsSquare::Run(Datasource& ds, Bignum& res, std::vector<Bignum>& bn, const std::optional<Bignum>& modulo) const {
1137
75
    (void)ds;
1138
1139
75
    if ( modulo != std::nullopt ) {
1140
0
        return false;
1141
0
    }
1142
1143
75
    try {
1144
75
        res = ::Botan::is_perfect_square(bn[0].Ref()) == 0 ? 0 : 1;
1145
75
    } catch ( ::Botan::Invalid_Argument& e ) {
1146
        /* is_perfect_square() is expected to throw in this case */
1147
16
        if ( bn[0].Ref() < 1 ) {
1148
16
            return false;
1149
16
        }
1150
1151
        /* Rethrow */
1152
0
        throw e;
1153
16
    }
1154
1155
59
    return true;
1156
75
}
1157
1158
} /* namespace Botan_bignum */
1159
} /* namespace module */
1160
} /* namespace cryptofuzz */