Coverage Report

Created: 2024-11-21 06:51

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