Coverage Report

Created: 2024-06-28 06:19

/src/cryptofuzz/modules/libecc/module.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "module.h"
2
#include <cryptofuzz/util.h>
3
#include <cryptofuzz/repository.h>
4
#include <boost/lexical_cast.hpp>
5
#include <iostream>
6
7
#define STRINGIFY(x) #x
8
#define TOSTRING(x) STRINGIFY(x)
9
10
extern "C" {
11
    #include <libecc/libsig.h>
12
    #include <libecc/hash/hmac.h>
13
}
14
15
namespace cryptofuzz {
16
namespace module {
17
namespace libecc_detail {
18
    Datasource* global_ds = nullptr;
19
    FILE* fp_dev_urandom = nullptr;
20
    const ec_sig_mapping *sm_ecdsa, *sm_ecgdsa, *sm_ecrdsa;
21
22
    std::map<uint64_t, const ec_str_params*> curveLUT;
23
24
90
    static void AddCurve(const uint64_t curveID, const std::string& curveName) {
25
90
        int ret;
26
90
        const ec_str_params *curve_params;
27
28
90
        ret = ec_get_curve_params_by_name((const u8*)curveName.c_str(), curveName.size() + 1, &curve_params);
29
30
90
        CF_ASSERT((!ret) && (curve_params != nullptr), "Cannot initialize curve");
31
32
90
        curveLUT[curveID] = curve_params;
33
90
    }
34
35
5.22k
    static const ec_str_params* GetCurve(const component::CurveType& curveType) {
36
5.22k
        if ( curveLUT.find(curveType.Get()) == curveLUT.end() ) {
37
0
            return nullptr;
38
0
        }
39
40
5.22k
        return curveLUT.at(curveType.Get());
41
5.22k
    }
42
1.30k
    std::optional<component::BignumPair> To_Component_BignumPair(const ec_pub_key& pub) {
43
1.30k
        std::optional<component::BignumPair> ret = std::nullopt;
44
45
1.30k
        uint8_t* out = nullptr;
46
1.30k
        const size_t outSize = EC_PUB_KEY_EXPORT_SIZE(&pub);
47
1.30k
        CF_ASSERT((outSize % 2) == 0, "Public key byte size is not even");
48
1.30k
        CF_ASSERT((outSize % 3) == 0, "Public key byte size is not multiple of 3");
49
1.30k
        out = util::malloc(outSize);
50
1.30k
        CF_CHECK_EQ(ec_pub_key_export_to_buf(&pub, out, outSize), 0);
51
1.30k
        {
52
1.30k
            const size_t pointSize = outSize / 3;
53
1.30k
            const auto X = util::BinToDec(out, pointSize);
54
1.30k
            const auto Y = util::BinToDec(out + pointSize, pointSize);
55
56
1.30k
            ret = {X, Y};
57
1.30k
        }
58
59
1.30k
end:
60
1.30k
        util::free(out);
61
62
1.30k
        return ret;
63
1.30k
    }
64
65
17.2k
    bool To_nn_t(const component::Bignum& bn, nn_t nn) {
66
17.2k
        const auto data = util::DecToBin(bn.ToTrimmedString());
67
17.2k
        if ( data == std::nullopt ) {
68
0
            return false;
69
0
        }
70
17.2k
        if ( (8 * data->size()) > NN_USABLE_MAX_BIT_LEN ) {
71
4.12k
            return false;
72
4.12k
        }
73
74
13.0k
        CF_ASSERT(!nn_init_from_buf(nn, data->data(), data->size()), "nn_init_from_buf error " __FILE__ ":" TOSTRING(__LINE__));
75
76
13.0k
        return true;
77
13.0k
    }
78
79
4.09k
    component::Bignum To_Component_Bignum(const nn_src_t nn, const bool negative = false) {
80
4.09k
        std::vector<uint8_t> data(nn->wlen * WORD_BYTES);
81
82
4.09k
        if ( data.size() == 0 ) {
83
850
            data.resize(1);
84
850
        }
85
86
4.09k
        CF_ASSERT(!nn_export_to_buf(data.data(), data.size(), nn), "nn_export_to_buf error " __FILE__ ":" TOSTRING(__LINE__));
87
88
4.09k
        const auto s = util::BinToDec(data.data(), data.size());
89
90
4.09k
        if ( negative && s != "0" ) {
91
51
            return std::string("-") + s;
92
4.04k
        } else {
93
4.04k
            return s;
94
4.04k
        }
95
4.09k
    }
96
97
262
    std::optional<uint16_t> To_uint16_t(const component::Bignum& bn) {
98
262
        const auto data = util::DecToBin(bn.ToTrimmedString(), sizeof(uint16_t));
99
262
        if ( data == std::nullopt ) {
100
69
            return std::nullopt;
101
69
        }
102
103
193
        return (((size_t)data->data()[0]) << 8) + data->data()[1];
104
262
    }
105
106
1.60k
    const hash_mapping* To_hash_mapping(const uint64_t digestType) {
107
1.60k
        const hash_mapping *hm;
108
1.60k
        switch ( digestType ) {
109
196
            case    CF_DIGEST("SHA224"):
110
196
                CF_ASSERT(!get_hash_by_type(SHA224, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
111
196
                return hm;
112
127
            case    CF_DIGEST("SHA256"):
113
127
                CF_ASSERT(!get_hash_by_type(SHA256, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
114
127
                return hm;
115
196
            case    CF_DIGEST("SHA384"):
116
196
                CF_ASSERT(!get_hash_by_type(SHA384, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
117
196
                return hm;
118
130
            case    CF_DIGEST("SHA512"):
119
130
                CF_ASSERT(!get_hash_by_type(SHA512, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
120
130
                return hm;
121
102
            case    CF_DIGEST("SHA512-224"):
122
102
                CF_ASSERT(!get_hash_by_type(SHA512_224, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
123
102
                return hm;
124
76
            case    CF_DIGEST("SHA512-256"):
125
76
                CF_ASSERT(!get_hash_by_type(SHA512_256, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
126
76
                return hm;
127
40
            case    CF_DIGEST("SHA3-224"):
128
40
                CF_ASSERT(!get_hash_by_type(SHA3_224, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
129
40
                return hm;
130
60
            case    CF_DIGEST("SHA3-256"):
131
60
                CF_ASSERT(!get_hash_by_type(SHA3_256, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
132
60
                return hm;
133
75
            case    CF_DIGEST("SHA3-384"):
134
75
                CF_ASSERT(!get_hash_by_type(SHA3_384, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
135
75
                return hm;
136
62
            case    CF_DIGEST("SHA3-512"):
137
62
                CF_ASSERT(!get_hash_by_type(SHA3_512, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
138
62
                return hm;
139
108
            case    CF_DIGEST("SM3"):
140
108
                CF_ASSERT(!get_hash_by_type(SM3, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
141
108
                return hm;
142
37
            case    CF_DIGEST("SHAKE256_114"):
143
37
                CF_ASSERT(!get_hash_by_type(SHAKE256, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
144
37
                return hm;
145
118
            case    CF_DIGEST("STREEBOG-256"):
146
118
                CF_ASSERT(!get_hash_by_type(STREEBOG256, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
147
118
                return hm;
148
77
            case    CF_DIGEST("STREEBOG-512"):
149
77
                CF_ASSERT(!get_hash_by_type(STREEBOG512, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
150
77
                return hm;
151
109
            case    CF_DIGEST("RIPEMD160"):
152
109
                CF_ASSERT(!get_hash_by_type(RIPEMD160, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
153
109
                return hm;
154
18
            case    CF_DIGEST("BASH224"):
155
18
                CF_ASSERT(!get_hash_by_type(BASH224, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
156
18
                return hm;
157
18
            case    CF_DIGEST("BASH256"):
158
18
                CF_ASSERT(!get_hash_by_type(BASH256, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
159
18
                return hm;
160
20
            case    CF_DIGEST("BASH384"):
161
20
                CF_ASSERT(!get_hash_by_type(BASH384, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
162
20
                return hm;
163
28
            case    CF_DIGEST("BASH512"):
164
28
                CF_ASSERT(!get_hash_by_type(BASH512, &hm) && (hm != nullptr), "get_hash_by_type error " __FILE__ ":" TOSTRING(__LINE__));
165
28
                return hm;
166
7
            default:
167
7
                return nullptr;
168
1.60k
        }
169
1.60k
    }
170
171
2.73k
    std::optional<hash_alg_type> To_hash_alg_type(const uint64_t digestType) {
172
2.73k
        switch ( digestType ) {
173
200
            case    CF_DIGEST("SHA224"):
174
200
                return SHA224;
175
482
            case    CF_DIGEST("SHA256"):
176
482
                return SHA256;
177
154
            case    CF_DIGEST("SHA384"):
178
154
                return SHA384;
179
139
            case    CF_DIGEST("SHA512"):
180
139
                return SHA512;
181
105
            case    CF_DIGEST("SHA512-224"):
182
105
                return SHA512_224;
183
125
            case    CF_DIGEST("SHA512-256"):
184
125
                return SHA512_256;
185
97
            case    CF_DIGEST("SHA3-224"):
186
97
                return SHA3_224;
187
123
            case    CF_DIGEST("SHA3-256"):
188
123
                return SHA3_256;
189
64
            case    CF_DIGEST("SHA3-384"):
190
64
                return SHA3_384;
191
91
            case    CF_DIGEST("SHA3-512"):
192
91
                return SHA3_512;
193
335
            case    CF_DIGEST("SM3"):
194
335
                return SM3;
195
66
            case    CF_DIGEST("SHAKE256_114"):
196
66
                return SHAKE256;
197
84
            case    CF_DIGEST("STREEBOG-256"):
198
84
                return STREEBOG256;
199
208
            case    CF_DIGEST("STREEBOG-512"):
200
208
                return STREEBOG512;
201
192
            case    CF_DIGEST("RIPEMD160"):
202
192
                return RIPEMD160;
203
50
            case    CF_DIGEST("BASH224"):
204
50
                return BASH224;
205
65
            case    CF_DIGEST("BASH256"):
206
65
                return BASH256;
207
69
            case    CF_DIGEST("BASH384"):
208
69
                return BASH384;
209
83
            case    CF_DIGEST("BASH512"):
210
83
                return BASH512;
211
3
            default:
212
3
                return std::nullopt;
213
2.73k
        }
214
2.73k
    }
215
}
216
}
217
}
218
219
16.9k
extern "C" int get_random(unsigned char *buf, u16 len) {
220
16.9k
    CF_ASSERT(cryptofuzz::module::libecc_detail::global_ds != nullptr, "Global datasource is NULL");
221
222
16.9k
    if ( len == 0 ) {
223
0
        return 0;
224
0
    }
225
226
16.9k
    try {
227
16.9k
        const auto data = cryptofuzz::module::libecc_detail::global_ds->GetData(0, len, len);
228
16.9k
        memcpy(buf, data.data(), len);
229
16.9k
        return 0;
230
16.9k
    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
231
232
14.0k
    CF_ASSERT(fread(buf, len, 1, cryptofuzz::module::libecc_detail::fp_dev_urandom) == 1, "Reading from /dev/urandom failed");
233
234
14.0k
    return 0;
235
14.0k
}
236
237
namespace cryptofuzz {
238
namespace module {
239
240
libecc::libecc(void) :
241
2
    Module("libecc") {
242
2
    CF_ASSERT((libecc_detail::fp_dev_urandom = fopen("/dev/urandom", "rb")) != NULL, "Failed to open /dev/urandom");
243
2
    CF_ASSERT((!get_sig_by_name("ECDSA", &(libecc_detail::sm_ecdsa))) && ((libecc_detail::sm_ecdsa) != nullptr), "Cannot initialize ECDSA");
244
2
    CF_ASSERT((!get_sig_by_name("ECGDSA", &(libecc_detail::sm_ecgdsa))) && ((libecc_detail::sm_ecgdsa) != nullptr), "Cannot initialize ECGDSA");
245
2
    CF_ASSERT((!get_sig_by_name("ECRDSA", &(libecc_detail::sm_ecrdsa))) && ((libecc_detail::sm_ecrdsa) != nullptr), "Cannot initialize ECRDSA");
246
247
    /* Load curves */
248
2
    libecc_detail::AddCurve(CF_ECC_CURVE("brainpool192r1"), "BRAINPOOLP192R1");
249
2
    libecc_detail::AddCurve(CF_ECC_CURVE("brainpool192t1"), "BRAINPOOLP192T1");
250
2
    libecc_detail::AddCurve(CF_ECC_CURVE("brainpool224r1"), "BRAINPOOLP224R1");
251
2
    libecc_detail::AddCurve(CF_ECC_CURVE("brainpool224t1"), "BRAINPOOLP224T1");
252
2
    libecc_detail::AddCurve(CF_ECC_CURVE("brainpool256r1"), "BRAINPOOLP256R1");
253
2
    libecc_detail::AddCurve(CF_ECC_CURVE("brainpool256t1"), "BRAINPOOLP256T1");
254
2
    libecc_detail::AddCurve(CF_ECC_CURVE("brainpool320r1"), "BRAINPOOLP320R1");
255
2
    libecc_detail::AddCurve(CF_ECC_CURVE("brainpool320t1"), "BRAINPOOLP320T1");
256
2
    libecc_detail::AddCurve(CF_ECC_CURVE("brainpool384r1"), "BRAINPOOLP384R1");
257
2
    libecc_detail::AddCurve(CF_ECC_CURVE("brainpool384t1"), "BRAINPOOLP384T1");
258
2
    libecc_detail::AddCurve(CF_ECC_CURVE("brainpool512r1"), "BRAINPOOLP512R1");
259
2
    libecc_detail::AddCurve(CF_ECC_CURVE("brainpool512t1"), "BRAINPOOLP512T1");
260
2
    libecc_detail::AddCurve(CF_ECC_CURVE("secp112r2"), "USER_DEFINED_SECP112R2");
261
2
    libecc_detail::AddCurve(CF_ECC_CURVE("secp128r2"), "USER_DEFINED_SECP128R2");
262
2
    libecc_detail::AddCurve(CF_ECC_CURVE("secp192r1"), "SECP192R1");
263
2
    libecc_detail::AddCurve(CF_ECC_CURVE("secp192k1"), "SECP192K1");
264
2
    libecc_detail::AddCurve(CF_ECC_CURVE("secp224r1"), "SECP224R1");
265
2
    libecc_detail::AddCurve(CF_ECC_CURVE("secp224k1"), "SECP224K1");
266
2
    libecc_detail::AddCurve(CF_ECC_CURVE("secp256r1"), "SECP256R1");
267
2
    libecc_detail::AddCurve(CF_ECC_CURVE("secp256k1"), "SECP256K1");
268
2
    libecc_detail::AddCurve(CF_ECC_CURVE("secp384r1"), "SECP384R1");
269
2
    libecc_detail::AddCurve(CF_ECC_CURVE("secp521r1"), "SECP521R1");
270
2
    libecc_detail::AddCurve(CF_ECC_CURVE("frp256v1"), "FRP256V1");
271
2
    libecc_detail::AddCurve(CF_ECC_CURVE("secp256k1"), "SECP256K1");
272
2
    libecc_detail::AddCurve(CF_ECC_CURVE("sm2p256v1"), "SM2P256V1");
273
2
    libecc_detail::AddCurve(CF_ECC_CURVE("gost_256A"), "GOST_R3410_2012_256_PARAMSETA");
274
2
    libecc_detail::AddCurve(CF_ECC_CURVE("gost_512A"), "GOST_R3410_2012_512_PARAMSETA");
275
2
    libecc_detail::AddCurve(CF_ECC_CURVE("gostr3410_2001_cryptopro_a"), "GOST_R3410_2001_CRYPTOPRO_A_PARAMSET");
276
2
    libecc_detail::AddCurve(CF_ECC_CURVE("gostr3410_2001_cryptopro_b"), "GOST_R3410_2001_CRYPTOPRO_B_PARAMSET");
277
2
    libecc_detail::AddCurve(CF_ECC_CURVE("gostr3410_2001_cryptopro_c"), "GOST_R3410_2001_CRYPTOPRO_C_PARAMSET");
278
2
    libecc_detail::AddCurve(CF_ECC_CURVE("gostr3410_2001_cryptopro_xcha"), "GOST_R3410_2001_CRYPTOPRO_XCHA_PARAMSET");
279
2
    libecc_detail::AddCurve(CF_ECC_CURVE("gostr3410_2001_cryptopro_xchb"), "GOST_R3410_2001_CRYPTOPRO_XCHB_PARAMSET");
280
2
    libecc_detail::AddCurve(CF_ECC_CURVE("gostr3410_2001_test"), "GOST_R3410_2001_TESTPARAMSET");
281
2
    libecc_detail::AddCurve(CF_ECC_CURVE("tc26_gost_3410_12_256_a"), "GOST_R3410_2012_256_PARAMSETA");
282
2
    libecc_detail::AddCurve(CF_ECC_CURVE("tc26_gost_3410_12_256_b"), "GOST_R3410_2012_256_PARAMSETB");
283
2
    libecc_detail::AddCurve(CF_ECC_CURVE("tc26_gost_3410_12_256_c"), "GOST_R3410_2012_256_PARAMSETC");
284
2
    libecc_detail::AddCurve(CF_ECC_CURVE("tc26_gost_3410_12_256_d"), "GOST_R3410_2012_256_PARAMSETD");
285
2
    libecc_detail::AddCurve(CF_ECC_CURVE("tc26_gost_3410_12_512_a"), "GOST_R3410_2012_512_PARAMSETA");
286
2
    libecc_detail::AddCurve(CF_ECC_CURVE("tc26_gost_3410_12_512_b"), "GOST_R3410_2012_512_PARAMSETB");
287
2
    libecc_detail::AddCurve(CF_ECC_CURVE("tc26_gost_3410_12_512_c"), "GOST_R3410_2012_512_PARAMSETC");
288
2
    libecc_detail::AddCurve(CF_ECC_CURVE("tc26_gost_3410_12_512_test"), "GOST_R3410_2012_512_PARAMSETTEST");
289
290
    /* NOTE: Ed25519 and Ed448 are mapped to WEI25519 and WEI448 by libecc
291
     * through isogenies.
292
     */
293
2
    libecc_detail::AddCurve(CF_ECC_CURVE("ed25519"), "WEI25519");
294
2
    libecc_detail::AddCurve(CF_ECC_CURVE("ed448"), "WEI448");
295
    /* NOTE: x25519 and x448 are mapped to WEI25519 and WEI448 by libecc
296
     * through isogenies.
297
     */
298
2
    libecc_detail::AddCurve(CF_ECC_CURVE("x25519"), "WEI25519");
299
2
    libecc_detail::AddCurve(CF_ECC_CURVE("x448"), "WEI448");
300
301
    /* TODO */
302
#if 0
303
    "GOST256"
304
    "GOST512"
305
#endif
306
2
}
307
308
1.60k
std::optional<component::Digest> libecc::OpDigest(operation::Digest& op) {
309
1.60k
    std::optional<component::Digest> ret = std::nullopt;
310
1.60k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
311
312
1.60k
    hash_context ctx;
313
1.60k
    uint8_t* out = nullptr;
314
1.60k
    const hash_mapping* hash;
315
316
1.60k
    CF_CHECK_NE(hash = libecc_detail::To_hash_mapping(op.digestType.Get()), nullptr);
317
318
    /* Initialize */
319
1.59k
    CF_ASSERT(!(hash->hfunc_init(&ctx)), "hfunc_init error " __FILE__ ":" TOSTRING(__LINE__));
320
321
1.59k
    {
322
    /* Process */
323
1.59k
        const auto parts = util::ToParts(ds, op.cleartext);
324
206k
        for (const auto& part : parts) {
325
206k
            if ( part.first == nullptr ) {
326
238
                continue;
327
238
            }
328
206k
            CF_ASSERT(!(hash->hfunc_update(&ctx, part.first, part.second)), "hfunc_update error " __FILE__ ":" TOSTRING(__LINE__));
329
206k
        }
330
1.59k
    }
331
332
    /* Finalize */
333
1.59k
    {
334
1.59k
        out = util::malloc(hash->digest_size);
335
1.59k
        CF_ASSERT(!(hash->hfunc_finalize(&ctx, out)), "hfunc_finalize error " __FILE__ ":" TOSTRING(__LINE__));
336
337
1.59k
        ret = component::Digest(out, hash->digest_size);
338
1.59k
    }
339
340
1.60k
end:
341
1.60k
    util::free(out);
342
343
1.60k
    return ret;
344
1.59k
}
345
346
1.23k
std::optional<component::MAC> libecc::OpHMAC(operation::HMAC& op) {
347
1.23k
    std::optional<component::MAC> ret = std::nullopt;
348
1.23k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
349
350
1.23k
    bool oneShot = false;
351
1.23k
    uint8_t outlen = 0;
352
1.23k
    uint8_t* out = nullptr;
353
1.23k
    std::optional<hash_alg_type> hash;
354
355
1.23k
    CF_CHECK_NE(hash = libecc_detail::To_hash_alg_type(op.digestType.Get()), std::nullopt);
356
357
1.23k
    try {
358
1.23k
        outlen = ds.Get<uint8_t>();
359
1.23k
    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
360
361
1.23k
    try {
362
1.23k
        oneShot = ds.Get<bool>();
363
1.23k
    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
364
365
1.23k
    out = util::malloc(outlen);
366
367
1.23k
    if ( oneShot == true ) {
368
602
        CF_CHECK_EQ(hmac(
369
602
                    op.cipher.key.GetPtr(),
370
602
                    op.cipher.key.GetSize(),
371
602
                    *hash,
372
602
                    op.cleartext.GetPtr(),
373
602
                    op.cleartext.GetSize(),
374
602
                    out, &outlen
375
602
                    ), 0);
376
377
317
        ret = component::Digest(out, outlen);
378
630
    } else {
379
630
        hmac_context ctx;
380
381
        /* Initialize */
382
630
        CF_CHECK_EQ(hmac_init(
383
630
                    &ctx,
384
630
                    op.cipher.key.GetPtr(),
385
630
                    op.cipher.key.GetSize(),
386
630
                    *hash), 0);
387
388
566
        {
389
566
            const auto parts = util::ToParts(ds, op.cleartext);
390
391
64.6k
            for (const auto& part : parts) {
392
64.6k
                if ( part.first == nullptr ) {
393
69
                    continue;
394
69
                }
395
396
64.5k
                CF_CHECK_EQ(hmac_update(&ctx, part.first, part.second), 0);
397
64.5k
            }
398
566
        }
399
400
        /* Finalize */
401
566
        {
402
566
            CF_CHECK_EQ(hmac_finalize(&ctx, out, &outlen), 0);
403
371
            ret = component::Digest(out, outlen);
404
371
        }
405
371
    }
406
407
1.23k
end:
408
1.23k
    util::free(out);
409
410
1.23k
    return ret;
411
1.23k
}
412
413
0
std::optional<component::ECC_KeyPair> libecc::OpECC_GenerateKeyPair(operation::ECC_GenerateKeyPair& op) {
414
0
    std::optional<component::ECC_KeyPair> ret = std::nullopt;
415
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
416
0
    libecc_detail::global_ds = &ds;
417
418
0
    const ec_str_params* curve_params;
419
0
    ec_params params;
420
0
    ec_key_pair kp;
421
0
  bitcnt_t priv_len;
422
0
    uint8_t* priv_bytes = nullptr;
423
424
0
    CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
425
0
    CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
426
0
    CF_CHECK_EQ(ec_key_pair_gen(&kp, &params, ECDSA), 0);
427
0
    CF_CHECK_EQ(nn_bitlen(&(kp.priv_key.x), &priv_len), 0);
428
0
    priv_len = (priv_len + 7) / 8;
429
0
    priv_bytes = util::malloc(priv_len);
430
0
    CF_CHECK_EQ(ec_priv_key_export_to_buf(&kp.priv_key, priv_bytes, priv_len), 0);
431
432
0
    {
433
0
        CF_CHECK_EQ(prj_pt_unique(&kp.pub_key.y, &kp.pub_key.y), 0);
434
0
        const auto pub = libecc_detail::To_Component_BignumPair(kp.pub_key);
435
0
        CF_CHECK_NE(pub, std::nullopt);
436
437
0
        ret = { util::BinToDec(priv_bytes, priv_len), *pub };
438
0
    }
439
440
0
end:
441
0
    libecc_detail::global_ds = nullptr;
442
0
    util::free(priv_bytes);
443
0
    return ret;
444
0
}
445
446
289
std::optional<bool> libecc::OpECC_ValidatePubkey(operation::ECC_ValidatePubkey& op) {
447
289
    std::optional<bool> ret = std::nullopt;
448
289
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
449
289
    libecc_detail::global_ds = &ds;
450
451
289
    const ec_str_params* curve_params;
452
289
    ec_params params;
453
289
    ec_pub_key pub_key;
454
455
    /* Load curve.
456
     * NOTE: this will be WEI25519 or WEI448 (libecc uses isogenies for ed25519, ed448, x25519 and x448)
457
     * for EdDSA and X25519/X448
458
     */
459
289
    CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
460
289
    CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
461
462
    /* Skip the ed25519, ed448, x25519 and x448 special cases */
463
289
    if ( op.curveType.Is(CF_ECC_CURVE("ed25519")) || op.curveType.Is(CF_ECC_CURVE("ed448")) ) {
464
        /* XXX: see if OpECC_ValidatePubkey is called on x coordinates only, or points on Edwards curves? */
465
0
        goto end;
466
0
    }
467
289
    if ( op.curveType.Is(CF_ECC_CURVE("x25519")) || op.curveType.Is(CF_ECC_CURVE("x448")) ) {
468
        /* XXX: see if OpECC_ValidatePubkey is called on x coordinates only encoded strings? */
469
0
        goto end;
470
0
    }
471
472
289
    {
473
        /* Generic case, extract X and Y, and check the point on the curve */
474
289
        const auto ax_bin = util::DecToBin(op.pub.first.ToTrimmedString());
475
289
        const auto ay_bin = util::DecToBin(op.pub.second.ToTrimmedString());
476
289
        fp x, y;
477
289
        bool x_inited = false, y_inited = false;
478
289
        u8 *pub_buff = NULL;
479
289
        u16 coord_len = (u16)BYTECEIL(params.ec_fp.p_bitlen);
480
481
289
        if(fp_init_from_buf(&x, &(params.ec_fp), ax_bin->data(), ax_bin->size())){
482
21
            ret = false;
483
21
            goto end1;
484
21
        }
485
268
        x_inited = true;
486
487
268
        if(fp_init_from_buf(&y, &(params.ec_fp), ay_bin->data(), ay_bin->size())){
488
23
            ret = false;
489
23
            goto end1;
490
23
        }
491
245
        y_inited = true;
492
493
        /* Allocate a buffer for our stringified public key */
494
245
        pub_buff = util::malloc(coord_len * 2);
495
496
245
        if(fp_export_to_buf(&pub_buff[0], coord_len, &x)){
497
0
            ret = false;
498
0
            goto end1;
499
0
        }
500
245
        if(fp_export_to_buf(&pub_buff[coord_len], coord_len, &y)){
501
0
            ret = false;
502
0
            goto end1;
503
0
        }
504
505
        /* Try to import the public key on the curve (and perform the underlying checks).
506
         * This will return an error if the public key is rejected!
507
         * NOTE: we choose randomly ECDSA as the signature algorithm type as all the signatures expect
508
   * a point on their curve anyways!
509
         */
510
245
        if(ec_pub_key_import_from_aff_buf(&pub_key, &params, &pub_buff[0], coord_len * 2, ECDSA)){
511
200
            ret = false;
512
200
            goto end1;
513
200
        }
514
515
45
        ret = true;
516
517
289
end1:
518
289
        if(pub_buff != NULL){
519
245
            util::free(pub_buff);
520
245
        }
521
289
        if ( x_inited == true ) {
522
268
            fp_uninit(&x);
523
268
        }
524
289
        if ( y_inited == true ) {
525
245
            fp_uninit(&y);
526
245
        }
527
289
    }
528
529
289
end:
530
289
    libecc_detail::global_ds = nullptr;
531
532
289
    return ret;
533
289
}
534
535
namespace libecc_detail {
536
1.44k
std::optional<component::ECC_PublicKey> OpECC_PrivateToPublic(Datasource& ds, const component::CurveType& curveType, const component::Bignum& _priv) {
537
1.44k
    std::optional<component::ECC_PublicKey> ret = std::nullopt;
538
539
1.44k
    libecc_detail::global_ds = &ds;
540
1.44k
    uint8_t* out = nullptr;
541
1.44k
    const ec_str_params* curve_params;
542
1.44k
    ec_params params;
543
1.44k
    ec_alg_type sig_type;
544
1.44k
    ec_priv_key priv;
545
1.44k
    ec_pub_key pub;
546
1.44k
    std::optional<std::vector<uint8_t>> priv_bytes;
547
    /* Load curve.
548
     * NOTE: this will be WEI25519 or WEI448 (libecc uses isogenies for ed25519, ed448, x25519 and x448)
549
     * for EdDSA and X25519/X448
550
     */
551
1.44k
    CF_CHECK_NE(curve_params = libecc_detail::GetCurve(curveType), nullptr);
552
1.44k
    CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
553
554
    /* EdDSA case is apart */
555
1.44k
    if ( curveType.Is(CF_ECC_CURVE("ed25519")) || curveType.Is(CF_ECC_CURVE("ed448")) ) {
556
0
        u8 key_size = 0;
557
0
        u8 pub_buff[57];
558
0
        if ( curveType.Is(CF_ECC_CURVE("ed25519")) ) {
559
0
            sig_type = EDDSA25519;
560
0
            key_size = 32;
561
0
        } else {
562
0
            sig_type = EDDSA448;
563
0
            key_size = 57;
564
0
        }
565
0
        CF_CHECK_NE(priv_bytes = util::DecToBin(_priv.ToTrimmedString(), key_size), std::nullopt);
566
        /* Import our private key */
567
0
        CF_ASSERT(!eddsa_import_priv_key(&priv, priv_bytes->data(), priv_bytes->size(), &params, sig_type), "eddsa_import_priv_key error " __FILE__ ":" TOSTRING(__LINE__));
568
        /* Import our public key */
569
0
        memset(&pub, 0, sizeof(pub));
570
0
        CF_ASSERT(!eddsa_init_pub_key(&pub, &priv), "eddsa_init_pub_key error" __FILE__ ":" TOSTRING(__LINE__));
571
        /* Export our public key to a buffer */
572
0
        memset(&pub_buff, 0, sizeof(pub_buff));
573
0
        CF_ASSERT(!eddsa_export_pub_key(&pub, pub_buff, key_size), "eddsa_export_pub_key error" __FILE__ ":" TOSTRING(__LINE__));
574
        /* Now export to a big int */
575
0
        {
576
0
            ret = { util::BinToDec(pub_buff, key_size), "0" };
577
0
        }
578
0
    }
579
    /* X25519/X448 case is apart */
580
1.44k
    else if ( curveType.Is(CF_ECC_CURVE("x25519")) || curveType.Is(CF_ECC_CURVE("x448")) ) {
581
0
        u8 key_size = 0;
582
0
        u8 pub_buff[56];
583
0
        if ( curveType.Is(CF_ECC_CURVE("x25519")) ) {
584
0
            key_size = 32;
585
0
        } else {
586
0
            key_size = 56;
587
0
        }
588
0
        CF_CHECK_NE(priv_bytes = util::DecToBin(_priv.ToTrimmedString(), key_size), std::nullopt);
589
        /* Derive our public key */
590
0
        memset(&pub_buff, 0, sizeof(pub_buff));
591
0
        if(key_size == 32){
592
0
            CF_ASSERT(!x25519_init_pub_key(priv_bytes->data(), pub_buff), "x25519_init_pub_key error" __FILE__ ":" TOSTRING(__LINE__));
593
0
        }
594
0
        else{
595
0
            CF_ASSERT(!x448_init_pub_key(priv_bytes->data(), pub_buff), "x448_init_pub_key error" __FILE__ ":" TOSTRING(__LINE__));
596
0
        }
597
        /* Now export to a big int */
598
0
        {
599
0
            ret = { util::BinToDec(pub_buff, key_size), "0" };
600
0
        }
601
0
    }
602
1.44k
    else {
603
1.44k
        CF_CHECK_NE(priv_bytes = util::DecToBin(_priv.ToTrimmedString()), std::nullopt);
604
1.44k
        CF_CHECK_LTE(8 * priv_bytes->size(), NN_USABLE_MAX_BIT_LEN);
605
606
1.41k
        sig_type = libecc_detail::sm_ecdsa->type;
607
608
1.41k
        CF_ASSERT(!ec_priv_key_import_from_buf(&priv, &params, priv_bytes->data(), priv_bytes->size(), sig_type), "ec_priv_key_import_from_buf error " __FILE__ ":" TOSTRING(__LINE__));
609
1.41k
        memset(&pub, 0, sizeof(pub));
610
1.41k
        CF_CHECK_EQ(init_pubkey_from_privkey(&pub, &priv), 0);
611
1.38k
        CF_CHECK_EQ(pub.magic, PUB_KEY_MAGIC);
612
613
        /* Get the unique affine point representation */
614
        /* prj_pt_unique can fail if scalar is 0 or multiple of curve order */
615
        /* TODO assert that IF it fails, it's because of this reason */
616
1.38k
        CF_CHECK_EQ(prj_pt_unique(&pub.y, &pub.y), 0);
617
618
1.30k
        {
619
1.30k
            const auto _ret = libecc_detail::To_Component_BignumPair(pub);
620
1.30k
            const auto order = cryptofuzz::repository::ECC_CurveToOrder(curveType.Get());
621
1.30k
            CF_CHECK_NE(order, std::nullopt);
622
1.24k
            CF_CHECK_TRUE(_priv.IsLessThan(*order));
623
1.24k
            ret = _ret;
624
1.24k
        }
625
1.24k
    }
626
1.44k
end:
627
1.44k
    util::free(out);
628
629
1.44k
    libecc_detail::global_ds = nullptr;
630
631
1.44k
    return ret;
632
1.44k
}
633
}
634
635
577
std::optional<component::ECC_PublicKey> libecc::OpECC_PrivateToPublic(operation::ECC_PrivateToPublic& op) {
636
577
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
637
638
577
    return libecc_detail::OpECC_PrivateToPublic(ds, op.curveType, op.priv);
639
577
}
640
641
642
namespace libecc_detail {
643
2.23k
    static bool IsValidECxDSASize(const Buffer& msg) {
644
        /* libecc does not adequately handle large ECxDSA messages due to
645
         * limitations of its bignum library.
646
         *
647
         * 64 bytes corresponds with the largest hash that could reasonably be
648
         * used in a real world scenario (like SHA-512) so let's limit it to that.
649
         */
650
2.23k
        return msg.GetSize() <= 64;
651
2.23k
    }
652
653
    typedef int (*ecxdsa_sign_raw_t)(struct ec_sign_context *ctx, const u8 *input, u8 inputlen, u8 *sig, u8 siglen, const u8 *nonce, u8 noncelen);
654
    typedef int (*ecxdsa_sign_update_t)(struct ec_sign_context *ctx, const u8 *chunk, u32 chunklen);
655
    typedef int (*ecxdsa_sign_finalize_t)(struct ec_sign_context *ctx, u8 *sig, u8 siglen);
656
    typedef int (*ecxdsa_rfc6979_sign_finalize_t)(struct ec_sign_context *ctx, u8 *sig, u8 siglen, ec_alg_type key_type);
657
658
    template <class Operation, ec_alg_type AlgType>
659
    std::optional<component::ECDSA_Signature> ECxDSA_Sign(
660
            const Operation& op,
661
            const ecxdsa_sign_raw_t ecxdsa_sign_raw,
662
            const ecxdsa_sign_update_t ecxdsa_sign_update,
663
            const ecxdsa_sign_finalize_t ecxdsa_sign_finalize,
664
1.11k
            const ecxdsa_rfc6979_sign_finalize_t ecxdsa_rfc6979_sign_finalize = nullptr) {
665
1.11k
        if ( IsValidECxDSASize(op.cleartext) == false ) {
666
62
            return std::nullopt;
667
62
        }
668
669
1.04k
        if ( op.UseRFC6979Nonce() && ecxdsa_rfc6979_sign_finalize == nullptr ) {
670
12
            return std::nullopt;
671
12
        }
672
673
1.03k
        std::optional<component::ECDSA_Signature> ret = std::nullopt;
674
675
1.03k
        Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
676
1.03k
        std::optional<component::ECC_PublicKey> pub = std::nullopt;
677
1.03k
        const ec_str_params* curve_params;
678
1.03k
        std::optional<std::vector<uint8_t>> priv_bytes;
679
1.03k
        ec_params params;
680
1.03k
        ec_key_pair kp;
681
1.03k
        struct ec_sign_context ctx;
682
1.03k
        size_t signature_size = 0;
683
1.03k
        uint8_t* signature = nullptr;
684
1.03k
        std::optional<std::vector<uint8_t>> nonce_bytes;
685
1.03k
        std::optional<hash_alg_type> hash;
686
1.03k
        util::Multipart parts;
687
1.03k
        const ec_alg_type alg = op.UseRFC6979Nonce() ? DECDSA : AlgType;
688
689
1.03k
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
690
750
            CF_CHECK_TRUE(op.UseRandomNonce() || op.UseRFC6979Nonce());
691
655
            CF_CHECK_NE(hash = libecc_detail::To_hash_alg_type(op.digestType.Get()), std::nullopt);
692
655
        } else {
693
286
            CF_CHECK_TRUE(op.UseSpecifiedNonce());
694
213
        }
695
696
868
        CF_CHECK_NE(pub = libecc_detail::OpECC_PrivateToPublic(ds, op.curveType, op.priv), std::nullopt);
697
698
819
        libecc_detail::global_ds = &ds;
699
700
        /* Load curve */
701
819
        CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
702
819
        CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
703
704
819
        {
705
819
            const auto priv_str = op.priv.ToTrimmedString();
706
819
            CF_CHECK_NE(priv_bytes = util::DecToBin(priv_str), std::nullopt);
707
819
            CF_CHECK_LTE((8 * priv_bytes->size()), NN_USABLE_MAX_BIT_LEN);
708
819
            CF_CHECK_EQ(ec_key_pair_import_from_priv_key_buf(&kp,
709
819
                        &params,
710
819
                        priv_bytes->data(), priv_bytes->size(),
711
819
                        alg), 0);
712
819
        }
713
714
819
        signature_size = ECDSA_SIGLEN(kp.priv_key.params->ec_gen_order_bitlen);
715
819
        CF_ASSERT((signature_size % 2) == 0, "Signature size is not multiple of 2");
716
819
        signature = util::malloc(signature_size);
717
718
819
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
719
205
            CF_CHECK_EQ(ec_sign_init(&ctx, &kp, alg, SHA256, nullptr, 0), 0);
720
614
        } else {
721
614
            CF_CHECK_EQ(ec_sign_init(&ctx, &kp, alg, *hash, nullptr, 0), 0);
722
614
        }
723
724
819
        if ( op.UseSpecifiedNonce() == true ) {
725
            /* ecdsa_sign_raw crashes if nonce is 0 */
726
205
            CF_CHECK_NE(op.nonce.ToTrimmedString(), "0");
727
728
187
            CF_CHECK_NE(nonce_bytes = util::DecToBin(op.nonce.ToTrimmedString()), std::nullopt);
729
730
            /* ecdsa_sign_raw supports nonce up to 255 bytes */
731
187
            CF_CHECK_LTE(nonce_bytes->size(), 255);
732
178
        }
733
734
792
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
735
614
            parts = util::ToParts(ds, op.cleartext);
736
614
        }
737
738
792
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
739
178
            CF_CHECK_EQ(ecxdsa_sign_raw(
740
178
                        &ctx,
741
178
                        op.cleartext.GetPtr(), op.cleartext.GetSize(),
742
178
                        signature, signature_size,
743
178
                        op.UseSpecifiedNonce() ? nonce_bytes->data() : nullptr,
744
178
                        op.UseSpecifiedNonce() ? nonce_bytes->size() : 0), 0);
745
614
        } else {
746
17.3k
            for (const auto& part : parts) {
747
17.3k
                CF_CHECK_EQ(ecxdsa_sign_update(&ctx, part.first, part.second), 0);
748
17.2k
            }
749
750
516
            if ( op.UseRandomNonce() ) {
751
516
                CF_CHECK_EQ(ecxdsa_sign_finalize(&ctx, signature, signature_size), 0);
752
516
            } else if ( op.UseRFC6979Nonce() ) {
753
0
                CF_CHECK_EQ(ecxdsa_rfc6979_sign_finalize(&ctx, signature, signature_size, DECDSA), 0);
754
0
            } else {
755
0
                CF_UNREACHABLE();
756
0
            }
757
516
        }
758
759
662
        {
760
662
            auto sig = component::ECDSA_Signature{
761
662
                {
762
662
                    util::BinToDec(signature, signature_size / 2),
763
662
                        util::BinToDec(signature + (signature_size / 2), signature_size / 2),
764
662
                },
765
662
                *pub
766
662
            };
767
768
662
            if ( AlgType == ECDSA ) {
769
433
                CF_NORET(util::AdjustECDSASignature(op.curveType.Get(), sig.signature.second));
770
433
            }
771
772
662
            ret = sig;
773
662
        }
774
775
1.03k
end:
776
1.03k
        util::free(signature);
777
778
1.03k
        libecc_detail::global_ds = nullptr;
779
1.03k
        return ret;
780
662
    }
std::__1::optional<cryptofuzz::component::ECDSA_Signature> cryptofuzz::module::libecc_detail::ECxDSA_Sign<cryptofuzz::operation::ECDSA_Sign, (ec_alg_type)1>(cryptofuzz::operation::ECDSA_Sign const&, int (*)(ec_sign_context*, unsigned char const*, unsigned char, unsigned char*, unsigned char, unsigned char const*, unsigned char), int (*)(ec_sign_context*, unsigned char const*, unsigned int), int (*)(ec_sign_context*, unsigned char*, unsigned char), int (*)(ec_sign_context*, unsigned char*, unsigned char, ec_alg_type))
Line
Count
Source
664
753
            const ecxdsa_rfc6979_sign_finalize_t ecxdsa_rfc6979_sign_finalize = nullptr) {
665
753
        if ( IsValidECxDSASize(op.cleartext) == false ) {
666
44
            return std::nullopt;
667
44
        }
668
669
709
        if ( op.UseRFC6979Nonce() && ecxdsa_rfc6979_sign_finalize == nullptr ) {
670
0
            return std::nullopt;
671
0
        }
672
673
709
        std::optional<component::ECDSA_Signature> ret = std::nullopt;
674
675
709
        Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
676
709
        std::optional<component::ECC_PublicKey> pub = std::nullopt;
677
709
        const ec_str_params* curve_params;
678
709
        std::optional<std::vector<uint8_t>> priv_bytes;
679
709
        ec_params params;
680
709
        ec_key_pair kp;
681
709
        struct ec_sign_context ctx;
682
709
        size_t signature_size = 0;
683
709
        uint8_t* signature = nullptr;
684
709
        std::optional<std::vector<uint8_t>> nonce_bytes;
685
709
        std::optional<hash_alg_type> hash;
686
709
        util::Multipart parts;
687
709
        const ec_alg_type alg = op.UseRFC6979Nonce() ? DECDSA : AlgType;
688
689
709
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
690
550
            CF_CHECK_TRUE(op.UseRandomNonce() || op.UseRFC6979Nonce());
691
478
            CF_CHECK_NE(hash = libecc_detail::To_hash_alg_type(op.digestType.Get()), std::nullopt);
692
478
        } else {
693
159
            CF_CHECK_TRUE(op.UseSpecifiedNonce());
694
103
        }
695
696
581
        CF_CHECK_NE(pub = libecc_detail::OpECC_PrivateToPublic(ds, op.curveType, op.priv), std::nullopt);
697
698
553
        libecc_detail::global_ds = &ds;
699
700
        /* Load curve */
701
553
        CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
702
553
        CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
703
704
553
        {
705
553
            const auto priv_str = op.priv.ToTrimmedString();
706
553
            CF_CHECK_NE(priv_bytes = util::DecToBin(priv_str), std::nullopt);
707
553
            CF_CHECK_LTE((8 * priv_bytes->size()), NN_USABLE_MAX_BIT_LEN);
708
553
            CF_CHECK_EQ(ec_key_pair_import_from_priv_key_buf(&kp,
709
553
                        &params,
710
553
                        priv_bytes->data(), priv_bytes->size(),
711
553
                        alg), 0);
712
553
        }
713
714
553
        signature_size = ECDSA_SIGLEN(kp.priv_key.params->ec_gen_order_bitlen);
715
553
        CF_ASSERT((signature_size % 2) == 0, "Signature size is not multiple of 2");
716
553
        signature = util::malloc(signature_size);
717
718
553
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
719
103
            CF_CHECK_EQ(ec_sign_init(&ctx, &kp, alg, SHA256, nullptr, 0), 0);
720
450
        } else {
721
450
            CF_CHECK_EQ(ec_sign_init(&ctx, &kp, alg, *hash, nullptr, 0), 0);
722
450
        }
723
724
553
        if ( op.UseSpecifiedNonce() == true ) {
725
            /* ecdsa_sign_raw crashes if nonce is 0 */
726
103
            CF_CHECK_NE(op.nonce.ToTrimmedString(), "0");
727
728
91
            CF_CHECK_NE(nonce_bytes = util::DecToBin(op.nonce.ToTrimmedString()), std::nullopt);
729
730
            /* ecdsa_sign_raw supports nonce up to 255 bytes */
731
91
            CF_CHECK_LTE(nonce_bytes->size(), 255);
732
88
        }
733
734
538
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
735
450
            parts = util::ToParts(ds, op.cleartext);
736
450
        }
737
738
538
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
739
88
            CF_CHECK_EQ(ecxdsa_sign_raw(
740
88
                        &ctx,
741
88
                        op.cleartext.GetPtr(), op.cleartext.GetSize(),
742
88
                        signature, signature_size,
743
88
                        op.UseSpecifiedNonce() ? nonce_bytes->data() : nullptr,
744
88
                        op.UseSpecifiedNonce() ? nonce_bytes->size() : 0), 0);
745
450
        } else {
746
14.1k
            for (const auto& part : parts) {
747
14.1k
                CF_CHECK_EQ(ecxdsa_sign_update(&ctx, part.first, part.second), 0);
748
14.0k
            }
749
750
358
            if ( op.UseRandomNonce() ) {
751
358
                CF_CHECK_EQ(ecxdsa_sign_finalize(&ctx, signature, signature_size), 0);
752
358
            } else if ( op.UseRFC6979Nonce() ) {
753
0
                CF_CHECK_EQ(ecxdsa_rfc6979_sign_finalize(&ctx, signature, signature_size, DECDSA), 0);
754
0
            } else {
755
0
                CF_UNREACHABLE();
756
0
            }
757
358
        }
758
759
433
        {
760
433
            auto sig = component::ECDSA_Signature{
761
433
                {
762
433
                    util::BinToDec(signature, signature_size / 2),
763
433
                        util::BinToDec(signature + (signature_size / 2), signature_size / 2),
764
433
                },
765
433
                *pub
766
433
            };
767
768
433
            if ( AlgType == ECDSA ) {
769
433
                CF_NORET(util::AdjustECDSASignature(op.curveType.Get(), sig.signature.second));
770
433
            }
771
772
433
            ret = sig;
773
433
        }
774
775
709
end:
776
709
        util::free(signature);
777
778
709
        libecc_detail::global_ds = nullptr;
779
709
        return ret;
780
433
    }
std::__1::optional<cryptofuzz::component::ECDSA_Signature> cryptofuzz::module::libecc_detail::ECxDSA_Sign<cryptofuzz::operation::ECGDSA_Sign, (ec_alg_type)6>(cryptofuzz::operation::ECGDSA_Sign const&, int (*)(ec_sign_context*, unsigned char const*, unsigned char, unsigned char*, unsigned char, unsigned char const*, unsigned char), int (*)(ec_sign_context*, unsigned char const*, unsigned int), int (*)(ec_sign_context*, unsigned char*, unsigned char), int (*)(ec_sign_context*, unsigned char*, unsigned char, ec_alg_type))
Line
Count
Source
664
204
            const ecxdsa_rfc6979_sign_finalize_t ecxdsa_rfc6979_sign_finalize = nullptr) {
665
204
        if ( IsValidECxDSASize(op.cleartext) == false ) {
666
8
            return std::nullopt;
667
8
        }
668
669
196
        if ( op.UseRFC6979Nonce() && ecxdsa_rfc6979_sign_finalize == nullptr ) {
670
6
            return std::nullopt;
671
6
        }
672
673
190
        std::optional<component::ECDSA_Signature> ret = std::nullopt;
674
675
190
        Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
676
190
        std::optional<component::ECC_PublicKey> pub = std::nullopt;
677
190
        const ec_str_params* curve_params;
678
190
        std::optional<std::vector<uint8_t>> priv_bytes;
679
190
        ec_params params;
680
190
        ec_key_pair kp;
681
190
        struct ec_sign_context ctx;
682
190
        size_t signature_size = 0;
683
190
        uint8_t* signature = nullptr;
684
190
        std::optional<std::vector<uint8_t>> nonce_bytes;
685
190
        std::optional<hash_alg_type> hash;
686
190
        util::Multipart parts;
687
190
        const ec_alg_type alg = op.UseRFC6979Nonce() ? DECDSA : AlgType;
688
689
190
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
690
128
            CF_CHECK_TRUE(op.UseRandomNonce() || op.UseRFC6979Nonce());
691
112
            CF_CHECK_NE(hash = libecc_detail::To_hash_alg_type(op.digestType.Get()), std::nullopt);
692
112
        } else {
693
62
            CF_CHECK_TRUE(op.UseSpecifiedNonce());
694
55
        }
695
696
167
        CF_CHECK_NE(pub = libecc_detail::OpECC_PrivateToPublic(ds, op.curveType, op.priv), std::nullopt);
697
698
156
        libecc_detail::global_ds = &ds;
699
700
        /* Load curve */
701
156
        CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
702
156
        CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
703
704
156
        {
705
156
            const auto priv_str = op.priv.ToTrimmedString();
706
156
            CF_CHECK_NE(priv_bytes = util::DecToBin(priv_str), std::nullopt);
707
156
            CF_CHECK_LTE((8 * priv_bytes->size()), NN_USABLE_MAX_BIT_LEN);
708
156
            CF_CHECK_EQ(ec_key_pair_import_from_priv_key_buf(&kp,
709
156
                        &params,
710
156
                        priv_bytes->data(), priv_bytes->size(),
711
156
                        alg), 0);
712
156
        }
713
714
156
        signature_size = ECDSA_SIGLEN(kp.priv_key.params->ec_gen_order_bitlen);
715
156
        CF_ASSERT((signature_size % 2) == 0, "Signature size is not multiple of 2");
716
156
        signature = util::malloc(signature_size);
717
718
156
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
719
51
            CF_CHECK_EQ(ec_sign_init(&ctx, &kp, alg, SHA256, nullptr, 0), 0);
720
105
        } else {
721
105
            CF_CHECK_EQ(ec_sign_init(&ctx, &kp, alg, *hash, nullptr, 0), 0);
722
105
        }
723
724
156
        if ( op.UseSpecifiedNonce() == true ) {
725
            /* ecdsa_sign_raw crashes if nonce is 0 */
726
51
            CF_CHECK_NE(op.nonce.ToTrimmedString(), "0");
727
728
48
            CF_CHECK_NE(nonce_bytes = util::DecToBin(op.nonce.ToTrimmedString()), std::nullopt);
729
730
            /* ecdsa_sign_raw supports nonce up to 255 bytes */
731
48
            CF_CHECK_LTE(nonce_bytes->size(), 255);
732
45
        }
733
734
150
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
735
105
            parts = util::ToParts(ds, op.cleartext);
736
105
        }
737
738
150
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
739
45
            CF_CHECK_EQ(ecxdsa_sign_raw(
740
45
                        &ctx,
741
45
                        op.cleartext.GetPtr(), op.cleartext.GetSize(),
742
45
                        signature, signature_size,
743
45
                        op.UseSpecifiedNonce() ? nonce_bytes->data() : nullptr,
744
45
                        op.UseSpecifiedNonce() ? nonce_bytes->size() : 0), 0);
745
105
        } else {
746
1.34k
            for (const auto& part : parts) {
747
1.34k
                CF_CHECK_EQ(ecxdsa_sign_update(&ctx, part.first, part.second), 0);
748
1.33k
            }
749
750
102
            if ( op.UseRandomNonce() ) {
751
102
                CF_CHECK_EQ(ecxdsa_sign_finalize(&ctx, signature, signature_size), 0);
752
102
            } else if ( op.UseRFC6979Nonce() ) {
753
0
                CF_CHECK_EQ(ecxdsa_rfc6979_sign_finalize(&ctx, signature, signature_size, DECDSA), 0);
754
0
            } else {
755
0
                CF_UNREACHABLE();
756
0
            }
757
102
        }
758
759
134
        {
760
134
            auto sig = component::ECDSA_Signature{
761
134
                {
762
134
                    util::BinToDec(signature, signature_size / 2),
763
134
                        util::BinToDec(signature + (signature_size / 2), signature_size / 2),
764
134
                },
765
134
                *pub
766
134
            };
767
768
134
            if ( AlgType == ECDSA ) {
769
0
                CF_NORET(util::AdjustECDSASignature(op.curveType.Get(), sig.signature.second));
770
0
            }
771
772
134
            ret = sig;
773
134
        }
774
775
190
end:
776
190
        util::free(signature);
777
778
190
        libecc_detail::global_ds = nullptr;
779
190
        return ret;
780
134
    }
std::__1::optional<cryptofuzz::component::ECDSA_Signature> cryptofuzz::module::libecc_detail::ECxDSA_Sign<cryptofuzz::operation::ECRDSA_Sign, (ec_alg_type)7>(cryptofuzz::operation::ECRDSA_Sign const&, int (*)(ec_sign_context*, unsigned char const*, unsigned char, unsigned char*, unsigned char, unsigned char const*, unsigned char), int (*)(ec_sign_context*, unsigned char const*, unsigned int), int (*)(ec_sign_context*, unsigned char*, unsigned char), int (*)(ec_sign_context*, unsigned char*, unsigned char, ec_alg_type))
Line
Count
Source
664
153
            const ecxdsa_rfc6979_sign_finalize_t ecxdsa_rfc6979_sign_finalize = nullptr) {
665
153
        if ( IsValidECxDSASize(op.cleartext) == false ) {
666
10
            return std::nullopt;
667
10
        }
668
669
143
        if ( op.UseRFC6979Nonce() && ecxdsa_rfc6979_sign_finalize == nullptr ) {
670
6
            return std::nullopt;
671
6
        }
672
673
137
        std::optional<component::ECDSA_Signature> ret = std::nullopt;
674
675
137
        Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
676
137
        std::optional<component::ECC_PublicKey> pub = std::nullopt;
677
137
        const ec_str_params* curve_params;
678
137
        std::optional<std::vector<uint8_t>> priv_bytes;
679
137
        ec_params params;
680
137
        ec_key_pair kp;
681
137
        struct ec_sign_context ctx;
682
137
        size_t signature_size = 0;
683
137
        uint8_t* signature = nullptr;
684
137
        std::optional<std::vector<uint8_t>> nonce_bytes;
685
137
        std::optional<hash_alg_type> hash;
686
137
        util::Multipart parts;
687
137
        const ec_alg_type alg = op.UseRFC6979Nonce() ? DECDSA : AlgType;
688
689
137
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
690
72
            CF_CHECK_TRUE(op.UseRandomNonce() || op.UseRFC6979Nonce());
691
65
            CF_CHECK_NE(hash = libecc_detail::To_hash_alg_type(op.digestType.Get()), std::nullopt);
692
65
        } else {
693
65
            CF_CHECK_TRUE(op.UseSpecifiedNonce());
694
55
        }
695
696
120
        CF_CHECK_NE(pub = libecc_detail::OpECC_PrivateToPublic(ds, op.curveType, op.priv), std::nullopt);
697
698
110
        libecc_detail::global_ds = &ds;
699
700
        /* Load curve */
701
110
        CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
702
110
        CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
703
704
110
        {
705
110
            const auto priv_str = op.priv.ToTrimmedString();
706
110
            CF_CHECK_NE(priv_bytes = util::DecToBin(priv_str), std::nullopt);
707
110
            CF_CHECK_LTE((8 * priv_bytes->size()), NN_USABLE_MAX_BIT_LEN);
708
110
            CF_CHECK_EQ(ec_key_pair_import_from_priv_key_buf(&kp,
709
110
                        &params,
710
110
                        priv_bytes->data(), priv_bytes->size(),
711
110
                        alg), 0);
712
110
        }
713
714
110
        signature_size = ECDSA_SIGLEN(kp.priv_key.params->ec_gen_order_bitlen);
715
110
        CF_ASSERT((signature_size % 2) == 0, "Signature size is not multiple of 2");
716
110
        signature = util::malloc(signature_size);
717
718
110
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
719
51
            CF_CHECK_EQ(ec_sign_init(&ctx, &kp, alg, SHA256, nullptr, 0), 0);
720
59
        } else {
721
59
            CF_CHECK_EQ(ec_sign_init(&ctx, &kp, alg, *hash, nullptr, 0), 0);
722
59
        }
723
724
110
        if ( op.UseSpecifiedNonce() == true ) {
725
            /* ecdsa_sign_raw crashes if nonce is 0 */
726
51
            CF_CHECK_NE(op.nonce.ToTrimmedString(), "0");
727
728
48
            CF_CHECK_NE(nonce_bytes = util::DecToBin(op.nonce.ToTrimmedString()), std::nullopt);
729
730
            /* ecdsa_sign_raw supports nonce up to 255 bytes */
731
48
            CF_CHECK_LTE(nonce_bytes->size(), 255);
732
45
        }
733
734
104
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
735
59
            parts = util::ToParts(ds, op.cleartext);
736
59
        }
737
738
104
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
739
45
            CF_CHECK_EQ(ecxdsa_sign_raw(
740
45
                        &ctx,
741
45
                        op.cleartext.GetPtr(), op.cleartext.GetSize(),
742
45
                        signature, signature_size,
743
45
                        op.UseSpecifiedNonce() ? nonce_bytes->data() : nullptr,
744
45
                        op.UseSpecifiedNonce() ? nonce_bytes->size() : 0), 0);
745
59
        } else {
746
1.78k
            for (const auto& part : parts) {
747
1.78k
                CF_CHECK_EQ(ecxdsa_sign_update(&ctx, part.first, part.second), 0);
748
1.77k
            }
749
750
56
            if ( op.UseRandomNonce() ) {
751
56
                CF_CHECK_EQ(ecxdsa_sign_finalize(&ctx, signature, signature_size), 0);
752
56
            } else if ( op.UseRFC6979Nonce() ) {
753
0
                CF_CHECK_EQ(ecxdsa_rfc6979_sign_finalize(&ctx, signature, signature_size, DECDSA), 0);
754
0
            } else {
755
0
                CF_UNREACHABLE();
756
0
            }
757
56
        }
758
759
95
        {
760
95
            auto sig = component::ECDSA_Signature{
761
95
                {
762
95
                    util::BinToDec(signature, signature_size / 2),
763
95
                        util::BinToDec(signature + (signature_size / 2), signature_size / 2),
764
95
                },
765
95
                *pub
766
95
            };
767
768
95
            if ( AlgType == ECDSA ) {
769
0
                CF_NORET(util::AdjustECDSASignature(op.curveType.Get(), sig.signature.second));
770
0
            }
771
772
95
            ret = sig;
773
95
        }
774
775
137
end:
776
137
        util::free(signature);
777
778
137
        libecc_detail::global_ds = nullptr;
779
137
        return ret;
780
95
    }
781
782
    typedef int (*ecxdsa_verify_raw_t)(struct ec_verify_context *ctx, const u8 *input, u8 inputlen);
783
    typedef int (*ecxdsa_verify_update_t)(struct ec_verify_context *ctx, const u8 *chunk, u32 chunklen);
784
    typedef int (*ecxdsa_verify_finalize_t)(struct ec_verify_context *ctx);
785
786
    template <class Operation, ec_alg_type AlgType>
787
    std::optional<bool> ECxDSA_Verify(
788
            const Operation& op,
789
            const ec_sig_mapping* sm,
790
            const ecxdsa_verify_raw_t ecxdsa_verify_raw,
791
            const ecxdsa_verify_update_t ecxdsa_verify_update,
792
1.12k
            const ecxdsa_verify_finalize_t ecxdsa_verify_finalize) {
793
1.12k
        if ( IsValidECxDSASize(op.cleartext) == false ) {
794
29
            return std::nullopt;
795
29
        }
796
797
1.09k
        std::optional<bool> ret = std::nullopt;
798
1.09k
        Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
799
1.09k
        libecc_detail::global_ds = &ds;
800
801
1.09k
        const ec_str_params* curve_params;
802
1.09k
        ec_params params;
803
1.09k
        struct ec_verify_context ctx;
804
1.09k
        ec_key_pair kp;
805
1.09k
        std::vector<uint8_t> pub;
806
1.09k
        std::vector<uint8_t> sig;
807
1.09k
        std::optional<std::vector<uint8_t>> X, Y, Z;
808
1.09k
        std::optional<hash_alg_type> hash;
809
1.09k
        util::Multipart parts;
810
811
1.09k
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
812
845
            CF_CHECK_NE(hash = libecc_detail::To_hash_alg_type(op.digestType.Get()), std::nullopt);
813
845
        }
814
815
        /* Load curve */
816
1.09k
        CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
817
1.09k
        CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
818
819
1.09k
        {
820
1.09k
            const size_t signature_size = ECDSA_SIGLEN(params.ec_gen_order_bitlen);
821
1.09k
            CF_ASSERT((signature_size % 2) == 0, "Signature size is not multiple of 2");
822
823
1.09k
            std::optional<std::vector<uint8_t>> R, S;
824
1.09k
            CF_CHECK_NE(R = util::DecToBin(op.signature.signature.first.ToTrimmedString(), signature_size / 2), std::nullopt);
825
1.05k
            CF_CHECK_NE(S = util::DecToBin(op.signature.signature.second.ToTrimmedString(), signature_size / 2), std::nullopt);
826
827
1.02k
            sig.insert(std::end(sig), std::begin(*R), std::end(*R));
828
1.02k
            sig.insert(std::end(sig), std::begin(*S), std::end(*S));
829
1.02k
        }
830
831
1.02k
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
832
776
            parts = util::ToParts(ds, op.cleartext);
833
776
        }
834
835
1.02k
        {
836
1.02k
            const size_t pubSize = BYTECEIL(params.ec_curve.a.ctx->p_bitlen) * 3;
837
1.02k
            CF_ASSERT((pubSize % 2) == 0, "Public key byte size is not even");
838
1.02k
            CF_ASSERT((pubSize % 3) == 0, "Public key byte size is not multiple of 3");
839
1.02k
            pub.resize(pubSize, 0);
840
841
1.02k
            const size_t pointSize = pubSize / 3;
842
1.02k
            CF_CHECK_NE(X = util::DecToBin(op.signature.pub.first.ToTrimmedString(), pointSize), std::nullopt);
843
997
            CF_CHECK_NE(Y = util::DecToBin(op.signature.pub.second.ToTrimmedString(), pointSize), std::nullopt);
844
963
            CF_CHECK_NE(Z = util::DecToBin("1", pointSize), std::nullopt);
845
846
963
            memcpy(pub.data(), X->data(), pointSize);
847
963
            memcpy(pub.data() + pointSize, Y->data(), pointSize);
848
963
            memcpy(pub.data() + pointSize * 2, Z->data(), pointSize);
849
850
963
            CF_CHECK_EQ(ec_pub_key_import_from_buf(
851
963
                        &kp.pub_key,
852
963
                        &params,
853
963
                        pub.data(), pub.size(),
854
963
                        sm->type), 0);
855
856
834
            int check;
857
834
            CF_ASSERT(!prj_pt_is_on_curve(&kp.pub_key.y, &check), "prj_pt_is_on_curve error " __FILE__ ":" TOSTRING(__LINE__));
858
834
            CF_CHECK_EQ(check, 1);
859
834
        }
860
861
834
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
862
217
            CF_CHECK_EQ(ec_verify_init(&ctx, &(kp.pub_key), sig.data(), sig.size(), AlgType, SHA256, nullptr, 0), 0);
863
617
        } else {
864
617
            CF_CHECK_EQ(ec_verify_init(&ctx, &(kp.pub_key), sig.data(), sig.size(), AlgType, *hash, nullptr, 0), 0);
865
571
        }
866
867
771
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
868
200
            const auto cleartext_ptr = op.cleartext.GetPtr();
869
870
            /* libecc has an explicit check for NULL input which causes ecdsa_verify_raw
871
             * to return false even if the signature is valid.
872
             *
873
             * See also OSS-Fuzz issue #33808
874
             */
875
200
            CF_CHECK_NE(cleartext_ptr, nullptr);
876
877
187
            ret = ecxdsa_verify_raw(&ctx, cleartext_ptr, op.cleartext.GetSize()) == 0;
878
571
        } else {
879
31.0k
            for (const auto& part : parts) {
880
31.0k
                CF_CHECK_EQ(ecxdsa_verify_update(&ctx, part.first, part.second), 0);
881
31.0k
            }
882
883
562
            ret = ecxdsa_verify_finalize(&ctx) == 0;
884
562
        }
885
886
1.09k
end:
887
1.09k
        libecc_detail::global_ds = nullptr;
888
889
1.09k
        return ret;
890
771
    }
std::__1::optional<bool> cryptofuzz::module::libecc_detail::ECxDSA_Verify<cryptofuzz::operation::ECDSA_Verify, (ec_alg_type)1>(cryptofuzz::operation::ECDSA_Verify const&, ec_sig_mapping const*, int (*)(ec_verify_context*, unsigned char const*, unsigned char), int (*)(ec_verify_context*, unsigned char const*, unsigned int), int (*)(ec_verify_context*))
Line
Count
Source
792
752
            const ecxdsa_verify_finalize_t ecxdsa_verify_finalize) {
793
752
        if ( IsValidECxDSASize(op.cleartext) == false ) {
794
15
            return std::nullopt;
795
15
        }
796
797
737
        std::optional<bool> ret = std::nullopt;
798
737
        Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
799
737
        libecc_detail::global_ds = &ds;
800
801
737
        const ec_str_params* curve_params;
802
737
        ec_params params;
803
737
        struct ec_verify_context ctx;
804
737
        ec_key_pair kp;
805
737
        std::vector<uint8_t> pub;
806
737
        std::vector<uint8_t> sig;
807
737
        std::optional<std::vector<uint8_t>> X, Y, Z;
808
737
        std::optional<hash_alg_type> hash;
809
737
        util::Multipart parts;
810
811
737
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
812
540
            CF_CHECK_NE(hash = libecc_detail::To_hash_alg_type(op.digestType.Get()), std::nullopt);
813
540
        }
814
815
        /* Load curve */
816
737
        CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
817
737
        CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
818
819
737
        {
820
737
            const size_t signature_size = ECDSA_SIGLEN(params.ec_gen_order_bitlen);
821
737
            CF_ASSERT((signature_size % 2) == 0, "Signature size is not multiple of 2");
822
823
737
            std::optional<std::vector<uint8_t>> R, S;
824
737
            CF_CHECK_NE(R = util::DecToBin(op.signature.signature.first.ToTrimmedString(), signature_size / 2), std::nullopt);
825
705
            CF_CHECK_NE(S = util::DecToBin(op.signature.signature.second.ToTrimmedString(), signature_size / 2), std::nullopt);
826
827
689
            sig.insert(std::end(sig), std::begin(*R), std::end(*R));
828
689
            sig.insert(std::end(sig), std::begin(*S), std::end(*S));
829
689
        }
830
831
689
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
832
500
            parts = util::ToParts(ds, op.cleartext);
833
500
        }
834
835
689
        {
836
689
            const size_t pubSize = BYTECEIL(params.ec_curve.a.ctx->p_bitlen) * 3;
837
689
            CF_ASSERT((pubSize % 2) == 0, "Public key byte size is not even");
838
689
            CF_ASSERT((pubSize % 3) == 0, "Public key byte size is not multiple of 3");
839
689
            pub.resize(pubSize, 0);
840
841
689
            const size_t pointSize = pubSize / 3;
842
689
            CF_CHECK_NE(X = util::DecToBin(op.signature.pub.first.ToTrimmedString(), pointSize), std::nullopt);
843
679
            CF_CHECK_NE(Y = util::DecToBin(op.signature.pub.second.ToTrimmedString(), pointSize), std::nullopt);
844
672
            CF_CHECK_NE(Z = util::DecToBin("1", pointSize), std::nullopt);
845
846
672
            memcpy(pub.data(), X->data(), pointSize);
847
672
            memcpy(pub.data() + pointSize, Y->data(), pointSize);
848
672
            memcpy(pub.data() + pointSize * 2, Z->data(), pointSize);
849
850
672
            CF_CHECK_EQ(ec_pub_key_import_from_buf(
851
672
                        &kp.pub_key,
852
672
                        &params,
853
672
                        pub.data(), pub.size(),
854
672
                        sm->type), 0);
855
856
612
            int check;
857
612
            CF_ASSERT(!prj_pt_is_on_curve(&kp.pub_key.y, &check), "prj_pt_is_on_curve error " __FILE__ ":" TOSTRING(__LINE__));
858
612
            CF_CHECK_EQ(check, 1);
859
612
        }
860
861
612
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
862
168
            CF_CHECK_EQ(ec_verify_init(&ctx, &(kp.pub_key), sig.data(), sig.size(), AlgType, SHA256, nullptr, 0), 0);
863
444
        } else {
864
444
            CF_CHECK_EQ(ec_verify_init(&ctx, &(kp.pub_key), sig.data(), sig.size(), AlgType, *hash, nullptr, 0), 0);
865
435
        }
866
867
593
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
868
158
            const auto cleartext_ptr = op.cleartext.GetPtr();
869
870
            /* libecc has an explicit check for NULL input which causes ecdsa_verify_raw
871
             * to return false even if the signature is valid.
872
             *
873
             * See also OSS-Fuzz issue #33808
874
             */
875
158
            CF_CHECK_NE(cleartext_ptr, nullptr);
876
877
151
            ret = ecxdsa_verify_raw(&ctx, cleartext_ptr, op.cleartext.GetSize()) == 0;
878
435
        } else {
879
25.4k
            for (const auto& part : parts) {
880
25.4k
                CF_CHECK_EQ(ecxdsa_verify_update(&ctx, part.first, part.second), 0);
881
25.4k
            }
882
883
432
            ret = ecxdsa_verify_finalize(&ctx) == 0;
884
432
        }
885
886
737
end:
887
737
        libecc_detail::global_ds = nullptr;
888
889
737
        return ret;
890
593
    }
std::__1::optional<bool> cryptofuzz::module::libecc_detail::ECxDSA_Verify<cryptofuzz::operation::ECGDSA_Verify, (ec_alg_type)6>(cryptofuzz::operation::ECGDSA_Verify const&, ec_sig_mapping const*, int (*)(ec_verify_context*, unsigned char const*, unsigned char), int (*)(ec_verify_context*, unsigned char const*, unsigned int), int (*)(ec_verify_context*))
Line
Count
Source
792
227
            const ecxdsa_verify_finalize_t ecxdsa_verify_finalize) {
793
227
        if ( IsValidECxDSASize(op.cleartext) == false ) {
794
8
            return std::nullopt;
795
8
        }
796
797
219
        std::optional<bool> ret = std::nullopt;
798
219
        Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
799
219
        libecc_detail::global_ds = &ds;
800
801
219
        const ec_str_params* curve_params;
802
219
        ec_params params;
803
219
        struct ec_verify_context ctx;
804
219
        ec_key_pair kp;
805
219
        std::vector<uint8_t> pub;
806
219
        std::vector<uint8_t> sig;
807
219
        std::optional<std::vector<uint8_t>> X, Y, Z;
808
219
        std::optional<hash_alg_type> hash;
809
219
        util::Multipart parts;
810
811
219
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
812
192
            CF_CHECK_NE(hash = libecc_detail::To_hash_alg_type(op.digestType.Get()), std::nullopt);
813
192
        }
814
815
        /* Load curve */
816
219
        CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
817
219
        CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
818
819
219
        {
820
219
            const size_t signature_size = ECDSA_SIGLEN(params.ec_gen_order_bitlen);
821
219
            CF_ASSERT((signature_size % 2) == 0, "Signature size is not multiple of 2");
822
823
219
            std::optional<std::vector<uint8_t>> R, S;
824
219
            CF_CHECK_NE(R = util::DecToBin(op.signature.signature.first.ToTrimmedString(), signature_size / 2), std::nullopt);
825
212
            CF_CHECK_NE(S = util::DecToBin(op.signature.signature.second.ToTrimmedString(), signature_size / 2), std::nullopt);
826
827
202
            sig.insert(std::end(sig), std::begin(*R), std::end(*R));
828
202
            sig.insert(std::end(sig), std::begin(*S), std::end(*S));
829
202
        }
830
831
202
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
832
175
            parts = util::ToParts(ds, op.cleartext);
833
175
        }
834
835
202
        {
836
202
            const size_t pubSize = BYTECEIL(params.ec_curve.a.ctx->p_bitlen) * 3;
837
202
            CF_ASSERT((pubSize % 2) == 0, "Public key byte size is not even");
838
202
            CF_ASSERT((pubSize % 3) == 0, "Public key byte size is not multiple of 3");
839
202
            pub.resize(pubSize, 0);
840
841
202
            const size_t pointSize = pubSize / 3;
842
202
            CF_CHECK_NE(X = util::DecToBin(op.signature.pub.first.ToTrimmedString(), pointSize), std::nullopt);
843
196
            CF_CHECK_NE(Y = util::DecToBin(op.signature.pub.second.ToTrimmedString(), pointSize), std::nullopt);
844
185
            CF_CHECK_NE(Z = util::DecToBin("1", pointSize), std::nullopt);
845
846
185
            memcpy(pub.data(), X->data(), pointSize);
847
185
            memcpy(pub.data() + pointSize, Y->data(), pointSize);
848
185
            memcpy(pub.data() + pointSize * 2, Z->data(), pointSize);
849
850
185
            CF_CHECK_EQ(ec_pub_key_import_from_buf(
851
185
                        &kp.pub_key,
852
185
                        &params,
853
185
                        pub.data(), pub.size(),
854
185
                        sm->type), 0);
855
856
138
            int check;
857
138
            CF_ASSERT(!prj_pt_is_on_curve(&kp.pub_key.y, &check), "prj_pt_is_on_curve error " __FILE__ ":" TOSTRING(__LINE__));
858
138
            CF_CHECK_EQ(check, 1);
859
138
        }
860
861
138
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
862
22
            CF_CHECK_EQ(ec_verify_init(&ctx, &(kp.pub_key), sig.data(), sig.size(), AlgType, SHA256, nullptr, 0), 0);
863
116
        } else {
864
116
            CF_CHECK_EQ(ec_verify_init(&ctx, &(kp.pub_key), sig.data(), sig.size(), AlgType, *hash, nullptr, 0), 0);
865
90
        }
866
867
108
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
868
18
            const auto cleartext_ptr = op.cleartext.GetPtr();
869
870
            /* libecc has an explicit check for NULL input which causes ecdsa_verify_raw
871
             * to return false even if the signature is valid.
872
             *
873
             * See also OSS-Fuzz issue #33808
874
             */
875
18
            CF_CHECK_NE(cleartext_ptr, nullptr);
876
877
15
            ret = ecxdsa_verify_raw(&ctx, cleartext_ptr, op.cleartext.GetSize()) == 0;
878
90
        } else {
879
4.66k
            for (const auto& part : parts) {
880
4.66k
                CF_CHECK_EQ(ecxdsa_verify_update(&ctx, part.first, part.second), 0);
881
4.66k
            }
882
883
87
            ret = ecxdsa_verify_finalize(&ctx) == 0;
884
87
        }
885
886
219
end:
887
219
        libecc_detail::global_ds = nullptr;
888
889
219
        return ret;
890
108
    }
std::__1::optional<bool> cryptofuzz::module::libecc_detail::ECxDSA_Verify<cryptofuzz::operation::ECRDSA_Verify, (ec_alg_type)7>(cryptofuzz::operation::ECRDSA_Verify const&, ec_sig_mapping const*, int (*)(ec_verify_context*, unsigned char const*, unsigned char), int (*)(ec_verify_context*, unsigned char const*, unsigned int), int (*)(ec_verify_context*))
Line
Count
Source
792
149
            const ecxdsa_verify_finalize_t ecxdsa_verify_finalize) {
793
149
        if ( IsValidECxDSASize(op.cleartext) == false ) {
794
6
            return std::nullopt;
795
6
        }
796
797
143
        std::optional<bool> ret = std::nullopt;
798
143
        Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
799
143
        libecc_detail::global_ds = &ds;
800
801
143
        const ec_str_params* curve_params;
802
143
        ec_params params;
803
143
        struct ec_verify_context ctx;
804
143
        ec_key_pair kp;
805
143
        std::vector<uint8_t> pub;
806
143
        std::vector<uint8_t> sig;
807
143
        std::optional<std::vector<uint8_t>> X, Y, Z;
808
143
        std::optional<hash_alg_type> hash;
809
143
        util::Multipart parts;
810
811
143
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
812
113
            CF_CHECK_NE(hash = libecc_detail::To_hash_alg_type(op.digestType.Get()), std::nullopt);
813
113
        }
814
815
        /* Load curve */
816
143
        CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
817
143
        CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
818
819
143
        {
820
143
            const size_t signature_size = ECDSA_SIGLEN(params.ec_gen_order_bitlen);
821
143
            CF_ASSERT((signature_size % 2) == 0, "Signature size is not multiple of 2");
822
823
143
            std::optional<std::vector<uint8_t>> R, S;
824
143
            CF_CHECK_NE(R = util::DecToBin(op.signature.signature.first.ToTrimmedString(), signature_size / 2), std::nullopt);
825
137
            CF_CHECK_NE(S = util::DecToBin(op.signature.signature.second.ToTrimmedString(), signature_size / 2), std::nullopt);
826
827
131
            sig.insert(std::end(sig), std::begin(*R), std::end(*R));
828
131
            sig.insert(std::end(sig), std::begin(*S), std::end(*S));
829
131
        }
830
831
131
        if ( !op.digestType.Is(CF_DIGEST("NULL")) ) {
832
101
            parts = util::ToParts(ds, op.cleartext);
833
101
        }
834
835
131
        {
836
131
            const size_t pubSize = BYTECEIL(params.ec_curve.a.ctx->p_bitlen) * 3;
837
131
            CF_ASSERT((pubSize % 2) == 0, "Public key byte size is not even");
838
131
            CF_ASSERT((pubSize % 3) == 0, "Public key byte size is not multiple of 3");
839
131
            pub.resize(pubSize, 0);
840
841
131
            const size_t pointSize = pubSize / 3;
842
131
            CF_CHECK_NE(X = util::DecToBin(op.signature.pub.first.ToTrimmedString(), pointSize), std::nullopt);
843
122
            CF_CHECK_NE(Y = util::DecToBin(op.signature.pub.second.ToTrimmedString(), pointSize), std::nullopt);
844
106
            CF_CHECK_NE(Z = util::DecToBin("1", pointSize), std::nullopt);
845
846
106
            memcpy(pub.data(), X->data(), pointSize);
847
106
            memcpy(pub.data() + pointSize, Y->data(), pointSize);
848
106
            memcpy(pub.data() + pointSize * 2, Z->data(), pointSize);
849
850
106
            CF_CHECK_EQ(ec_pub_key_import_from_buf(
851
106
                        &kp.pub_key,
852
106
                        &params,
853
106
                        pub.data(), pub.size(),
854
106
                        sm->type), 0);
855
856
84
            int check;
857
84
            CF_ASSERT(!prj_pt_is_on_curve(&kp.pub_key.y, &check), "prj_pt_is_on_curve error " __FILE__ ":" TOSTRING(__LINE__));
858
84
            CF_CHECK_EQ(check, 1);
859
84
        }
860
861
84
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
862
27
            CF_CHECK_EQ(ec_verify_init(&ctx, &(kp.pub_key), sig.data(), sig.size(), AlgType, SHA256, nullptr, 0), 0);
863
57
        } else {
864
57
            CF_CHECK_EQ(ec_verify_init(&ctx, &(kp.pub_key), sig.data(), sig.size(), AlgType, *hash, nullptr, 0), 0);
865
46
        }
866
867
70
        if ( op.digestType.Is(CF_DIGEST("NULL")) ) {
868
24
            const auto cleartext_ptr = op.cleartext.GetPtr();
869
870
            /* libecc has an explicit check for NULL input which causes ecdsa_verify_raw
871
             * to return false even if the signature is valid.
872
             *
873
             * See also OSS-Fuzz issue #33808
874
             */
875
24
            CF_CHECK_NE(cleartext_ptr, nullptr);
876
877
21
            ret = ecxdsa_verify_raw(&ctx, cleartext_ptr, op.cleartext.GetSize()) == 0;
878
46
        } else {
879
891
            for (const auto& part : parts) {
880
891
                CF_CHECK_EQ(ecxdsa_verify_update(&ctx, part.first, part.second), 0);
881
888
            }
882
883
43
            ret = ecxdsa_verify_finalize(&ctx) == 0;
884
43
        }
885
886
143
end:
887
143
        libecc_detail::global_ds = nullptr;
888
889
143
        return ret;
890
70
    }
891
} /* namespace libecc_detail */
892
893
894
/* EdDSA cases */
895
namespace libecc_detail {
896
0
    std::optional<component::ECDSA_Signature> EdDSA_Sign(operation::ECDSA_Sign& op) {
897
0
        ec_key_pair kp;
898
0
        const ec_str_params* curve_params;
899
0
        ec_params params;
900
0
        ec_alg_type sig_type;
901
0
        hash_alg_type hash_type;
902
0
        uint8_t* signature = nullptr;
903
0
        std::optional<component::ECDSA_Signature> ret = std::nullopt;
904
0
        Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
905
0
        std::optional<component::ECC_PublicKey> pub = std::nullopt;
906
0
        libecc_detail::global_ds = &ds;
907
0
        u8 key_size = 0;
908
0
        u8 siglen;
909
910
        /* Load curve.
911
         * NOTE: this will be WEI25519 or WEI448 (libecc uses isogenies for ed25519, ed448, x25519 and x448)
912
         */
913
0
        CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
914
0
        CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
915
916
0
        if ( op.curveType.Is(CF_ECC_CURVE("ed25519")) ){
917
            /* Ed25519 case */
918
0
            key_size = 32;
919
0
            sig_type = EDDSA25519;
920
0
            if ( !op.digestType.Is(CF_DIGEST("NULL")) && !op.digestType.Is(CF_DIGEST("SHA512")) ) {
921
0
                return std::nullopt;
922
0
            }
923
0
            hash_type = SHA512;
924
0
        }
925
0
        else if ( op.curveType.Is(CF_ECC_CURVE("ed448")) ){
926
            /* Ed448 case */
927
0
            key_size = 56;
928
0
            sig_type = EDDSA448;
929
0
            if ( !op.digestType.Is(CF_DIGEST("NULL")) && !op.digestType.Is(CF_DIGEST("SHAKE256_114")) ) {
930
0
                return std::nullopt;
931
0
            }
932
0
            hash_type = SHAKE256;
933
0
        }
934
0
        else{
935
0
            goto end;
936
0
        }
937
0
        {
938
            /* Extract the private key */
939
0
            const auto _priv_bytes = util::DecToBin(op.priv.ToTrimmedString(), key_size);
940
0
            if ( (_priv_bytes == std::nullopt) || (_priv_bytes->size() != key_size) ) {
941
0
                return std::nullopt;
942
0
            }
943
            /* Import our key pair */
944
0
        CF_CHECK_EQ(eddsa_import_key_pair_from_priv_key_buf(&kp, _priv_bytes->data(), key_size, &params, sig_type), 0);
945
        /* Now sign */
946
0
            siglen = (2 * key_size);
947
0
            signature = util::malloc(siglen);
948
            /* In case of NULL pointer as cleartext, replace it by an empty string with the same size */
949
0
            if(op.cleartext.GetPtr() == NULL){
950
0
                const unsigned char msg[] = "";
951
0
            CF_CHECK_EQ(_ec_sign(signature, siglen, &kp, msg, 0, nullptr, sig_type, hash_type, nullptr, 0), 0);
952
0
            }
953
0
            else{
954
0
            CF_CHECK_EQ(_ec_sign(signature, siglen, &kp, op.cleartext.GetPtr(), op.cleartext.GetSize(), nullptr, sig_type, hash_type, nullptr, 0), 0);
955
0
            }
956
0
        }
957
        /* Get the public key */
958
0
        CF_CHECK_NE(pub = libecc_detail::OpECC_PrivateToPublic(ds, op.curveType, op.priv), std::nullopt);
959
960
0
        ret = {
961
0
            {
962
0
                util::BinToDec(signature, siglen / 2),
963
0
                util::BinToDec(signature + (siglen / 2), siglen / 2),
964
0
            },
965
0
            *pub
966
0
        };
967
0
end:
968
0
        util::free(signature);
969
0
        libecc_detail::global_ds = nullptr;
970
971
0
        return ret;
972
0
    }
973
    /***************************************************************************/
974
0
    std::optional<bool> EdDSA_Verify(operation::ECDSA_Verify& op) {
975
0
        std::optional<bool> ret = std::nullopt;
976
0
        Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
977
0
        libecc_detail::global_ds = &ds;
978
979
0
        const ec_str_params* curve_params;
980
0
        ec_params params;
981
0
        struct ec_verify_context ctx;
982
0
        ec_pub_key pub_key;
983
0
        std::optional<std::vector<uint8_t>> pub;
984
0
        std::vector<uint8_t> sig;
985
0
        u8 key_size = 0;
986
0
        ec_alg_type sig_type;
987
0
        hash_alg_type hash_type;
988
0
        bool oneShot = true;
989
990
        /* Streaming mode or not? */
991
0
        try { oneShot = ds.Get<bool>(); } catch ( ... ) { }
992
993
        /* Load curve.
994
         * NOTE: this will be WEI25519 or WEI448 (libecc uses isogenies for ed25519, ed448, x25519 and x448)
995
         */
996
0
        CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
997
0
        CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
998
999
0
        if ( op.curveType.Is(CF_ECC_CURVE("ed25519")) ){
1000
            /* Ed25519 case */
1001
0
            key_size = 32;
1002
0
            sig_type = EDDSA25519;
1003
0
            if ( !op.digestType.Is(CF_DIGEST("NULL")) && !op.digestType.Is(CF_DIGEST("SHA512")) ) {
1004
0
                return std::nullopt;
1005
0
            }
1006
0
            hash_type = SHA512;
1007
0
        }
1008
0
        else if ( op.curveType.Is(CF_ECC_CURVE("ed448")) ){
1009
            /* Ed448 case */
1010
0
            key_size = 56;
1011
0
            sig_type = EDDSA448;
1012
0
            if ( !op.digestType.Is(CF_DIGEST("NULL")) && !op.digestType.Is(CF_DIGEST("SHAKE256_114")) ) {
1013
0
                return std::nullopt;
1014
0
            }
1015
0
            hash_type = SHAKE256;
1016
0
        }
1017
0
        else{
1018
0
            goto end;
1019
0
        }
1020
1021
0
        {
1022
            /* Extract our signature */
1023
0
            const size_t signature_size = (2 * key_size);
1024
0
            CF_ASSERT((signature_size % 2) == 0, "Signature size is not multiple of 2");
1025
1026
0
            std::optional<std::vector<uint8_t>> R, S;
1027
0
            CF_CHECK_NE(R = util::DecToBin(op.signature.signature.first.ToTrimmedString(), signature_size / 2), std::nullopt);
1028
0
            CF_CHECK_NE(S = util::DecToBin(op.signature.signature.second.ToTrimmedString(), signature_size / 2), std::nullopt);
1029
1030
0
            sig.insert(std::end(sig), std::begin(*R), std::end(*R));
1031
0
            sig.insert(std::end(sig), std::begin(*S), std::end(*S));
1032
0
        }
1033
1034
0
        {
1035
            /* Extract the public key */
1036
0
            CF_CHECK_NE(pub = util::DecToBin(op.signature.pub.first.ToTrimmedString(), key_size), std::nullopt);
1037
            /* Import it */
1038
0
            CF_CHECK_EQ(eddsa_import_pub_key(&pub_key, (*pub).data(), (*pub).size(), &params, sig_type), 0);
1039
0
        }
1040
1041
        /* Proceed with the verification */
1042
0
        if ( oneShot == true ) {
1043
            /* Non streaming mode */
1044
            /* In case of NULL pointer as cleartext, replace it by an empty string with the same size */
1045
0
            if(op.cleartext.GetPtr() == NULL){
1046
0
                const unsigned char msg[] = "";
1047
0
                ret = ec_verify(sig.data(), sig.size(), &pub_key, msg, 0, sig_type, hash_type, nullptr, 0) == 0;
1048
0
            }
1049
0
            else{
1050
0
                ret = ec_verify(sig.data(), sig.size(), &pub_key, op.cleartext.GetPtr(), op.cleartext.GetSize(), sig_type, hash_type, nullptr, 0) == 0;
1051
0
            }
1052
0
        }
1053
0
        else{
1054
            /* Sreaming mode */
1055
0
            const auto parts = util::ToParts(ds, op.cleartext);
1056
0
            CF_CHECK_EQ(ec_verify_init(&ctx, &pub_key, sig.data(), sig.size(), sig_type, hash_type, nullptr, 0), 0);
1057
1058
0
            for (const auto& part : parts) {
1059
0
                CF_CHECK_EQ(ec_verify_update(&ctx, part.first, part.second), 0);
1060
0
            }
1061
1062
0
            ret = ec_verify_finalize(&ctx) == 0;
1063
0
        }
1064
1065
0
end:
1066
0
        libecc_detail::global_ds = nullptr;
1067
1068
0
        return ret;
1069
0
    }
1070
} /* namespace libecc_detail */
1071
1072
1073
/*************************/
1074
753
std::optional<component::ECDSA_Signature> libecc::OpECDSA_Sign(operation::ECDSA_Sign& op) {
1075
753
    if ( op.curveType.Is(CF_ECC_CURVE("ed25519")) || op.curveType.Is(CF_ECC_CURVE("ed448")) ) {
1076
        /* EdDSA cases */
1077
0
        return libecc_detail::EdDSA_Sign(op);
1078
0
    }
1079
753
    else{
1080
        /* ECxDSA cases */
1081
753
        return libecc_detail::ECxDSA_Sign<operation::ECDSA_Sign, ECDSA>(op, ecdsa_sign_raw, _ecdsa_sign_update, _ecdsa_sign_finalize, __ecdsa_sign_finalize);
1082
753
    }
1083
753
}
1084
1085
204
std::optional<component::ECGDSA_Signature> libecc::OpECGDSA_Sign(operation::ECGDSA_Sign& op) {
1086
204
    if ( op.curveType.Is(CF_ECC_CURVE("ed25519")) || op.curveType.Is(CF_ECC_CURVE("ed448")) ) {
1087
        /* EdDSA does not make sense in OpECGDSA_Sign */
1088
0
        return std::nullopt;
1089
0
    }
1090
204
    else{
1091
204
        return libecc_detail::ECxDSA_Sign<operation::ECGDSA_Sign, ECGDSA>(op, ecgdsa_sign_raw, _ecgdsa_sign_update, _ecgdsa_sign_finalize);
1092
204
    }
1093
204
}
1094
1095
153
std::optional<component::ECRDSA_Signature> libecc::OpECRDSA_Sign(operation::ECRDSA_Sign& op) {
1096
153
    if ( op.curveType.Is(CF_ECC_CURVE("ed25519")) || op.curveType.Is(CF_ECC_CURVE("ed448")) ) {
1097
        /* EdDSA does not make sense in OpECRDSA_Sign */
1098
0
        return std::nullopt;
1099
0
    }
1100
153
    else{
1101
153
        return libecc_detail::ECxDSA_Sign<operation::ECRDSA_Sign, ECRDSA>(op, ecrdsa_sign_raw, _ecrdsa_sign_update, _ecrdsa_sign_finalize);
1102
153
    }
1103
153
}
1104
1105
752
std::optional<bool> libecc::OpECDSA_Verify(operation::ECDSA_Verify& op) {
1106
752
    if ( op.curveType.Is(CF_ECC_CURVE("ed25519")) || op.curveType.Is(CF_ECC_CURVE("ed448")) ) {
1107
        /* EdDSA cases */
1108
0
        return libecc_detail::EdDSA_Verify(op);
1109
0
    }
1110
752
    else{
1111
752
        return libecc_detail::ECxDSA_Verify<operation::ECDSA_Verify, ECDSA>(op, libecc_detail::sm_ecdsa, ecdsa_verify_raw, _ecdsa_verify_update, _ecdsa_verify_finalize);
1112
752
    }
1113
752
}
1114
1115
227
std::optional<bool> libecc::OpECGDSA_Verify(operation::ECGDSA_Verify& op) {
1116
227
    if ( op.curveType.Is(CF_ECC_CURVE("ed25519")) || op.curveType.Is(CF_ECC_CURVE("ed448")) ) {
1117
        /* EdDSA does not make sense in OpECGDSA_Verify */
1118
0
        return std::nullopt;
1119
0
    }
1120
227
    else{
1121
227
        return libecc_detail::ECxDSA_Verify<operation::ECGDSA_Verify, ECGDSA>(op, libecc_detail::sm_ecgdsa, ecgdsa_verify_raw, _ecgdsa_verify_update, _ecgdsa_verify_finalize);
1122
227
    }
1123
227
}
1124
1125
149
std::optional<bool> libecc::OpECRDSA_Verify(operation::ECRDSA_Verify& op) {
1126
149
    if ( op.curveType.Is(CF_ECC_CURVE("ed25519")) || op.curveType.Is(CF_ECC_CURVE("ed448")) ) {
1127
        /* EdDSA does not make sense in OpECRDSA_Verify */
1128
0
        return std::nullopt;
1129
0
    }
1130
149
    else{
1131
149
        return libecc_detail::ECxDSA_Verify<operation::ECRDSA_Verify, ECRDSA>(op, libecc_detail::sm_ecrdsa, ecrdsa_verify_raw, _ecrdsa_verify_update, _ecrdsa_verify_finalize);
1132
149
    }
1133
149
}
1134
1135
namespace libecc_detail {
1136
    bool LoadPoint(
1137
            fuzzing::datasource::Datasource& ds,
1138
            const component::ECC_Point in,
1139
            prj_pt& out,
1140
            const ec_params& params,
1141
1.80k
            const component::CurveType curveType) {
1142
1.80k
        bool ret = false;
1143
1.80k
        fp x, y, z;
1144
1145
1.80k
        bool projective = false;
1146
1.80k
        try {
1147
1.80k
            projective = ds.Get<bool>();
1148
1.80k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
1149
1150
1.80k
        if ( projective == false ) {
1151
1.10k
            const auto x_bin = util::DecToBin(in.first.ToTrimmedString());
1152
1.10k
            const auto y_bin = util::DecToBin(in.second.ToTrimmedString());
1153
1154
1.10k
            CF_CHECK_TRUE(!fp_init_from_buf(&x, &(params.ec_fp), x_bin->data(), x_bin->size()));
1155
1.03k
            CF_CHECK_TRUE(!fp_init_from_buf(&y, &(params.ec_fp), y_bin->data(), y_bin->size()));
1156
968
            CF_ASSERT(!fp_init(&z, &(params.ec_fp)), "fp_init error " __FILE__ ":" TOSTRING(__LINE__));
1157
968
            CF_ASSERT(!fp_one(&z), "fp_one error " __FILE__ ":" TOSTRING(__LINE__));
1158
968
            CF_CHECK_TRUE(!prj_pt_init_from_coords(&out, &(params.ec_curve), &x, &y, &z));
1159
968
        } else {
1160
698
            const auto proj = util::ToRandomProjective(
1161
698
                    ds,
1162
698
                    in.first.ToTrimmedString(),
1163
698
                    in.second.ToTrimmedString(),
1164
698
                    curveType.Get(),
1165
698
                    false /* not jacobian */);
1166
1167
698
            const auto x_bin = util::DecToBin(proj[0]);
1168
698
            const auto y_bin = util::DecToBin(proj[1]);
1169
698
            const auto z_bin = util::DecToBin(proj[2]);
1170
1171
698
            CF_CHECK_TRUE(!fp_init_from_buf(&x, &(params.ec_fp), x_bin->data(), x_bin->size()));
1172
672
            CF_CHECK_TRUE(!fp_init_from_buf(&y, &(params.ec_fp), y_bin->data(), y_bin->size()));
1173
654
            CF_CHECK_TRUE(!fp_init_from_buf(&z, &(params.ec_fp), z_bin->data(), z_bin->size()));
1174
654
            CF_CHECK_TRUE(!prj_pt_init_from_coords(&out, &(params.ec_curve), &x, &y, &z));
1175
654
        }
1176
1177
1.62k
        ret = true;
1178
1.80k
end:
1179
1.80k
        return ret;
1180
1.62k
    }
1181
1182
    std::optional<component::ECC_Point> SavePoint(
1183
            const prj_pt& res,
1184
909
            const ec_params& params) {
1185
909
        std::optional<component::ECC_Point> ret = std::nullopt;
1186
1187
909
        aff_pt res_aff;
1188
1189
909
        CF_CHECK_TRUE(!prj_pt_to_aff(&res_aff, &res));
1190
1191
794
        {
1192
794
            const size_t coordinateSize = BYTECEIL(params.ec_curve.a.ctx->p_bitlen);
1193
794
            const size_t pointSize = coordinateSize * 2;
1194
1195
794
            uint8_t out_bytes[pointSize];
1196
1197
794
            CF_CHECK_EQ(aff_pt_export_to_buf(&res_aff, out_bytes, pointSize), 0);
1198
1199
258
            const auto X = util::BinToDec(out_bytes, coordinateSize);
1200
258
            const auto Y = util::BinToDec(out_bytes + coordinateSize, coordinateSize);
1201
1202
258
            ret = {X, Y};
1203
258
        }
1204
1205
909
end:
1206
909
        return ret;
1207
258
    }
1208
}
1209
1210
349
std::optional<component::ECC_Point> libecc::OpECC_Point_Add(operation::ECC_Point_Add& op) {
1211
349
    std::optional<component::ECC_Point> ret = std::nullopt;
1212
349
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1213
1214
349
    libecc_detail::global_ds = &ds;
1215
1216
349
    const ec_str_params* curve_params;
1217
349
    ec_params params;
1218
349
    prj_pt res, a, b;
1219
1220
    /* Load curve */
1221
349
    CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
1222
349
    CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
1223
1224
349
    CF_ASSERT(!prj_pt_init(&res, &(params.ec_curve)), "prj_pt_init error " __FILE__ ":" TOSTRING(__LINE__));
1225
1226
    /* Load points */
1227
349
    CF_CHECK_TRUE(libecc_detail::LoadPoint(ds, op.a, a, params, op.curveType));
1228
316
    CF_CHECK_TRUE(libecc_detail::LoadPoint(ds, op.b, b, params, op.curveType));
1229
1230
    /* Add points */
1231
287
    CF_CHECK_TRUE(!prj_pt_add(&res, &a, &b));
1232
1233
    /* Save result */
1234
287
    ret = libecc_detail::SavePoint(res, params);
1235
1236
287
    prj_pt_uninit(&res);
1237
287
    prj_pt_uninit(&a);
1238
287
    prj_pt_uninit(&b);
1239
1240
349
end:
1241
349
    libecc_detail::global_ds = nullptr;
1242
1243
349
    return ret;
1244
287
}
1245
1246
582
std::optional<component::ECC_Point> libecc::OpECC_Point_Mul(operation::ECC_Point_Mul& op) {
1247
582
    std::optional<component::ECC_Point> ret = std::nullopt;
1248
582
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1249
1250
582
    const ec_str_params* curve_params;
1251
582
    ec_params params;
1252
582
    prj_pt res, a;
1253
582
    nn b;
1254
582
    bool use_blinding = false;
1255
1256
582
    libecc_detail::global_ds = &ds;
1257
1258
    /* Load curve */
1259
582
    CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
1260
582
    CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
1261
1262
582
    CF_ASSERT(!prj_pt_init(&res, &(params.ec_curve)), "prj_pt_init error " __FILE__ ":" TOSTRING(__LINE__));
1263
1264
    /* Load point */
1265
582
    CF_CHECK_TRUE(libecc_detail::LoadPoint(ds, op.a, a, params, op.curveType));
1266
1267
    /* Load scalar */
1268
546
    CF_CHECK_TRUE(libecc_detail::To_nn_t(op.b, &b));
1269
1270
461
    try {
1271
461
        use_blinding = ds.Get<bool>();
1272
461
    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
1273
1274
    /* Multiply point by scalar */
1275
461
    if ( use_blinding == false ) {
1276
329
        CF_CHECK_TRUE(!prj_pt_mul(&res, &b, &a));
1277
132
    } else {
1278
132
        CF_CHECK_TRUE(!prj_pt_mul_blind(&res, &b, &a));
1279
57
    }
1280
1281
    /* Save result */
1282
149
    ret = libecc_detail::SavePoint(res, params);
1283
1284
149
    prj_pt_uninit(&res);
1285
149
    prj_pt_uninit(&a);
1286
1287
582
end:
1288
582
    libecc_detail::global_ds = nullptr;
1289
1290
582
    return ret;
1291
149
}
1292
1293
374
std::optional<component::ECC_Point> libecc::OpECC_Point_Dbl(operation::ECC_Point_Dbl& op) {
1294
374
    std::optional<component::ECC_Point> ret = std::nullopt;
1295
374
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1296
1297
374
    const ec_str_params* curve_params;
1298
374
    ec_params params;
1299
374
    prj_pt res, a;
1300
1301
374
    libecc_detail::global_ds = &ds;
1302
1303
    /* Load curve */
1304
374
    CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
1305
374
    CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
1306
1307
374
    CF_ASSERT(!prj_pt_init(&res, &(params.ec_curve)), "prj_pt_init error " __FILE__ ":" TOSTRING(__LINE__));
1308
1309
    /* Load point */
1310
374
    CF_CHECK_TRUE(libecc_detail::LoadPoint(ds, op.a, a, params, op.curveType));
1311
1312
    /* Double */
1313
318
    CF_CHECK_TRUE(!prj_pt_dbl(&res, &a));
1314
1315
    /* Save result */
1316
318
    ret = libecc_detail::SavePoint(res, params);
1317
1318
318
    prj_pt_uninit(&res);
1319
318
    prj_pt_uninit(&a);
1320
1321
374
end:
1322
374
    libecc_detail::global_ds = nullptr;
1323
1324
374
    return ret;
1325
318
}
1326
1327
180
std::optional<component::ECC_Point> libecc::OpECC_Point_Neg(operation::ECC_Point_Neg& op) {
1328
180
    std::optional<component::ECC_Point> ret = std::nullopt;
1329
180
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1330
1331
180
    const ec_str_params* curve_params;
1332
180
    ec_params params;
1333
180
    prj_pt res, a;
1334
1335
180
    libecc_detail::global_ds = &ds;
1336
1337
    /* Load curve */
1338
180
    CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
1339
180
    CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
1340
1341
180
    CF_ASSERT(!prj_pt_init(&res, &(params.ec_curve)), "prj_pt_init error " __FILE__ ":" TOSTRING(__LINE__));
1342
1343
    /* Load point */
1344
180
    CF_CHECK_TRUE(libecc_detail::LoadPoint(ds, op.a, a, params, op.curveType));
1345
1346
    /* Negate */
1347
155
    CF_CHECK_TRUE(!prj_pt_neg(&res, &a));
1348
1349
    /* Save result */
1350
155
    ret = libecc_detail::SavePoint(res, params);
1351
1352
155
    prj_pt_uninit(&res);
1353
155
    prj_pt_uninit(&a);
1354
1355
180
end:
1356
180
    libecc_detail::global_ds = nullptr;
1357
1358
180
    return ret;
1359
155
}
1360
1361
0
std::optional<bool> libecc::OpECC_Point_Cmp(operation::ECC_Point_Cmp& op) {
1362
0
    std::optional<bool> ret = std::nullopt;
1363
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1364
1365
0
    libecc_detail::global_ds = &ds;
1366
1367
0
    const ec_str_params* curve_params;
1368
0
    ec_params params;
1369
0
    prj_pt a, b;
1370
0
    int cmp;
1371
1372
    /* Load curve */
1373
0
    CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
1374
0
    CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
1375
1376
    /* Load points */
1377
0
    CF_CHECK_TRUE(libecc_detail::LoadPoint(ds, op.a, a, params, op.curveType));
1378
0
    CF_CHECK_TRUE(libecc_detail::LoadPoint(ds, op.b, b, params, op.curveType));
1379
1380
1381
0
    CF_CHECK_TRUE(!prj_pt_cmp(&a, &b, &cmp));
1382
0
    ret = cmp == 0;
1383
1384
0
    prj_pt_uninit(&a);
1385
0
    prj_pt_uninit(&b);
1386
1387
0
end:
1388
0
    libecc_detail::global_ds = nullptr;
1389
1390
0
    return ret;
1391
0
}
1392
1393
98
std::optional<component::Secret> libecc::OpECDH_Derive(operation::ECDH_Derive& op) {
1394
98
    std::optional<component::Secret> ret = std::nullopt;
1395
98
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1396
1397
98
    libecc_detail::global_ds = &ds;
1398
1399
98
    const ec_str_params* curve_params;
1400
98
    ec_params params;
1401
1402
    /* Extract the private key */
1403
98
    std::optional<std::vector<uint8_t>> priv_bytes;
1404
98
    std::string priv_str;
1405
98
    priv_str = op.priv.ToTrimmedString();
1406
98
    CF_CHECK_NE(priv_bytes = util::DecToBin(priv_str), std::nullopt);
1407
98
    CF_CHECK_LTE((8 * priv_bytes->size()), NN_USABLE_MAX_BIT_LEN);
1408
1409
    /* Load curve.
1410
     * NOTE: this will be WEI25519 or WEI448 (libecc uses isogenies for ed25519, ed448, x25519 and x448).
1411
     * Our underlying X25519 and X448 operations will perform these isogenies transparently.
1412
     */
1413
88
    CF_CHECK_NE(curve_params = libecc_detail::GetCurve(op.curveType), nullptr);
1414
88
    CF_ASSERT(!import_params(&params, curve_params), "import_params error " __FILE__ ":" TOSTRING(__LINE__));
1415
1416
88
    if ( op.curveType.Is(CF_ECC_CURVE("x25519")) ){
1417
0
        u8 shared_secret[X25519_SIZE];
1418
0
        std::optional<std::vector<uint8_t>> pub;
1419
        /* X25519 case, check sizes */
1420
0
        CF_CHECK_EQ(priv_bytes->size(), X25519_SIZE);
1421
        /* Import the peer public key in a buffer */
1422
0
        CF_CHECK_NE(pub = util::DecToBin(op.pub.first.ToTrimmedString(), X25519_SIZE), std::nullopt);
1423
        /* Derive our secret */
1424
0
        CF_CHECK_EQ(x25519_derive_secret(priv_bytes->data(), pub->data(), shared_secret), 0);
1425
  /* Return the shared secret */
1426
0
        ret = component::Secret(Buffer(shared_secret, X25519_SIZE));
1427
0
    }
1428
88
    else if ( op.curveType.Is(CF_ECC_CURVE("x448")) ){
1429
0
        u8 shared_secret[X448_SIZE];
1430
0
        std::optional<std::vector<uint8_t>> pub;
1431
        /* X448 case, check size */
1432
0
        CF_CHECK_EQ(priv_bytes->size(), X448_SIZE);
1433
        /* Import the peer public key in a buffer */
1434
0
        CF_CHECK_NE(pub = util::DecToBin(op.pub.first.ToTrimmedString(), X448_SIZE), std::nullopt);
1435
        /* Derive our secret */
1436
0
        CF_CHECK_EQ(x448_derive_secret(priv_bytes->data(), pub->data(), shared_secret), 0);
1437
  /* Return the shared secret */
1438
0
        ret = component::Secret(Buffer(shared_secret, X448_SIZE));
1439
0
    }
1440
88
    else{
1441
        /* ECCDH generic case */
1442
88
        ec_priv_key priv;
1443
88
        std::vector<uint8_t> pub;
1444
88
        u8 size;
1445
88
        u8 shared_secret[1024];
1446
1447
        /* Get the size of our shared secret depending on the curve */
1448
88
        CF_CHECK_EQ(ecccdh_shared_secret_size(&params, &size), 0);
1449
1450
        /* Import our private key */
1451
88
        CF_ASSERT(!ec_priv_key_import_from_buf(&priv, &params, priv_bytes->data(), priv_bytes->size(), ECCCDH), "ec_priv_key_import_from_buf error " __FILE__ ":" TOSTRING(__LINE__));
1452
        /* Import the peer public key in a buffer */
1453
88
        std::optional<std::vector<uint8_t>> X, Y;
1454
88
        const size_t pubSize = BYTECEIL(params.ec_curve.a.ctx->p_bitlen) * 3;
1455
88
        CF_ASSERT((pubSize % 2) == 0, "Public key byte size is not even");
1456
88
        CF_ASSERT((pubSize % 3) == 0, "Public key byte size is not multiple of 3");
1457
1458
88
        const size_t pointSize = pubSize / 3;
1459
88
        CF_CHECK_NE(X = util::DecToBin(op.pub.first.ToTrimmedString(), pointSize), std::nullopt);
1460
73
        CF_CHECK_NE(Y = util::DecToBin(op.pub.second.ToTrimmedString(), pointSize), std::nullopt);
1461
1462
59
        pub.resize((2 * pointSize), 0);
1463
59
        memcpy(pub.data(), X->data(), pointSize);
1464
59
        memcpy(pub.data() + pointSize, Y->data(), pointSize);
1465
1466
  /* Compute the shared secret */
1467
59
        CF_CHECK_EQ(ecccdh_derive_secret(&priv, pub.data(), pub.size(), shared_secret, size), 0);
1468
1469
  /* Return the shared secret */
1470
16
        ret = component::Secret(Buffer(shared_secret, size));
1471
16
    }
1472
1473
98
end:
1474
98
    libecc_detail::global_ds = nullptr;
1475
1476
98
    return ret;
1477
88
}
1478
1479
namespace libecc_detail {
1480
191
    static std::optional<word_t> ToWord(const component::Bignum& bn) {
1481
191
        try {
1482
191
            return boost::lexical_cast<word_t>(bn.ToTrimmedString());
1483
191
        } catch ( const boost::bad_lexical_cast &e ) {
1484
37
            return std::nullopt;
1485
37
        }
1486
191
    }
1487
1488
    class Bignum {
1489
        private:
1490
            nn v;
1491
        public:
1492
43.9k
            Bignum(void) {
1493
43.9k
                CF_ASSERT(
1494
43.9k
                        !nn_init(&v, 0),
1495
43.9k
                        "nn_init error " __FILE__ ":" TOSTRING(__LINE__));
1496
43.9k
            }
1497
1498
78.7k
            ~Bignum() { }
1499
1500
16.6k
            bool Set(const component::Bignum& bn) {
1501
16.6k
                return To_nn_t(bn, &v);
1502
16.6k
            }
1503
1504
24.6k
            nn_t GetPtr(void) {
1505
24.6k
                return &v;
1506
24.6k
            }
1507
1508
0
            std::optional<component::Bignum> ToComponentBignum(void) {
1509
0
                return To_Component_Bignum(&v);
1510
0
            }
1511
1512
4.26k
            inline int Cmp(const Bignum& rhs) {
1513
4.26k
                int check;
1514
4.26k
                CF_ASSERT(
1515
4.26k
                        !nn_cmp(&v, &rhs.v, &check),
1516
4.26k
                        "nn_cmp error " __FILE__ ":" TOSTRING(__LINE__));
1517
4.26k
                return check;
1518
4.26k
            }
1519
3.49k
            inline bool operator==(const Bignum& rhs) {
1520
3.49k
                return Cmp(rhs) == 0;
1521
3.49k
            }
1522
1523
722
            inline bool operator>(const Bignum& rhs) {
1524
722
                return Cmp(rhs) > 0;
1525
722
            }
1526
1527
557
            void SetZero(void) {
1528
557
                CF_ASSERT(
1529
557
                        !nn_zero(&v),
1530
557
                        "nn_zero error " __FILE__ ":" TOSTRING(__LINE__));
1531
557
            }
1532
1533
21
            void SetOne(void) {
1534
21
                CF_ASSERT(
1535
21
                        !nn_one(&v),
1536
21
                        "nn_one error " __FILE__ ":" TOSTRING(__LINE__));
1537
21
            }
1538
1539
98
            void SetWord(const word_t w) {
1540
98
                CF_ASSERT(
1541
98
                        !nn_set_word_value(&v, w),
1542
98
                        "nn_set_word error " __FILE__ ":" TOSTRING(__LINE__));
1543
98
            }
1544
1545
359
            bool IsZero(void) {
1546
359
                int check;
1547
359
                CF_ASSERT(
1548
359
                        !nn_iszero(&v, &check),
1549
359
                        "nn_iszero error " __FILE__ ":" TOSTRING(__LINE__));
1550
359
                return check == 1;
1551
359
            }
1552
1553
70
            bool IsOne(void) {
1554
70
                int check;
1555
70
                CF_ASSERT(
1556
70
                        !nn_isone(&v, &check),
1557
70
                        "nn_isone error " __FILE__ ":" TOSTRING(__LINE__));
1558
70
                return check == 1;
1559
70
            }
1560
1561
66
            bool IsOdd(void) {
1562
66
                int check;
1563
66
                CF_ASSERT(
1564
66
                        !nn_isodd(&v, &check),
1565
66
                        "nn_isodd error " __FILE__ ":" TOSTRING(__LINE__));
1566
66
                return check == 1;
1567
66
            }
1568
1569
329
            bitcnt_t NumBits(void) {
1570
329
                bitcnt_t numbits;
1571
329
                CF_ASSERT(
1572
329
                        !nn_bitlen(&v, &numbits),
1573
329
                        "nn_bitlen error " __FILE__ ":" TOSTRING(__LINE__));
1574
329
                return numbits;
1575
329
            }
1576
    };
1577
1578
    class BignumCluster {
1579
        private:
1580
            Datasource& ds;
1581
            std::array<Bignum, 4> bn;
1582
            std::optional<size_t> res_index = std::nullopt;
1583
        public:
1584
            BignumCluster(Datasource& ds, Bignum bn0, Bignum bn1, Bignum bn2, Bignum bn3) :
1585
                ds(ds),
1586
                bn({bn0, bn1, bn2, bn3})
1587
8.70k
                { }
1588
1589
12.3k
            Bignum& operator[](const size_t index) {
1590
12.3k
                if ( index >= bn.size() ) {
1591
0
                    abort();
1592
0
                }
1593
1594
12.3k
                try {
1595
                    /* Rewire? */
1596
12.3k
                    if ( ds.Get<bool>() == true ) {
1597
                        /* Pick a random bignum */
1598
3.55k
                        const size_t newIndex = ds.Get<uint8_t>() % 4;
1599
1600
                        /* Same value? */
1601
3.55k
                        if ( bn[newIndex] == bn[index] ) {
1602
                            /* Then return reference to other bignum */
1603
1.18k
                            return bn[newIndex];
1604
1.18k
                        }
1605
1606
                        /* Fall through */
1607
3.55k
                    }
1608
12.3k
                } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
1609
1610
11.1k
                return bn[index];
1611
12.3k
            }
1612
1613
0
            Bignum& Get(const size_t index) {
1614
0
                if ( index >= bn.size() ) {
1615
0
                    abort();
1616
0
                }
1617
0
1618
0
                return bn[index];
1619
0
            }
1620
1621
16.6k
            bool Set(const size_t index, const component::Bignum& v) {
1622
16.6k
                if ( index >= bn.size() ) {
1623
0
                    abort();
1624
0
                }
1625
1626
16.6k
                return bn[index].Set(v);
1627
16.6k
            }
1628
1629
3.82k
            nn_t GetResPtr(void) {
1630
3.82k
                CF_ASSERT(res_index == std::nullopt, "Reusing result pointer");
1631
1632
3.82k
                res_index = 0;
1633
1634
3.82k
                try { res_index = ds.Get<uint8_t>() % 4; }
1635
3.82k
                catch ( fuzzing::datasource::Datasource::OutOfData ) { }
1636
1637
3.82k
                return bn[*res_index].GetPtr();
1638
3.82k
            }
1639
1640
3.29k
            void CopyResult(Bignum& res) {
1641
3.29k
                CF_ASSERT(res_index != std::nullopt, "Result index is undefined");
1642
1643
3.29k
                const auto src = bn[*res_index].GetPtr();
1644
3.29k
                auto dest = res.GetPtr();
1645
1646
3.29k
                CF_ASSERT(
1647
3.29k
                        !nn_copy(dest, src),
1648
3.29k
                        "nn_copy error " __FILE__ ":" TOSTRING(__LINE__));
1649
3.29k
            }
1650
    };
1651
}
1652
1653
8.70k
std::optional<component::Bignum> libecc::OpBignumCalc(operation::BignumCalc& op) {
1654
8.70k
    std::optional<component::Bignum> ret = std::nullopt;
1655
8.70k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1656
1657
8.70k
    libecc_detail::global_ds = &ds;
1658
1659
8.70k
    libecc_detail::Bignum result;
1660
8.70k
    libecc_detail::BignumCluster bn{ds,
1661
8.70k
        libecc_detail::Bignum(),
1662
8.70k
        libecc_detail::Bignum(),
1663
8.70k
        libecc_detail::Bignum(),
1664
8.70k
        libecc_detail::Bignum()
1665
8.70k
    };
1666
8.70k
    bool negative = false;
1667
1668
8.70k
    if ( repository::CalcOpToNumParams(op.calcOp.Get()) > 0 ) {
1669
8.68k
        CF_CHECK_TRUE(bn.Set(0, op.bn0));
1670
6.41k
    }
1671
6.43k
    if ( repository::CalcOpToNumParams(op.calcOp.Get()) > 1 ) {
1672
6.02k
        CF_CHECK_TRUE(bn.Set(1, op.bn1));
1673
5.10k
    }
1674
5.51k
    if ( repository::CalcOpToNumParams(op.calcOp.Get()) > 2 ) {
1675
1.95k
        CF_CHECK_TRUE(bn.Set(2, op.bn2));
1676
1.10k
    }
1677
1678
4.66k
    switch ( op.calcOp.Get() ) {
1679
72
        case    CF_CALCOP("Add(A,B)"):
1680
72
            {
1681
72
                bool inc = false;
1682
1683
72
                if ( op.bn1.ToTrimmedString() == "1") {
1684
10
                    try {
1685
10
                        inc = ds.Get<bool>();
1686
10
                    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
1687
10
                }
1688
72
                if ( inc == false ) {
1689
65
                    CF_CHECK_EQ(nn_add(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr()), 0);
1690
65
                } else {
1691
7
                    CF_CHECK_EQ(nn_inc(bn.GetResPtr(), bn[0].GetPtr()), 0);
1692
7
                }
1693
72
                CF_NORET(bn.CopyResult(result));
1694
72
            }
1695
0
            break;
1696
218
        case    CF_CALCOP("Sub(A,B)"):
1697
218
            {
1698
218
                CF_CHECK_TRUE(bn[0] > bn[1]);
1699
1700
145
                bool dec = false;
1701
1702
145
                if ( op.bn1.ToTrimmedString() == "1") {
1703
26
                    try {
1704
26
                        dec = ds.Get<bool>();
1705
26
                    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
1706
26
                }
1707
1708
145
                if ( dec == false ) {
1709
139
                    CF_CHECK_EQ(nn_sub(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr()), 0);
1710
139
                } else {
1711
6
                    CF_CHECK_EQ(nn_dec(bn.GetResPtr(), bn[0].GetPtr()), 0);
1712
6
                }
1713
145
                CF_NORET(bn.CopyResult(result));
1714
145
            }
1715
0
            break;
1716
61
        case    CF_CALCOP("LShift1(A)"):
1717
61
            {
1718
61
                CF_CHECK_EQ(nn_lshift(bn.GetResPtr(), bn[0].GetPtr(), 1), 0);
1719
61
                CF_NORET(bn.CopyResult(result));
1720
1721
61
                CF_CHECK_LT(result.NumBits(), NN_MAX_BIT_LEN);
1722
61
            }
1723
0
            break;
1724
148
        case    CF_CALCOP("RShift(A,B)"):
1725
148
            {
1726
148
                std::optional<uint16_t> count;
1727
148
                CF_CHECK_NE(count = libecc_detail::To_uint16_t(op.bn1), std::nullopt);
1728
1729
99
                CF_CHECK_EQ(nn_rshift(bn.GetResPtr(), bn[0].GetPtr(), *count), 0);
1730
99
                CF_NORET(bn.CopyResult(result));
1731
99
            }
1732
0
            break;
1733
91
        case    CF_CALCOP("Mul(A,B)"):
1734
91
            {
1735
91
                bool mul_word = false;
1736
91
                std::optional<word_t> w;
1737
1738
91
                try {
1739
91
                    mul_word = ds.Get<bool>();
1740
91
                } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
1741
1742
91
                if ( mul_word == true ) {
1743
53
                    w = libecc_detail::ToWord(op.bn1);
1744
53
                    if ( w == std::nullopt ) {
1745
17
                        mul_word = false;
1746
17
                    }
1747
53
                }
1748
1749
91
                if ( mul_word == false ) {
1750
55
                    CF_CHECK_EQ(nn_mul(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr()), 0);
1751
55
                } else {
1752
36
                    CF_CHECK_EQ(nn_mul_word(bn.GetResPtr(), bn[0].GetPtr(), *w), 0);
1753
36
                }
1754
1755
91
                CF_NORET(bn.CopyResult(result));
1756
91
            }
1757
0
            break;
1758
246
        case    CF_CALCOP("Div(A,B)"):
1759
246
            {
1760
246
                libecc_detail::Bignum _remainder;
1761
246
                nn_t remainder = bn[2].GetPtr();
1762
246
                nn_t res = bn.GetResPtr();
1763
246
                nn_t bn0 = bn[0].GetPtr();
1764
246
                nn_t bn1 = bn[1].GetPtr();
1765
                /* Ensure that result pointers do not overlap */
1766
246
                if ( res == remainder ) {
1767
40
                    remainder = _remainder.GetPtr();
1768
40
                }
1769
246
                CF_CHECK_EQ(nn_divrem(res, remainder, bn0, bn1), 0);
1770
227
                CF_NORET(bn.CopyResult(result));
1771
227
            }
1772
0
            break;
1773
617
        case    CF_CALCOP("GCD(A,B)"):
1774
617
            {
1775
617
                int sign;
1776
617
                CF_CHECK_EQ(nn_gcd(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr(), &sign), 0);
1777
617
                CF_NORET(bn.CopyResult(result));
1778
617
            }
1779
0
            break;
1780
144
        case    CF_CALCOP("Mod(A,B)"):
1781
144
            CF_CHECK_FALSE(bn[1].IsZero());
1782
135
            CF_CHECK_EQ(nn_mod(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr()), 0);
1783
135
            CF_NORET(bn.CopyResult(result));
1784
135
            break;
1785
73
        case    CF_CALCOP("Sqr(A)"):
1786
73
            CF_CHECK_EQ(nn_sqr(bn.GetResPtr(), bn[0].GetPtr()), 0);
1787
73
            CF_NORET(bn.CopyResult(result));
1788
73
            break;
1789
28
        case    CF_CALCOP("And(A,B)"):
1790
28
            CF_CHECK_EQ(nn_and(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr()), 0);
1791
28
            CF_NORET(bn.CopyResult(result));
1792
28
            break;
1793
37
        case    CF_CALCOP("Or(A,B)"):
1794
37
            CF_CHECK_EQ(nn_or(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr()), 0);
1795
37
            CF_NORET(bn.CopyResult(result));
1796
37
            break;
1797
26
        case    CF_CALCOP("Xor(A,B)"):
1798
26
            CF_CHECK_EQ(nn_xor(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr()), 0);
1799
26
            CF_NORET(bn.CopyResult(result));
1800
26
            break;
1801
1.13k
        case    CF_CALCOP("InvMod(A,B)"):
1802
1.13k
            {
1803
1.13k
                bool use_nn_modinv_2exp = false;
1804
1.13k
                bitcnt_t exponent = 0;
1805
1806
1.13k
                try {
1807
1.13k
                    use_nn_modinv_2exp = ds.Get<bool>();
1808
1.13k
                } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
1809
1810
1.13k
                if ( use_nn_modinv_2exp == true ) {
1811
                    /* Determine if 2^exponent == modulus */
1812
193
                    const auto numbits = bn[1].NumBits();
1813
193
                    if ( numbits == 0 ) {
1814
13
                        use_nn_modinv_2exp = false;
1815
180
                    } else {
1816
180
                        size_t num_1_bits = 0;
1817
1.33k
                        for (bitcnt_t i = 0; i < numbits; i++) {
1818
1.32k
                            u8 bitval;
1819
1.32k
                            CF_ASSERT(
1820
1.32k
                                    nn_getbit(bn[1].GetPtr(), i, &bitval) == 0,
1821
1.32k
                                    "nn_getbit error " __FILE__ ":" TOSTRING(__LINE__));
1822
1.32k
                            if ( bitval ) {
1823
344
                                num_1_bits++;
1824
344
                                if ( num_1_bits > 1 ) {
1825
164
                                    use_nn_modinv_2exp = false;
1826
164
                                    break;
1827
164
                                }
1828
976
                            } else {
1829
976
                                exponent++;
1830
976
                            }
1831
1.32k
                        }
1832
180
                    }
1833
193
                }
1834
1835
1.13k
                if ( use_nn_modinv_2exp == true && exponent == 0 ) {
1836
                    /* XXX bug */
1837
5
                    use_nn_modinv_2exp = false;
1838
5
                }
1839
1840
1.13k
                if ( use_nn_modinv_2exp == true ) {
1841
11
                    int x_isodd;
1842
11
                    CF_CHECK_EQ(
1843
11
                            nn_modinv_2exp(
1844
11
                                bn.GetResPtr(),
1845
11
                                bn[0].GetPtr(),
1846
11
                                exponent,
1847
11
                                &x_isodd), 0);
1848
11
                    CF_NORET(bn.CopyResult(result));
1849
1.12k
                } else {
1850
1.12k
                    if ( nn_modinv(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr()) == 0 ) {
1851
661
                        CF_NORET(bn.CopyResult(result));
1852
661
                    } else {
1853
464
                        CF_NORET(result.SetZero());
1854
464
                    }
1855
1.12k
                }
1856
1.13k
            }
1857
1.13k
            break;
1858
1.13k
        case    CF_CALCOP("ExpMod(A,B,C)"):
1859
711
            CF_CHECK_EQ(nn_mod_pow(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr()), 0);
1860
690
            CF_NORET(bn.CopyResult(result));
1861
690
            break;
1862
50
        case    CF_CALCOP("MulMod(A,B,C)"):
1863
50
            CF_CHECK_TRUE(bn[2].IsOdd());
1864
31
            CF_CHECK_TRUE(bn[2] > bn[0]);
1865
18
            CF_CHECK_TRUE(bn[2] > bn[1]);
1866
1867
6
            CF_CHECK_EQ(nn_mod_mul(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr()), 0);
1868
6
            CF_NORET(bn.CopyResult(result));
1869
6
            break;
1870
106
        case    CF_CALCOP("AddMod(A,B,C)"):
1871
106
            {
1872
106
                CF_CHECK_TRUE(bn[2] > bn[0]);
1873
53
                CF_CHECK_TRUE(bn[2] > bn[1]);
1874
1875
37
                bool mod_inc = false;
1876
1877
37
                if ( op.bn1.ToTrimmedString() == "1") {
1878
13
                    try {
1879
13
                        mod_inc = ds.Get<bool>();
1880
13
                    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
1881
13
                }
1882
1883
37
                if ( mod_inc == false ) {
1884
                    /* Aliasing bug */
1885
                    //CF_CHECK_EQ(nn_mod_add(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr()), 0);
1886
                    //CF_NORET(bn.CopyResult(result));
1887
33
                    CF_CHECK_EQ(nn_mod_add(result.GetPtr(), bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr()), 0);
1888
33
                } else {
1889
                    /* Aliasing bug */
1890
                    //CF_CHECK_EQ(nn_mod_inc(bn.GetResPtr(), bn[0].GetPtr(), bn[2].GetPtr()), 0);
1891
                    //CF_NORET(bn.CopyResult(result));
1892
1893
4
                    CF_CHECK_EQ(nn_mod_inc(result.GetPtr(), bn[0].GetPtr(), bn[2].GetPtr()), 0);
1894
4
                }
1895
37
            }
1896
37
            break;
1897
151
        case    CF_CALCOP("SubMod(A,B,C)"):
1898
151
            {
1899
151
                CF_CHECK_TRUE(bn[2] > bn[0]);
1900
130
                CF_CHECK_TRUE(bn[2] > bn[1]);
1901
1902
105
                bool mod_dec = false;
1903
1904
105
                if ( op.bn1.ToTrimmedString() == "1") {
1905
55
                    try {
1906
55
                        mod_dec = ds.Get<bool>();
1907
55
                    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
1908
55
                }
1909
1910
105
                if ( mod_dec == false ) {
1911
95
                    CF_CHECK_EQ(nn_mod_sub(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr(), bn[2].GetPtr()), 0);
1912
95
                } else {
1913
10
                    CF_CHECK_EQ(nn_mod_dec(bn.GetResPtr(), bn[0].GetPtr(), bn[2].GetPtr()), 0);
1914
10
                }
1915
1916
105
                CF_NORET(bn.CopyResult(result));
1917
105
            }
1918
0
            break;
1919
47
        case    CF_CALCOP("LRot(A,B,C)"):
1920
47
            {
1921
47
                std::optional<uint16_t> count, bitlen;
1922
1923
47
                CF_CHECK_NE(count = libecc_detail::To_uint16_t(op.bn1), std::nullopt);
1924
38
                CF_CHECK_NE(bitlen = libecc_detail::To_uint16_t(op.bn2), std::nullopt);
1925
1926
35
                CF_CHECK_EQ(nn_lrot(bn.GetResPtr(), bn[0].GetPtr(), *count, *bitlen), 0);
1927
22
                CF_NORET(bn.CopyResult(result));
1928
22
            }
1929
0
            break;
1930
17
        case    CF_CALCOP("RRot(A,B,C)"):
1931
17
            {
1932
17
                std::optional<uint16_t> count, bitlen;
1933
1934
17
                CF_CHECK_NE(count = libecc_detail::To_uint16_t(op.bn1), std::nullopt);
1935
12
                CF_CHECK_NE(bitlen = libecc_detail::To_uint16_t(op.bn2), std::nullopt);
1936
1937
9
                CF_CHECK_EQ(nn_rrot(bn.GetResPtr(), bn[0].GetPtr(), *count, *bitlen), 0);
1938
3
                CF_NORET(bn.CopyResult(result));
1939
3
            }
1940
0
            break;
1941
57
        case    CF_CALCOP("ExtGCD_X(A,B)"):
1942
90
        case    CF_CALCOP("ExtGCD_Y(A,B)"):
1943
90
            {
1944
                /* NOTE: internally, libecc should support a = 0 or b = 0. Is this test necessary?
1945
                */
1946
90
                CF_CHECK_FALSE(bn[0].IsZero());
1947
84
                CF_CHECK_FALSE(bn[1].IsZero());
1948
1949
78
                int sign;
1950
1951
78
                libecc_detail::Bignum _tmp1, _tmp2;
1952
78
                nn_t tmp1 = bn[2].GetPtr();
1953
78
                nn_t tmp2 = bn[3].GetPtr();
1954
78
                nn_t res = bn.GetResPtr();
1955
78
                nn_t bn0 = bn[0].GetPtr();
1956
78
                nn_t bn1 = bn[1].GetPtr();
1957
1958
                /* Ensure that result pointers do not overlap */
1959
78
                if ( tmp1 == tmp2 || res == tmp1 || res == tmp2 ) {
1960
33
                    tmp1 = _tmp1.GetPtr();
1961
33
                    tmp2 = _tmp2.GetPtr();
1962
33
                }
1963
1964
78
                if ( op.calcOp.Get() == CF_CALCOP("ExtGCD_X(A,B)") ) {
1965
50
                    CF_CHECK_EQ(nn_xgcd(tmp1, res, tmp2, bn0, bn1, &sign), 0);
1966
50
                    negative = sign == -1;
1967
50
                } else {
1968
28
                    CF_CHECK_EQ(nn_xgcd(tmp1, tmp2, res, bn0, bn1, &sign), 0);
1969
28
                    negative = sign == 1;
1970
28
                }
1971
1972
78
                CF_NORET(bn.CopyResult(result));
1973
78
            }
1974
0
            break;
1975
9
        case    CF_CALCOP("IsZero(A)"):
1976
9
            bn[0].IsZero() ? result.SetOne() : result.SetZero();
1977
9
            break;
1978
70
        case    CF_CALCOP("IsOne(A)"):
1979
70
            bn[0].IsOne() ? result.SetOne() : result.SetZero();
1980
70
            break;
1981
16
        case    CF_CALCOP("IsOdd(A)"):
1982
16
            bn[0].IsOdd() ? result.SetOne() : result.SetZero();
1983
16
            break;
1984
75
        case    CF_CALCOP("NumBits(A)"):
1985
75
            {
1986
75
                const auto numbits = bn[0].NumBits();
1987
1988
75
                static_assert(sizeof(numbits) <= sizeof(word_t));
1989
75
                CF_NORET(result.SetWord(numbits));
1990
75
            }
1991
75
            break;
1992
114
        case    CF_CALCOP("Bit(A,B)"):
1993
114
            try {
1994
114
                const auto count = boost::lexical_cast<bitcnt_t>(op.bn1.ToTrimmedString());
1995
1996
114
                u8 bitval;
1997
114
                CF_CHECK_EQ(nn_getbit(bn[0].GetPtr(), count, &bitval), 0);
1998
1999
109
                static_assert(sizeof(bitval) <= sizeof(word_t));
2000
109
                CF_NORET(result.SetWord(bitval));
2001
109
            } catch ( const boost::bad_lexical_cast &e ) {
2002
86
            }
2003
109
            break;
2004
166
        case    CF_CALCOP("Cmp(A,B)"):
2005
166
            {
2006
166
                bool cmp_word = false;
2007
166
                std::optional<word_t> w;
2008
2009
166
                try {
2010
166
                    cmp_word = ds.Get<bool>();
2011
166
                } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
2012
2013
166
                if ( cmp_word == true ) {
2014
138
                    w = libecc_detail::ToWord(op.bn1);
2015
138
                    if ( w == std::nullopt ) {
2016
20
                        cmp_word = false;
2017
20
                    }
2018
138
                }
2019
2020
166
                if ( cmp_word == false ) {
2021
48
                    ret = component::Bignum{ std::to_string(bn[0].Cmp(bn[1])) };
2022
48
                    goto end;
2023
118
                } else {
2024
118
                    int cmp;
2025
118
                    CF_CHECK_EQ(nn_cmp_word(bn[0].GetPtr(), *w, &cmp), 0);
2026
118
                    ret = component::Bignum{ std::to_string(cmp) };
2027
118
                    goto end;
2028
118
                }
2029
166
            }
2030
0
            break;
2031
15
        case    CF_CALCOP("NegMod(A,B)"):
2032
15
            CF_CHECK_FALSE(bn[1].IsZero());
2033
2034
12
            CF_CHECK_EQ(nn_mod_neg(bn.GetResPtr(), bn[0].GetPtr(), bn[1].GetPtr()), 0);
2035
6
            CF_NORET(bn.CopyResult(result));
2036
6
            break;
2037
14
        case    CF_CALCOP("Zero()"):
2038
14
            CF_NORET(result.SetZero());
2039
14
            break;
2040
5
        case    CF_CALCOP("One()"):
2041
5
            CF_NORET(result.SetOne());
2042
5
            break;
2043
9
        case    CF_CALCOP("CondAdd(A,B,C)"):
2044
9
            CF_CHECK_EQ(nn_cnd_add(
2045
9
                        !bn[2].IsZero(),
2046
9
                        bn.GetResPtr(),
2047
9
                        bn[0].GetPtr(),
2048
9
                        bn[1].GetPtr()), 0);
2049
9
            CF_NORET(bn.CopyResult(result));
2050
9
            break;
2051
15
        case    CF_CALCOP("CondSub(A,B,C)"):
2052
15
            CF_CHECK_TRUE(bn[0] > bn[1]);
2053
8
            CF_CHECK_EQ(nn_cnd_sub(
2054
8
                        !bn[2].IsZero(),
2055
8
                        bn.GetResPtr(),
2056
8
                        bn[0].GetPtr(),
2057
8
                        bn[1].GetPtr()), 0);
2058
8
            CF_NORET(bn.CopyResult(result));
2059
8
            break;
2060
90
        case    CF_CALCOP("RandMod(A)"):
2061
90
            CF_CHECK_EQ(nn_get_random_mod(
2062
90
                        bn.GetResPtr(),
2063
90
                        bn[0].GetPtr()), 0);
2064
84
            CF_NORET(bn.CopyResult(result));
2065
84
            break;
2066
0
        default:
2067
0
            goto end;
2068
4.66k
    }
2069
2070
4.09k
    ret = libecc_detail::To_Component_Bignum(result.GetPtr(), negative);
2071
2072
8.70k
end:
2073
8.70k
    libecc_detail::global_ds = nullptr;
2074
2075
8.70k
    return ret;
2076
4.09k
}
2077
2078
} /* namespace module */
2079
} /* namespace cryptofuzz */