Coverage Report

Created: 2024-09-11 06:39

/src/cryptofuzz/modules/secp256k1/module.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "module.h"
2
#include <cryptofuzz/util.h>
3
#include <cryptofuzz/crypto.h>
4
#include <boost/multiprecision/cpp_int.hpp>
5
#include <sstream>
6
7
extern "C" {
8
    #include <secp256k1.h>
9
    #include <secp256k1_recovery.h>
10
#if \
11
    !defined(SECP256K1_COMMIT_642cd062bdd2d28a8a84d4cb6dedbfe435ee5869) && \
12
    !defined(SECP256K1_COMMIT_c663397f46152e96c548ba392858c730e132dd7a) && \
13
    !defined(SECP256K1_COMMIT_cb32940df3e20ccdcbee7eaf5cda93c18a92fb3e) && \
14
    !defined(SECP255K1_COMMIT_9d560f992db26612ce2630b194aef5f44d63a530)
15
    #include <secp256k1_schnorrsig.h>
16
#endif
17
    #include <secp256k1_ecdh.h>
18
    #include "secp256k1_api.h"
19
}
20
21
namespace cryptofuzz {
22
namespace module {
23
24
secp256k1::secp256k1(void) :
25
6
    Module("secp256k1") { }
26
27
namespace secp256k1_detail {
28
52.5k
    static int CheckRet(const int ret) {
29
52.5k
        CF_ASSERT(ret == 0 || ret == 1, "Unexpected return value");
30
31
52.5k
        return ret;
32
52.5k
    }
33
34
36.4k
    static bool EncodeBignum(const std::string s, uint8_t* out) {
35
36.4k
        std::vector<uint8_t> v;
36
36.4k
        boost::multiprecision::cpp_int c(s);
37
36.4k
        boost::multiprecision::export_bits(c, std::back_inserter(v), 8);
38
36.4k
        if ( v.size() > 32 ) {
39
693
            return false;
40
693
        }
41
35.7k
        const auto diff = 32 - v.size();
42
43
35.7k
        memset(out, 0, 32);
44
35.7k
        memcpy(out + diff, v.data(), v.size());
45
46
35.7k
        return true;
47
36.4k
    }
48
49
21.7k
    static std::string toString(const boost::multiprecision::cpp_int& i) {
50
21.7k
        std::stringstream ss;
51
21.7k
        ss << i;
52
53
21.7k
        if ( ss.str().empty() ) {
54
0
            return "0";
55
21.7k
        } else {
56
21.7k
            return ss.str();
57
21.7k
        }
58
21.7k
    }
59
60
3.52k
    std::optional<component::ECC_PublicKey> To_ECC_PublicKey(const secp256k1_context* ctx, const secp256k1_pubkey* pubkey) {
61
3.52k
        std::optional<component::ECC_PublicKey> ret = std::nullopt;
62
3.52k
        std::vector<uint8_t> pubkey_bytes(65);
63
3.52k
        size_t pubkey_bytes_size = pubkey_bytes.size();
64
65
3.52k
        CF_CHECK_EQ(
66
3.52k
                CheckRet(secp256k1_ec_pubkey_serialize(ctx, pubkey_bytes.data(), &pubkey_bytes_size, pubkey, SECP256K1_FLAGS_TYPE_COMPRESSION)), 1);
67
3.52k
        CF_CHECK_EQ(pubkey_bytes_size, 65);
68
69
3.52k
        {
70
3.52k
            boost::multiprecision::cpp_int x, y;
71
72
3.52k
            boost::multiprecision::import_bits(x, pubkey_bytes.begin() + 1, pubkey_bytes.begin() + 1 + 32);
73
3.52k
            boost::multiprecision::import_bits(y, pubkey_bytes.begin() + 1 + 32, pubkey_bytes.end());
74
75
3.52k
            ret = {secp256k1_detail::toString(x), secp256k1_detail::toString(y)};
76
3.52k
        }
77
78
3.52k
end:
79
3.52k
        return ret;
80
3.52k
    }
81
82
707
    bool PrivkeyToBytes(const component::ECC_PrivateKey& priv, uint8_t privkey_bytes[32]) {
83
707
        bool ret = false;
84
85
707
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
86
707
                    priv.ToTrimmedString(),
87
707
                    privkey_bytes), true);
88
89
687
        ret = true;
90
707
end:
91
707
        return ret;
92
687
    }
93
94
687
    bool PubkeyToBytes(const component::ECC_PublicKey& pub, uint8_t pubkey_bytes[65]) {
95
687
        bool ret = false;
96
97
687
        pubkey_bytes[0] = 4;
98
99
687
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
100
687
                    pub.first.ToTrimmedString(),
101
687
                    pubkey_bytes + 1), true);
102
670
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
103
670
                    pub.second.ToTrimmedString(),
104
670
                    pubkey_bytes + 1 + 32), true);
105
645
        ret = true;
106
107
687
end:
108
687
        return ret;
109
645
    }
110
111
    template <class T>
112
418
    void AssertZero(const T* v) {
113
418
        const static T nulls = {0};
114
418
        CF_ASSERT(memcmp(v, &nulls, sizeof(T)) == 0, "Variable is not all zeroes");
115
418
    }
void cryptofuzz::module::secp256k1_detail::AssertZero<secp256k1_ecdsa_recoverable_signature>(secp256k1_ecdsa_recoverable_signature const*)
Line
Count
Source
112
8
    void AssertZero(const T* v) {
113
8
        const static T nulls = {0};
114
8
        CF_ASSERT(memcmp(v, &nulls, sizeof(T)) == 0, "Variable is not all zeroes");
115
8
    }
void cryptofuzz::module::secp256k1_detail::AssertZero<secp256k1_pubkey>(secp256k1_pubkey const*)
Line
Count
Source
112
410
    void AssertZero(const T* v) {
113
410
        const static T nulls = {0};
114
410
        CF_ASSERT(memcmp(v, &nulls, sizeof(T)) == 0, "Variable is not all zeroes");
115
410
    }
116
117
    class Context {
118
        private:
119
            Datasource& ds;
120
            secp256k1_context* ctx = nullptr;
121
14.0k
            void randomizeContext(void) {
122
14.0k
#if !defined(SECP256K1_COMMIT_c663397f46152e96c548ba392858c730e132dd7a) && \
123
14.0k
    !defined(SECP256K1_COMMIT_cb32940df3e20ccdcbee7eaf5cda93c18a92fb3e) && \
124
14.0k
    !defined(SECP255K1_COMMIT_9d560f992db26612ce2630b194aef5f44d63a530)
125
14.0k
                std::vector<uint8_t> seed;
126
127
14.0k
                try {
128
14.0k
                    if ( ds.Get<bool>() ) {
129
8.09k
                        seed = ds.GetData(0, 32, 32);
130
8.09k
                        CF_ASSERT(
131
8.09k
                                CheckRet(secp256k1_context_randomize(ctx, seed.data())) == 1,
132
8.09k
                                "Call to secp256k1_context_randomize failed");
133
8.09k
                    }
134
14.0k
                } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
135
14.0k
#endif
136
14.0k
            }
137
138
11.4k
            void clone(void) {
139
11.4k
                const auto newCtx = secp256k1_context_clone(ctx);
140
11.4k
                CF_ASSERT(newCtx != nullptr, "secp256k1_context_clone failed");
141
11.4k
                CF_NORET(secp256k1_context_destroy(ctx));
142
11.4k
                ctx = newCtx;
143
11.4k
            }
144
145
        public:
146
            Context(Datasource& ds, const unsigned int flags) :
147
14.6k
                ds(ds) {
148
14.6k
                    CF_ASSERT((ctx = secp256k1_context_create(flags)) != nullptr, "Cannot create secp256k1 context");
149
14.6k
            }
150
14.6k
            ~Context(void) {
151
14.6k
                GetPtr();
152
153
14.6k
                CF_NORET(secp256k1_context_destroy(ctx));
154
14.6k
                ctx = nullptr;
155
14.6k
            }
156
39.2k
            secp256k1_context* GetPtr(void) {
157
39.2k
                try {
158
39.2k
                    if ( ds.Get<bool>() ) {
159
14.0k
                        randomizeContext();
160
14.0k
                    }
161
162
39.2k
                    if ( ds.Get<bool>() ) {
163
11.4k
                        clone();
164
11.4k
                    }
165
39.2k
                } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
166
167
39.2k
                return ctx;
168
39.2k
            }
169
30.2k
            secp256k1_context* GetPtrDirect(void) {
170
30.2k
                return ctx;
171
30.2k
            }
172
    };
173
174
    class ECDSA_Recoverable_Signature {
175
        private:
176
            Datasource& ds;
177
            Context& ctx;
178
            bool initialized = false;
179
            secp256k1_ecdsa_recoverable_signature* sig = nullptr;
180
181
697
            void serializeCompact(void) {
182
697
                uint8_t data[64];
183
184
697
                int id;
185
186
697
                if ( CheckRet(secp256k1_ecdsa_recoverable_signature_serialize_compact(
187
697
                            ctx.GetPtr(),
188
697
                            data,
189
697
                            &id,
190
697
                            sig)) == 1 ) {
191
697
                    CF_ASSERT(
192
697
                            CheckRet(secp256k1_ecdsa_recoverable_signature_parse_compact(
193
697
                                ctx.GetPtr(),
194
697
                                sig,
195
697
                                data,
196
697
                                id)) == 1,
197
697
                            "Cannot deserialize compact recoverable signature");
198
697
                }
199
697
            }
200
201
390
            void convert(void) {
202
390
                secp256k1_ecdsa_signature sig_;
203
390
                CheckRet(secp256k1_ecdsa_recoverable_signature_convert(ctx.GetPtr(), &sig_, sig));
204
390
            }
205
        public:
206
            ECDSA_Recoverable_Signature(Datasource& ds, Context& ctx) :
207
1.83k
                ds(ds), ctx(ctx) {
208
1.83k
                sig = static_cast<secp256k1_ecdsa_recoverable_signature*>(malloc(sizeof(secp256k1_ecdsa_recoverable_signature)));
209
1.83k
            }
210
1.83k
            ~ECDSA_Recoverable_Signature(void) {
211
1.83k
                GetPtr();
212
213
1.83k
                free(sig);
214
1.83k
                sig = nullptr;
215
1.83k
            }
216
1.54k
            void SetInitialized(void) {
217
1.54k
                initialized = true;
218
1.54k
            }
219
3.39k
            secp256k1_ecdsa_recoverable_signature* GetPtr() {
220
3.39k
                if ( initialized == true ) {
221
1.54k
                    try {
222
1.54k
                        if ( ds.Get<bool>() ) {
223
697
                            serializeCompact();
224
697
                        }
225
226
1.54k
                        if ( ds.Get<bool>() ) {
227
390
                            convert();
228
390
                        }
229
1.54k
                    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
230
1.54k
                }
231
3.39k
                return sig;
232
3.39k
            }
233
234
1.54k
            secp256k1_ecdsa_recoverable_signature* GetPtrDirect(void) const {
235
1.54k
                return sig;
236
1.54k
            }
237
238
1.55k
            bool ParseCompact(const uint8_t* data, const uint8_t id) {
239
1.55k
                const auto ctxPtr = ctx.GetPtrDirect();
240
1.55k
                const auto sigPtr = GetPtr();
241
242
1.55k
                const bool ret = CheckRet(secp256k1_ecdsa_recoverable_signature_parse_compact(ctxPtr, sigPtr, data, id)) == 1;
243
244
1.55k
                if ( ret ) {
245
1.54k
                    SetInitialized();
246
1.54k
                } else {
247
                    /* https://github.com/bitcoin-core/secp256k1/blob/8ae56e33e749e16880dbfb4444fdae238b4426ac/src/modules/recovery/main_impl.h#L55 */
248
8
                    secp256k1_detail::AssertZero<>(sigPtr);
249
8
                }
250
251
1.55k
                return ret;
252
1.55k
            }
253
    };
254
255
    class Pubkey {
256
        private:
257
            Datasource& ds;
258
            Context& ctx;
259
            bool initialized = false;
260
            secp256k1_pubkey* pub = nullptr;
261
262
0
            void serialize(void) {
263
0
                uint8_t* data = nullptr;
264
0
                size_t original_size = 0;
265
0
                try {
266
0
                    original_size = ds.Get<uint16_t>();
267
0
                    size_t size = original_size;
268
0
                    data = util::malloc(size);
269
0
270
0
                    if ( data != nullptr ) {
271
0
                        unsigned int flags = SECP256K1_FLAGS_TYPE_COMPRESSION;
272
0
                        if ( ds.Get<bool>() ) {
273
0
                            flags |= SECP256K1_FLAGS_BIT_COMPRESSION;
274
0
                        }
275
0
276
0
                        bool validOutsize;
277
0
278
0
                        if ( flags & SECP256K1_FLAGS_BIT_COMPRESSION ) {
279
0
                            validOutsize = size >= 33;
280
0
                        } else {
281
0
                            validOutsize = size >= 65;
282
0
                        }
283
0
284
0
                        if ( validOutsize ) {
285
0
                            if (
286
0
                                CheckRet(secp256k1_ec_pubkey_serialize(
287
0
                                        ctx.GetPtr(),
288
0
                                        data,
289
0
                                        &size,
290
0
                                        pub,
291
0
                                        flags)) == 1 ) {
292
0
                                CF_ASSERT(
293
0
                                        CheckRet(secp256k1_ec_pubkey_parse(
294
0
                                            ctx.GetPtr(),
295
0
                                            pub,
296
0
                                            data,
297
0
                                            size)) == 1,
298
0
                                        "Cannot deserialize pubkey");
299
0
                            }
300
0
                        }
301
0
                    }
302
0
                } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
303
0
304
0
                if ( original_size > 0 ) {
305
0
                    util::free(data);
306
0
                }
307
0
            }
308
        public:
309
            Pubkey(Datasource& ds, Context& ctx) :
310
12.8k
                ds(ds), ctx(ctx) {
311
12.8k
                pub = static_cast<secp256k1_pubkey*>(malloc(sizeof(secp256k1_pubkey)));
312
12.8k
            }
313
12.8k
            ~Pubkey(void) {
314
12.8k
                GetPtr();
315
316
12.8k
                free(pub);
317
12.8k
                pub = nullptr;
318
12.8k
            }
319
10.8k
            void SetInitialized(void) {
320
10.8k
                initialized = true;
321
10.8k
            }
322
32.5k
            secp256k1_pubkey* GetPtr() {
323
32.5k
                return pub;
324
0
                if ( initialized == true ) {
325
0
                    try {
326
0
                        if ( ds.Get<bool>() ) {
327
0
                            serialize();
328
0
                        }
329
0
                    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
330
0
                }
331
0
                return pub;
332
0
            }
333
6.27k
            bool Create(const uint8_t key[32]) {
334
6.27k
                const auto ctxPtr = ctx.GetPtrDirect();
335
6.27k
                const auto pubPtr = GetPtr();
336
337
6.27k
                const bool ret = CheckRet(secp256k1_ec_pubkey_create(ctxPtr, pubPtr, key)) == 1;
338
339
6.27k
                if ( ret ) {
340
6.17k
                    SetInitialized();
341
6.17k
                }
342
343
6.27k
                return ret;
344
6.27k
            }
345
346
3.78k
            bool Serialize(uint8_t* data, size_t* size) {
347
3.78k
                const auto ctxPtr = ctx.GetPtrDirect();
348
3.78k
                const auto pubPtr = GetPtr();
349
350
3.78k
                const bool ret = CheckRet(secp256k1_ec_pubkey_serialize(ctxPtr, data, size, pubPtr, SECP256K1_FLAGS_TYPE_COMPRESSION)) == 1;
351
352
3.78k
                if ( ret ) {
353
3.78k
                    CF_ASSERT(*size == 65, "Serialized pubkey is not 65 bytes");
354
3.78k
                }
355
356
3.78k
                return ret;
357
3.78k
            }
358
359
4.03k
            bool Parse(const uint8_t* data, size_t size) {
360
4.03k
                const auto ctxPtr = ctx.GetPtrDirect();
361
4.03k
                const auto pubPtr = GetPtr();
362
363
4.03k
                const bool ret = CheckRet(secp256k1_ec_pubkey_parse(ctxPtr, pubPtr, data, size)) == 1;
364
365
4.03k
                if ( ret ) {
366
3.53k
                    SetInitialized();
367
3.53k
                }
368
369
4.03k
                return ret;
370
4.03k
            }
371
372
#if !defined(SECP256K1_COMMIT_cb32940df3e20ccdcbee7eaf5cda93c18a92fb3e) && \
373
    !defined(SECP255K1_COMMIT_9d560f992db26612ce2630b194aef5f44d63a530)
374
496
            bool ECDH(uint8_t out[32], const uint8_t key[32]) {
375
496
                const auto ctxPtr = ctx.GetPtrDirect();
376
496
                const auto pubPtr = GetPtr();
377
378
496
                return CheckRet(secp256k1_ecdh(ctxPtr, out, pubPtr, key, nullptr, nullptr)) == 1;
379
496
            }
380
#endif
381
382
1.54k
            bool Recover(ECDSA_Recoverable_Signature& sig, const uint8_t hash[32]) {
383
1.54k
                const auto ctxPtr = ctx.GetPtrDirect();
384
1.54k
                const auto sigPtr = sig.GetPtrDirect();
385
1.54k
                const auto pubPtr = GetPtr();
386
387
1.54k
                const bool ret = CheckRet(secp256k1_ecdsa_recover(ctxPtr, pubPtr, sigPtr, hash)) == 1;
388
389
1.54k
                if ( ret == true ) {
390
1.13k
                    SetInitialized();
391
1.13k
                } else {
392
                    /* https://github.com/bitcoin-core/secp256k1/blob/8ae56e33e749e16880dbfb4444fdae238b4426ac/src/modules/recovery/main_impl.h#L155 */
393
410
                    AssertZero<>(pubPtr);
394
410
                }
395
396
1.54k
                return ret;
397
1.54k
            }
398
399
2.99k
            secp256k1_pubkey* GetPtrDirect(void) const {
400
2.99k
                return pub;
401
2.99k
            }
402
    };
403
404
    class ECDSA_Signature {
405
        private:
406
            Datasource& ds;
407
            Context& ctx;
408
            bool initialized = false;
409
            secp256k1_ecdsa_signature* sig = nullptr;
410
411
3.58k
            void serializeDER(void) {
412
3.58k
                const size_t original_size = ds.Get<uint16_t>();
413
3.58k
                size_t size = original_size;
414
3.58k
                uint8_t* data = util::malloc(size);
415
416
3.58k
                if ( data != nullptr ) {
417
3.28k
                    if ( CheckRet(secp256k1_ecdsa_signature_serialize_der(
418
3.28k
                                ctx.GetPtr(),
419
3.28k
                                data,
420
3.28k
                                &size,
421
3.28k
                                sig)) == 1 ) {
422
3.22k
                        CF_ASSERT(
423
3.22k
                                CheckRet(secp256k1_ecdsa_signature_parse_der(
424
3.22k
                                    ctx.GetPtr(),
425
3.22k
                                    sig,
426
3.22k
                                    data,
427
3.22k
                                    size)) == 1,
428
3.22k
                                "Cannot deserialize DER signature");
429
3.22k
                    }
430
3.28k
                }
431
432
3.58k
                if ( original_size > 0 ) {
433
3.24k
                    util::free(data);
434
3.24k
                }
435
3.58k
            }
436
437
2.69k
            void serializeCompact(void) {
438
2.69k
                uint8_t data[64];
439
440
2.69k
                if ( CheckRet(secp256k1_ecdsa_signature_serialize_compact(
441
2.69k
                            ctx.GetPtr(),
442
2.69k
                            data,
443
2.69k
                            sig)) == 1 ) {
444
2.69k
                    CF_ASSERT(
445
2.69k
                            CheckRet(secp256k1_ecdsa_signature_parse_compact(
446
2.69k
                                ctx.GetPtr(),
447
2.69k
                                sig,
448
2.69k
                                data)) == 1,
449
2.69k
                            "Cannot deserialize compact signature");
450
2.69k
                }
451
2.69k
            }
452
        public:
453
            ECDSA_Signature(Datasource& ds, Context& ctx) :
454
6.19k
                ds(ds), ctx(ctx) {
455
6.19k
                sig = static_cast<secp256k1_ecdsa_signature*>(malloc(sizeof(secp256k1_ecdsa_signature)));
456
6.19k
            }
457
6.19k
            ~ECDSA_Signature(void) {
458
6.19k
                GetPtr();
459
460
6.19k
                free(sig);
461
6.19k
                sig = nullptr;
462
6.19k
            }
463
5.64k
            void SetInitialized(void) {
464
5.64k
                initialized = true;
465
5.64k
            }
466
20.5k
            secp256k1_ecdsa_signature* GetPtr() {
467
20.5k
                if ( initialized == true ) {
468
14.2k
                    try {
469
14.2k
                        if ( ds.Get<bool>() ) {
470
3.58k
                            serializeDER();
471
3.58k
                        }
472
473
14.2k
                        if ( ds.Get<bool>() ) {
474
2.69k
                            serializeCompact();
475
2.69k
                        }
476
14.2k
                    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
477
14.2k
                }
478
20.5k
                return sig;
479
20.5k
            }
480
481
3.00k
            bool ParseCompact(const uint8_t* data) {
482
3.00k
                const auto ctxPtr = ctx.GetPtrDirect();
483
3.00k
                const auto sigPtr = GetPtr();
484
485
3.00k
                const bool ret = CheckRet(secp256k1_ecdsa_signature_parse_compact(ctxPtr, sigPtr, data)) == 1;
486
487
3.00k
                if ( ret ) {
488
2.99k
                    SetInitialized();
489
2.99k
                }
490
491
3.00k
                return ret;
492
3.00k
            }
493
494
2.99k
            void Normalize(void) {
495
2.99k
                const auto ctxPtr = ctx.GetPtrDirect();
496
2.99k
                const auto sigPtr = GetPtr();
497
498
                /* ignore ret */ CheckRet(secp256k1_ecdsa_signature_normalize(ctxPtr, sigPtr, sigPtr));
499
2.99k
            }
500
501
2.99k
            bool Verify(const uint8_t hash[32], Pubkey& pub) {
502
2.99k
                const auto sigPtr = GetPtr();
503
2.99k
                const auto ctxPtr = ctx.GetPtrDirect();
504
2.99k
                const auto pubPtr = pub.GetPtrDirect();
505
506
2.99k
                return CheckRet(secp256k1_ecdsa_verify(ctxPtr, sigPtr, hash, pubPtr)) == 1;
507
2.99k
            }
508
    };
509
510
3.70k
    std::optional<component::ECC_PublicKey> OpECC_PrivateToPublic(Datasource& ds, const std::string priv) {
511
3.70k
        std::optional<component::ECC_PublicKey> ret = std::nullopt;
512
3.70k
        secp256k1_detail::Context ctx(ds, SECP256K1_CONTEXT_SIGN);
513
3.70k
        secp256k1_detail::Pubkey pub(ds, ctx);
514
3.70k
        std::vector<uint8_t> pubkey_bytes(65);
515
3.70k
        uint8_t key[32];
516
517
3.70k
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
518
3.70k
                    priv,
519
3.70k
                    key), true);
520
3.62k
        CF_CHECK_TRUE(pub.Create(key));
521
522
3.52k
        {
523
3.52k
            const auto ctxPtr = ctx.GetPtrDirect();
524
3.52k
            const auto pubPtr = pub.GetPtr();
525
526
3.52k
            ret = To_ECC_PublicKey(ctxPtr, pubPtr);
527
3.52k
        }
528
529
3.70k
end:
530
3.70k
        return ret;
531
3.52k
    }
532
533
1.44k
    static int nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
534
1.44k
        (void)nonce32;
535
1.44k
        (void)msg32;
536
1.44k
        (void)key32;
537
1.44k
        (void)algo16;
538
1.44k
        (void)counter;
539
540
1.44k
        memcpy(nonce32, data, 32);
541
542
1.44k
        return counter == 0;
543
1.44k
    }
544
545
#if \
546
        !defined(SECP256K1_COMMIT_642cd062bdd2d28a8a84d4cb6dedbfe435ee5869) && \
547
        !defined(SECP256K1_COMMIT_c663397f46152e96c548ba392858c730e132dd7a) && \
548
        !defined(SECP256K1_COMMIT_cb32940df3e20ccdcbee7eaf5cda93c18a92fb3e) && \
549
        !defined(SECP255K1_COMMIT_9d560f992db26612ce2630b194aef5f44d63a530)
550
    static int nonce_function_schnorrsig(
551
            unsigned char *nonce32,
552
            const unsigned char *msg,
553
            size_t msglen,
554
            const unsigned char *key32,
555
            const unsigned char *xonly_pk32,
556
            const unsigned char *algo,
557
            size_t algolen,
558
696
            void *data) {
559
696
        (void)nonce32;
560
696
        (void)msg;
561
696
        (void)msglen;
562
696
        (void)key32;
563
696
        (void)xonly_pk32;
564
696
        (void)algo;
565
696
        (void)algolen;
566
567
696
        memcpy(nonce32, data, 32);
568
569
696
        return 1;
570
696
    }
571
#endif
572
}
573
574
1.05k
std::optional<component::ECC_PublicKey> secp256k1::OpECC_PrivateToPublic(operation::ECC_PrivateToPublic& op) {
575
1.05k
    std::optional<component::ECC_PublicKey> ret = std::nullopt;
576
1.05k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
577
1.05k
    util::SetGlobalDs(&ds);
578
579
1.05k
    CF_CHECK_EQ(op.curveType.Get(), CF_ECC_CURVE("secp256k1"));
580
581
1.05k
    ret = secp256k1_detail::OpECC_PrivateToPublic(ds, op.priv.ToTrimmedString());
582
583
1.05k
end:
584
1.05k
    util::UnsetGlobalDs();
585
586
1.05k
    return ret;
587
1.05k
}
588
589
400
std::optional<bool> secp256k1::OpECC_ValidatePubkey(operation::ECC_ValidatePubkey& op) {
590
400
    std::optional<bool> ret = std::nullopt;
591
400
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
592
400
    util::SetGlobalDs(&ds);
593
594
400
    secp256k1_detail::Context ctx(ds, SECP256K1_CONTEXT_VERIFY);
595
400
    secp256k1_detail::Pubkey pub(ds, ctx);
596
400
    uint8_t pubkey_bytes[65];
597
400
    pubkey_bytes[0] = 4;
598
599
400
    CF_CHECK_EQ(op.curveType.Get(), CF_ECC_CURVE("secp256k1"));
600
601
400
    CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
602
400
                op.pub.first.ToTrimmedString(),
603
400
                pubkey_bytes + 1), true);
604
366
    CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
605
366
                op.pub.second.ToTrimmedString(),
606
366
                pubkey_bytes + 1 + 32), true);
607
608
336
    ret = pub.Parse(pubkey_bytes, sizeof(pubkey_bytes));
609
610
400
end:
611
400
    util::UnsetGlobalDs();
612
613
400
    return ret;
614
336
}
615
616
2.93k
std::optional<component::ECDSA_Signature> secp256k1::OpECDSA_Sign(operation::ECDSA_Sign& op) {
617
2.93k
    std::optional<component::ECDSA_Signature> ret = std::nullopt;
618
2.93k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
619
2.93k
    util::SetGlobalDs(&ds);
620
621
2.93k
    secp256k1_detail::Context ctx(ds, SECP256K1_CONTEXT_SIGN);
622
2.93k
    secp256k1_detail::Pubkey pub(ds, ctx);
623
2.93k
    secp256k1_detail::ECDSA_Signature sig(ds, ctx);
624
2.93k
    std::vector<uint8_t> sig_bytes(64);
625
2.93k
    std::vector<uint8_t> pubkey_bytes(65);
626
2.93k
    size_t pubkey_bytes_size = pubkey_bytes.size();
627
2.93k
    uint8_t key[32];
628
2.93k
    uint8_t hash[32];
629
2.93k
    uint8_t specified_nonce[32];
630
631
2.93k
    CF_CHECK_TRUE(op.UseRFC6979Nonce() || op.UseSpecifiedNonce());
632
633
2.87k
    CF_CHECK_EQ(op.curveType.Get(), CF_ECC_CURVE("secp256k1"));
634
635
2.87k
    CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
636
2.87k
                op.priv.ToTrimmedString(),
637
2.87k
                key), true);
638
639
2.82k
    if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
640
1.32k
        const auto CT = op.cleartext.ECDSA_Pad(32);
641
1.32k
        memcpy(hash, CT.GetPtr(), sizeof(hash));
642
1.49k
    } else if ( op.digestType.Get() == CF_DIGEST("SHA256") ) {
643
1.41k
        const auto _hash = crypto::sha256(op.cleartext.Get());
644
1.41k
        memcpy(hash, _hash.data(), _hash.size());
645
1.41k
    } else {
646
81
        goto end;
647
81
    }
648
649
2.73k
    if ( op.UseRFC6979Nonce() == true ) {
650
1.28k
        CF_CHECK_EQ(secp256k1_ecdsa_sign(ctx.GetPtr(), sig.GetPtr(), hash, key, secp256k1_nonce_function_rfc6979, nullptr), 1);
651
1.24k
        sig.SetInitialized();
652
1.45k
    } else if ( op.UseSpecifiedNonce() == true ) {
653
1.45k
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
654
1.45k
                    op.nonce.ToTrimmedString(),
655
1.45k
                    specified_nonce), true);
656
1.44k
        CF_CHECK_EQ(secp256k1_ecdsa_sign(ctx.GetPtr(), sig.GetPtr(), hash, key, secp256k1_detail::nonce_function, specified_nonce), 1);
657
1.40k
        sig.SetInitialized();
658
1.40k
    } else {
659
0
        CF_UNREACHABLE();
660
0
    }
661
662
2.65k
    CF_CHECK_EQ(secp256k1_ecdsa_signature_serialize_compact(ctx.GetPtr(), sig_bytes.data(), sig.GetPtr()), 1);
663
664
2.65k
    CF_CHECK_TRUE(pub.Create(key));
665
2.65k
    CF_CHECK_TRUE(pub.Serialize(pubkey_bytes.data(), &pubkey_bytes_size));
666
667
2.65k
    {
668
2.65k
        boost::multiprecision::cpp_int r, s;
669
670
2.65k
        auto component_pubkey = secp256k1_detail::OpECC_PrivateToPublic(ds, op.priv.ToTrimmedString());
671
2.65k
        CF_CHECK_NE(component_pubkey, std::nullopt);
672
673
2.65k
        boost::multiprecision::import_bits(r, sig_bytes.begin(), sig_bytes.begin() + 32);
674
2.65k
        boost::multiprecision::import_bits(s, sig_bytes.begin() + 32, sig_bytes.end());
675
676
2.65k
        ret = component::ECDSA_Signature(
677
2.65k
                {secp256k1_detail::toString(r), secp256k1_detail::toString(s)},
678
2.65k
                *component_pubkey);
679
2.65k
    }
680
681
2.93k
end:
682
2.93k
    util::UnsetGlobalDs();
683
684
2.93k
    return ret;
685
2.65k
}
686
687
3.26k
std::optional<bool> secp256k1::OpECDSA_Verify(operation::ECDSA_Verify& op) {
688
3.26k
    std::optional<bool> ret = std::nullopt;
689
3.26k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
690
3.26k
    util::SetGlobalDs(&ds);
691
692
3.26k
    secp256k1_detail::Context ctx(ds, SECP256K1_CONTEXT_VERIFY);
693
3.26k
    secp256k1_detail::Pubkey pub(ds, ctx);
694
3.26k
    secp256k1_detail::ECDSA_Signature sig(ds, ctx);
695
3.26k
    uint8_t pubkey_bytes[65];
696
3.26k
    uint8_t sig_bytes[64];
697
3.26k
    uint8_t hash[32];
698
699
3.26k
    CF_CHECK_EQ(op.curveType.Get(), CF_ECC_CURVE("secp256k1"));
700
701
3.26k
    if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
702
1.55k
        const auto CT = op.cleartext.ECDSA_Pad(32);
703
1.55k
        memcpy(hash, CT.GetPtr(), sizeof(hash));
704
1.70k
    } else if ( op.digestType.Get() == CF_DIGEST("SHA256") ) {
705
1.57k
        const auto _hash = crypto::sha256(op.cleartext.Get());
706
1.57k
        memcpy(hash, _hash.data(), _hash.size());
707
1.57k
    } else {
708
132
        goto end;
709
132
    }
710
711
    /* Beyond this point, a failure definitely means that the
712
     * pubkey or signature is invalid */
713
3.12k
    ret = false;
714
715
3.12k
    pubkey_bytes[0] = 4;
716
3.12k
    CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
717
3.12k
                op.signature.pub.first.ToTrimmedString(),
718
3.12k
                pubkey_bytes + 1), true);
719
3.11k
    CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
720
3.11k
                op.signature.pub.second.ToTrimmedString(),
721
3.11k
                pubkey_bytes + 1 + 32), true);
722
723
3.10k
    CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
724
3.10k
                op.signature.signature.first.ToTrimmedString(),
725
3.10k
                sig_bytes), true);
726
3.07k
    CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
727
3.07k
                op.signature.signature.second.ToTrimmedString(),
728
3.07k
                sig_bytes + 32), true);
729
730
3.05k
    CF_CHECK_TRUE(pub.Parse(pubkey_bytes, sizeof(pubkey_bytes)));
731
732
3.00k
    CF_CHECK_TRUE(sig.ParseCompact(sig_bytes));
733
2.99k
    sig.Normalize();
734
735
2.99k
    ret = sig.Verify(hash, pub);
736
737
3.26k
end:
738
3.26k
    util::UnsetGlobalDs();
739
740
3.26k
    return ret;
741
2.99k
}
742
743
1.83k
std::optional<component::ECC_PublicKey> secp256k1::OpECDSA_Recover(operation::ECDSA_Recover& op) {
744
1.83k
    std::optional<component::ECC_PublicKey> ret = std::nullopt;
745
1.83k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
746
1.83k
    util::SetGlobalDs(&ds);
747
748
1.83k
    secp256k1_detail::Context ctx(ds, SECP256K1_CONTEXT_VERIFY);
749
1.83k
    secp256k1_detail::Pubkey pub(ds, ctx);
750
1.83k
    secp256k1_detail::ECDSA_Recoverable_Signature sig(ds, ctx);
751
1.83k
    uint8_t sig_bytes[64];
752
1.83k
    uint8_t hash[32];
753
1.83k
    std::vector<uint8_t> pubkey_bytes(65);
754
1.83k
    size_t pubkey_bytes_size = pubkey_bytes.size();
755
756
1.83k
    CF_CHECK_EQ(op.curveType.Get(), CF_ECC_CURVE("secp256k1"));
757
1.83k
    CF_CHECK_LTE(op.id, 3);
758
759
1.79k
    if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
760
1.18k
        const auto CT = op.cleartext.ECDSA_Pad(32);
761
1.18k
        memcpy(hash, CT.GetPtr(), sizeof(hash));
762
1.18k
    } else if ( op.digestType.Get() == CF_DIGEST("SHA256") ) {
763
420
        const auto _hash = crypto::sha256(op.cleartext.Get());
764
420
        memcpy(hash, _hash.data(), _hash.size());
765
420
    } else {
766
189
        goto end;
767
189
    }
768
769
1.60k
    CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
770
1.60k
                op.signature.first.ToTrimmedString(),
771
1.60k
                sig_bytes), true);
772
1.58k
    CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
773
1.58k
                op.signature.second.ToTrimmedString(),
774
1.58k
                sig_bytes + 32), true);
775
776
1.55k
    CF_CHECK_TRUE(sig.ParseCompact(sig_bytes, op.id));
777
778
1.54k
    CF_CHECK_TRUE(pub.Recover(sig, hash));
779
1.13k
    CF_CHECK_TRUE(pub.Serialize(pubkey_bytes.data(), &pubkey_bytes_size));
780
781
1.13k
    {
782
1.13k
        boost::multiprecision::cpp_int x, y;
783
784
1.13k
        boost::multiprecision::import_bits(x, pubkey_bytes.begin() + 1, pubkey_bytes.begin() + 33);
785
1.13k
        boost::multiprecision::import_bits(y, pubkey_bytes.begin() + 33, pubkey_bytes.end());
786
787
1.13k
        ret = component::ECC_PublicKey(secp256k1_detail::toString(x), secp256k1_detail::toString(y));
788
1.13k
    }
789
790
1.83k
end:
791
1.83k
    util::UnsetGlobalDs();
792
793
1.83k
    return ret;
794
1.13k
}
795
796
#if \
797
        !defined(SECP256K1_COMMIT_642cd062bdd2d28a8a84d4cb6dedbfe435ee5869) && \
798
        !defined(SECP256K1_COMMIT_c663397f46152e96c548ba392858c730e132dd7a) && \
799
        !defined(SECP256K1_COMMIT_cb32940df3e20ccdcbee7eaf5cda93c18a92fb3e) && \
800
        !defined(SECP255K1_COMMIT_9d560f992db26612ce2630b194aef5f44d63a530)
801
1.27k
std::optional<component::Schnorr_Signature> secp256k1::OpSchnorr_Sign(operation::Schnorr_Sign& op) {
802
1.27k
    std::optional<component::Schnorr_Signature> ret = std::nullopt;
803
1.27k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
804
1.27k
    util::SetGlobalDs(&ds);
805
806
1.27k
    secp256k1_detail::Context ctx(ds, SECP256K1_CONTEXT_SIGN);
807
1.27k
    secp256k1_xonly_pubkey pubkey;
808
1.27k
    std::vector<uint8_t> sig_bytes(64);
809
1.27k
    std::vector<uint8_t> pubkey_bytes(32);
810
1.27k
    secp256k1_keypair keypair;
811
1.27k
    uint8_t key[32];
812
1.27k
    Buffer input;
813
1.27k
    uint8_t specified_nonce[32];
814
1.27k
    secp256k1_schnorrsig_extraparams extraparams;
815
816
1.27k
    CF_CHECK_TRUE(op.UseBIP340Nonce() || op.UseSpecifiedNonce() );
817
818
1.23k
    CF_CHECK_EQ(op.curveType.Get(), CF_ECC_CURVE("secp256k1"));
819
820
1.23k
    CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
821
1.23k
                op.priv.ToTrimmedString(),
822
1.23k
                key), true);
823
824
1.20k
    CF_CHECK_EQ(secp256k1_keypair_create(ctx.GetPtr(), &keypair, key), 1);
825
826
1.18k
    if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
827
670
        input = op.cleartext;
828
670
    } else if ( op.digestType.Get() == CF_DIGEST("SHA256") ) {
829
460
        input = op.cleartext.SHA256();
830
460
    } else {
831
53
        goto end;
832
53
    }
833
834
1.13k
    if ( op.UseBIP340Nonce() == true ) {
835
421
        extraparams.noncefp = secp256k1_nonce_function_bip340;
836
421
        extraparams.ndata = nullptr;
837
709
    } else if ( op.UseSpecifiedNonce() == true ) {
838
709
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
839
709
                    op.nonce.ToTrimmedString(),
840
709
                    specified_nonce), true);
841
696
        extraparams.noncefp = secp256k1_detail::nonce_function_schnorrsig;
842
696
        extraparams.ndata = specified_nonce;
843
696
    } else {
844
0
        CF_UNREACHABLE();
845
0
    }
846
847
    /* Manually set magic until this is fixed:
848
     * https://github.com/bitcoin-core/secp256k1/issues/962
849
     */
850
1.11k
    extraparams.magic[0] = 0xDA;
851
1.11k
    extraparams.magic[1] = 0x6F;
852
1.11k
    extraparams.magic[2] = 0xB3;
853
1.11k
    extraparams.magic[3] = 0x8C;
854
855
1.11k
    CF_CHECK_EQ(
856
1.11k
            secp256k1_detail::CheckRet(
857
1.11k
                secp256k1_schnorrsig_sign_custom(ctx.GetPtr(), sig_bytes.data(), input.GetPtr(), input.GetSize(), &keypair, &extraparams)
858
1.11k
        ), 1);
859
860
1.09k
    CF_CHECK_EQ(secp256k1_keypair_xonly_pub(ctx.GetPtr(), &pubkey, nullptr, &keypair), 1);
861
1.09k
    CF_CHECK_EQ(secp256k1_xonly_pubkey_serialize(ctx.GetPtr(), pubkey_bytes.data(), &pubkey), 1);
862
863
1.09k
    {
864
1.09k
        boost::multiprecision::cpp_int x, r, s;
865
866
1.09k
        boost::multiprecision::import_bits(x, pubkey_bytes.begin(), pubkey_bytes.end());
867
1.09k
        boost::multiprecision::import_bits(r, sig_bytes.begin(), sig_bytes.begin() + 32);
868
1.09k
        boost::multiprecision::import_bits(s, sig_bytes.begin() + 32, sig_bytes.end());
869
870
1.09k
        ret = component::Schnorr_Signature(
871
1.09k
                {secp256k1_detail::toString(r), secp256k1_detail::toString(s)},
872
1.09k
                {secp256k1_detail::toString(x), "0"});
873
1.09k
    }
874
875
1.27k
end:
876
1.27k
    util::UnsetGlobalDs();
877
878
1.27k
    return ret;
879
1.09k
}
880
881
582
std::optional<bool> secp256k1::OpSchnorr_Verify(operation::Schnorr_Verify& op) {
882
582
    std::optional<bool> ret = std::nullopt;
883
582
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
884
582
    util::SetGlobalDs(&ds);
885
886
582
    secp256k1_detail::Context ctx(ds, SECP256K1_CONTEXT_VERIFY);
887
582
    secp256k1_xonly_pubkey pubkey;
888
582
    uint8_t pubkey_bytes[32];
889
582
    uint8_t sig_bytes[64];
890
582
    Buffer input;
891
892
582
    CF_CHECK_EQ(op.curveType.Get(), CF_ECC_CURVE("secp256k1"));
893
894
582
    if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
895
280
        input = op.cleartext;
896
302
    } else if ( op.digestType.Get() == CF_DIGEST("SHA256") ) {
897
264
        input = op.cleartext.SHA256();
898
264
    } else {
899
38
        goto end;
900
38
    }
901
902
    /* Beyond this point, a failure definitely means that the
903
     * pubkey or signature is invalid */
904
544
    ret = false;
905
906
544
    CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
907
544
                op.signature.pub.first.ToTrimmedString(),
908
544
                pubkey_bytes), true);
909
910
535
    CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
911
535
                op.signature.signature.first.ToTrimmedString(),
912
535
                sig_bytes), true);
913
525
    CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
914
525
                op.signature.signature.second.ToTrimmedString(),
915
525
                sig_bytes + 32), true);
916
917
512
    CF_CHECK_EQ(secp256k1_xonly_pubkey_parse(ctx.GetPtr(), &pubkey, pubkey_bytes), 1);
918
919
453
    ret = secp256k1_detail::CheckRet(
920
453
            secp256k1_schnorrsig_verify(ctx.GetPtr(), sig_bytes, input.GetPtr(), input.GetSize(), &pubkey)
921
453
            ) == 1 ? true : false;
922
923
582
end:
924
582
    util::UnsetGlobalDs();
925
926
582
    return ret;
927
453
}
928
#endif
929
930
#if !defined(SECP256K1_COMMIT_cb32940df3e20ccdcbee7eaf5cda93c18a92fb3e) && \
931
    !defined(SECP255K1_COMMIT_9d560f992db26612ce2630b194aef5f44d63a530)
932
707
std::optional<component::Secret> secp256k1::OpECDH_Derive(operation::ECDH_Derive& op) {
933
707
    std::optional<component::Secret> ret = std::nullopt;
934
707
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
935
707
    util::SetGlobalDs(&ds);
936
937
707
    secp256k1_detail::Context ctx(ds, SECP256K1_CONTEXT_SIGN);
938
707
    secp256k1_detail::Pubkey pub(ds, ctx);
939
707
    uint8_t privkey_bytes[32];
940
707
    uint8_t pubkey_bytes[65];
941
707
    uint8_t out[32];
942
943
707
    CF_CHECK_EQ(op.curveType.Get(), CF_ECC_CURVE("secp256k1"));
944
945
707
    memset(out, 0, 32);
946
947
707
    CF_CHECK_TRUE(secp256k1_detail::PrivkeyToBytes(op.priv, privkey_bytes));
948
687
    CF_CHECK_TRUE(secp256k1_detail::PubkeyToBytes(op.pub, pubkey_bytes));
949
950
645
    CF_CHECK_TRUE(pub.Parse(pubkey_bytes, sizeof(pubkey_bytes)));
951
952
496
    CF_CHECK_TRUE(pub.ECDH(out, privkey_bytes));
953
954
478
#if !defined(CRYPTOFUZZ_DISABLE_SPECIAL_ECDH)
955
478
    ret = component::Secret(Buffer(out, sizeof(out)));
956
478
#endif
957
958
707
end:
959
707
    util::UnsetGlobalDs();
960
707
    return ret;
961
478
}
962
#endif
963
964
namespace secp256k1_detail {
965
1.78k
    bool ToScalar(void* scalar, const component::Bignum& bn) {
966
1.78k
        bool ret = false;
967
1.78k
        std::optional<std::vector<uint8_t>> bin;
968
1.78k
        int overflow;
969
970
1.78k
        CF_CHECK_NE(bin = util::DecToBin(bn.ToTrimmedString(), 32), std::nullopt);
971
1.73k
        CF_NORET(cryptofuzz_secp256k1_scalar_set_b32(scalar, bin->data(), &overflow));
972
1.73k
        CF_CHECK_EQ(overflow, 0);
973
974
1.73k
        ret = true;
975
1.78k
end:
976
1.78k
        return ret;
977
1.73k
    }
978
979
0
    bool ToFe(void* fe, const component::Bignum& bn) {
980
0
        bool ret = false;
981
0
        std::optional<std::vector<uint8_t>> bin;
982
983
0
        CF_CHECK_NE(bin = util::DecToBin(bn.ToTrimmedString(), 32), std::nullopt);
984
0
        CF_CHECK_EQ(cryptofuzz_secp256k1_fe_set_b32_limit(fe, bin->data()), 1);
985
986
0
        ret = true;
987
0
end:
988
0
        return ret;
989
0
    }
990
991
0
    std::optional<component::Bignum> ToComponentBignum_scalar(const void* scalar) {
992
0
        std::optional<component::Bignum> ret = std::nullopt;
993
994
0
        uint8_t scalar_bytes[32];
995
996
0
        CF_NORET(cryptofuzz_secp256k1_scalar_get_b32(scalar_bytes, scalar));
997
998
0
        ret = component::Bignum(util::BinToDec(scalar_bytes, sizeof(scalar_bytes)));
999
1000
0
        return ret;
1001
0
    }
1002
1003
0
    std::optional<component::Bignum> ToComponentBignum_fe(fuzzing::datasource::Datasource& ds, void* fe) {
1004
0
        std::optional<component::Bignum> ret = std::nullopt;
1005
1006
0
        uint8_t fe_bytes[32];
1007
1008
0
        bool var = false;
1009
0
        try { var = ds.Get<bool>(); } catch ( ... ) { }
1010
1011
0
        CF_NORET(cryptofuzz_secp256k1_fe_get_b32(fe_bytes, fe, var ? 1 : 0));
1012
1013
0
        ret = component::Bignum(util::BinToDec(fe_bytes, sizeof(fe_bytes)));
1014
1015
0
        return ret;
1016
0
    }
1017
}
1018
1019
383
std::optional<component::ECC_Point> secp256k1::OpECC_Point_Add(operation::ECC_Point_Add& op) {
1020
383
    std::optional<component::ECC_Point> ret = std::nullopt;
1021
383
    if ( !op.curveType.Is(CF_ECC_CURVE("secp256k1")) ) {
1022
0
        return ret;
1023
0
    }
1024
383
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1025
1026
383
    void* a_ge = util::malloc(cryptofuzz_secp256k1_ge_size());
1027
383
    void* b_ge = util::malloc(cryptofuzz_secp256k1_ge_size());
1028
383
    void* res_ge = util::malloc(cryptofuzz_secp256k1_ge_size());
1029
1030
383
    void* a_gej = util::malloc(cryptofuzz_secp256k1_gej_size());
1031
383
    void* b_gej = util::malloc(cryptofuzz_secp256k1_gej_size());
1032
383
    void* res_gej = util::malloc(cryptofuzz_secp256k1_gej_size());
1033
1034
383
    {
1035
383
        uint8_t point_bytes[65];
1036
383
        point_bytes[0] = 4;
1037
383
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
1038
383
                    op.a.first.ToTrimmedString(),
1039
383
                    point_bytes + 1), true);
1040
356
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
1041
356
                    op.a.second.ToTrimmedString(),
1042
356
                    point_bytes + 1 + 32), true);
1043
1044
338
        CF_CHECK_EQ(
1045
338
                secp256k1_detail::CheckRet(
1046
338
                    cryptofuzz_secp256k1_eckey_pubkey_parse(a_ge, point_bytes, sizeof(point_bytes))
1047
338
                ), 1);
1048
159
    }
1049
1050
0
    {
1051
159
        uint8_t point_bytes[65];
1052
159
        point_bytes[0] = 4;
1053
159
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
1054
159
                    op.b.first.ToTrimmedString(),
1055
159
                    point_bytes + 1), true);
1056
148
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
1057
148
                    op.b.second.ToTrimmedString(),
1058
148
                    point_bytes + 1 + 32), true);
1059
1060
135
        CF_CHECK_EQ(
1061
135
                secp256k1_detail::CheckRet(
1062
135
                    cryptofuzz_secp256k1_eckey_pubkey_parse(b_ge, point_bytes, sizeof(point_bytes))
1063
135
                ), 1);
1064
88
    }
1065
1066
88
    CF_NORET(cryptofuzz_secp256k1_gej_set_ge(a_gej, a_ge));
1067
88
    CF_NORET(cryptofuzz_secp256k1_gej_set_ge(b_gej, b_ge));
1068
1069
88
    {
1070
88
        bool var = false;
1071
88
        try { var = ds.Get<bool>(); } catch ( ... ) { }
1072
1073
88
        if ( var == false ) {
1074
60
            CF_NORET(cryptofuzz_secp256k1_gej_add_ge(res_gej, a_gej, b_gej));
1075
60
        } else {
1076
28
            CF_NORET(cryptofuzz_secp256k1_gej_add_ge_var(res_gej, a_gej, b_ge, nullptr));
1077
28
        }
1078
88
    }
1079
1080
88
    CF_NORET(cryptofuzz_secp256k1_ge_set_gej(res_ge, res_gej));
1081
1082
88
    {
1083
88
        std::vector<uint8_t> point_bytes(65);
1084
88
        size_t point_bytes_size = point_bytes.size();
1085
88
        CF_CHECK_EQ(
1086
88
                secp256k1_detail::CheckRet(
1087
88
                    cryptofuzz_secp256k1_eckey_pubkey_serialize(res_ge, point_bytes.data(), &point_bytes_size, 0)
1088
88
                    ), 1);
1089
1090
80
        {
1091
80
            boost::multiprecision::cpp_int x, y;
1092
1093
80
            boost::multiprecision::import_bits(x, point_bytes.begin() + 1, point_bytes.begin() + 1 + 32);
1094
80
            boost::multiprecision::import_bits(y, point_bytes.begin() + 1 + 32, point_bytes.end());
1095
1096
80
            ret = {secp256k1_detail::toString(x), secp256k1_detail::toString(y)};
1097
80
        }
1098
80
    }
1099
1100
383
end:
1101
383
    util::free(a_ge);
1102
383
    util::free(b_ge);
1103
383
    util::free(res_ge);
1104
1105
383
    util::free(a_gej);
1106
383
    util::free(b_gej);
1107
383
    util::free(res_gej);
1108
1109
383
    return ret;
1110
80
}
1111
1112
2.04k
std::optional<component::ECC_Point> secp256k1::OpECC_Point_Mul(operation::ECC_Point_Mul& op) {
1113
2.04k
    std::optional<component::ECC_Point> ret = std::nullopt;
1114
2.04k
    if ( !op.curveType.Is(CF_ECC_CURVE("secp256k1")) ) {
1115
0
        return ret;
1116
0
    }
1117
2.04k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1118
1119
2.04k
    void* a_ge = util::malloc(cryptofuzz_secp256k1_ge_size());
1120
2.04k
    void* b = util::malloc(cryptofuzz_secp256k1_scalar_type_size());
1121
2.04k
    void* res_ge = util::malloc(cryptofuzz_secp256k1_ge_size());
1122
1123
2.04k
    void* a_gej = util::malloc(cryptofuzz_secp256k1_gej_size());
1124
2.04k
    void* res_gej = util::malloc(cryptofuzz_secp256k1_gej_size());
1125
1126
2.04k
    {
1127
2.04k
        uint8_t point_bytes[65];
1128
2.04k
        point_bytes[0] = 4;
1129
2.04k
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
1130
2.04k
                    op.a.first.ToTrimmedString(),
1131
2.04k
                    point_bytes + 1), true);
1132
2.02k
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
1133
2.02k
                    op.a.second.ToTrimmedString(),
1134
2.02k
                    point_bytes + 1 + 32), true);
1135
1136
1.99k
        CF_CHECK_EQ(cryptofuzz_secp256k1_eckey_pubkey_parse(a_ge, point_bytes, sizeof(point_bytes)), 1);
1137
1.78k
    }
1138
1139
1.78k
    CF_CHECK_TRUE(secp256k1_detail::ToScalar(b, op.b));
1140
1141
1.73k
    CF_NORET(cryptofuzz_secp256k1_gej_set_ge(a_gej, a_ge));
1142
1143
1.73k
#if \
1144
1.73k
    !defined(SECP256K1_COMMIT_642cd062bdd2d28a8a84d4cb6dedbfe435ee5869) && \
1145
1.73k
    !defined(SECP256K1_COMMIT_c663397f46152e96c548ba392858c730e132dd7a) && \
1146
1.73k
    !defined(SECP256K1_COMMIT_cb32940df3e20ccdcbee7eaf5cda93c18a92fb3e) && \
1147
1.73k
    !defined(SECP255K1_COMMIT_9d560f992db26612ce2630b194aef5f44d63a530)
1148
1.73k
    CF_NORET(cryptofuzz_secp256k1_ecmult(res_gej, a_gej, b, nullptr));
1149
#else
1150
    /* TODO */
1151
    goto end;
1152
#endif
1153
1154
1.73k
    CF_NORET(cryptofuzz_secp256k1_ge_set_gej(res_ge, res_gej));
1155
1156
1.73k
    {
1157
1.73k
        std::vector<uint8_t> point_bytes(65);
1158
1.73k
        size_t point_bytes_size = point_bytes.size();
1159
1.73k
        {
1160
1.73k
            const bool ok = cryptofuzz_secp256k1_eckey_pubkey_serialize(res_ge, point_bytes.data(), &point_bytes_size, 0) == 1;
1161
1.73k
            if ( cryptofuzz_secp256k1_scalar_is_zero(b) ) {
1162
30
                CF_ASSERT(ok == false, "Point multiplication by 0 does not yield point at infinity");
1163
30
                goto end;
1164
30
            }
1165
1166
1.70k
            CF_ASSERT(ok == true, "Point multiplication of valid point yields invalid point");
1167
1.70k
        }
1168
1169
0
        {
1170
1.70k
            boost::multiprecision::cpp_int x, y;
1171
1172
1.70k
            boost::multiprecision::import_bits(x, point_bytes.begin() + 1, point_bytes.begin() + 1 + 32);
1173
1.70k
            boost::multiprecision::import_bits(y, point_bytes.begin() + 1 + 32, point_bytes.end());
1174
1175
1.70k
            ret = {secp256k1_detail::toString(x), secp256k1_detail::toString(y)};
1176
1.70k
        }
1177
1.70k
    }
1178
1179
2.04k
end:
1180
2.04k
    util::free(a_ge);
1181
2.04k
    util::free(b);
1182
2.04k
    util::free(res_ge);
1183
1184
2.04k
    util::free(a_gej);
1185
2.04k
    util::free(res_gej);
1186
1187
2.04k
    return ret;
1188
1.70k
}
1189
1190
286
std::optional<component::ECC_Point> secp256k1::OpECC_Point_Neg(operation::ECC_Point_Neg& op) {
1191
286
    std::optional<component::ECC_Point> ret = std::nullopt;
1192
286
    if ( !op.curveType.Is(CF_ECC_CURVE("secp256k1")) ) {
1193
0
        return ret;
1194
0
    }
1195
286
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1196
1197
286
    void* a_ge = util::malloc(cryptofuzz_secp256k1_ge_size());
1198
286
    void* res_ge = util::malloc(cryptofuzz_secp256k1_ge_size());
1199
1200
286
    void* a_gej = util::malloc(cryptofuzz_secp256k1_gej_size());
1201
286
    void* res_gej = util::malloc(cryptofuzz_secp256k1_gej_size());
1202
1203
286
    {
1204
286
        uint8_t point_bytes[65];
1205
286
        point_bytes[0] = 4;
1206
286
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
1207
286
                    op.a.first.ToTrimmedString(),
1208
286
                    point_bytes + 1), true);
1209
252
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
1210
252
                    op.a.second.ToTrimmedString(),
1211
252
                    point_bytes + 1 + 32), true);
1212
1213
230
        CF_CHECK_EQ(
1214
230
                secp256k1_detail::CheckRet(
1215
230
                    cryptofuzz_secp256k1_eckey_pubkey_parse(a_ge, point_bytes, sizeof(point_bytes))
1216
230
                ), 1);
1217
66
    }
1218
1219
66
    CF_NORET(cryptofuzz_secp256k1_gej_set_ge(a_gej, a_ge));
1220
1221
66
    CF_NORET(cryptofuzz_secp256k1_gej_neg(res_gej, a_gej));
1222
1223
66
    CF_NORET(cryptofuzz_secp256k1_ge_set_gej(res_ge, res_gej));
1224
1225
66
    {
1226
66
        std::vector<uint8_t> point_bytes(65);
1227
66
        size_t point_bytes_size = point_bytes.size();
1228
1229
66
        {
1230
66
            const bool ok = secp256k1_detail::CheckRet(
1231
66
                    cryptofuzz_secp256k1_eckey_pubkey_serialize(res_ge, point_bytes.data(), &point_bytes_size, 0)
1232
66
                    ) == 1;
1233
66
            CF_ASSERT(ok, "Negation of valid point yields invalid point");
1234
66
        }
1235
1236
0
        {
1237
66
            boost::multiprecision::cpp_int x, y;
1238
1239
66
            boost::multiprecision::import_bits(x, point_bytes.begin() + 1, point_bytes.begin() + 1 + 32);
1240
66
            boost::multiprecision::import_bits(y, point_bytes.begin() + 1 + 32, point_bytes.end());
1241
1242
66
            ret = {secp256k1_detail::toString(x), secp256k1_detail::toString(y)};
1243
66
        }
1244
66
    }
1245
1246
286
end:
1247
286
    util::free(a_ge);
1248
286
    util::free(res_ge);
1249
1250
286
    util::free(a_gej);
1251
286
    util::free(res_gej);
1252
1253
286
    return ret;
1254
66
}
1255
1256
408
std::optional<component::ECC_Point> secp256k1::OpECC_Point_Dbl(operation::ECC_Point_Dbl& op) {
1257
408
    std::optional<component::ECC_Point> ret = std::nullopt;
1258
408
    if ( !op.curveType.Is(CF_ECC_CURVE("secp256k1")) ) {
1259
0
        return ret;
1260
0
    }
1261
408
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1262
1263
408
    void* a_ge = util::malloc(cryptofuzz_secp256k1_ge_size());
1264
408
    void* res_ge = util::malloc(cryptofuzz_secp256k1_ge_size());
1265
1266
408
    void* a_gej = util::malloc(cryptofuzz_secp256k1_gej_size());
1267
408
    void* res_gej = util::malloc(cryptofuzz_secp256k1_gej_size());
1268
1269
408
    {
1270
408
        uint8_t point_bytes[65];
1271
408
        point_bytes[0] = 4;
1272
408
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
1273
408
                    op.a.first.ToTrimmedString(),
1274
408
                    point_bytes + 1), true);
1275
381
        CF_CHECK_EQ(secp256k1_detail::EncodeBignum(
1276
381
                    op.a.second.ToTrimmedString(),
1277
381
                    point_bytes + 1 + 32), true);
1278
1279
354
        CF_CHECK_EQ(
1280
354
                secp256k1_detail::CheckRet(
1281
354
                    cryptofuzz_secp256k1_eckey_pubkey_parse(a_ge, point_bytes, sizeof(point_bytes))
1282
354
                ), 1);
1283
94
    }
1284
1285
94
    CF_NORET(cryptofuzz_secp256k1_gej_set_ge(a_gej, a_ge));
1286
1287
94
    {
1288
94
        bool var = false;
1289
94
        try { var = ds.Get<bool>(); } catch ( ... ) { }
1290
1291
94
#if \
1292
94
    !defined(SECP256K1_COMMIT_642cd062bdd2d28a8a84d4cb6dedbfe435ee5869) && \
1293
94
    !defined(SECP256K1_COMMIT_c663397f46152e96c548ba392858c730e132dd7a) && \
1294
94
    !defined(SECP256K1_COMMIT_cb32940df3e20ccdcbee7eaf5cda93c18a92fb3e) && \
1295
94
    !defined(SECP255K1_COMMIT_9d560f992db26612ce2630b194aef5f44d63a530)
1296
94
        if ( var == false ) {
1297
60
            CF_NORET(cryptofuzz_secp256k1_gej_double(res_gej, a_gej));
1298
60
        } else {
1299
34
            CF_NORET(cryptofuzz_secp256k1_gej_double_var(res_gej, a_gej, nullptr));
1300
34
        }
1301
#else
1302
        CF_NORET(cryptofuzz_secp256k1_gej_double_var(res_gej, a_gej, nullptr));
1303
#endif
1304
94
    }
1305
1306
94
    CF_NORET(cryptofuzz_secp256k1_ge_set_gej(res_ge, res_gej));
1307
1308
94
    {
1309
94
        std::vector<uint8_t> point_bytes(65);
1310
94
        size_t point_bytes_size = point_bytes.size();
1311
94
        CF_CHECK_EQ(
1312
94
                secp256k1_detail::CheckRet(
1313
94
                    cryptofuzz_secp256k1_eckey_pubkey_serialize(res_ge, point_bytes.data(), &point_bytes_size, 0)
1314
94
                    ), 1);
1315
1316
94
        {
1317
94
            boost::multiprecision::cpp_int x, y;
1318
1319
94
            boost::multiprecision::import_bits(x, point_bytes.begin() + 1, point_bytes.begin() + 1 + 32);
1320
94
            boost::multiprecision::import_bits(y, point_bytes.begin() + 1 + 32, point_bytes.end());
1321
1322
94
            ret = {secp256k1_detail::toString(x), secp256k1_detail::toString(y)};
1323
94
        }
1324
94
    }
1325
1326
408
end:
1327
408
    util::free(a_ge);
1328
408
    util::free(res_ge);
1329
1330
408
    util::free(a_gej);
1331
408
    util::free(res_gej);
1332
1333
408
    return ret;
1334
94
}
1335
1336
namespace secp256k1_detail {
1337
0
    std::optional<component::Bignum> OpBignumCalc_Mod(operation::BignumCalc& op, const bool mod) {
1338
0
        std::optional<component::Bignum> ret = std::nullopt;
1339
0
        Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1340
1341
0
        void* a = util::malloc(cryptofuzz_secp256k1_scalar_type_size());
1342
0
        void* b = util::malloc(cryptofuzz_secp256k1_scalar_type_size());
1343
0
        void* res = util::malloc(cryptofuzz_secp256k1_scalar_type_size());
1344
1345
0
        CF_CHECK_TRUE(secp256k1_detail::ToScalar(a, op.bn0));
1346
0
        CF_CHECK_TRUE(secp256k1_detail::ToScalar(b, op.bn1));
1347
1348
0
        switch ( op.calcOp.Get() ) {
1349
0
            case    CF_CALCOP("IsZero(A)"):
1350
0
                CF_NORET(cryptofuzz_secp256k1_scalar_set_int(
1351
0
                            res,
1352
0
                            cryptofuzz_secp256k1_scalar_is_zero(a)));
1353
0
                break;
1354
0
            case    CF_CALCOP("IsOne(A)"):
1355
0
                CF_NORET(cryptofuzz_secp256k1_scalar_set_int(
1356
0
                            res,
1357
0
                            cryptofuzz_secp256k1_scalar_is_one(a)));
1358
0
                break;
1359
0
            case    CF_CALCOP("IsEven(A)"):
1360
0
                CF_NORET(cryptofuzz_secp256k1_scalar_set_int(
1361
0
                            res,
1362
0
                            cryptofuzz_secp256k1_scalar_is_even(a)));
1363
0
                break;
1364
0
            case    CF_CALCOP("IsEq(A,B)"):
1365
0
                CF_NORET(cryptofuzz_secp256k1_scalar_set_int(
1366
0
                            res,
1367
0
                            cryptofuzz_secp256k1_scalar_eq(a, b)));
1368
0
                break;
1369
0
            case    CF_CALCOP("Add(A,B)"):
1370
0
                {
1371
0
                    const auto overflow = secp256k1_detail::CheckRet(
1372
0
                            cryptofuzz_secp256k1_scalar_add(res, a, b)
1373
0
                            );
1374
1375
                    /* Ignore overflow in mod mode */
1376
0
                    if ( mod == false ) {
1377
0
                        CF_CHECK_EQ(overflow, 0);
1378
0
                    }
1379
0
                }
1380
0
                break;
1381
0
            case    CF_CALCOP("Mul(A,B)"):
1382
0
                CF_CHECK_TRUE(mod);
1383
0
                CF_NORET(cryptofuzz_secp256k1_scalar_mul(res, a, b));
1384
0
                break;
1385
0
            case    CF_CALCOP("InvMod(A,B)"):
1386
0
                {
1387
0
                    CF_CHECK_TRUE(mod);
1388
1389
0
                    bool var = false;
1390
0
                    try { var = ds.Get<bool>(); } catch ( ... ) { }
1391
1392
0
                    if ( var == false ) {
1393
0
                        CF_NORET(cryptofuzz_secp256k1_scalar_inverse(res, a));
1394
0
                    } else {
1395
0
                        CF_NORET(cryptofuzz_secp256k1_scalar_inverse_var(res, a));
1396
0
                    }
1397
0
                }
1398
0
                break;
1399
0
#if \
1400
0
    !defined(SECP256K1_COMMIT_642cd062bdd2d28a8a84d4cb6dedbfe435ee5869) && \
1401
0
    !defined(SECP256K1_COMMIT_c663397f46152e96c548ba392858c730e132dd7a) && \
1402
0
    !defined(SECP256K1_COMMIT_cb32940df3e20ccdcbee7eaf5cda93c18a92fb3e) && \
1403
0
    !defined(SECP255K1_COMMIT_9d560f992db26612ce2630b194aef5f44d63a530)
1404
0
            case    CF_CALCOP("CondSet(A,B)"):
1405
0
                memset(res, 0, cryptofuzz_secp256k1_scalar_type_size());
1406
0
                CF_NORET(cryptofuzz_secp256k1_scalar_cmov(
1407
0
                            res,
1408
0
                            a,
1409
0
                            !cryptofuzz_secp256k1_scalar_is_zero(b)));
1410
0
                break;
1411
0
#endif
1412
0
            case    CF_CALCOP("Bit(A,B)"):
1413
0
                {
1414
0
                    std::optional<std::vector<uint8_t>> bin;
1415
0
                    CF_CHECK_NE(bin = util::DecToBin(op.bn1.ToTrimmedString(), 1), std::nullopt);
1416
0
                    const auto offset = bin->data()[0];
1417
0
                    CF_CHECK_LT(offset, 32);
1418
1419
0
                    bool var = false;
1420
0
                    try { var = ds.Get<bool>(); } catch ( ... ) { }
1421
1422
0
                    if ( var == false ) {
1423
0
                        CF_NORET(cryptofuzz_secp256k1_scalar_set_int(
1424
0
                                    res,
1425
0
                                    cryptofuzz_secp256k1_scalar_get_bits_limb32(a, offset, 1)));
1426
0
                    } else {
1427
0
                        CF_NORET(cryptofuzz_secp256k1_scalar_set_int(
1428
0
                                    res,
1429
0
                                    cryptofuzz_secp256k1_scalar_get_bits_var(a, offset, 1)));
1430
0
                    }
1431
0
                }
1432
0
                break;
1433
0
            case    CF_CALCOP("Set(A)"):
1434
0
                {
1435
0
                    std::optional<std::vector<uint8_t>> bin;
1436
0
                    CF_CHECK_NE(bin = util::DecToBin(op.bn0.ToTrimmedString(), 1), std::nullopt);
1437
0
                    CF_NORET(cryptofuzz_secp256k1_scalar_set_int(res, bin->data()[0]));
1438
0
                }
1439
0
                break;
1440
0
            default:
1441
0
                goto end;
1442
0
        }
1443
1444
0
        ret = secp256k1_detail::ToComponentBignum_scalar(res);
1445
1446
0
end:
1447
0
        util::free(a);
1448
0
        util::free(b);
1449
0
        util::free(res);
1450
1451
0
        return ret;
1452
0
    }
1453
1454
0
    std::optional<component::Bignum> OpBignumCalc_Prime(operation::BignumCalc& op, const bool mod) {
1455
0
        std::optional<component::Bignum> ret = std::nullopt;
1456
0
        if ( mod == false ) {
1457
            /* XXX */
1458
0
            return ret;
1459
0
        }
1460
0
        Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1461
1462
0
        void* a = util::malloc(cryptofuzz_secp256k1_fe_size());
1463
0
        void* b = util::malloc(cryptofuzz_secp256k1_fe_size());
1464
0
        void* res = util::malloc(cryptofuzz_secp256k1_fe_size());
1465
1466
0
        CF_CHECK_TRUE(secp256k1_detail::ToFe(a, op.bn0));
1467
0
        CF_CHECK_TRUE(secp256k1_detail::ToFe(b, op.bn1));
1468
1469
0
        switch ( op.calcOp.Get() ) {
1470
0
            case    CF_CALCOP("Add(A,B)"):
1471
0
                {
1472
0
                    CF_NORET(cryptofuzz_secp256k1_fe_add(a, b));
1473
0
                    memcpy(res, a, cryptofuzz_secp256k1_fe_size());
1474
0
                }
1475
0
                break;
1476
0
            case    CF_CALCOP("Mul(A,B)"):
1477
0
                {
1478
0
                    CF_NORET(cryptofuzz_secp256k1_fe_mul(res, a, b));
1479
0
                }
1480
0
                break;
1481
0
            case    CF_CALCOP("Sqr(A)"):
1482
0
                {
1483
0
                    CF_NORET(cryptofuzz_secp256k1_fe_sqr(res, a));
1484
0
                }
1485
0
                break;
1486
0
            case    CF_CALCOP("InvMod(A,B)"):
1487
0
                {
1488
0
                    bool var = false;
1489
0
                    try { var = ds.Get<bool>(); } catch ( ... ) { }
1490
1491
0
                    if ( var == false ) {
1492
0
                        CF_NORET(cryptofuzz_secp256k1_fe_inv(res, a));
1493
0
                    } else {
1494
0
                        CF_NORET(cryptofuzz_secp256k1_fe_inv_var(res, a));
1495
0
                    }
1496
0
                }
1497
0
                break;
1498
0
            case    CF_CALCOP("Sqrt(A)"):
1499
0
                {
1500
0
                    if ( cryptofuzz_secp256k1_fe_sqrt(res, a) == 1 ) {
1501
0
                        CF_NORET(cryptofuzz_secp256k1_fe_sqr(res, res));
1502
0
                    } else {
1503
0
                        CF_NORET(cryptofuzz_secp256k1_fe_clear(res));
1504
0
                    }
1505
0
                }
1506
0
                break;
1507
0
            case    CF_CALCOP("IsOdd(A)"):
1508
0
                {
1509
0
                    CF_NORET(cryptofuzz_secp256k1_fe_set_int(res,
1510
0
                        cryptofuzz_secp256k1_fe_is_odd(a)
1511
0
                    ));
1512
0
                }
1513
0
                break;
1514
0
            case    CF_CALCOP("IsZero(A)"):
1515
0
                {
1516
0
                    CF_NORET(cryptofuzz_secp256k1_fe_set_int(res,
1517
0
                        cryptofuzz_secp256k1_fe_is_zero(a)
1518
0
                    ));
1519
0
                }
1520
0
                break;
1521
0
            case    CF_CALCOP("IsEq(A,B)"):
1522
0
                {
1523
0
                    const int r = cryptofuzz_secp256k1_fe_equal(a, b);
1524
1525
0
                    CF_NORET(cryptofuzz_secp256k1_fe_set_int(res, r));
1526
0
                }
1527
0
                break;
1528
0
            case    CF_CALCOP("Cmp(A,B)"):
1529
0
                {
1530
0
                    const auto r = cryptofuzz_secp256k1_fe_cmp_var(a, b);
1531
1532
0
                    ret = component::Bignum(std::to_string(r));
1533
1534
0
                    goto end;
1535
0
                }
1536
0
                break;
1537
0
            case    CF_CALCOP("CondSet(A,B)"):
1538
0
                {
1539
0
                    CF_NORET(cryptofuzz_secp256k1_fe_clear(res));
1540
1541
0
                    CF_NORET(cryptofuzz_secp256k1_fe_cmov(
1542
0
                                res,
1543
0
                                a,
1544
0
                                !cryptofuzz_secp256k1_fe_is_zero(b)));
1545
0
                }
1546
0
                break;
1547
0
            case    CF_CALCOP("Set(A)"):
1548
0
                {
1549
0
                    uint8_t which = 0;
1550
0
                    try { which = ds.Get<uint8_t>() % 2; } catch ( ... ) { }
1551
1552
0
                    switch ( which ) {
1553
0
                        case    0:
1554
0
                            {
1555
0
                                void* r = util::malloc(cryptofuzz_secp256k1_fe_storage_size());
1556
0
                                CF_NORET(cryptofuzz_secp256k1_fe_to_storage(r, a));
1557
0
                                CF_NORET(cryptofuzz_secp256k1_fe_from_storage(res, r));
1558
0
                                util::free(r);
1559
0
                            }
1560
0
                            break;
1561
0
                        case    1:
1562
0
                            {
1563
#ifdef SECP256K1_WIDEMUL_INT128
1564
                                void* r = util::malloc(cryptofuzz_secp256k1_fe_signed62_size());
1565
                                CF_NORET(cryptofuzz_secp256k1_fe_to_signed62(r, a));
1566
                                CF_NORET(cryptofuzz_secp256k1_fe_from_signed62(res, r));
1567
                                util::free(r);
1568
#else
1569
0
                                goto end;
1570
0
#endif
1571
0
                            }
1572
0
                            break;
1573
0
                        default:
1574
0
                            CF_UNREACHABLE();
1575
0
                            break;
1576
0
                    }
1577
0
                }
1578
0
                break;
1579
0
            default:
1580
0
                goto end;
1581
0
        }
1582
1583
0
        ret = secp256k1_detail::ToComponentBignum_fe(ds, res);
1584
1585
0
end:
1586
0
        util::free(a);
1587
0
        util::free(b);
1588
0
        util::free(res);
1589
1590
0
        return ret;
1591
0
    }
1592
}
1593
1594
2.78k
std::optional<component::Bignum> secp256k1::OpBignumCalc(operation::BignumCalc& op) {
1595
2.78k
    if ( op.modulo == std::nullopt ) {
1596
0
        return secp256k1_detail::OpBignumCalc_Mod(op, false);
1597
2.78k
    } else if ( op.modulo->ToTrimmedString() == "115792089237316195423570985008687907852837564279074904382605163141518161494337" ) {
1598
0
        return secp256k1_detail::OpBignumCalc_Mod(op, true);
1599
2.78k
    } else if ( op.modulo->ToTrimmedString() == "115792089237316195423570985008687907853269984665640564039457584007908834671663" ) {
1600
0
        return secp256k1_detail::OpBignumCalc_Prime(op, true);
1601
2.78k
    } else {
1602
2.78k
        return std::nullopt;
1603
2.78k
    }
1604
2.78k
}
1605
1606
#if 0
1607
        case    CF_CALCOP("Sqrt(A)"):
1608
            {
1609
                secp256k1_fe_sqrt(&data->fe[0], &t);
1610
            }
1611
            break;
1612
#endif
1613
1614
2.78k
bool secp256k1::SupportsModularBignumCalc(void) const {
1615
2.78k
    return true;
1616
2.78k
}
1617
1618
} /* namespace module */
1619
} /* namespace cryptofuzz */