Coverage Report

Created: 2023-12-08 07:00

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