Coverage Report

Created: 2024-11-21 06:38

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