Coverage Report

Created: 2025-03-09 06:52

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