Coverage Report

Created: 2023-02-22 06:39

/src/cryptofuzz/modules/libgmp/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
5
#include "bn_ops.h"
6
7
1.56k
#define GET_WHICH(max) uint8_t which = 0; try { which = ds.Get<uint8_t>(); which %= ((max)+1); } catch ( ... ) { }
8
9
namespace cryptofuzz {
10
namespace module {
11
#if !defined(HAVE_MINI_GMP)
12
namespace libgmp_detail {
13
    extern gmp_randstate_t rng_state;
14
}
15
#endif
16
namespace libgmp_bignum {
17
18
73
bool Add::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
19
73
    bool ret = false;
20
21
73
    GET_WHICH(1);
22
73
    switch ( which ) {
23
12
        case    0:
24
            /* noret */ mpz_add(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
25
12
            break;
26
61
        case    1:
27
61
            {
28
61
                const auto bn1 = bn[1].GetUnsignedLong();
29
61
                CF_CHECK_NE(bn1, std::nullopt);
30
31
51
                /* noret */ mpz_add_ui(res.GetPtr(), bn[0].GetPtr(), *bn1);
32
51
            }
33
0
            break;
34
0
        default:
35
0
            return false;
36
73
    }
37
38
63
    ret = true;
39
40
73
end:
41
73
    return ret;
42
63
}
43
44
173
bool Sub::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
45
173
    bool ret = false;
46
47
173
    GET_WHICH(2);
48
173
    switch ( which ) {
49
42
        case    0:
50
            /* noret */ mpz_sub(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
51
42
            break;
52
69
        case    1:
53
69
            {
54
69
                const auto bn1 = bn[1].GetUnsignedLong();
55
69
                CF_CHECK_NE(bn1, std::nullopt);
56
57
67
                /* noret */ mpz_sub_ui(res.GetPtr(), bn[0].GetPtr(), *bn1);
58
67
            }
59
0
            break;
60
62
        case    2:
61
62
            {
62
62
                const auto bn0 = bn[0].GetUnsignedLong();
63
62
                CF_CHECK_NE(bn0, std::nullopt);
64
65
53
                /* noret */ mpz_ui_sub(res.GetPtr(), *bn0, bn[1].GetPtr());
66
53
            }
67
0
            break;
68
0
        default:
69
0
            return false;
70
173
    }
71
72
162
    ret = true;
73
74
173
end:
75
173
    return ret;
76
162
}
77
78
121
bool Mul::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
79
121
    bool ret = false;
80
81
121
    GET_WHICH(2);
82
121
    switch ( which ) {
83
50
        case    0:
84
            /* noret */ mpz_mul(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
85
50
            break;
86
42
        case    1:
87
42
            {
88
42
                const auto bn1 = bn[1].GetUnsignedLong();
89
42
                CF_CHECK_NE(bn1, std::nullopt);
90
91
30
                /* noret */ mpz_mul_ui(res.GetPtr(), bn[0].GetPtr(), *bn1);
92
30
            }
93
0
            break;
94
29
        case    2:
95
29
            {
96
29
                const auto bn1 = bn[1].GetSignedLong();
97
29
                CF_CHECK_NE(bn1, std::nullopt);
98
99
16
                /* noret */ mpz_mul_si(res.GetPtr(), bn[0].GetPtr(), *bn1);
100
16
            }
101
0
            break;
102
0
        default:
103
0
            return false;
104
121
    }
105
106
96
    ret = true;
107
108
121
end:
109
121
    return ret;
110
96
}
111
112
0
bool Div::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
113
0
    bool ret = false;
114
115
0
    GET_WHICH(3);
116
0
    switch ( which ) {
117
0
#if !defined(HAVE_MINI_GMP)
118
0
        case    0:
119
0
            CF_CHECK_NE(mpz_cmp_ui(bn[1].GetPtr(), 0), 0);
120
121
0
            /* noret */ mpz_div(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
122
0
            break;
123
0
        case    1:
124
0
            {
125
0
                CF_CHECK_NE(mpz_cmp_ui(bn[1].GetPtr(), 0), 0);
126
127
0
                const auto bn1 = bn[1].GetUnsignedLong();
128
0
                CF_CHECK_NE(bn1, std::nullopt);
129
130
0
                /* noret */ mpz_div_ui(res.GetPtr(), bn[0].GetPtr(), *bn1);
131
0
            }
132
0
            break;
133
0
#endif
134
0
        case    2:
135
0
            {
136
0
                CF_CHECK_NE(mpz_cmp_ui(bn[1].GetPtr(), 0), 0);
137
138
0
                CF_CHECK_NE(mpz_divisible_p(bn[0].GetPtr(), bn[1].GetPtr()), 0);
139
140
0
                /* noret */ mpz_divexact(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
141
0
            }
142
0
            break;
143
0
        case    3:
144
0
            {
145
0
                CF_CHECK_NE(mpz_cmp_ui(bn[1].GetPtr(), 0), 0);
146
147
0
                const auto bn1 = bn[1].GetUnsignedLong();
148
0
                CF_CHECK_NE(bn1, std::nullopt);
149
150
0
                CF_CHECK_NE(mpz_divisible_ui_p(bn[0].GetPtr(), *bn1), 0);
151
152
0
                /* noret */ mpz_divexact_ui(res.GetPtr(), bn[0].GetPtr(), *bn1);
153
0
            }
154
0
            break;
155
0
        default:
156
0
            return false;
157
0
    }
158
159
    /* Negative not supported */
160
0
    CF_CHECK_GTE(mpz_sgn(bn[0].GetPtr()), 0);
161
0
    CF_CHECK_GTE(mpz_sgn(bn[1].GetPtr()), 0);
162
163
0
    ret = true;
164
165
0
end:
166
0
    return ret;
167
0
}
168
169
0
bool ExpMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
170
0
    bool ret = false;
171
172
0
    GET_WHICH(2);
173
174
0
    CF_CHECK_NE(mpz_cmp_ui(bn[2].GetPtr(), 0), 0);
175
176
#if defined(HAVE_MINI_GMP)
177
    /* Avoid timeouts */
178
    CF_CHECK_LTE(mpz_sizeinbase(bn[0].GetPtr(), 2), 2000);
179
    CF_CHECK_LTE(mpz_sizeinbase(bn[1].GetPtr(), 2), 2000);
180
    CF_CHECK_LTE(mpz_sizeinbase(bn[2].GetPtr(), 2), 2000);
181
#endif
182
183
0
    switch ( which ) {
184
0
        case    0:
185
            /* "Negative exp is supported if the inverse base-1 mod mod exists.
186
             *  If an inverse doesn’t exist then a divide by zero is raised."
187
             */
188
0
            CF_CHECK_GTE(mpz_sgn(bn[1].GetPtr()), 0);
189
190
0
            /* noret */ mpz_powm(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr());
191
0
            break;
192
0
        case    1:
193
0
            {
194
0
                const auto bn1 = bn[1].GetUnsignedLong();
195
0
                CF_CHECK_NE(bn1, std::nullopt);
196
197
0
                /* noret */ mpz_powm_ui(res.GetPtr(), bn[0].GetPtr(), *bn1, bn[2].GetPtr());
198
0
            }
199
0
            break;
200
0
#if !defined(HAVE_MINI_GMP)
201
0
        case    2:
202
0
            {
203
0
                CF_CHECK_GTE(mpz_sgn(bn[1].GetPtr()), 0);
204
205
                /* "It is required that exp > 0 and that mod is odd." */
206
0
                CF_CHECK_NE(mpz_cmp_ui(bn[1].GetPtr(), 0), 1);
207
208
0
                const auto ptr = bn[2].GetPtr();
209
0
                CF_CHECK_EQ(mpz_odd_p(ptr), 1);
210
211
0
                /* noret */ mpz_powm_sec(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr());
212
0
            }
213
0
            break;
214
0
#endif
215
0
        default:
216
0
            return false;
217
0
    }
218
219
0
    ret = true;
220
221
0
end:
222
0
    return ret;
223
0
}
224
225
enum GCDType : uint8_t {
226
    GCD = 0,
227
    ExtGCD_X = 1,
228
    ExtGCD_Y = 2,
229
};
230
231
257
static void GCD_ExtGCD_SetResult(mpz_ptr res, const mpz_ptr X, const mpz_ptr Y, const GCDType type) {
232
257
    if ( type == GCDType::GCD ) {
233
        /* do nothing */
234
131
    } else if ( type == GCDType::ExtGCD_X ) {
235
        /* noret */ mpz_set(res, X);
236
70
    } else if ( type == GCDType::ExtGCD_Y ) {
237
        /* noret */ mpz_set(res, Y);
238
70
    } else {
239
0
        CF_UNREACHABLE();
240
0
    }
241
257
}
242
243
913
static bool GCD_ExtGCD(Datasource& ds, Bignum& res, BignumCluster& bn, const GCDType type) {
244
913
    bool ret = false;
245
246
913
    GET_WHICH(2);
247
913
    switch ( which ) {
248
617
        case    0:
249
617
            CF_CHECK_EQ(type, GCDType::GCD);
250
            /* noret */ mpz_gcd(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
251
596
            break;
252
39
        case    1:
253
39
            {
254
39
                CF_CHECK_EQ(type, GCDType::GCD);
255
256
34
                const auto bn1 = bn[1].GetUnsignedLong();
257
34
                CF_CHECK_NE(bn1, std::nullopt);
258
259
28
                /* ignore ret */ mpz_gcd_ui(res.GetPtr(), bn[0].GetPtr(), *bn1);
260
28
            }
261
0
            break;
262
257
        case    2:
263
257
            {
264
257
                Bignum t1, t2;
265
266
257
                /* noret */ mpz_gcdext(res.GetPtr(), t1.GetPtr(), t2.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
267
257
                CF_NORET(GCD_ExtGCD_SetResult(res.GetPtr(), t1.GetPtr(), t2.GetPtr(), type));
268
257
            }
269
257
            break;
270
0
        default:
271
0
            return false;
272
913
    }
273
274
881
    ret = true;
275
276
913
end:
277
913
    return ret;
278
881
}
279
280
756
bool GCD::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
281
756
    return GCD_ExtGCD(ds, res, bn, GCDType::GCD);
282
756
}
283
284
74
bool ExtGCD_X::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
285
74
    return GCD_ExtGCD(ds, res, bn, GCDType::ExtGCD_X);
286
74
}
287
288
83
bool ExtGCD_Y::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
289
83
    return GCD_ExtGCD(ds, res, bn, GCDType::ExtGCD_Y);
290
83
}
291
292
0
bool Jacobi::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
293
0
#if !defined(HAVE_MINI_GMP)
294
0
    GET_WHICH(2);
295
0
    switch ( which ) {
296
0
        case    0:
297
0
            res.Set( std::to_string(mpz_jacobi(bn[0].GetPtr(), bn[1].GetPtr())) );
298
0
            return true;
299
0
        case    1:
300
0
            {
301
0
                const auto bn1 = bn[1].GetSignedLong();
302
0
                CF_CHECK_NE(bn1, std::nullopt);
303
0
                res.Set( std::to_string(mpz_kronecker_si(bn[0].GetPtr(), *bn1)) );
304
0
            }
305
0
            return true;
306
0
        case    2:
307
0
            {
308
0
                const auto bn1 = bn[1].GetUnsignedLong();
309
0
                CF_CHECK_NE(bn1, std::nullopt);
310
0
                res.Set( std::to_string(mpz_kronecker_ui(bn[0].GetPtr(), *bn1)) );
311
0
            }
312
0
            return true;
313
0
        default:
314
0
            return false;
315
0
    }
316
317
0
end:
318
0
    return false;
319
#else
320
    (void)ds;
321
    (void)res;
322
    (void)bn;
323
324
    return false;
325
#endif
326
0
}
327
328
0
bool Cmp::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
329
0
    bool ret = false;
330
331
0
    int cmp;
332
333
0
    GET_WHICH(2);
334
0
    switch ( which ) {
335
0
        case    0:
336
0
            cmp = mpz_cmp(bn[0].GetPtr(), bn[1].GetPtr());
337
0
            break;
338
0
        case    1:
339
0
            {
340
0
                const auto bn1 = bn[1].GetSignedLong();
341
0
                CF_CHECK_NE(bn1, std::nullopt);
342
343
0
                cmp = mpz_cmp_si(bn[0].GetPtr(), *bn1);
344
0
            }
345
0
            break;
346
0
        case    2:
347
0
            {
348
0
                const auto bn1 = bn[1].GetUnsignedLong();
349
0
                CF_CHECK_NE(bn1, std::nullopt);
350
351
0
                cmp = mpz_cmp_ui(bn[0].GetPtr(), *bn1);
352
0
            }
353
0
            break;
354
0
        default:
355
0
            goto end;
356
0
    }
357
358
0
    if ( cmp < 0 ) {
359
0
        res.Set("-1");
360
0
    } else if ( cmp > 0 ) {
361
0
        res.Set("1");
362
0
    } else {
363
0
        res.Set("0");
364
0
    }
365
366
0
    ret = true;
367
368
0
end:
369
0
    return ret;
370
0
}
371
372
0
bool LCM::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
373
0
    bool ret = false;
374
375
0
    GET_WHICH(1);
376
0
    switch ( which ) {
377
0
        case    0:
378
            /* noret */ mpz_lcm(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
379
0
            break;
380
0
        case    1:
381
0
            {
382
0
                const auto bn1 = bn[1].GetUnsignedLong();
383
0
                CF_CHECK_NE(bn1, std::nullopt);
384
385
0
                /* noret */ mpz_lcm_ui(res.GetPtr(), bn[0].GetPtr(), *bn1);
386
0
            }
387
0
            break;
388
0
        default:
389
0
            return false;
390
0
    }
391
392
    /* Negative not supported */
393
0
    CF_CHECK_GTE(mpz_sgn(bn[0].GetPtr()), 0);
394
0
    CF_CHECK_GTE(mpz_sgn(bn[1].GetPtr()), 0);
395
396
0
    ret = true;
397
398
0
end:
399
0
    return ret;
400
0
}
401
402
30
bool Xor::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
403
30
    (void)ds;
404
405
30
    /* noret */ mpz_xor(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
406
407
30
    return true;
408
30
}
409
410
26
bool And::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
411
26
    (void)ds;
412
413
26
    /* noret */ mpz_and(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
414
415
26
    return true;
416
26
}
417
418
0
bool Abs::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
419
0
    (void)ds;
420
421
0
    /* noret */ mpz_abs(res.GetPtr(), bn[0].GetPtr());
422
423
0
    return true;
424
0
}
425
426
0
bool Neg::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
427
0
    (void)ds;
428
429
0
    /* noret */ mpz_neg(res.GetPtr(), bn[0].GetPtr());
430
431
0
    return true;
432
0
}
433
434
0
bool Sqrt::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
435
0
    bool ret = false;
436
0
    (void)ds;
437
438
0
    CF_CHECK_GTE(mpz_sgn(bn[0].GetPtr()), 0);
439
440
0
    /* noret */ mpz_sqrt(res.GetPtr(), bn[0].GetPtr());
441
0
    ret = true;
442
443
0
end:
444
0
    return ret;
445
0
}
446
447
0
bool SqrtCeil::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
448
0
    bool ret = false;
449
0
    (void)ds;
450
451
0
    libgmp_bignum::Bignum rem;
452
453
0
    CF_CHECK_GTE(mpz_sgn(bn[0].GetPtr()), 0);
454
455
0
    /* noret */ mpz_sqrt(res.GetPtr(), bn[0].GetPtr());
456
    /* noret */ mpz_sqrtrem(bn[1].GetPtr(), rem.GetPtr(), bn[0].GetPtr());
457
0
    if ( mpz_sgn(rem.GetPtr()) != 0 ) {
458
        /* noret */ mpz_add_ui(res.GetPtr(), res.GetPtr(), 1);
459
0
    }
460
0
    ret = true;
461
462
0
end:
463
0
    return ret;
464
0
}
465
466
329
bool Sqr::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
467
329
    (void)ds;
468
469
329
    /* noret */ mpz_pow_ui(res.GetPtr(), bn[0].GetPtr(), 2);
470
471
329
    return true;
472
329
}
473
474
0
bool CmpAbs::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
475
0
    bool ret = false;
476
477
0
    int cmp;
478
479
0
    GET_WHICH(1);
480
0
    switch ( which ) {
481
0
        case    0:
482
0
            cmp = mpz_cmpabs(bn[0].GetPtr(), bn[1].GetPtr());
483
0
            break;
484
0
        case    1:
485
0
            {
486
0
                const auto bn1 = bn[1].GetUnsignedLong();
487
0
                CF_CHECK_NE(bn1, std::nullopt);
488
489
0
                cmp = mpz_cmpabs_ui(bn[0].GetPtr(), *bn1);
490
0
            }
491
0
            break;
492
0
        default:
493
0
            goto end;
494
0
    }
495
496
0
    if ( cmp < 0 ) {
497
0
        res.Set("-1");
498
0
    } else if ( cmp > 0 ) {
499
0
        res.Set("1");
500
0
    } else {
501
0
        res.Set("0");
502
0
    }
503
504
0
    ret = true;
505
506
0
end:
507
0
    return ret;
508
0
}
509
510
5
bool IsZero::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
511
5
    (void)ds;
512
513
5
    res.Set( std::to_string(mpz_sgn(bn[0].GetPtr()) == 0 ? 1 : 0) );
514
515
5
    return true;
516
5
}
517
518
0
bool IsNeg::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
519
0
    (void)ds;
520
521
0
    res.Set( std::to_string(mpz_sgn(bn[0].GetPtr()) < 0 ? 1 : 0) );
522
523
0
    return true;
524
0
}
525
526
200
bool AddMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
527
200
    (void)ds;
528
200
    bool ret = false;
529
530
200
    CF_CHECK_NE(mpz_cmp_ui(bn[2].GetPtr(), 0), 0);
531
532
197
    /* noret */ mpz_add(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
533
    /* noret */ mpz_mod(res.GetPtr(), res.GetPtr(), bn[2].GetPtr());
534
535
    /* Negative modulus currently not supported */
536
197
    CF_CHECK_GTE(mpz_sgn(bn[2].GetPtr()), 0);
537
538
197
    ret = true;
539
540
200
end:
541
200
    return ret;
542
197
}
543
544
246
bool SubMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
545
246
    (void)ds;
546
246
    bool ret = false;
547
548
246
    CF_CHECK_NE(mpz_cmp_ui(bn[2].GetPtr(), 0), 0);
549
550
244
    /* noret */ mpz_sub(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
551
    /* noret */ mpz_mod(res.GetPtr(), res.GetPtr(), bn[2].GetPtr());
552
553
    /* Negative modulus currently not supported */
554
244
    CF_CHECK_GTE(mpz_sgn(bn[2].GetPtr()), 0);
555
556
244
    ret = true;
557
558
246
end:
559
246
    return ret;
560
244
}
561
562
123
bool MulMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
563
123
    (void)ds;
564
123
    bool ret = false;
565
566
123
    CF_CHECK_NE(mpz_cmp_ui(bn[2].GetPtr(), 0), 0);
567
568
120
    /* noret */ mpz_mul(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
569
    /* noret */ mpz_mod(res.GetPtr(), res.GetPtr(), bn[2].GetPtr());
570
571
    /* Negative modulus currently not supported */
572
120
    CF_CHECK_GTE(mpz_sgn(bn[2].GetPtr()), 0);
573
574
120
    ret = true;
575
576
123
end:
577
123
    return ret;
578
120
}
579
580
0
bool SqrMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
581
0
    (void)ds;
582
0
    bool ret = false;
583
584
0
    CF_CHECK_NE(mpz_cmp_ui(bn[1].GetPtr(), 0), 0);
585
586
0
    /* noret */ mpz_pow_ui(res.GetPtr(), bn[0].GetPtr(), 2);
587
    /* noret */ mpz_mod(res.GetPtr(), res.GetPtr(), bn[1].GetPtr());
588
589
    /* Negative modulus currently not supported */
590
0
    CF_CHECK_GTE(mpz_sgn(bn[1].GetPtr()), 0);
591
592
0
    ret = true;
593
594
0
end:
595
0
    return ret;
596
0
}
597
598
0
bool Mod_NIST_192::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
599
0
    (void)ds;
600
601
0
    Bignum p192;
602
0
    p192.Set("6277101735386680763835789423207666416083908700390324961279");
603
604
0
    /* noret */ mpz_mod(res.GetPtr(), bn[0].GetPtr(), p192.GetPtr());
605
606
0
    return true;
607
0
}
608
609
0
bool Mod_NIST_224::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
610
0
    (void)ds;
611
612
0
    Bignum p224;
613
0
    p224.Set("26959946667150639794667015087019630673557916260026308143510066298881");
614
615
0
    /* noret */ mpz_mod(res.GetPtr(), bn[0].GetPtr(), p224.GetPtr());
616
617
0
    return true;
618
0
}
619
620
0
bool Mod_NIST_256::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
621
0
    (void)ds;
622
623
0
    Bignum p256;
624
0
    p256.Set("115792089210356248762697446949407573530086143415290314195533631308867097853951");
625
626
0
    /* noret */ mpz_mod(res.GetPtr(), bn[0].GetPtr(), p256.GetPtr());
627
628
0
    return true;
629
0
}
630
631
0
bool Mod_NIST_384::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
632
0
    (void)ds;
633
634
0
    Bignum p384;
635
0
    p384.Set("39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319");
636
637
0
    /* noret */ mpz_mod(res.GetPtr(), bn[0].GetPtr(), p384.GetPtr());
638
639
0
    return true;
640
0
}
641
642
0
bool Mod_NIST_521::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
643
0
    (void)ds;
644
645
0
    Bignum p521;
646
0
    p521.Set("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151");
647
648
0
    /* noret */ mpz_mod(res.GetPtr(), bn[0].GetPtr(), p521.GetPtr());
649
650
0
    return true;
651
0
}
652
653
0
bool SetBit::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
654
0
    (void)ds;
655
0
    bool ret = false;
656
657
0
    const auto position_sl = bn[1].GetSignedLong();
658
0
    CF_CHECK_NE(position_sl, std::nullopt);
659
0
    CF_CHECK_GTE(mpz_sgn(bn[0].GetPtr()), 0);
660
0
    CF_CHECK_GTE(mpz_sgn(bn[1].GetPtr()), 0);
661
662
0
    /* noret */ mpz_setbit(bn.GetDestPtr(0), *position_sl);
663
    /* noret */ mpz_set(res.GetPtr(), bn[0].GetPtr());
664
665
0
    ret = true;
666
667
0
end:
668
0
    return ret;
669
0
}
670
671
0
bool ClearBit::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
672
0
    (void)ds;
673
0
    bool ret = false;
674
675
0
    const auto position_sl = bn[1].GetSignedLong();
676
0
    CF_CHECK_NE(position_sl, std::nullopt);
677
0
    CF_CHECK_GTE(mpz_sgn(bn[0].GetPtr()), 0);
678
679
0
    /* noret */ mpz_clrbit(bn.GetDestPtr(0), *position_sl);
680
    /* noret */ mpz_set(res.GetPtr(), bn[0].GetPtr());
681
682
0
    ret = true;
683
684
0
end:
685
0
    return ret;
686
0
}
687
688
73
bool Bit::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
689
73
    (void)ds;
690
73
    bool ret = false;
691
692
73
    const auto position_sl = bn[1].GetSignedLong();
693
73
    CF_CHECK_NE(position_sl, std::nullopt);
694
695
    /* Negative not supported */
696
54
    CF_CHECK_GTE(mpz_sgn(bn[0].GetPtr()), 0);
697
698
54
    res.Set( std::to_string(mpz_tstbit(bn[0].GetPtr(), *position_sl)) );
699
700
54
    ret = true;
701
702
73
end:
703
73
    return ret;
704
54
}
705
706
1.45k
bool InvMod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
707
1.45k
    (void)ds;
708
1.45k
    bool ret = false;
709
710
    /* "The behaviour of this function is undefined when op2 is zero." */
711
1.45k
    CF_CHECK_NE(mpz_sgn(bn[1].GetPtr()), 0);
712
713
1.43k
    if ( mpz_invert(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr()) == 0 ) {
714
        /* Modular inverse does not exist */
715
775
        res.Set("0");
716
775
    }
717
718
1.43k
    ret = true;
719
720
1.45k
end:
721
1.45k
    return ret;
722
1.43k
}
723
724
10
bool IsOdd::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
725
10
    (void)ds;
726
727
    /* "These macros evaluate their argument more than once." */
728
10
    const auto ptr = bn[0].GetPtr();
729
10
    res.Set( std::to_string(mpz_odd_p(ptr)) );
730
731
10
    return true;
732
10
}
733
734
0
bool IsEven::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
735
0
    (void)ds;
736
737
    /* "These macros evaluate their argument more than once." */
738
0
    const auto ptr = bn[0].GetPtr();
739
0
    res.Set( std::to_string(mpz_even_p(ptr)) );
740
741
0
    return true;
742
0
}
743
744
0
bool IsPow2::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
745
0
    (void)ds;
746
747
0
    if ( mpz_popcount(bn[0].GetPtr()) == 1 ) {
748
0
        res.Set("1");
749
0
    } else {
750
0
        res.Set("0");
751
0
    }
752
753
0
    return true;
754
0
}
755
756
0
bool NumLSZeroBits::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
757
0
    (void)ds;
758
759
0
    auto numBits = mpz_scan1(bn[0].GetPtr(), 0);
760
0
    if ( numBits == (mp_bitcnt_t)-1 ) {
761
0
        numBits = 0;
762
0
    }
763
0
    res.Set( std::to_string(numBits) );
764
765
0
    return true;
766
0
}
767
768
0
bool Factorial::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
769
0
    (void)ds;
770
0
    bool ret = false;
771
772
0
    const auto bn0 = bn[0].GetUnsignedLong();
773
0
    CF_CHECK_NE(bn0, std::nullopt);
774
0
    CF_CHECK_LTE(*bn0, 1500);
775
776
0
    CF_NORET(mpz_fac_ui(res.GetPtr(), *bn0));
777
778
0
    ret = true;
779
780
0
end:
781
0
    return ret;
782
0
}
783
784
0
bool Cbrt::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
785
0
    (void)ds;
786
787
0
    /* ignore ret */ mpz_root(res.GetPtr(), bn[0].GetPtr(), 3);
788
789
0
    return true;
790
0
}
791
792
0
bool SqrtRem::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
793
0
    bool ret = false;
794
0
    (void)ds;
795
796
0
    CF_CHECK_GTE(mpz_sgn(bn[0].GetPtr()), 0);
797
798
0
    /* noret */ mpz_sqrtrem(bn[1].GetPtr(), res.GetPtr(), bn[0].GetPtr());
799
0
    ret = true;
800
801
0
end:
802
0
    return ret;
803
0
}
804
805
0
bool CbrtRem::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
806
0
    (void)ds;
807
808
0
    /* noret */ mpz_rootrem(bn[1].GetPtr(), res.GetPtr(), bn[0].GetPtr(), 3);
809
810
0
    return true;
811
0
}
812
813
0
bool Nthrt::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
814
/* Too slow in mini-gmp */
815
0
#if !defined(HAVE_MINI_GMP)
816
0
    (void)ds;
817
0
    bool ret = false;
818
819
0
    const auto bn1 = bn[1].GetUnsignedLong();
820
0
    CF_CHECK_NE(bn1, std::nullopt);
821
0
    CF_CHECK_NE(*bn1, 0);
822
0
    CF_CHECK_GTE(mpz_sgn(bn[0].GetPtr()), 0);
823
824
0
    /* noret */ mpz_root(res.GetPtr(), bn[0].GetPtr(), *bn1);
825
826
0
    ret = true;
827
0
end:
828
0
    return ret;
829
#else
830
    (void)ds;
831
    (void)res;
832
    (void)bn;
833
834
    return false;
835
#endif
836
0
}
837
838
0
bool NthrtRem::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
839
/* Too slow in mini-gmp */
840
0
#if !defined(HAVE_MINI_GMP)
841
0
    (void)ds;
842
0
    bool ret = false;
843
844
0
    const auto bn1 = bn[1].GetUnsignedLong();
845
0
    CF_CHECK_NE(bn1, std::nullopt);
846
0
    CF_CHECK_NE(*bn1, 0);
847
0
    CF_CHECK_GTE(mpz_sgn(bn[0].GetPtr()), 0);
848
849
0
    /* noret */ mpz_rootrem(bn[1].GetPtr(), res.GetPtr(), bn[0].GetPtr(), *bn1);
850
851
0
    ret = true;
852
0
end:
853
0
    return ret;
854
#else
855
    (void)ds;
856
    (void)res;
857
    (void)bn;
858
859
    return false;
860
#endif
861
0
}
862
863
0
bool IsSquare::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
864
0
#if !defined(HAVE_MINI_GMP)
865
0
    (void)ds;
866
867
0
    res.Set(
868
0
            mpz_perfect_square_p(bn[0].GetPtr()) == 0 ? std::string("0") : std::string("1")
869
0
    );
870
871
0
    return true;
872
#else
873
    (void)ds;
874
    (void)res;
875
    (void)bn;
876
877
    return false;
878
#endif
879
0
}
880
881
0
bool Exp::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
882
0
    bool ret = false;
883
884
0
    GET_WHICH(1);
885
0
    switch ( which ) {
886
0
        case    0:
887
0
            {
888
0
                const auto bn1 = bn[1].GetUnsignedLong();
889
0
                CF_CHECK_NE(bn1, std::nullopt);
890
891
0
                /* noret */ mpz_pow_ui(res.GetPtr(), bn[0].GetPtr(), *bn1);
892
0
            }
893
0
            break;
894
0
        case    1:
895
0
            {
896
0
                const auto bn0 = bn[0].GetUnsignedLong();
897
0
                CF_CHECK_NE(bn0, std::nullopt);
898
899
0
                const auto bn1 = bn[1].GetUnsignedLong();
900
0
                CF_CHECK_NE(bn1, std::nullopt);
901
902
0
                /* noret */ mpz_ui_pow_ui(res.GetPtr(), *bn0, *bn1);
903
0
            }
904
0
            break;
905
0
        default:
906
0
            return false;
907
0
    }
908
909
0
    ret = true;
910
911
0
end:
912
0
    return ret;
913
0
}
914
915
26
bool Or::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
916
26
    (void)ds;
917
918
26
    /* noret */ mpz_ior(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
919
920
26
    return true;
921
26
}
922
923
0
bool AddMul::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
924
0
    bool ret = false;
925
926
0
    GET_WHICH(1);
927
0
    switch ( which ) {
928
0
        case    0:
929
            /* noret */ mpz_set(res.GetPtr(), bn[0].GetPtr());
930
            /* noret */ mpz_addmul(res.GetPtr(), bn[1].GetPtr(), bn[2].GetPtr());
931
0
            break;
932
0
        case    1:
933
0
            {
934
0
                const auto bn2 = bn[2].GetUnsignedLong();
935
0
                CF_CHECK_NE(bn2, std::nullopt);
936
937
0
                /* noret */ mpz_set(res.GetPtr(), bn[0].GetPtr());
938
                /* noret */ mpz_addmul_ui(res.GetPtr(), bn[1].GetPtr(), *bn2);
939
0
            }
940
0
            break;
941
0
        default:
942
0
            return false;
943
0
    }
944
945
0
    ret = true;
946
947
0
end:
948
0
    return ret;
949
0
}
950
951
0
bool SubMul::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
952
0
    bool ret = false;
953
954
0
    GET_WHICH(1);
955
0
    switch ( which ) {
956
0
        case    0:
957
            /* noret */ mpz_set(res.GetPtr(), bn[0].GetPtr());
958
            /* noret */ mpz_submul(res.GetPtr(), bn[1].GetPtr(), bn[2].GetPtr());
959
0
            break;
960
0
        case    1:
961
0
            {
962
0
                const auto bn2 = bn[2].GetUnsignedLong();
963
0
                CF_CHECK_NE(bn2, std::nullopt);
964
965
0
                /* noret */ mpz_set(res.GetPtr(), bn[0].GetPtr());
966
                /* noret */ mpz_submul_ui(res.GetPtr(), bn[1].GetPtr(), *bn2);
967
0
            }
968
0
            break;
969
0
        default:
970
0
            return false;
971
0
    }
972
973
0
    ret = true;
974
975
0
end:
976
0
    return ret;
977
0
}
978
979
0
bool Primorial::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
980
0
#if !defined(HAVE_MINI_GMP)
981
0
    (void)ds;
982
0
    bool ret = false;
983
984
0
    const auto bn0 = bn[0].GetUnsignedLong();
985
0
    CF_CHECK_NE(bn0, std::nullopt);
986
0
    CF_CHECK_LTE(*bn0, 10000);
987
988
0
    /* noret */ mpz_primorial_ui(res.GetPtr(), *bn0);
989
990
0
    ret = true;
991
992
0
end:
993
0
    return ret;
994
#else
995
    (void)ds;
996
    (void)res;
997
    (void)bn;
998
999
    return false;
1000
#endif
1001
0
}
1002
1003
0
bool Lucas::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1004
0
#if !defined(HAVE_MINI_GMP)
1005
0
    (void)ds;
1006
0
    bool ret = false;
1007
1008
0
    const auto bn0 = bn[0].GetUnsignedLong();
1009
0
    CF_CHECK_NE(bn0, std::nullopt);
1010
0
    CF_CHECK_LTE(*bn0, 10000);
1011
1012
0
    /* noret */ mpz_lucnum_ui(res.GetPtr(), *bn0);
1013
1014
0
    ret = true;
1015
1016
0
end:
1017
0
    return ret;
1018
#else
1019
    (void)ds;
1020
    (void)res;
1021
    (void)bn;
1022
1023
    return false;
1024
#endif
1025
0
}
1026
1027
0
bool Fibonacci::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1028
0
    (void)ds;
1029
0
    bool ret = false;
1030
1031
0
    const auto bn0 = bn[0].GetUnsignedLong();
1032
0
    CF_CHECK_NE(bn0, std::nullopt);
1033
0
    CF_CHECK_LTE(*bn0, 10000);
1034
1035
0
    /* noret */ mpz_fac_ui(res.GetPtr(), *bn0);
1036
1037
0
    ret = true;
1038
1039
0
end:
1040
0
    return ret;
1041
0
}
1042
1043
0
bool Set::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1044
0
    bool ret = false;
1045
1046
0
    GET_WHICH(3);
1047
0
    switch ( which ) {
1048
0
        case    0:
1049
            /* noret */ mpz_set(res.GetPtr(), bn[0].GetPtr());
1050
0
            break;
1051
0
        case    1:
1052
0
            {
1053
0
                const auto bn0 = bn[0].GetUnsignedLong();
1054
0
                CF_CHECK_NE(bn0, std::nullopt);
1055
1056
0
                /* noret */ mpz_clear(res.GetPtr());
1057
                /* noret */ mpz_init_set_ui(res.GetPtr(), *bn0);
1058
0
            }
1059
0
            break;
1060
0
        case    2:
1061
0
            {
1062
0
                const auto bn0 = bn[0].GetSignedLong();
1063
0
                CF_CHECK_NE(bn0, std::nullopt);
1064
1065
0
                /* noret */ mpz_clear(res.GetPtr());
1066
                /* noret */ mpz_init_set_si(res.GetPtr(), *bn0);
1067
0
            }
1068
0
            break;
1069
0
        case    3:
1070
            /* noret */ mpz_swap(res.GetPtr(), bn[0].GetPtr());
1071
0
            break;
1072
0
        default:
1073
0
            return false;
1074
0
    }
1075
1076
0
    ret = true;
1077
1078
0
end:
1079
0
    return ret;
1080
0
}
1081
1082
0
bool BinCoeff::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1083
0
    bool ret = false;
1084
1085
0
    std::optional<unsigned long int> bn0, bn1;
1086
1087
0
    GET_WHICH(1);
1088
1089
0
    bn0 = bn[0].GetUnsignedLong();
1090
0
    CF_CHECK_NE(bn0, std::nullopt);
1091
0
#if !defined(HAVE_MINI_GMP)
1092
0
    CF_CHECK_LTE(*bn0, 100000);
1093
#else
1094
    /* Too slow otherwise */
1095
    CF_CHECK_LTE(*bn0, 1000);
1096
#endif
1097
1098
0
    bn1 = bn[1].GetUnsignedLong();
1099
0
    CF_CHECK_NE(bn1, std::nullopt);
1100
0
#if !defined(HAVE_MINI_GMP)
1101
0
    CF_CHECK_LTE(*bn1, 100000);
1102
#else
1103
    /* Too slow otherwise */
1104
    CF_CHECK_LTE(*bn0, 1000);
1105
#endif
1106
1107
0
    switch ( which ) {
1108
0
#if !defined(HAVE_MINI_GMP)
1109
0
        case    0:
1110
            /* noret */ mpz_bin_ui(res.GetPtr(), bn[0].GetPtr(), *bn1);
1111
0
            break;
1112
0
#endif
1113
0
        case    1:
1114
            /* noret */ mpz_bin_uiui(res.GetPtr(), *bn0, *bn1);
1115
0
            break;
1116
0
        default:
1117
0
            goto end;
1118
0
    }
1119
1120
0
    ret = true;
1121
1122
0
end:
1123
0
    return ret;
1124
0
}
1125
1126
0
bool HamDist::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1127
0
    (void)ds;
1128
1129
0
    res.Set( std::to_string(mpz_hamdist(bn[0].GetPtr(), bn[1].GetPtr())) );
1130
1131
0
    return true;
1132
0
}
1133
1134
283
bool Mod::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1135
283
    bool ret = false;
1136
1137
283
    GET_WHICH(1);
1138
283
    switch ( which ) {
1139
201
        case    0:
1140
201
            CF_CHECK_NE(mpz_cmp_ui(bn[1].GetPtr(), 0), 0);
1141
1142
197
            /* noret */ mpz_mod(res.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr());
1143
197
            break;
1144
82
        case    1:
1145
82
            {
1146
82
                CF_CHECK_NE(mpz_cmp_ui(bn[1].GetPtr(), 0), 0);
1147
1148
80
                const auto bn1 = bn[1].GetUnsignedLong();
1149
80
                CF_CHECK_NE(bn1, std::nullopt);
1150
1151
43
                /* ignore ret */ mpz_mod_ui(res.GetPtr(), bn[0].GetPtr(), *bn1);
1152
43
            }
1153
0
            break;
1154
0
        default:
1155
0
            return false;
1156
283
    }
1157
1158
    /* Negative not supported */
1159
240
    CF_CHECK_GTE(mpz_sgn(bn[0].GetPtr()), 0);
1160
240
    CF_CHECK_GTE(mpz_sgn(bn[1].GetPtr()), 0);
1161
1162
240
    ret = true;
1163
1164
283
end:
1165
283
    return ret;
1166
240
}
1167
1168
0
bool IsPower::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1169
0
#if !defined(HAVE_MINI_GMP)
1170
0
    (void)ds;
1171
1172
0
    res.Set(
1173
0
            mpz_perfect_power_p(bn[0].GetPtr()) == 0 ? std::string("0") : std::string("1")
1174
0
    );
1175
1176
0
    return true;
1177
#else
1178
    (void)ds;
1179
    (void)res;
1180
    (void)bn;
1181
1182
    return false;
1183
#endif
1184
0
}
1185
1186
0
bool Prime::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1187
0
#if !defined(HAVE_MINI_GMP)
1188
0
    (void)bn;
1189
1190
0
    uint16_t bits = 0;
1191
1192
0
    try {
1193
0
        bits = ds.Get<uint16_t>();
1194
0
    } catch ( ... ) { }
1195
1196
0
    bits %= (512+1);
1197
1198
0
    if ( bits == 0 ) {
1199
0
        bits = 1;
1200
0
    }
1201
1202
0
    /* noret */ mpz_urandomb(res.GetPtr(), libgmp_detail::rng_state, bits);
1203
    /* noret */ mpz_nextprime(res.GetPtr(), res.GetPtr());
1204
1205
0
    return true;
1206
#else
1207
    (void)ds;
1208
    (void)res;
1209
    (void)bn;
1210
1211
    return false;
1212
#endif
1213
0
}
1214
1215
0
bool IsPrime::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1216
0
    (void)ds;
1217
0
    bool ret = false;
1218
1219
#if defined(HAVE_MINI_GMP)
1220
    CF_CHECK_LTE(mpz_sizeinbase(bn[0].GetPtr(), 2), 2000);
1221
#endif
1222
1223
0
    if ( mpz_probab_prime_p(bn[0].GetPtr(), 15) == 0 ) {
1224
0
        res.Set("0");
1225
0
    } else {
1226
0
        res.Set("1");
1227
0
    }
1228
1229
0
    ret = true;
1230
#if defined(HAVE_MINI_GMP)
1231
end:
1232
#endif
1233
0
    return ret;
1234
0
}
1235
1236
0
bool Rand::Run(Datasource& ds, Bignum& res, BignumCluster& bn) const {
1237
0
#if !defined(HAVE_MINI_GMP)
1238
0
    (void)bn;
1239
1240
0
    uint16_t bits = 0;
1241
1242
0
    try {
1243
0
        bits = ds.Get<uint16_t>();
1244
0
    } catch ( ... ) { }
1245
1246
0
    bits %= (10000+1);
1247
1248
0
    if ( bits == 0 ) {
1249
0
        bits = 1;
1250
0
    }
1251
1252
0
    /* noret */ mpz_urandomb(res.GetPtr(), libgmp_detail::rng_state, 512);
1253
1254
0
    return true;
1255
#else
1256
    (void)ds;
1257
    (void)res;
1258
    (void)bn;
1259
1260
    return false;
1261
#endif
1262
0
}
1263
1264
} /* namespace libgmp_bignum */
1265
} /* namespace module */
1266
} /* namespace cryptofuzz */