Coverage Report

Created: 2022-08-24 06:31

/src/cryptofuzz/tests.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "tests.h"
2
#include <fuzzing/datasource/id.hpp>
3
#include <cryptofuzz/repository.h>
4
#include <cryptofuzz/util.h>
5
#include <boost/multiprecision/cpp_int.hpp>
6
#include <iostream>
7
8
namespace cryptofuzz {
9
namespace tests {
10
11
template <class ResultType, class OperationType>
12
845
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
845
    if ( result != std::nullopt && op.keySize != result->GetSize() ) {
14
        /* TODO include module name in abort message */
15
0
        util::abort({op.Name(), "invalid keySize"});
16
0
    }
17
845
}
void cryptofuzz::tests::verifyKeySize<std::__1::optional<cryptofuzz::Buffer>, cryptofuzz::operation::KDF_SCRYPT>(cryptofuzz::operation::KDF_SCRYPT const&, std::__1::optional<cryptofuzz::Buffer> const&)
Line
Count
Source
12
120
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
120
    if ( result != std::nullopt && op.keySize != result->GetSize() ) {
14
        /* TODO include module name in abort message */
15
0
        util::abort({op.Name(), "invalid keySize"});
16
0
    }
17
120
}
void cryptofuzz::tests::verifyKeySize<std::__1::optional<cryptofuzz::Buffer>, cryptofuzz::operation::KDF_HKDF>(cryptofuzz::operation::KDF_HKDF const&, std::__1::optional<cryptofuzz::Buffer> const&)
Line
Count
Source
12
92
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
92
    if ( result != std::nullopt && op.keySize != result->GetSize() ) {
14
        /* TODO include module name in abort message */
15
0
        util::abort({op.Name(), "invalid keySize"});
16
0
    }
17
92
}
void cryptofuzz::tests::verifyKeySize<std::__1::optional<cryptofuzz::Buffer>, cryptofuzz::operation::KDF_TLS1_PRF>(cryptofuzz::operation::KDF_TLS1_PRF const&, std::__1::optional<cryptofuzz::Buffer> const&)
Line
Count
Source
12
66
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
66
    if ( result != std::nullopt && op.keySize != result->GetSize() ) {
14
        /* TODO include module name in abort message */
15
0
        util::abort({op.Name(), "invalid keySize"});
16
0
    }
17
66
}
void cryptofuzz::tests::verifyKeySize<std::__1::optional<cryptofuzz::Buffer>, cryptofuzz::operation::KDF_PBKDF>(cryptofuzz::operation::KDF_PBKDF const&, std::__1::optional<cryptofuzz::Buffer> const&)
Line
Count
Source
12
100
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
100
    if ( result != std::nullopt && op.keySize != result->GetSize() ) {
14
        /* TODO include module name in abort message */
15
0
        util::abort({op.Name(), "invalid keySize"});
16
0
    }
17
100
}
void cryptofuzz::tests::verifyKeySize<std::__1::optional<cryptofuzz::Buffer>, cryptofuzz::operation::KDF_PBKDF1>(cryptofuzz::operation::KDF_PBKDF1 const&, std::__1::optional<cryptofuzz::Buffer> const&)
Line
Count
Source
12
59
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
59
    if ( result != std::nullopt && op.keySize != result->GetSize() ) {
14
        /* TODO include module name in abort message */
15
0
        util::abort({op.Name(), "invalid keySize"});
16
0
    }
17
59
}
void cryptofuzz::tests::verifyKeySize<std::__1::optional<cryptofuzz::Buffer>, cryptofuzz::operation::KDF_PBKDF2>(cryptofuzz::operation::KDF_PBKDF2 const&, std::__1::optional<cryptofuzz::Buffer> const&)
Line
Count
Source
12
60
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
60
    if ( result != std::nullopt && op.keySize != result->GetSize() ) {
14
        /* TODO include module name in abort message */
15
0
        util::abort({op.Name(), "invalid keySize"});
16
0
    }
17
60
}
void cryptofuzz::tests::verifyKeySize<std::__1::optional<cryptofuzz::Buffer>, cryptofuzz::operation::KDF_ARGON2>(cryptofuzz::operation::KDF_ARGON2 const&, std::__1::optional<cryptofuzz::Buffer> const&)
Line
Count
Source
12
25
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
25
    if ( result != std::nullopt && op.keySize != result->GetSize() ) {
14
        /* TODO include module name in abort message */
15
0
        util::abort({op.Name(), "invalid keySize"});
16
0
    }
17
25
}
void cryptofuzz::tests::verifyKeySize<std::__1::optional<cryptofuzz::Buffer>, cryptofuzz::operation::KDF_SSH>(cryptofuzz::operation::KDF_SSH const&, std::__1::optional<cryptofuzz::Buffer> const&)
Line
Count
Source
12
89
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
89
    if ( result != std::nullopt && op.keySize != result->GetSize() ) {
14
        /* TODO include module name in abort message */
15
0
        util::abort({op.Name(), "invalid keySize"});
16
0
    }
17
89
}
void cryptofuzz::tests::verifyKeySize<std::__1::optional<cryptofuzz::Buffer>, cryptofuzz::operation::KDF_X963>(cryptofuzz::operation::KDF_X963 const&, std::__1::optional<cryptofuzz::Buffer> const&)
Line
Count
Source
12
82
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
82
    if ( result != std::nullopt && op.keySize != result->GetSize() ) {
14
        /* TODO include module name in abort message */
15
0
        util::abort({op.Name(), "invalid keySize"});
16
0
    }
17
82
}
void cryptofuzz::tests::verifyKeySize<std::__1::optional<cryptofuzz::Buffer>, cryptofuzz::operation::KDF_BCRYPT>(cryptofuzz::operation::KDF_BCRYPT const&, std::__1::optional<cryptofuzz::Buffer> const&)
Line
Count
Source
12
3
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
3
    if ( result != std::nullopt && op.keySize != result->GetSize() ) {
14
        /* TODO include module name in abort message */
15
0
        util::abort({op.Name(), "invalid keySize"});
16
0
    }
17
3
}
void cryptofuzz::tests::verifyKeySize<std::__1::optional<cryptofuzz::Buffer>, cryptofuzz::operation::KDF_SP_800_108>(cryptofuzz::operation::KDF_SP_800_108 const&, std::__1::optional<cryptofuzz::Buffer> const&)
Line
Count
Source
12
149
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
149
    if ( result != std::nullopt && op.keySize != result->GetSize() ) {
14
        /* TODO include module name in abort message */
15
0
        util::abort({op.Name(), "invalid keySize"});
16
0
    }
17
149
}
18
19
1.63k
void test(const operation::Digest& op, const std::optional<component::Digest>& result) {
20
1.63k
    if ( result == std::nullopt ) {
21
151
        return;
22
151
    }
23
24
1.47k
    const auto expectedSize = repository::DigestSize(op.digestType.Get());
25
26
1.47k
    if ( expectedSize == std::nullopt ) {
27
83
        return;
28
83
    }
29
30
1.39k
    if ( result->GetSize() != *expectedSize ) {
31
0
        printf("Expected vs actual digest size: %zu / %zu\n", *expectedSize, result->GetSize());
32
0
        abort();
33
0
    }
34
1.39k
}
35
36
1.55k
void test(const operation::HMAC& op, const std::optional<component::MAC>& result) {
37
1.55k
    if ( result == std::nullopt ) {
38
257
        return;
39
257
    }
40
41
1.29k
    const auto expectedSize = repository::DigestSize(op.digestType.Get());
42
43
1.29k
    if ( expectedSize == std::nullopt ) {
44
96
        return;
45
96
    }
46
47
1.19k
    if ( result->GetSize() != *expectedSize ) {
48
0
        printf("Expected vs actual digest size: %zu / %zu\n", *expectedSize, result->GetSize());
49
0
        abort();
50
0
    }
51
1.19k
}
52
53
61
void test(const operation::UMAC& op, const std::optional<component::MAC>& result) {
54
61
    if ( result == std::nullopt ) {
55
61
        return;
56
61
    }
57
58
0
    if (
59
0
            ( op.type == 0 && result->GetSize() > (32/8) ) ||
60
0
            ( op.type == 1 && result->GetSize() > (64/8) ) ||
61
0
            ( op.type == 2 && result->GetSize() > (96/8) ) ||
62
0
            ( op.type == 3 && result->GetSize() > (128/8) )
63
0
    ) {
64
0
        printf("UMAC: Overlong result: %zu\n", result->GetSize());
65
0
        abort();
66
0
    }
67
0
}
68
69
2.65k
static void test_ChaCha20_Poly1305_IV(const operation::SymmetricEncrypt& op, const std::optional<component::Ciphertext>& result) {
70
2.65k
    using fuzzing::datasource::ID;
71
72
    /*
73
     * OpenSSL CVE-2019-1543
74
     * https://www.openssl.org/news/secadv/20190306.txt
75
     */
76
77
2.65k
    if ( op.cipher.cipherType.Get() != CF_CIPHER("CHACHA20_POLY1305") ) {
78
2.58k
        return;
79
2.58k
    }
80
81
67
    if ( result == std::nullopt ) {
82
56
        return;
83
56
    }
84
85
11
    if ( op.cipher.iv.GetSize() > 12 ) {
86
0
        abort();
87
0
    }
88
11
}
89
90
2.65k
static void test_XChaCha20_Poly1305_IV(const operation::SymmetricEncrypt& op, const std::optional<component::Ciphertext>& result) {
91
2.65k
    using fuzzing::datasource::ID;
92
93
2.65k
    if ( op.cipher.cipherType.Get() != CF_CIPHER("XCHACHA20_POLY1305") ) {
94
2.60k
        return;
95
2.60k
    }
96
97
45
    if ( result == std::nullopt ) {
98
32
        return;
99
32
    }
100
101
13
    if ( op.cipher.iv.GetSize() != 24 ) {
102
0
        printf("XChaCha20-Poly1305 succeeded with an IV of %zu bytes large, but only IVs of 24 bytes are valid\n", op.cipher.iv.GetSize());
103
0
        abort();
104
0
    }
105
13
}
106
107
2.65k
static void test_AES_CCM_Wycheproof(const operation::SymmetricEncrypt& op, const std::optional<component::Ciphertext>& result) {
108
2.65k
    bool fail = false;
109
110
2.65k
    if ( result == std::nullopt ) {
111
1.53k
        return;
112
1.53k
    }
113
114
1.12k
    switch ( op.cipher.cipherType.Get() ) {
115
0
        case CF_CIPHER("AES_128_CCM"):
116
0
        case CF_CIPHER("AES_192_CCM"):
117
62
        case CF_CIPHER("AES_256_CCM"):
118
62
            break;
119
1.05k
        default:
120
1.05k
            return;
121
1.12k
    }
122
123
62
    if ( op.cipher.iv.GetSize() < 7 || op.cipher.iv.GetSize() > 13 ) {
124
0
        printf("AES CCM: Invalid IV size\n");
125
0
        fail = true;
126
0
    }
127
128
62
    if ( result->tag != std::nullopt ) {
129
0
        static const std::vector<size_t> validTagSizes = {4, 6, 8, 10, 12, 14, 16};
130
131
0
        if ( std::find(validTagSizes.begin(), validTagSizes.end(), result->tag->GetSize()) == validTagSizes.end() ) {
132
0
            printf("AES CCM: Invalid tag size\n");
133
0
            fail = true;
134
0
        }
135
0
    }
136
137
62
    if ( fail == true ) {
138
0
        printf("AES CCM tests based on Wycheproof: https://github.com/google/wycheproof/blob/4672ff74d68766e7785c2cac4c597effccef2c5c/testvectors/aes_ccm_test.json#L11\n");
139
0
        abort();
140
0
    }
141
62
}
142
143
2.65k
static void test_AES_GCM_Wycheproof(const operation::SymmetricEncrypt& op, const std::optional<component::Ciphertext>& result) {
144
2.65k
    bool fail = false;
145
146
2.65k
    if ( result == std::nullopt ) {
147
1.53k
        return;
148
1.53k
    }
149
150
1.12k
    switch ( op.cipher.cipherType.Get() ) {
151
25
        case CF_CIPHER("AES_128_GCM"):
152
43
        case CF_CIPHER("AES_192_GCM"):
153
48
        case CF_CIPHER("AES_256_GCM"):
154
48
            break;
155
1.07k
        default:
156
1.07k
            return;
157
1.12k
    }
158
159
48
    if ( op.cipher.iv.GetSize() == 0 ) {
160
0
        printf("AES GCM: Invalid IV size\n");
161
0
        fail = true;
162
0
    }
163
164
48
    if ( fail == true ) {
165
0
        printf("AES GCM tests based on Wycheproof: https://github.com/google/wycheproof/blob/4672ff74d68766e7785c2cac4c597effccef2c5c/testvectors/aes_gcm_test.json#L13\n");
166
0
        abort();
167
0
    }
168
48
}
169
170
2.65k
void test(const operation::SymmetricEncrypt& op, const std::optional<component::Ciphertext>& result) {
171
2.65k
    test_ChaCha20_Poly1305_IV(op, result);
172
2.65k
    test_XChaCha20_Poly1305_IV(op, result);
173
2.65k
    test_AES_CCM_Wycheproof(op, result);
174
2.65k
    test_AES_GCM_Wycheproof(op, result);
175
2.65k
}
176
177
1.81k
void test(const operation::SymmetricDecrypt& op, const std::optional<component::Cleartext>& result) {
178
1.81k
    (void)op;
179
1.81k
    (void)result;
180
1.81k
}
181
182
4.10k
void test(const operation::CMAC& op, const std::optional<component::MAC>& result) {
183
4.10k
    (void)op;
184
4.10k
    (void)result;
185
4.10k
}
186
187
120
void test(const operation::KDF_SCRYPT& op, const std::optional<component::Key>& result) {
188
120
    verifyKeySize(op, result);
189
120
}
190
191
92
static void test_HKDF_OutputSize(const operation::KDF_HKDF& op, const std::optional<component::Key>& result) {
192
92
    if ( result == std::nullopt ) {
193
92
        return;
194
92
    }
195
196
0
    const auto expectedSize = repository::DigestSize(op.digestType.Get());
197
198
0
    if ( expectedSize == std::nullopt ) {
199
0
        return;
200
0
    }
201
202
0
    const size_t maxOutputSize = 255 * *expectedSize;
203
204
0
    if ( result->GetSize() > maxOutputSize ) {
205
0
        printf("The output size of HKDF (%zu) is more than 255 * the size of the hash digest (%zu)\n", result->GetSize(), maxOutputSize);
206
0
        abort();
207
0
    }
208
0
}
209
210
92
void test(const operation::KDF_HKDF& op, const std::optional<component::Key>& result) {
211
92
    verifyKeySize(op, result);
212
213
92
    test_HKDF_OutputSize(op, result);
214
92
}
215
216
66
void test(const operation::KDF_TLS1_PRF& op, const std::optional<component::Key>& result) {
217
66
    verifyKeySize(op, result);
218
66
}
219
220
100
void test(const operation::KDF_PBKDF& op, const std::optional<component::Key>& result) {
221
100
    verifyKeySize(op, result);
222
100
}
223
224
59
void test(const operation::KDF_PBKDF1& op, const std::optional<component::Key>& result) {
225
59
    verifyKeySize(op, result);
226
59
}
227
228
60
void test(const operation::KDF_PBKDF2& op, const std::optional<component::Key>& result) {
229
60
    verifyKeySize(op, result);
230
60
}
231
232
25
void test(const operation::KDF_ARGON2& op, const std::optional<component::Key>& result) {
233
25
    verifyKeySize(op, result);
234
25
}
235
236
89
void test(const operation::KDF_SSH& op, const std::optional<component::Key>& result) {
237
89
    verifyKeySize(op, result);
238
89
}
239
240
82
void test(const operation::KDF_X963& op, const std::optional<component::Key>& result) {
241
82
    verifyKeySize(op, result);
242
82
}
243
244
3
void test(const operation::KDF_BCRYPT& op, const std::optional<component::Key>& result) {
245
3
    verifyKeySize(op, result);
246
3
}
247
248
149
void test(const operation::KDF_SP_800_108& op, const std::optional<component::Key>& result) {
249
149
    verifyKeySize(op, result);
250
149
}
251
252
384
static bool IsSpecialCurve(const uint64_t curveID) {
253
384
    switch ( curveID ) {
254
0
        case CF_ECC_CURVE("ed448"):
255
0
        case CF_ECC_CURVE("ed25519"):
256
0
        case CF_ECC_CURVE("x25519"):
257
0
        case CF_ECC_CURVE("x448"):
258
0
            return true;
259
384
        default:
260
384
            return false;
261
384
    }
262
384
}
263
264
1.45k
static void test_ECC_PrivateKey(const uint64_t curveID, const std::string priv) {
265
    /* Disabled until all modules comply by default */
266
1.45k
    return;
267
268
    /* Private key may be 0 with these curves */
269
0
    if ( IsSpecialCurve(curveID) ) {
270
0
        return;
271
0
    }
272
273
0
    if ( priv == "0" ) {
274
0
        std::cout << "0 is an invalid elliptic curve private key" << std::endl;
275
0
        ::abort();
276
0
    }
277
0
}
278
279
280
339
void test(const operation::ECC_PrivateToPublic& op, const std::optional<component::ECC_PublicKey>& result) {
281
339
    if ( result != std::nullopt ) {
282
267
        test_ECC_PrivateKey(op.curveType.Get(), op.priv.ToTrimmedString());
283
267
    }
284
339
}
285
286
174
void test(const operation::ECC_ValidatePubkey& op, const std::optional<bool>& result) {
287
174
    (void)op;
288
174
    (void)result;
289
174
}
290
291
843
void test(const operation::ECC_GenerateKeyPair& op, const std::optional<component::ECC_KeyPair>& result) {
292
843
    if ( result != std::nullopt ) {
293
809
        test_ECC_PrivateKey(op.curveType.Get(), result->priv.ToTrimmedString());
294
809
    }
295
843
}
296
297
384
static void test_ECDSA_Signature(const uint64_t curveID, const std::string R, const std::string S) {
298
384
    if ( IsSpecialCurve(curveID) ) {
299
0
        return;
300
0
    }
301
302
384
    const boost::multiprecision::cpp_int r(R), s(S);
303
304
384
    if ( r < 1 ) {
305
0
        std::cout << "ECDSA signature invalid: R < 1" << std::endl;
306
0
        ::abort();
307
0
    }
308
384
    if ( s < 1 ) {
309
0
        std::cout << "ECDSA signature invalid: S < 1" << std::endl;
310
0
        ::abort();
311
0
    }
312
313
384
    const auto O = cryptofuzz::repository::ECC_CurveToOrder(curveID);
314
384
    if ( O == std::nullopt ) {
315
74
        return;
316
74
    }
317
318
310
    const boost::multiprecision::cpp_int o(*O);
319
320
310
    if ( r >= o ) {
321
0
        std::cout << "ECDSA signature invalid: R >= order" << std::endl;
322
0
        ::abort();
323
0
    }
324
325
310
    if ( s >= o ) {
326
0
        std::cout << "ECDSA signature invalid: S >= order" << std::endl;
327
0
        ::abort();
328
0
    }
329
310
}
330
331
0
static void test_BIP340_Schnorr_Signature(const uint64_t curveID, const std::string R, const std::string S) {
332
0
    boost::multiprecision::cpp_int r(R);
333
0
    boost::multiprecision::cpp_int s(S);
334
0
    if ( r < 1 ) {
335
0
        std::cout << "BIP340 Schnorr signature invalid: R < 1" << std::endl;
336
0
        ::abort();
337
0
    }
338
0
    if ( s < 1 ) {
339
0
        std::cout << "BIP340 Schnorr signature invalid: S < 1" << std::endl;
340
0
        ::abort();
341
0
    }
342
343
0
    const auto prime = cryptofuzz::repository::ECC_CurveToPrime(curveID);
344
0
    if ( prime != std::nullopt ) {
345
0
        const boost::multiprecision::cpp_int p(*prime);
346
0
        CF_ASSERT(r < p, "BIP340 Schnorr signature R should be less than curve P");
347
0
    }
348
349
0
    const auto order = cryptofuzz::repository::ECC_CurveToOrder(curveID);
350
0
    if ( order != std::nullopt ) {
351
0
        const boost::multiprecision::cpp_int n(*order);
352
0
        CF_ASSERT(s < n, "BIP340 Schnorr signature S should be less than curve N");
353
0
    }
354
0
}
355
356
449
void test(const operation::ECDSA_Sign& op, const std::optional<component::ECDSA_Signature>& result) {
357
449
    if ( result != std::nullopt ) {
358
379
        test_ECC_PrivateKey(op.curveType.Get(), op.priv.ToTrimmedString());
359
360
379
        if (
361
379
                op.UseSpecifiedNonce() == true &&
362
379
                !IsSpecialCurve(op.curveType.Get()) &&
363
379
                op.nonce.ToTrimmedString() == "0"
364
379
           ) {
365
0
            std::cout << "0 is an invalid ECDSA nonce" << std::endl;
366
0
            ::abort();
367
0
        }
368
369
379
        test_ECDSA_Signature(op.curveType.Get(),
370
379
                result->signature.first.ToTrimmedString(),
371
379
                result->signature.second.ToTrimmedString());
372
379
    }
373
449
}
374
375
39
void test(const operation::ECGDSA_Sign& op, const std::optional<component::ECGDSA_Signature>& result) {
376
39
    if ( result != std::nullopt ) {
377
0
        test_ECC_PrivateKey(op.curveType.Get(), op.priv.ToTrimmedString());
378
379
0
        if (
380
0
                op.UseSpecifiedNonce() == true &&
381
0
                !IsSpecialCurve(op.curveType.Get()) &&
382
0
                op.nonce.ToTrimmedString() == "0"
383
0
           ) {
384
0
            std::cout << "0 is an invalid ECGDSA nonce" << std::endl;
385
0
            ::abort();
386
0
        }
387
388
0
        test_ECDSA_Signature(op.curveType.Get(),
389
0
                result->signature.first.ToTrimmedString(),
390
0
                result->signature.second.ToTrimmedString());
391
0
    }
392
39
}
393
394
14
void test(const operation::ECRDSA_Sign& op, const std::optional<component::ECRDSA_Signature>& result) {
395
14
    if ( result != std::nullopt ) {
396
0
        test_ECC_PrivateKey(op.curveType.Get(), op.priv.ToTrimmedString());
397
398
0
        if (
399
0
                op.UseSpecifiedNonce() == true &&
400
0
                !IsSpecialCurve(op.curveType.Get()) &&
401
0
                op.nonce.ToTrimmedString() == "0"
402
0
           ) {
403
0
            std::cout << "0 is an invalid ECRDSA nonce" << std::endl;
404
0
            ::abort();
405
0
        }
406
407
0
        test_ECDSA_Signature(op.curveType.Get(),
408
0
                result->signature.first.ToTrimmedString(),
409
0
                result->signature.second.ToTrimmedString());
410
0
    }
411
14
}
412
413
20
void test(const operation::Schnorr_Sign& op, const std::optional<component::Schnorr_Signature>& result) {
414
20
    if ( result != std::nullopt ) {
415
0
        test_ECC_PrivateKey(op.curveType.Get(), op.priv.ToTrimmedString());
416
417
0
        if (
418
0
                op.UseSpecifiedNonce() == true &&
419
0
                !IsSpecialCurve(op.curveType.Get()) &&
420
0
                op.nonce.ToTrimmedString() == "0"
421
0
           ) {
422
0
            std::cout << "0 is an invalid Schnorr nonce" << std::endl;
423
0
            ::abort();
424
0
        }
425
426
0
        test_BIP340_Schnorr_Signature(op.curveType.Get(),
427
0
                result->signature.first.ToTrimmedString(),
428
0
                result->signature.second.ToTrimmedString());
429
0
    }
430
20
}
431
432
257
void test(const operation::ECDSA_Verify& op, const std::optional<bool>& result) {
433
257
    if ( result != std::nullopt && *result == true ) {
434
5
        test_ECDSA_Signature(op.curveType.Get(),
435
5
                op.signature.signature.first.ToTrimmedString(),
436
5
                op.signature.signature.second.ToTrimmedString());
437
5
    }
438
257
}
439
440
15
void test(const operation::ECGDSA_Verify& op, const std::optional<bool>& result) {
441
15
    if ( result != std::nullopt && *result == true ) {
442
0
        test_ECDSA_Signature(op.curveType.Get(),
443
0
                op.signature.signature.first.ToTrimmedString(),
444
0
                op.signature.signature.second.ToTrimmedString());
445
0
    }
446
15
}
447
448
18
void test(const operation::ECRDSA_Verify& op, const std::optional<bool>& result) {
449
18
    if ( result != std::nullopt && *result == true ) {
450
0
        test_ECDSA_Signature(op.curveType.Get(),
451
0
                op.signature.signature.first.ToTrimmedString(),
452
0
                op.signature.signature.second.ToTrimmedString());
453
0
    }
454
18
}
455
456
26
void test(const operation::Schnorr_Verify& op, const std::optional<bool>& result) {
457
26
    if ( result != std::nullopt && *result == true ) {
458
0
        test_BIP340_Schnorr_Signature(op.curveType.Get(),
459
0
                op.signature.signature.first.ToTrimmedString(),
460
0
                op.signature.signature.second.ToTrimmedString());
461
0
    }
462
26
}
463
464
11
void test(const operation::ECDSA_Recover& op, const std::optional<component::ECC_PublicKey>& result) {
465
11
    if ( result != std::nullopt ) {
466
0
        if ( op.id > 3 ) {
467
0
            std::cout << "Invalid recovery ID" << std::endl;
468
0
            ::abort();
469
0
        }
470
0
    }
471
11
    if ( result != std::nullopt ) {
472
0
        test_ECDSA_Signature(op.curveType.Get(),
473
0
                op.signature.first.ToTrimmedString(),
474
0
                op.signature.second.ToTrimmedString());
475
0
    }
476
11
}
477
478
25
void test(const operation::ECDH_Derive& op, const std::optional<component::Secret>& result) {
479
25
    (void)op;
480
25
    (void)result;
481
25
}
482
483
6
void test(const operation::ECIES_Encrypt& op, const std::optional<component::Ciphertext>& result) {
484
    /* TODO check minimum size? */
485
6
    (void)op;
486
6
    (void)result;
487
6
}
488
489
24
void test(const operation::ECIES_Decrypt& op, const std::optional<component::Cleartext>& result) {
490
24
    (void)op;
491
24
    (void)result;
492
24
}
493
494
42
void test(const operation::ECC_Point_Add& op, const std::optional<component::ECC_Point>& result) {
495
42
    (void)op;
496
42
    (void)result;
497
42
}
498
499
40
void test(const operation::ECC_Point_Mul& op, const std::optional<component::ECC_Point>& result) {
500
40
    (void)op;
501
40
    (void)result;
502
40
}
503
504
40
void test(const operation::ECC_Point_Neg& op, const std::optional<component::ECC_Point>& result) {
505
40
    (void)op;
506
40
    (void)result;
507
40
}
508
509
37
void test(const operation::ECC_Point_Dbl& op, const std::optional<component::ECC_Point>& result) {
510
37
    (void)op;
511
37
    (void)result;
512
37
}
513
514
515
void test(const operation::DH_GenerateKeyPair& op, const std::optional<component::DH_KeyPair>& result) {
515
515
    (void)op;
516
515
    (void)result;
517
515
}
518
519
103
void test(const operation::DH_Derive& op, const std::optional<component::Bignum>& result) {
520
103
    (void)op;
521
103
    (void)result;
522
103
}
523
524
24
void test(const operation::BLS_PrivateToPublic& op, const std::optional<component::BLS_PublicKey>& result) {
525
24
    (void)op;
526
24
    (void)result;
527
24
}
528
529
25
void test(const operation::BLS_PrivateToPublic_G2& op, const std::optional<component::G2>& result) {
530
25
    (void)op;
531
25
    (void)result;
532
25
}
533
534
14
void test(const operation::BLS_Sign& op, const std::optional<component::BLS_Signature>& result) {
535
14
    (void)op;
536
14
    (void)result;
537
14
}
538
539
9
void test(const operation::BLS_Verify& op, const std::optional<bool>& result) {
540
9
    (void)op;
541
9
    (void)result;
542
9
}
543
544
19
void test(const operation::BLS_BatchSign& op, const std::optional<component::BLS_BatchSignature>& result) {
545
19
    (void)op;
546
19
    (void)result;
547
19
}
548
549
8
void test(const operation::BLS_BatchVerify& op, const std::optional<bool>& result) {
550
8
    (void)op;
551
8
    (void)result;
552
8
}
553
554
16
void test(const operation::BLS_Aggregate_G1& op, const std::optional<component::G1>& result) {
555
16
    (void)op;
556
16
    (void)result;
557
16
}
558
559
14
void test(const operation::BLS_Aggregate_G2& op, const std::optional<component::G2>& result) {
560
14
    (void)op;
561
14
    (void)result;
562
14
}
563
564
23
void test(const operation::BLS_Pairing& op, const std::optional<component::Fp12>& result) {
565
23
    (void)op;
566
23
    (void)result;
567
23
}
568
569
10
void test(const operation::BLS_MillerLoop& op, const std::optional<component::Fp12>& result) {
570
10
    (void)op;
571
10
    (void)result;
572
10
}
573
574
13
void test(const operation::BLS_FinalExp& op, const std::optional<component::Fp12>& result) {
575
13
    (void)op;
576
13
    (void)result;
577
13
}
578
579
26
void test(const operation::BLS_HashToG1& op, const std::optional<component::G1>& result) {
580
26
    (void)op;
581
26
    (void)result;
582
26
}
583
584
22
void test(const operation::BLS_HashToG2& op, const std::optional<component::G2>& result) {
585
22
    (void)op;
586
22
    (void)result;
587
22
}
588
589
11
void test(const operation::BLS_MapToG1& op, const std::optional<component::G1>& result) {
590
11
    (void)op;
591
11
    (void)result;
592
11
}
593
594
19
void test(const operation::BLS_MapToG2& op, const std::optional<component::G2>& result) {
595
19
    (void)op;
596
19
    (void)result;
597
19
}
598
599
21
void test(const operation::BLS_IsG1OnCurve& op, const std::optional<bool>& result) {
600
21
    (void)op;
601
21
    (void)result;
602
21
}
603
604
37
void test(const operation::BLS_IsG2OnCurve& op, const std::optional<bool>& result) {
605
37
    (void)op;
606
37
    (void)result;
607
37
}
608
609
14
void test(const operation::BLS_GenerateKeyPair& op, const std::optional<component::BLS_KeyPair>& result) {
610
14
    (void)op;
611
14
    (void)result;
612
14
}
613
614
15
void test(const operation::BLS_Decompress_G1& op, const std::optional<component::G1>& result) {
615
15
    (void)op;
616
15
    (void)result;
617
15
}
618
619
25
void test(const operation::BLS_Compress_G1& op, const std::optional<component::Bignum>& result) {
620
25
    (void)op;
621
25
    (void)result;
622
25
}
623
624
23
void test(const operation::BLS_Decompress_G2& op, const std::optional<component::G2>& result) {
625
23
    (void)op;
626
23
    (void)result;
627
23
}
628
629
7
void test(const operation::BLS_Compress_G2& op, const std::optional<component::G1>& result) {
630
7
    (void)op;
631
7
    (void)result;
632
7
}
633
634
41
void test(const operation::BLS_G1_Add& op, const std::optional<component::G1>& result) {
635
41
    (void)op;
636
41
    (void)result;
637
41
}
638
639
18
void test(const operation::BLS_G1_Mul& op, const std::optional<component::G1>& result) {
640
18
    (void)op;
641
18
    (void)result;
642
18
}
643
644
19
void test(const operation::BLS_G1_IsEq& op, const std::optional<bool>& result) {
645
19
    (void)op;
646
19
    (void)result;
647
19
}
648
649
19
void test(const operation::BLS_G1_Neg& op, const std::optional<component::G1>& result) {
650
19
    (void)op;
651
19
    (void)result;
652
19
}
653
654
50
void test(const operation::BLS_G2_Add& op, const std::optional<component::G2>& result) {
655
50
    (void)op;
656
50
    (void)result;
657
50
}
658
659
35
void test(const operation::BLS_G2_Mul& op, const std::optional<component::G2>& result) {
660
35
    (void)op;
661
35
    (void)result;
662
35
}
663
664
28
void test(const operation::BLS_G2_IsEq& op, const std::optional<bool>& result) {
665
28
    (void)op;
666
28
    (void)result;
667
28
}
668
669
9
void test(const operation::BLS_G2_Neg& op, const std::optional<component::G2>& result) {
670
9
    (void)op;
671
9
    (void)result;
672
9
}
673
674
14
void test(const operation::Misc& op, const std::optional<Buffer>& result) {
675
14
    (void)op;
676
14
    (void)result;
677
14
}
678
679
11
void test(const operation::SR25519_Verify& op, const std::optional<bool>& result) {
680
11
    (void)op;
681
11
    (void)result;
682
11
}
683
684
namespace BignumCalc {
685
0
    static void Abort(const std::string& message, const std::string& opStr) {
686
0
        std::cout << "BignumCalc ( " << opStr << " ): " << message << std::endl;
687
0
        ::abort();
688
0
    }
689
275
    static void AssertBinary(const component::Bignum& result, const std::string& opStr) {
690
275
        const auto resultStr = result.ToTrimmedString();
691
275
        if ( !(resultStr == "0" || resultStr == "1") ) {
692
0
            Abort("Result must be 0 or 1", opStr);
693
0
        }
694
275
    }
695
154
    static void AssertTertiary(const component::Bignum& result, const std::string& opStr) {
696
154
        const auto resultStr = result.ToTrimmedString();
697
154
        if ( !(resultStr == "0" || resultStr == "1" || resultStr == "-1") ) {
698
0
            Abort("Result must be 0 or 1 or -1", opStr);
699
0
        }
700
154
    }
701
0
    static bool IsEqual(const component::Bignum& A, const component::Bignum& B) {
702
0
        return A.ToTrimmedString() == B.ToTrimmedString();
703
0
    }
704
84
    static bool IsZero(const component::Bignum& A) {
705
84
        return A.ToTrimmedString() == "0";
706
84
    }
707
181
    static bool SmallerThan(const component::Bignum& A, const component::Bignum& B) {
708
181
        return A.ToTrimmedString().size() < B.ToTrimmedString().size();
709
181
    }
710
49
    static bool LargerThan(const component::Bignum& A, const component::Bignum& B) {
711
49
        return A.ToTrimmedString().size() > B.ToTrimmedString().size();
712
49
    }
713
528
    static bool IsEqualOrLargerThan(const component::Bignum& A, const component::Bignum& B) {
714
528
        const auto a = A.ToTrimmedString();
715
528
        const auto b = B.ToTrimmedString();
716
528
        if ( a.size() > b.size() ) {
717
0
            return true;
718
0
        }
719
528
        if ( a.size() == b.size() ) {
720
330
            if ( a == b ) {
721
0
                return true;
722
0
            }
723
330
        }
724
528
        return false;
725
528
    }
726
528
    static void AssertModResult(const component::Bignum& result, const component::Bignum& mod, const std::string& opStr) {
727
528
        if ( IsEqualOrLargerThan(result, mod) ) {
728
0
            Abort("Result is equal to or larger than modulo", opStr);
729
0
        }
730
528
    }
731
111
    static void AssertNotSmallerThan(const component::Bignum& result, const component::Bignum& A, const std::string& opStr) {
732
111
        if ( SmallerThan(result, A) ) {
733
0
            Abort("Result is larger than the input", opStr);
734
0
        }
735
111
    }
736
28
    static void AssertNotLargerThan(const component::Bignum& result, const component::Bignum& A, const std::string& opStr) {
737
28
        if ( LargerThan(result, A) ) {
738
0
            Abort("Result is larger than the input", opStr);
739
0
        }
740
28
    }
741
}
742
743
2.50k
void test(const operation::BignumCalc& op, const std::optional<component::Bignum>& result) {
744
2.50k
    if ( result == std::nullopt ) {
745
767
        return;
746
767
    }
747
748
1.73k
    using namespace BignumCalc;
749
750
1.73k
    const auto calcOp = op.calcOp.Get();
751
752
    /* Negative numbers are not supported yet */
753
1.73k
    if (    op.bn0.IsNegative() ||
754
1.73k
            op.bn1.IsNegative() ||
755
1.73k
            op.bn2.IsNegative() ) {
756
0
        return;
757
0
    }
758
759
    /* Modular calculations are not supported yet */
760
1.73k
    if ( op.modulo != std::nullopt ) {
761
39
        return;
762
39
    }
763
764
1.69k
    switch ( calcOp ) {
765
35
        case    CF_CALCOP("Add(A,B)"):
766
35
            if (    SmallerThan(*result, op.bn0) ||
767
35
                    SmallerThan(*result, op.bn1) ) {
768
0
                Abort("Result is smaller than its operands", repository::CalcOpToString(calcOp));
769
0
            }
770
35
            break;
771
14
        case    CF_CALCOP("Div(A,B)"):
772
14
            if ( IsZero(op.bn1) ) {
773
0
                Abort("Division by zero should not produce a result", repository::CalcOpToString(calcOp));
774
0
            }
775
776
14
            if ( LargerThan(*result, op.bn0) ) {
777
0
                Abort("Result is larger than the dividend", repository::CalcOpToString(calcOp));
778
0
            }
779
14
            break;
780
16
        case    CF_CALCOP("Mul(A,B)"):
781
16
            if ( IsZero(op.bn0) || IsZero(op.bn1) ) {
782
8
                if ( !IsZero(*result) ) {
783
0
                    Abort("Result of Mul with zero operand is not zero", repository::CalcOpToString(calcOp));
784
0
                }
785
8
            }
786
16
            break;
787
36
        case    CF_CALCOP("Mod(A,B)"):
788
36
            BignumCalc::AssertModResult(*result, op.bn1, "Mod");
789
36
            break;
790
385
        case    CF_CALCOP("ExpMod(A,B,C)"):
791
385
            BignumCalc::AssertModResult(*result, op.bn2, "ExpMod");
792
385
            break;
793
26
        case    CF_CALCOP("AddMod(A,B,C)"):
794
26
            BignumCalc::AssertModResult(*result, op.bn2, "AddMod");
795
26
            break;
796
41
        case    CF_CALCOP("SubMod(A,B,C)"):
797
41
            BignumCalc::AssertModResult(*result, op.bn2, "SubMod");
798
41
            break;
799
14
        case    CF_CALCOP("MulMod(A,B,C)"):
800
14
            BignumCalc::AssertModResult(*result, op.bn2, "MulMod");
801
14
            break;
802
15
        case    CF_CALCOP("SqrMod(A,B)"):
803
15
            BignumCalc::AssertModResult(*result, op.bn1, "SqrMod");
804
15
            break;
805
0
        case    CF_CALCOP("SqrtMod(A,B)"):
806
0
            BignumCalc::AssertModResult(*result, op.bn1, "SqrtMod");
807
0
            break;
808
11
        case    CF_CALCOP("ModLShift(A,B,C)"):
809
11
            BignumCalc::AssertModResult(*result, op.bn2, "ModLShift");
810
11
            break;
811
5
        case    CF_CALCOP("Bit(A,B)"):
812
5
            BignumCalc::AssertBinary(*result, "Bit");
813
5
            break;
814
0
        case    CF_CALCOP("IsCoprime(A,B)"):
815
0
            BignumCalc::AssertBinary(*result, "IsCoprime");
816
0
            break;
817
0
        case    CF_CALCOP("IsEq(A,B)"):
818
0
            BignumCalc::AssertBinary(*result, "IsEq");
819
0
            break;
820
0
        case    CF_CALCOP("IsGt(A,B)"):
821
0
            BignumCalc::AssertBinary(*result, "IsGt");
822
0
            break;
823
0
        case    CF_CALCOP("IsGte(A,B)"):
824
0
            BignumCalc::AssertBinary(*result, "IsGte");
825
0
            break;
826
0
        case    CF_CALCOP("IsLt(A,B)"):
827
0
            BignumCalc::AssertBinary(*result, "IsLt");
828
0
            break;
829
0
        case    CF_CALCOP("IsLte(A,B)"):
830
0
            BignumCalc::AssertBinary(*result, "IsLte");
831
0
            break;
832
13
        case    CF_CALCOP("IsEven(A)"):
833
13
            BignumCalc::AssertBinary(*result, "IsEven");
834
13
            break;
835
11
        case    CF_CALCOP("IsOdd(A)"):
836
11
            BignumCalc::AssertBinary(*result, "IsOdd");
837
11
            break;
838
10
        case    CF_CALCOP("IsOne(A)"):
839
10
            BignumCalc::AssertBinary(*result, "IsOne");
840
10
            break;
841
0
        case    CF_CALCOP("IsPow2(A)"):
842
0
            BignumCalc::AssertBinary(*result, "IsPow2");
843
0
            break;
844
225
        case    CF_CALCOP("IsPrime(A)"):
845
225
            BignumCalc::AssertBinary(*result, "IsPrime");
846
225
            break;
847
11
        case    CF_CALCOP("IsZero(A)"):
848
11
            BignumCalc::AssertBinary(*result, "IsZero");
849
11
            break;
850
0
        case    CF_CALCOP("IsSquare(A)"):
851
0
            BignumCalc::AssertBinary(*result, "IsSquare");
852
0
            break;
853
0
        case    CF_CALCOP("IsPower(A)"):
854
0
            BignumCalc::AssertBinary(*result, "IsPower");
855
0
            break;
856
38
        case    CF_CALCOP("Cmp(A,B)"):
857
38
            BignumCalc::AssertTertiary(*result, "Cmp");
858
38
            break;
859
9
        case    CF_CALCOP("CmpAbs(A,B)"):
860
9
            BignumCalc::AssertTertiary(*result, "CmpAbs");
861
9
            break;
862
107
        case    CF_CALCOP("Jacobi(A,B)"):
863
107
            BignumCalc::AssertTertiary(*result, "Jacobi");
864
107
            break;
865
93
        case    CF_CALCOP("Sqr(A)"):
866
93
            AssertNotSmallerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
867
93
            break;
868
10
        case    CF_CALCOP("RShift(A,B)"):
869
10
            if ( IsZero(op.bn0) || IsZero(op.bn1) ) {
870
3
                if ( op.bn0.ToTrimmedString() != result->ToTrimmedString() ) {
871
0
                    Abort("Zero operand should not alter input", repository::CalcOpToString(calcOp));
872
0
                }
873
3
            }
874
875
10
            AssertNotLargerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
876
10
            break;
877
12
        case    CF_CALCOP("LShift1(A)"):
878
12
            if ( IsZero(op.bn0) ) {
879
6
                if ( op.bn0.ToTrimmedString() != result->ToTrimmedString() ) {
880
0
                    Abort("Zero input should remain zero", repository::CalcOpToString(calcOp));
881
0
                }
882
6
            }
883
884
12
            AssertNotSmallerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
885
12
            break;
886
6
        case    CF_CALCOP("SetBit(A,B)"):
887
6
            AssertNotSmallerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
888
6
            break;
889
18
        case    CF_CALCOP("ClearBit(A,B)"):
890
18
            AssertNotLargerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
891
18
            break;
892
0
        case    CF_CALCOP("Sqrt(A)"):
893
0
            AssertNotLargerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
894
0
            break;
895
0
        case    CF_CALCOP("Cbrt(A)"):
896
0
            AssertNotLargerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
897
0
            break;
898
0
        case    CF_CALCOP("MulAdd(A,B,C)"):
899
0
            AssertNotSmallerThan(*result, op.bn2, repository::CalcOpToString(calcOp));
900
0
            break;
901
0
        case    CF_CALCOP("Min(A,B)"):
902
0
        case    CF_CALCOP("Max(A,B)"):
903
0
            if ( !IsEqual(*result, op.bn0) && !IsEqual(*result, op.bn1) ) {
904
0
                Abort("Result is not an operand", repository::CalcOpToString(calcOp));
905
0
            }
906
0
            break;
907
7
        case    CF_CALCOP("Mask(A,B)"):
908
7
            if ( LargerThan(*result, op.bn0) ) {
909
0
                Abort("Result is larger than input", repository::CalcOpToString(calcOp));
910
0
            }
911
7
            break;
912
0
        case    CF_CALCOP("And(A,B)"):
913
0
            AssertNotLargerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
914
0
            AssertNotLargerThan(*result, op.bn1, repository::CalcOpToString(calcOp));
915
0
            break;
916
0
        case    CF_CALCOP("Or(A,B)"):
917
0
            AssertNotSmallerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
918
0
            AssertNotSmallerThan(*result, op.bn1, repository::CalcOpToString(calcOp));
919
0
            break;
920
0
        case    CF_CALCOP("Nthrt(A,B)"):
921
0
        case    CF_CALCOP("NthrtRem(A,B)"):
922
0
            if ( IsZero(op.bn1) ) {
923
0
                Abort("Root of zero should not produce a result", repository::CalcOpToString(calcOp));
924
0
            }
925
0
            break;
926
1.69k
    }
927
1.69k
}
928
929
62
void test(const operation::BignumCalc_Fp2& op, const std::optional<component::Fp2>& result) {
930
62
    (void)op;
931
62
    (void)result;
932
62
}
933
934
219
void test(const operation::BignumCalc_Fp12& op, const std::optional<component::Fp12>& result) {
935
219
    (void)op;
936
219
    (void)result;
937
219
}
938
939
} /* namespace tests */
940
} /* namespace cryptofuzz */