Coverage Report

Created: 2026-11-12 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cryptofuzz-heapmath/modules/wolfcrypt/bn_helper.cpp
Line
Count
Source
1
#include "bn_ops.h"
2
#include <iostream>
3
4
namespace cryptofuzz {
5
namespace module {
6
7
namespace wolfCrypt_detail {
8
#if defined(CRYPTOFUZZ_WOLFCRYPT_ALLOCATION_FAILURES)
9
    extern bool disableAllocationFailures;
10
    extern bool haveAllocFailure;
11
#endif
12
} /* namespace wolfCrypt_detail */
13
14
namespace wolfCrypt_bignum {
15
16
41.5k
Bignum::read_radix_error_t Bignum::read_radix(mp_int* dest, const std::string& str, const size_t base) {
17
41.5k
    return read_radix(dest, str.c_str(), base);
18
41.5k
}
19
20
41.9k
Bignum::read_radix_error_t Bignum::read_radix(mp_int* dest, const char* str, const size_t base) {
21
41.9k
    Bignum::read_radix_error_t ret;
22
23
    /* Create a temporary variable for storing the result of mp_read_radix,
24
     * because if mp_read_radix fails (e.g. due to allocation failure),
25
     * it will set the value of the destination variable to 0.
26
     *
27
     * See OSS-Fuzz 31709 / ZD 11834 for discussion. */
28
41.9k
    auto newMp = (mp_int*)util::malloc(sizeof(mp_int));
29
41.9k
    if ( mp_init(newMp) != MP_OKAY ) {
30
0
        util::free(newMp);
31
0
        return READ_RADIX_FAIL_MEMORY;
32
0
    }
33
34
41.9k
    wolfCrypt_detail::haveAllocFailure = false;
35
41.9k
    if ( mp_read_radix(newMp, str, base) != MP_OKAY ) {
36
737
        ret = wolfCrypt_detail::haveAllocFailure ? READ_RADIX_FAIL_MEMORY : READ_RADIX_FAIL_OTHER;
37
737
        goto end;
38
737
    }
39
40
41.2k
    wolfCrypt_detail::haveAllocFailure = false;
41
41.2k
    if ( mp_copy(newMp, dest) != MP_OKAY ) {
42
74
        ret = wolfCrypt_detail::haveAllocFailure ? READ_RADIX_FAIL_MEMORY : READ_RADIX_FAIL_OTHER;
43
74
        goto end;
44
74
    }
45
46
41.1k
    ret = READ_RADIX_OK;
47
48
41.9k
end:
49
41.9k
    CF_NORET(mp_clear(newMp));
50
41.9k
    util::free(newMp);
51
52
41.9k
    return ret;
53
41.1k
}
54
55
24.4k
void Bignum::baseConversion(void) const {
56
24.4k
#if !defined(WOLFSSL_SP_MATH)
57
24.4k
    uint8_t base = 2;
58
24.4k
    char* str = nullptr;
59
60
24.4k
    try { base = ds.Get<uint8_t>(); } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
61
62
#if defined(CRYPTOFUZZ_WOLFCRYPT_DEBUG)
63
    std::cout << "Convert to base " << std::to_string(base) << " and back" << std::endl;
64
#endif
65
24.4k
    {
66
24.4k
        int size;
67
24.4k
        CF_CHECK_EQ(mp_radix_size(mp, base, &size), MP_OKAY);
68
967
        CF_ASSERT(size > 0, "Output of mp_radix_size is 0 or less");
69
70
967
        str = (char*)util::malloc(size);
71
72
967
#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL) || !defined(USE_FAST_MATH)
73
967
        CF_CHECK_EQ(mp_toradix(mp, str, base), MP_OKAY);
74
#else
75
        wolfCrypt_detail::haveAllocFailure = false;
76
        CF_ASSERT(
77
                    mp_toradix(mp, str, base) == MP_OKAY ||
78
                    wolfCrypt_detail::haveAllocFailure ||
79
                    base < 2 ||
80
                    base > 64,
81
                    "wolfCrypt cannot convert mp to string");
82
83
        /* If allocation failure occurred, then do not use 'str' */
84
        CF_CHECK_FALSE(wolfCrypt_detail::haveAllocFailure);
85
#endif
86
87
859
        {
88
859
            const auto ret = read_radix(mp, str, base);
89
859
            CF_ASSERT(ret == READ_RADIX_OK || ret == READ_RADIX_FAIL_MEMORY, "wolfCrypt cannot parse the output of mp_toradix");
90
859
        }
91
859
    }
92
93
24.4k
end:
94
24.4k
    util::free(str);
95
24.4k
#endif
96
24.4k
}
97
98
7.01k
void Bignum::binaryConversion(void) const {
99
7.01k
    uint8_t* data = nullptr;
100
7.01k
    CF_CHECK_EQ(mp_isneg(mp), 0);
101
102
#if LIBWOLFSSL_VERSION_HEX == 0x05005001
103
    {
104
        /* Old version of the binary conversion logic, which doesn't crash if
105
         * mp_to_unsigned_bin_len() succeeds with an undersized buffer.
106
         *
107
         * This logic is retained specifically to prevent the libecc
108
         * OSS-Fuzz fuzzer from crashing, because this uses an older version
109
         * of wolfCrypt (specifically 0x05005001), which still has the
110
         * mp_to_unsigned_bin_len() bug.
111
         */
112
113
        const auto size = mp_unsigned_bin_size(mp);
114
        CF_ASSERT(size >= 0, "mp_unsigned_bin_size returned negative value");
115
116
        data = util::malloc(size);
117
        CF_CHECK_EQ(mp_to_unsigned_bin_len(mp, data, size), MP_OKAY);
118
119
        /* Ensure no allocation failure occurs in mp_read_unsigned_bin
120
         * because this can leave the mp in a corrupted state
121
         */
122
        const auto cached_disableAllocationFailures = wolfCrypt_detail::disableAllocationFailures;
123
        wolfCrypt_detail::disableAllocationFailures = true;
124
125
        CF_ASSERT(mp_read_unsigned_bin(mp, data, size) == MP_OKAY, "Cannot parse output of mp_to_unsigned_bin_len");
126
127
        wolfCrypt_detail::disableAllocationFailures = cached_disableAllocationFailures;
128
    }
129
#else
130
6.12k
    {
131
6.12k
        bool randomSize = false;
132
133
6.12k
        try { randomSize = ds.Get<bool>(); } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
134
135
6.12k
        size_t size = 0;
136
6.12k
        int numBits = 0;
137
138
6.12k
        if ( randomSize == false ) {
139
2.93k
            const auto size2 = mp_unsigned_bin_size(mp);
140
2.93k
            CF_ASSERT(size2 >= 0, "mp_unsigned_bin_size returned negative value");
141
2.93k
            size = size2;
142
3.18k
        } else {
143
3.18k
            try {
144
3.18k
                size = ds.Get<uint16_t>();
145
3.18k
            } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
146
147
3.18k
            numBits = mp_count_bits(mp);
148
3.18k
            CF_ASSERT(numBits >= 0, "mp_count_bits result is negative");
149
3.18k
        }
150
151
6.12k
        data = util::malloc(size);
152
6.12k
        CF_CHECK_EQ(mp_to_unsigned_bin_len(mp, data, size), MP_OKAY);
153
154
5.38k
        CF_ASSERT(
155
5.38k
                size * 8 >= static_cast<size_t>(numBits),
156
5.38k
                "mp_to_unsigned_bin_len succeeded with undersized buffer");
157
158
        /* Ensure no allocation failure occurs in mp_read_unsigned_bin
159
         * because this can leave the mp in a corrupted state
160
         */
161
5.38k
        const auto cached_disableAllocationFailures = wolfCrypt_detail::disableAllocationFailures;
162
5.38k
        wolfCrypt_detail::disableAllocationFailures = true;
163
164
5.38k
        if ( randomSize == false ) {
165
2.63k
            CF_ASSERT(mp_read_unsigned_bin(mp, data, size) == MP_OKAY, "Cannot parse output of mp_to_unsigned_bin_len");
166
2.74k
        } else {
167
            /* mp_read_unsigned_bin can fail if the input buffer is too large.
168
             *
169
             * Read into a temp variable, and copy to mp if reading succeeds, otherwise
170
             * retain old value in mp.
171
             */
172
2.74k
            Bignum tmp(ds);
173
2.74k
            if ( mp_read_unsigned_bin(tmp.GetPtrDirect(), data, size) == MP_OKAY ) {
174
2.74k
                /* ignore result */ mp_copy(tmp.GetPtrDirect(), mp);
175
2.74k
            }
176
2.74k
        }
177
178
5.38k
        wolfCrypt_detail::disableAllocationFailures = cached_disableAllocationFailures;
179
5.38k
    }
180
0
#endif
181
182
183
7.01k
end:
184
7.01k
    util::free(data);
185
7.01k
}
186
187
1.05M
void Bignum::invariants(void) const {
188
#if defined(WOLFSSL_SP_MATH) || defined(WOLFSSL_SP_MATH_ALL)
189
    CF_ASSERT(mp->used <= mp->size, "used is larger than size");
190
#elif !defined(USE_FAST_MATH)
191
1.05M
    CF_ASSERT(mp->used <= mp->alloc, "used is larger than size");
192
1.05M
#endif
193
1.05M
}
194
195
Bignum::Bignum(Datasource& ds, const bool mp_init_size_ok) :
196
419k
    ds(ds) {
197
419k
    mp = (mp_int*)util::malloc(sizeof(mp_int));
198
199
419k
    if ( init_mp_int(mp, ds, mp_init_size_ok) != MP_OKAY ) {
200
0
        util::free(mp);
201
0
        throw std::exception();
202
0
    }
203
419k
}
204
205
Bignum::Bignum(mp_int* mp, Datasource& ds) :
206
2.34k
    mp(mp),
207
2.34k
    ds(ds),
208
2.34k
    noFree(true)
209
2.34k
{ }
210
211
Bignum::Bignum(const Bignum& other) :
212
200k
    ds(other.ds) {
213
200k
    mp = (mp_int*)util::malloc(sizeof(mp_int));
214
200k
    if ( init_mp_int(mp, ds) != MP_OKAY ) {
215
0
        util::free(mp);
216
0
        throw std::exception();
217
0
    }
218
200k
    if ( mp_copy(other.mp, mp) != MP_OKAY ) {
219
43
        util::free(mp);
220
43
        throw std::exception();
221
43
    }
222
200k
}
223
224
Bignum::Bignum(const Bignum&& other) :
225
200k
    ds(other.ds) {
226
200k
    mp = (mp_int*)util::malloc(sizeof(mp_int));
227
200k
    if ( init_mp_int(mp, ds) != MP_OKAY ) {
228
0
        util::free(mp);
229
0
        throw std::exception();
230
0
    }
231
200k
    if ( mp_copy(other.mp, mp) != MP_OKAY ) {
232
241
        util::free(mp);
233
241
        throw std::exception();
234
241
    }
235
200k
}
236
237
838k
Bignum::~Bignum() {
238
838k
    invariants();
239
838k
    if ( noFree == false ) {
240
820k
        CF_NORET(mp_clear(mp));
241
820k
        util::free(mp);
242
820k
    }
243
838k
}
244
245
0
void Bignum::SetNoFree(void) {
246
0
    noFree = true;
247
0
}
248
249
295k
bool Bignum::Set(const std::string s) {
250
295k
    bool ret = false;
251
252
295k
    bool hex = false;
253
295k
    try {
254
295k
        hex = ds.Get<bool>();
255
295k
    } catch ( ... ) { }
256
257
#if defined(WOLFSSL_SP_MATH)
258
    hex = true;
259
#endif
260
261
295k
    if ( hex == true ) {
262
88.7k
        CF_CHECK_EQ(read_radix(mp, util::DecToHex(s), 16), READ_RADIX_OK);
263
206k
    } else {
264
206k
        CF_CHECK_EQ(read_radix(mp, s, 10), READ_RADIX_OK);
265
203k
    }
266
267
290k
    ret = true;
268
295k
end:
269
295k
    return ret;
270
290k
}
271
272
40.8k
bool Bignum::Set(const component::Bignum i) {
273
40.8k
    bool ret = false;
274
275
40.8k
    CF_CHECK_EQ(Set(i.ToString()), true);
276
277
39.8k
    ret = true;
278
40.8k
end:
279
40.8k
    return ret;
280
39.8k
}
281
282
53.1k
mp_int* Bignum::GetPtr(void) const {
283
53.1k
    invariants();
284
285
53.1k
    {
286
        /* Optionally clamp the bignum. This should not affect its value. */
287
288
53.1k
        bool clamp = false;
289
290
53.1k
        try { clamp = ds.Get<bool>(); } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
291
292
53.1k
        if ( clamp ) {
293
            /* Implemented as a macro so CF_NORET cannot be used here */
294
1.80k
            /* noret */ mp_clamp(mp);
295
1.80k
        }
296
53.1k
    }
297
298
53.1k
    {
299
        /* Optionally convert to a random base and back */
300
301
53.1k
        bool convert = false;
302
303
53.1k
        try { convert = ds.Get<bool>(); } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
304
305
53.1k
        if ( convert ) {
306
1.91k
            baseConversion();
307
1.91k
        }
308
53.1k
    }
309
310
53.1k
    {
311
        /* Optionally convert to bytes and back */
312
313
53.1k
        bool convert = false;
314
315
53.1k
        try { convert = ds.Get<bool>(); } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
316
317
53.1k
        if ( convert ) {
318
1.62k
            binaryConversion();
319
1.62k
        }
320
53.1k
    }
321
322
53.1k
    return mp;
323
53.1k
}
324
325
261k
mp_int* Bignum::GetPtrDirect(void) const {
326
261k
    return mp;
327
261k
}
328
329
1.37k
std::optional<uint64_t> Bignum::AsUint64(void) const {
330
1.37k
    std::optional<uint64_t> ret = std::nullopt;
331
1.37k
    uint64_t v = 0;
332
333
1.37k
#if !defined(WOLFSSL_SP_MATH)
334
1.37k
    CF_CHECK_EQ(mp_isneg(mp), 0);
335
1.31k
#endif
336
1.31k
    CF_CHECK_LTE(mp_count_bits(mp), (int)(sizeof(v) * 8));
337
1.24k
    CF_CHECK_EQ(mp_to_unsigned_bin_len(mp, (uint8_t*)&v, sizeof(v)), MP_OKAY);
338
1.23k
    v =
339
1.23k
        ((v & 0xFF00000000000000) >> 56) |
340
1.23k
        ((v & 0x00FF000000000000) >> 40) |
341
1.23k
        ((v & 0x0000FF0000000000) >> 24) |
342
1.23k
        ((v & 0x000000FF00000000) >>  8) |
343
1.23k
        ((v & 0x00000000FF000000) <<  8) |
344
1.23k
        ((v & 0x0000000000FF0000) << 24) |
345
1.23k
        ((v & 0x000000000000FF00) << 40) |
346
1.23k
        ((v & 0x00000000000000FF) << 56);
347
348
1.23k
    ret = v;
349
1.37k
end:
350
1.37k
    return ret;
351
1.23k
}
352
353
49.3k
std::optional<std::string> Bignum::ToDecString(void) {
354
49.3k
    std::optional<std::string> ret = std::nullopt;
355
49.3k
    char* str = nullptr;
356
357
#if defined(WOLFSSL_SP_MATH)
358
    str = (char*)util::malloc(8192);
359
360
    CF_CHECK_EQ(mp_tohex(mp, str), MP_OKAY);
361
    ret = { util::HexToDec(str) };
362
#else
363
49.3k
    bool hex = false;
364
49.3k
    int size;
365
366
49.3k
    try {
367
49.3k
        hex = ds.Get<bool>();
368
49.3k
    } catch ( ... ) { }
369
370
371
49.3k
    if ( hex == true ) {
372
3.78k
        CF_CHECK_EQ(mp_radix_size(mp, 16, &size), MP_OKAY);
373
3.61k
        CF_ASSERT(size > 0, "Output of mp_radix_size is 0 or less");
374
375
3.61k
        str = (char*)util::malloc(size+1);
376
377
3.61k
        CF_CHECK_EQ(mp_tohex(mp, str), MP_OKAY);
378
3.52k
        ret = { util::HexToDec(str) };
379
45.5k
    } else {
380
45.5k
        CF_CHECK_EQ(mp_radix_size(mp, 10, &size), MP_OKAY);
381
44.4k
        CF_ASSERT(size > 0, "Output of mp_radix_size is 0 or less");
382
383
44.4k
        str = (char*)util::malloc(size);
384
385
44.4k
        CF_CHECK_EQ(mp_toradix(mp, str, 10), MP_OKAY);
386
43.8k
        ret = std::string(str);
387
43.8k
    }
388
47.3k
#endif
389
390
49.3k
end:
391
49.3k
    free(str);
392
393
49.3k
    return ret;
394
49.3k
}
395
396
34.9k
std::optional<component::Bignum> Bignum::ToComponentBignum(void) {
397
34.9k
    std::optional<component::Bignum> ret = std::nullopt;
398
399
34.9k
    auto str = ToDecString();
400
34.9k
    CF_CHECK_NE(str, std::nullopt);
401
34.0k
    ret = { str };
402
34.9k
end:
403
34.9k
    return ret;
404
34.0k
}
405
406
22.9k
bool Bignum::ToBin(uint8_t* dest, const size_t size) {
407
22.9k
    bool ret = false;
408
409
22.9k
    const auto required = mp_unsigned_bin_size(GetPtr());
410
22.9k
    CF_ASSERT(required >= 0, "mp_unsigned_bin_size returned negative value");
411
412
22.9k
    CF_CHECK_GTE(size, static_cast<size_t>(required));
413
22.6k
    CF_CHECK_EQ(mp_to_unsigned_bin_len(GetPtr(), dest, size), MP_OKAY);
414
415
21.7k
    ret = true;
416
22.9k
end:
417
22.9k
    return ret;
418
21.7k
}
419
420
421
17.5k
std::optional<std::vector<uint8_t>> Bignum::ToBin(Datasource& ds, const component::Bignum b, std::optional<size_t> size) {
422
17.5k
    std::optional<std::vector<uint8_t>> ret = std::nullopt;
423
17.5k
    std::vector<uint8_t> v;
424
17.5k
    Bignum bn(ds);
425
17.5k
    uint16_t padding = 0;
426
427
17.5k
    CF_CHECK_EQ(bn.Set(b), true);
428
16.9k
    if ( size != std::nullopt ) {
429
0
        v.resize(*size);
430
16.9k
    } else {
431
16.9k
        try {
432
16.9k
            padding = ds.Get<uint16_t>();
433
16.9k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
434
435
16.9k
        v.resize( mp_unsigned_bin_size(bn.GetPtr()) + padding );
436
16.9k
    }
437
438
16.9k
    CF_CHECK_EQ(bn.ToBin(v.data(), v.size()), true);
439
440
16.0k
    ret = v;
441
17.5k
end:
442
17.5k
    return ret;
443
16.0k
}
444
445
bool Bignum::ToBin(
446
        Datasource& ds,
447
        const component::Bignum b,
448
        uint8_t* dest,
449
        const size_t size,
450
21.0k
        const bool mustSucceed) {
451
21.0k
    bool ret = false;
452
21.0k
    if ( mustSucceed == true ) {
453
16.3k
        std::optional<std::vector<uint8_t>> bytes;
454
16.3k
        CF_CHECK_NE(bytes = util::DecToBin(b.ToTrimmedString(), size), std::nullopt);
455
15.9k
        memcpy(dest, bytes->data(), bytes->size());
456
15.9k
        ret = true;
457
15.9k
    } else {
458
4.69k
        Bignum bn(ds);
459
460
4.69k
        CF_CHECK_EQ(bn.Set(b), true);
461
4.54k
        CF_CHECK_EQ(bn.ToBin(dest, size), true);
462
463
4.41k
        ret = true;
464
4.41k
    }
465
21.0k
end:
466
21.0k
    return ret;
467
21.0k
}
468
469
bool Bignum::ToBin(
470
        Datasource& ds,
471
        const component::BignumPair b,
472
        uint8_t* dest,
473
        const size_t size,
474
5.26k
        const bool mustSucceed) {
475
5.26k
    CF_ASSERT((size % 2) == 0, "Input size is not multiple of 2 in Bignum::ToBin");
476
477
5.26k
    bool ret = false;
478
5.26k
    const auto halfSize = size / 2;
479
480
5.26k
    CF_CHECK_EQ(ToBin(ds, b.first, dest, halfSize, mustSucceed), true);
481
5.16k
    CF_CHECK_EQ(ToBin(ds, b.second, dest + halfSize, halfSize, mustSucceed), true);
482
483
5.04k
    ret = true;
484
5.26k
end:
485
5.26k
    return ret;
486
5.04k
}
487
488
5.62k
std::optional<component::Bignum> Bignum::BinToBignum(Datasource& ds, const uint8_t* src, const size_t size) {
489
5.62k
    std::optional<component::Bignum> ret = std::nullopt;
490
491
5.62k
    wolfCrypt_bignum::Bignum bn(ds);
492
5.62k
    CF_CHECK_EQ(mp_read_unsigned_bin(bn.GetPtr(), src, size), MP_OKAY);
493
494
5.44k
    ret = bn.ToComponentBignum();
495
496
5.62k
end:
497
5.62k
    return ret;
498
5.44k
}
499
500
3.75k
std::optional<component::BignumPair> Bignum::BinToBignumPair(Datasource& ds, const uint8_t* src, const size_t size) {
501
3.75k
    CF_ASSERT((size % 2) == 0, "Input size is not multiple of 2 in Bignum::BinToBignumPair");
502
503
3.75k
    std::optional<component::BignumPair> ret = std::nullopt;
504
3.75k
    std::optional<component::Bignum> A, B;
505
3.75k
    const auto halfSize = size / 2;
506
507
3.75k
    {
508
3.75k
        wolfCrypt_bignum::Bignum bn(ds);
509
3.75k
        CF_CHECK_EQ(mp_read_unsigned_bin(bn.GetPtr(), src, halfSize), MP_OKAY);
510
3.74k
        CF_CHECK_NE(A = bn.ToComponentBignum(), std::nullopt);
511
3.69k
    }
512
513
0
    {
514
3.69k
        wolfCrypt_bignum::Bignum bn(ds);
515
3.69k
        CF_CHECK_EQ(mp_read_unsigned_bin(bn.GetPtr(), src + halfSize, halfSize), MP_OKAY);
516
3.67k
        CF_CHECK_NE(B = bn.ToComponentBignum(), std::nullopt);
517
3.63k
    }
518
519
520
0
    ret = {A->ToTrimmedString(), B->ToTrimmedString()};
521
522
3.75k
end:
523
3.75k
    return ret;
524
3.63k
}
525
526
49.9k
void Bignum::Randomize(void) {
527
49.9k
    std::vector<uint8_t> data;
528
49.9k
    try {
529
49.9k
        data = ds.GetData(0, 1, 1024);
530
49.9k
    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
531
532
49.9k
    if ( !data.empty() ) {
533
2.35k
        /* ignore return value */ mp_read_unsigned_bin(GetPtrDirect(), data.data(), data.size());
534
2.35k
    }
535
49.9k
}
536
537
10.2k
bool Bignum::operator==(const Bignum& rhs) const {
538
10.2k
    return mp_cmp(GetPtr(), rhs.GetPtr()) == MP_EQ;
539
10.2k
}
540
541
BignumCluster::BignumCluster(Datasource& ds, Bignum bn0, Bignum bn1, Bignum bn2, Bignum bn3) :
542
50.0k
    ds(ds),
543
50.0k
    bn({bn0, bn1, bn2, bn3})
544
50.0k
{ }
545
546
49.9k
BignumCluster::~BignumCluster() {
547
249k
    for (size_t i = 0; i < 4; i++) {
548
199k
        if ( cache.bn[i] == nullptr ) {
549
4.09k
            continue;
550
4.09k
        }
551
552
195k
        mp_clear(cache.bn[i]);
553
195k
        util::free(cache.bn[i]);
554
195k
    }
555
49.9k
}
556
557
95.4k
Bignum& BignumCluster::operator[](const size_t index) {
558
95.4k
    CF_ASSERT(index < bn.size(), "Invalid index requested in BignumCluster::operator[]");
559
560
95.4k
    try {
561
        /* Rewire? */
562
95.4k
        if ( ds.Get<bool>() == true ) {
563
            /* Pick a random bignum */
564
10.5k
            const auto newIndex = ds.Get<uint8_t>() % 4;
565
566
            /* Same value? */
567
10.5k
            if ( bn[newIndex] == bn[index] ) {
568
                /* Then return reference to other bignum */
569
3.36k
                return bn[newIndex];
570
3.36k
            }
571
572
            /* Fall through */
573
10.5k
        }
574
95.4k
    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
575
576
92.1k
    return bn[index];
577
95.4k
}
578
579
197k
bool BignumCluster::Set(const size_t index, const std::string s) {
580
197k
    CF_ASSERT(index < bn.size(), "Invalid index requested in BignumCluster::Set");
581
582
197k
    return bn[index].Set(s);
583
197k
}
584
585
641
mp_int* BignumCluster::GetDestPtr(const size_t index) {
586
    /* Because it is requested as a destination pointer,
587
     * this bignum will be altered, hence invalidate
588
     * the cache
589
     */
590
641
    InvalidateCache();
591
592
641
    return bn[index].GetPtr();
593
641
}
594
595
20.2k
mp_int* BignumCluster::GetResPtr(void) {
596
20.2k
    CF_ASSERT(res_index == std::nullopt, "Reusing result pointer");
597
598
20.2k
    res_index = 0;
599
600
20.2k
    try { res_index = ds.Get<uint8_t>() % 4; }
601
20.2k
    catch ( fuzzing::datasource::Datasource::OutOfData ) { }
602
603
20.2k
    InvalidateCache();
604
605
20.2k
    return bn[*res_index].GetPtr();
606
20.2k
}
607
608
13.6k
bool BignumCluster::CopyResult(Bignum& res) const {
609
13.6k
    bool ret = false;
610
611
13.6k
    CF_ASSERT(res_index != std::nullopt, "Result index is undefined");
612
13.6k
    wolfCrypt_detail::disableAllocationFailures = true;
613
614
13.6k
    const auto src = bn[*res_index].GetPtrDirect();
615
13.6k
    auto dest = res.GetPtr();
616
617
13.6k
    if ( mp_copy(src, dest) != MP_OKAY ) {
618
#if defined(USE_FAST_MATH)
619
        goto end;
620
#elif defined(USE_INTEGER_HEAP_MATH)
621
223
        CF_NORET(mp_clear(dest));
622
223
        CF_ASSERT(mp_init_size(dest, src->alloc) == 0, "Cannot initialze result");
623
223
        CF_ASSERT(
624
223
                mp_copy(src, dest) == MP_OKAY,
625
223
                "mp_copy failed unexpectedly");
626
#else
627
        CF_NORET(mp_clear(dest));
628
        CF_ASSERT(mp_init_size(dest, src->size) == 0, "Cannot initialze result");
629
        CF_ASSERT(
630
                mp_copy(src, dest) == MP_OKAY,
631
                "mp_copy failed unexpectedly");
632
#endif
633
223
    }
634
635
13.6k
    ret = true;
636
#if defined(USE_FAST_MATH)
637
end:
638
#endif
639
13.6k
    wolfCrypt_detail::disableAllocationFailures = false;
640
13.6k
    return ret;
641
13.6k
}
642
643
48.9k
void BignumCluster::Save(void) {
644
244k
    for (size_t i = 0; i < 4; i++) {
645
195k
        mp_int* cached_mp = (mp_int*)util::malloc(sizeof(mp_int));
646
647
195k
        wolfCrypt_detail::disableAllocationFailures = true;
648
649
195k
        CF_ASSERT(mp_init(cached_mp) == MP_OKAY, "mp_init failed unexpectedly");
650
195k
        CF_ASSERT(mp_copy(bn[i].GetPtrDirect(), cached_mp) == MP_OKAY, "mp_copy failed unexpectedly");
651
652
195k
        wolfCrypt_detail::disableAllocationFailures = false;
653
654
195k
        cache.bn[i] = cached_mp;
655
195k
    }
656
48.9k
}
657
658
21.0k
void BignumCluster::InvalidateCache(void) {
659
21.0k
    cache.invalid = true;
660
21.0k
}
661
662
22.1k
bool BignumCluster::EqualsCache(void) const {
663
22.1k
    if ( cache.invalid == true ) {
664
14.5k
        return true;
665
14.5k
    }
666
667
37.8k
    for (size_t i = 0; i < 4; i++) {
668
30.3k
        if ( cache.bn[i] == nullptr ) {
669
0
            continue;
670
0
        }
671
672
30.3k
        wolfCrypt_detail::disableAllocationFailures = true;
673
674
30.3k
        if ( mp_cmp(bn[i].GetPtrDirect(), cache.bn[i]) != MP_EQ ) {
675
#if defined(CRYPTOFUZZ_WOLFCRYPT_DEBUG)
676
            char str[8192];
677
678
            std::cout << "Bignum with index " << std::to_string(i) << " was changed" << std::endl;
679
680
            wolfCrypt_detail::disableAllocationFailures = true;
681
682
            CF_ASSERT(mp_tohex(cache.bn[i], str) == MP_OKAY, "mp_tohex failed unexpectedly");
683
            printf("it was: %s\n", str);
684
685
            CF_ASSERT(mp_tohex(bn[i].GetPtrDirect(), str) == MP_OKAY, "mp_tohex failed unexpectedly");
686
            printf("it is now %s\n", str);
687
688
#endif
689
0
            wolfCrypt_detail::disableAllocationFailures = false;
690
691
0
            return false;
692
0
        }
693
694
30.3k
        wolfCrypt_detail::disableAllocationFailures = false;
695
30.3k
    }
696
697
7.57k
    return true;
698
7.57k
}
699
700
} /* namespace wolfCrypt_bignum */
701
} /* namespace module */
702
} /* namespace cryptofuzz */