Coverage Report

Created: 2024-11-21 07:00

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