Coverage Report

Created: 2025-04-24 07:09

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