Coverage Report

Created: 2024-02-25 06:16

/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
25.8k
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
25.8k
    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.8k
}
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
1.47k
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
1.47k
    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
1.47k
}
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
11.6k
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
11.6k
    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
11.6k
}
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
1.06k
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
1.06k
    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
1.06k
}
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
786
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
786
    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
786
}
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
695
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
695
    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
695
}
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
4.04k
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
4.04k
    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
4.04k
}
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
1.08k
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
1.08k
    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
1.08k
}
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
724
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
724
    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
724
}
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
722
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
722
    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
722
}
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
389
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
389
    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
389
}
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
3.20k
void verifyKeySize(const OperationType& op, const ResultType& result) {
13
3.20k
    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.20k
}
18
19
6.86k
static void checkZeroResult(const std::optional<Buffer>& b) {
20
6.86k
    if ( b == std::nullopt ) {
21
0
        return;
22
0
    }
23
24
6.86k
    if ( b->GetSize() >= 16 ) {
25
5.87k
        const std::vector<uint8_t> zeroes(b->GetSize(), 0);
26
5.87k
        if ( b->Get() == zeroes ) {
27
0
            printf("An all-zero hash was returned. This might indicate a bug.\n");
28
0
            abort();
29
0
        }
30
5.87k
    }
31
6.86k
}
32
33
8.74k
void test(const operation::Digest& op, const std::optional<component::Digest>& result) {
34
8.74k
    if ( result == std::nullopt ) {
35
3.88k
        return;
36
3.88k
    }
37
38
4.86k
    {
39
4.86k
        const auto expectedSize = repository::DigestSize(op.digestType.Get());
40
41
4.86k
        if ( expectedSize != std::nullopt ) {
42
4.38k
            if ( result->GetSize() != *expectedSize ) {
43
0
                printf("Expected vs actual digest size: %zu / %zu\n", *expectedSize, result->GetSize());
44
0
                abort();
45
0
            }
46
4.38k
        }
47
4.86k
    }
48
49
#if 0
50
    if ( op.digestType.Is(CF_DIGEST("SHA1")) ) {
51
        /* https://words.filippo.io/dispatches/seeds-bounty/ */
52
53
        static const std::vector< std::vector<uint8_t> > hashes{
54
            /* NIST P-192 */
55
            {
56
                0x30, 0x45, 0xAE, 0x6F, 0xC8, 0x42, 0x2F, 0x64, 0xED, 0x57,
57
                    0x95, 0x28, 0xD3, 0x81, 0x20, 0xEA, 0xE1, 0x21, 0x96, 0xD5,
58
            },
59
            /* NIST P-224 */
60
            {
61
                0xBD, 0x71, 0x34, 0x47, 0x99, 0xD5, 0xC7, 0xFC, 0xDC, 0x45,
62
                0xB5, 0x9F, 0xA3, 0xB9, 0xAB, 0x8F, 0x6A, 0x94, 0x8B, 0xC5,
63
            },
64
            /* NIST P-256 */
65
            {
66
                0xC4, 0x9D, 0x36, 0x08, 0x86, 0xE7, 0x04, 0x93, 0x6A, 0x66,
67
                0x78, 0xE1, 0x13, 0x9D, 0x26, 0xB7, 0x81, 0x9F, 0x7E, 0x90,
68
            },
69
            /* NIST P-384 */
70
            {
71
                0xA3, 0x35, 0x92, 0x6A, 0xA3, 0x19, 0xA2, 0x7A, 0x1D, 0x00,
72
                0x89, 0x6A, 0x67, 0x73, 0xA4, 0x82, 0x7A, 0xCD, 0xAC, 0x73,
73
            },
74
            /* NIST P-521 */
75
            {
76
                0xD0, 0x9E, 0x88, 0x00, 0x29, 0x1C, 0xB8, 0x53, 0x96, 0xCC,
77
                0x67, 0x17, 0x39, 0x32, 0x84, 0xAA, 0xA0, 0xDA, 0x64, 0xBA,
78
            },
79
            /* ANSI prime192v2 */
80
            {
81
                0x31, 0xA9, 0x2E, 0xE2, 0x02, 0x9F, 0xD1, 0x0D, 0x90, 0x1B,
82
                0x11, 0x3E, 0x99, 0x07, 0x10, 0xF0, 0xD2, 0x1A, 0xC6, 0xB6,
83
            },
84
            /* ANSI prime192v3 */
85
            {
86
                0xC4, 0x69, 0x68, 0x44, 0x35, 0xDE, 0xB3, 0x78, 0xC4, 0xB6,
87
                0x5C, 0xA9, 0x59, 0x1E, 0x2A, 0x57, 0x63, 0x05, 0x9A, 0x2E,
88
            },
89
            /* ANSI prime239v1 */
90
            {
91
                0xE4, 0x3B, 0xB4, 0x60, 0xF0, 0xB8, 0x0C, 0xC0, 0xC0, 0xB0,
92
                0x75, 0x79, 0x8E, 0x94, 0x80, 0x60, 0xF8, 0x32, 0x1B, 0x7D,
93
            },
94
            /* ANSI prime239v2 */
95
            {
96
                0xE8, 0xB4, 0x01, 0x16, 0x04, 0x09, 0x53, 0x03, 0xCA, 0x3B,
97
                0x80, 0x99, 0x98, 0x2B, 0xE0, 0x9F, 0xCB, 0x9A, 0xE6, 0x16,
98
            },
99
            /* ANSI prime239v3 */
100
            {
101
                0x7D, 0x73, 0x74, 0x16, 0x8F, 0xFE, 0x34, 0x71, 0xB6, 0x0A,
102
                0x85, 0x76, 0x86, 0xA1, 0x94, 0x75, 0xD3, 0xBF, 0xA2, 0xFF,
103
            },
104
            /* NIST B-163 */
105
            {
106
                0x85, 0xE2, 0x5B, 0xFE, 0x5C, 0x86, 0x22, 0x6C, 0xDB, 0x12,
107
                0x01, 0x6F, 0x75, 0x53, 0xF9, 0xD0, 0xE6, 0x93, 0xA2, 0x68,
108
            },
109
            /* NIST B-233 */
110
            {
111
                0x74, 0xD5, 0x9F, 0xF0, 0x7F, 0x6B, 0x41, 0x3D, 0x0E, 0xA1,
112
                0x4B, 0x34, 0x4B, 0x20, 0xA2, 0xDB, 0x04, 0x9B, 0x50, 0xC3,
113
            },
114
            /* NIST B-283 */
115
            {
116
                0x77, 0xE2, 0xB0, 0x73, 0x70, 0xEB, 0x0F, 0x83, 0x2A, 0x6D,
117
                0xD5, 0xB6, 0x2D, 0xFC, 0x88, 0xCD, 0x06, 0xBB, 0x84, 0xBE,
118
            },
119
            /* NIST B-409 */
120
            {
121
                0x40, 0x99, 0xB5, 0xA4, 0x57, 0xF9, 0xD6, 0x9F, 0x79, 0x21,
122
                0x3D, 0x09, 0x4C, 0x4B, 0xCD, 0x4D, 0x42, 0x62, 0x21, 0x0B,
123
            },
124
            /* NIST B-571 */
125
            {
126
                0x2A, 0xA0, 0x58, 0xF7, 0x3A, 0x0E, 0x33, 0xAB, 0x48, 0x6B,
127
                0x0F, 0x61, 0x04, 0x10, 0xC5, 0x3A, 0x7F, 0x13, 0x23, 0x10,
128
            },
129
        };
130
131
        for (const auto& hash : hashes) {
132
            if ( result->Get() == hash ) abort();
133
        }
134
    }
135
#endif
136
137
4.86k
    checkZeroResult(result);
138
4.86k
}
139
140
4.55k
void test(const operation::HMAC& op, const std::optional<component::MAC>& result) {
141
4.55k
    if ( result == std::nullopt ) {
142
2.55k
        return;
143
2.55k
    }
144
145
2.00k
    {
146
2.00k
        const auto expectedSize = repository::DigestSize(op.digestType.Get());
147
148
2.00k
        if ( expectedSize != std::nullopt ) {
149
1.61k
            if ( result->GetSize() != *expectedSize ) {
150
0
                printf("Expected vs actual digest size: %zu / %zu\n", *expectedSize, result->GetSize());
151
0
                abort();
152
0
            }
153
1.61k
        }
154
2.00k
    }
155
156
2.00k
    checkZeroResult(result);
157
2.00k
}
158
159
5.88k
void test(const operation::UMAC& op, const std::optional<component::MAC>& result) {
160
5.88k
    if ( result == std::nullopt ) {
161
3.05k
        return;
162
3.05k
    }
163
164
2.83k
    if (
165
2.83k
            ( op.type == 0 && result->GetSize() > (32/8) ) ||
166
2.83k
            ( op.type == 1 && result->GetSize() > (64/8) ) ||
167
2.83k
            ( op.type == 2 && result->GetSize() > (96/8) ) ||
168
2.83k
            ( op.type == 3 && result->GetSize() > (128/8) )
169
2.83k
    ) {
170
0
        printf("UMAC: Overlong result: %zu\n", result->GetSize());
171
0
        abort();
172
0
    }
173
2.83k
}
174
175
26.8k
static void test_ChaCha20_Poly1305_IV(const operation::SymmetricEncrypt& op, const std::optional<component::Ciphertext>& result) {
176
26.8k
    using fuzzing::datasource::ID;
177
178
    /*
179
     * OpenSSL CVE-2019-1543
180
     * https://www.openssl.org/news/secadv/20190306.txt
181
     */
182
183
26.8k
    if ( op.cipher.cipherType.Get() != CF_CIPHER("CHACHA20_POLY1305") ) {
184
25.9k
        return;
185
25.9k
    }
186
187
847
    if ( result == std::nullopt ) {
188
695
        return;
189
695
    }
190
191
152
    if ( op.cipher.iv.GetSize() > 12 ) {
192
0
        abort();
193
0
    }
194
152
}
195
196
26.8k
static void test_XChaCha20_Poly1305_IV(const operation::SymmetricEncrypt& op, const std::optional<component::Ciphertext>& result) {
197
26.8k
    using fuzzing::datasource::ID;
198
199
26.8k
    if ( op.cipher.cipherType.Get() != CF_CIPHER("XCHACHA20_POLY1305") ) {
200
26.7k
        return;
201
26.7k
    }
202
203
65
    if ( result == std::nullopt ) {
204
65
        return;
205
65
    }
206
207
0
    if ( op.cipher.iv.GetSize() != 24 ) {
208
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());
209
0
        abort();
210
0
    }
211
0
}
212
213
26.8k
static void test_AES_CCM_Wycheproof(const operation::SymmetricEncrypt& op, const std::optional<component::Ciphertext>& result) {
214
26.8k
    bool fail = false;
215
216
26.8k
    if ( result == std::nullopt ) {
217
17.2k
        return;
218
17.2k
    }
219
220
9.61k
    switch ( op.cipher.cipherType.Get() ) {
221
130
        case CF_CIPHER("AES_128_CCM"):
222
288
        case CF_CIPHER("AES_192_CCM"):
223
447
        case CF_CIPHER("AES_256_CCM"):
224
447
            break;
225
9.16k
        default:
226
9.16k
            return;
227
9.61k
    }
228
229
447
    if ( op.cipher.iv.GetSize() < 7 || op.cipher.iv.GetSize() > 13 ) {
230
0
        printf("AES CCM: Invalid IV size\n");
231
0
        fail = true;
232
0
    }
233
234
447
    if ( result->tag != std::nullopt ) {
235
447
        static const std::vector<size_t> validTagSizes = {4, 6, 8, 10, 12, 14, 16};
236
237
447
        if ( std::find(validTagSizes.begin(), validTagSizes.end(), result->tag->GetSize()) == validTagSizes.end() ) {
238
0
            printf("AES CCM: Invalid tag size\n");
239
0
            fail = true;
240
0
        }
241
447
    }
242
243
447
    if ( fail == true ) {
244
0
        printf("AES CCM tests based on Wycheproof: https://github.com/google/wycheproof/blob/4672ff74d68766e7785c2cac4c597effccef2c5c/testvectors/aes_ccm_test.json#L11\n");
245
0
        abort();
246
0
    }
247
447
}
248
249
26.8k
static void test_AES_GCM_Wycheproof(const operation::SymmetricEncrypt& op, const std::optional<component::Ciphertext>& result) {
250
26.8k
    bool fail = false;
251
252
26.8k
    if ( result == std::nullopt ) {
253
17.2k
        return;
254
17.2k
    }
255
256
9.61k
    switch ( op.cipher.cipherType.Get() ) {
257
220
        case CF_CIPHER("AES_128_GCM"):
258
414
        case CF_CIPHER("AES_192_GCM"):
259
639
        case CF_CIPHER("AES_256_GCM"):
260
639
            break;
261
8.97k
        default:
262
8.97k
            return;
263
9.61k
    }
264
265
639
    if ( op.cipher.iv.GetSize() == 0 ) {
266
0
        printf("AES GCM: Invalid IV size\n");
267
0
        fail = true;
268
0
    }
269
270
639
    if ( fail == true ) {
271
0
        printf("AES GCM tests based on Wycheproof: https://github.com/google/wycheproof/blob/4672ff74d68766e7785c2cac4c597effccef2c5c/testvectors/aes_gcm_test.json#L13\n");
272
0
        abort();
273
0
    }
274
639
}
275
276
26.8k
void test(const operation::SymmetricEncrypt& op, const std::optional<component::Ciphertext>& result) {
277
26.8k
    test_ChaCha20_Poly1305_IV(op, result);
278
26.8k
    test_XChaCha20_Poly1305_IV(op, result);
279
26.8k
    test_AES_CCM_Wycheproof(op, result);
280
26.8k
    test_AES_GCM_Wycheproof(op, result);
281
26.8k
}
282
283
21.6k
void test(const operation::SymmetricDecrypt& op, const std::optional<component::Cleartext>& result) {
284
21.6k
    (void)op;
285
21.6k
    (void)result;
286
21.6k
}
287
288
5.36k
void test(const operation::CMAC& op, const std::optional<component::MAC>& result) {
289
5.36k
    (void)op;
290
5.36k
    (void)result;
291
5.36k
}
292
293
1.47k
void test(const operation::KDF_SCRYPT& op, const std::optional<component::Key>& result) {
294
1.47k
    verifyKeySize(op, result);
295
1.47k
}
296
297
11.6k
static void test_HKDF_OutputSize(const operation::KDF_HKDF& op, const std::optional<component::Key>& result) {
298
11.6k
    if ( result == std::nullopt ) {
299
6.51k
        return;
300
6.51k
    }
301
302
5.12k
    const auto expectedSize = repository::DigestSize(op.digestType.Get());
303
304
5.12k
    if ( expectedSize == std::nullopt ) {
305
642
        return;
306
642
    }
307
308
4.47k
    const size_t maxOutputSize = 255 * *expectedSize;
309
310
4.47k
    if ( result->GetSize() > maxOutputSize ) {
311
0
        printf("The output size of HKDF (%zu) is more than 255 * the size of the hash digest (%zu)\n", result->GetSize(), maxOutputSize);
312
0
        abort();
313
0
    }
314
4.47k
}
315
316
11.6k
void test(const operation::KDF_HKDF& op, const std::optional<component::Key>& result) {
317
11.6k
    verifyKeySize(op, result);
318
319
11.6k
    test_HKDF_OutputSize(op, result);
320
11.6k
}
321
322
1.06k
void test(const operation::KDF_TLS1_PRF& op, const std::optional<component::Key>& result) {
323
1.06k
    verifyKeySize(op, result);
324
1.06k
}
325
326
786
void test(const operation::KDF_PBKDF& op, const std::optional<component::Key>& result) {
327
786
    verifyKeySize(op, result);
328
786
}
329
330
695
void test(const operation::KDF_PBKDF1& op, const std::optional<component::Key>& result) {
331
695
    verifyKeySize(op, result);
332
695
}
333
334
4.04k
void test(const operation::KDF_PBKDF2& op, const std::optional<component::Key>& result) {
335
4.04k
    verifyKeySize(op, result);
336
4.04k
}
337
338
1.08k
void test(const operation::KDF_ARGON2& op, const std::optional<component::Key>& result) {
339
1.08k
    verifyKeySize(op, result);
340
1.08k
}
341
342
724
void test(const operation::KDF_SSH& op, const std::optional<component::Key>& result) {
343
724
    verifyKeySize(op, result);
344
724
}
345
346
722
void test(const operation::KDF_X963& op, const std::optional<component::Key>& result) {
347
722
    verifyKeySize(op, result);
348
722
}
349
350
389
void test(const operation::KDF_BCRYPT& op, const std::optional<component::Key>& result) {
351
389
    verifyKeySize(op, result);
352
389
}
353
354
3.20k
void test(const operation::KDF_SP_800_108& op, const std::optional<component::Key>& result) {
355
3.20k
    verifyKeySize(op, result);
356
3.20k
}
357
358
713
void test(const operation::KDF_SRTP& op, const std::optional<component::Key3>& result) {
359
713
    (void)op;
360
713
    (void)result;
361
713
}
362
363
758
void test(const operation::KDF_SRTCP& op, const std::optional<component::Key3>& result) {
364
758
    (void)op;
365
758
    (void)result;
366
758
}
367
368
2.37k
static bool IsSpecialCurve(const uint64_t curveID) {
369
2.37k
    switch ( curveID ) {
370
0
        case CF_ECC_CURVE("ed448"):
371
504
        case CF_ECC_CURVE("ed25519"):
372
504
        case CF_ECC_CURVE("x25519"):
373
504
        case CF_ECC_CURVE("x448"):
374
504
            return true;
375
1.87k
        default:
376
1.87k
            return false;
377
2.37k
    }
378
2.37k
}
379
380
3.14k
static void test_ECC_PrivateKey(const uint64_t curveID, const std::string priv) {
381
    /* Disabled until all modules comply by default */
382
3.14k
    return;
383
384
    /* Private key may be 0 with these curves */
385
0
    if ( IsSpecialCurve(curveID) ) {
386
0
        return;
387
0
    }
388
389
0
    if ( priv == "0" ) {
390
0
        std::cout << "0 is an invalid elliptic curve private key" << std::endl;
391
0
        ::abort();
392
0
    }
393
0
}
394
395
396
3.57k
void test(const operation::ECC_PrivateToPublic& op, const std::optional<component::ECC_PublicKey>& result) {
397
3.57k
    if ( result != std::nullopt ) {
398
1.09k
        test_ECC_PrivateKey(op.curveType.Get(), op.priv.ToTrimmedString());
399
1.09k
    }
400
3.57k
}
401
402
2.05k
void test(const operation::ECC_ValidatePubkey& op, const std::optional<bool>& result) {
403
2.05k
    (void)op;
404
2.05k
    (void)result;
405
2.05k
}
406
407
3.39k
void test(const operation::ECC_GenerateKeyPair& op, const std::optional<component::ECC_KeyPair>& result) {
408
3.39k
    if ( result != std::nullopt ) {
409
751
        test_ECC_PrivateKey(op.curveType.Get(), result->priv.ToTrimmedString());
410
751
    }
411
3.39k
}
412
413
2.34k
static void test_ECDSA_Signature(const uint64_t curveID, const std::string R, const std::string S) {
414
2.34k
    if ( IsSpecialCurve(curveID) ) {
415
475
        return;
416
475
    }
417
418
1.87k
    const boost::multiprecision::cpp_int r(R), s(S);
419
420
1.87k
    if ( r < 1 ) {
421
0
        std::cout << "ECDSA signature invalid: R < 1" << std::endl;
422
0
        ::abort();
423
0
    }
424
1.87k
    if ( s < 1 ) {
425
0
        std::cout << "ECDSA signature invalid: S < 1" << std::endl;
426
0
        ::abort();
427
0
    }
428
429
1.87k
    const auto O = cryptofuzz::repository::ECC_CurveToOrder(curveID);
430
1.87k
    if ( O == std::nullopt ) {
431
232
        return;
432
232
    }
433
434
1.63k
    const boost::multiprecision::cpp_int o(*O);
435
436
1.63k
    if ( r >= o ) {
437
0
        std::cout << "ECDSA signature invalid: R >= order" << std::endl;
438
0
        ::abort();
439
0
    }
440
441
1.63k
    if ( s >= o ) {
442
0
        std::cout << "ECDSA signature invalid: S >= order" << std::endl;
443
0
        ::abort();
444
0
    }
445
1.63k
}
446
447
0
static void test_BIP340_Schnorr_Signature(const uint64_t curveID, const std::string R, const std::string S) {
448
0
    boost::multiprecision::cpp_int r(R);
449
0
    boost::multiprecision::cpp_int s(S);
450
0
    if ( r < 1 ) {
451
0
        std::cout << "BIP340 Schnorr signature invalid: R < 1" << std::endl;
452
0
        ::abort();
453
0
    }
454
0
    if ( s < 1 ) {
455
0
        std::cout << "BIP340 Schnorr signature invalid: S < 1" << std::endl;
456
0
        ::abort();
457
0
    }
458
459
0
    const auto prime = cryptofuzz::repository::ECC_CurveToPrime(curveID);
460
0
    if ( prime != std::nullopt ) {
461
0
        const boost::multiprecision::cpp_int p(*prime);
462
0
        CF_ASSERT(r < p, "BIP340 Schnorr signature R should be less than curve P");
463
0
    }
464
465
0
    const auto order = cryptofuzz::repository::ECC_CurveToOrder(curveID);
466
0
    if ( order != std::nullopt ) {
467
0
        const boost::multiprecision::cpp_int n(*order);
468
0
        CF_ASSERT(s < n, "BIP340 Schnorr signature S should be less than curve N");
469
0
    }
470
0
}
471
472
271
void test(const operation::ECCSI_Sign& op, const std::optional<component::ECCSI_Signature>& result) {
473
271
    (void)op;
474
271
    (void)result;
475
271
}
476
2.53k
void test(const operation::ECDSA_Sign& op, const std::optional<component::ECDSA_Signature>& result) {
477
2.53k
    if ( result != std::nullopt ) {
478
1.17k
        test_ECC_PrivateKey(op.curveType.Get(), op.priv.ToTrimmedString());
479
480
1.17k
        if (
481
1.17k
                op.UseSpecifiedNonce() == true &&
482
1.17k
                !IsSpecialCurve(op.curveType.Get()) &&
483
1.17k
                op.nonce.ToTrimmedString() == "0"
484
1.17k
           ) {
485
0
            std::cout << "0 is an invalid ECDSA nonce" << std::endl;
486
0
            ::abort();
487
0
        }
488
489
1.17k
        test_ECDSA_Signature(op.curveType.Get(),
490
1.17k
                result->signature.first.ToTrimmedString(),
491
1.17k
                result->signature.second.ToTrimmedString());
492
1.17k
    }
493
2.53k
}
494
495
799
void test(const operation::ECGDSA_Sign& op, const std::optional<component::ECGDSA_Signature>& result) {
496
799
    if ( result != std::nullopt ) {
497
119
        test_ECC_PrivateKey(op.curveType.Get(), op.priv.ToTrimmedString());
498
499
119
        if (
500
119
                op.UseSpecifiedNonce() == true &&
501
119
                !IsSpecialCurve(op.curveType.Get()) &&
502
119
                op.nonce.ToTrimmedString() == "0"
503
119
           ) {
504
0
            std::cout << "0 is an invalid ECGDSA nonce" << std::endl;
505
0
            ::abort();
506
0
        }
507
508
119
        test_ECDSA_Signature(op.curveType.Get(),
509
119
                result->signature.first.ToTrimmedString(),
510
119
                result->signature.second.ToTrimmedString());
511
119
    }
512
799
}
513
514
285
void test(const operation::ECRDSA_Sign& op, const std::optional<component::ECRDSA_Signature>& result) {
515
285
    if ( result != std::nullopt ) {
516
0
        test_ECC_PrivateKey(op.curveType.Get(), op.priv.ToTrimmedString());
517
518
0
        if (
519
0
                op.UseSpecifiedNonce() == true &&
520
0
                !IsSpecialCurve(op.curveType.Get()) &&
521
0
                op.nonce.ToTrimmedString() == "0"
522
0
           ) {
523
0
            std::cout << "0 is an invalid ECRDSA nonce" << std::endl;
524
0
            ::abort();
525
0
        }
526
527
0
        test_ECDSA_Signature(op.curveType.Get(),
528
0
                result->signature.first.ToTrimmedString(),
529
0
                result->signature.second.ToTrimmedString());
530
0
    }
531
285
}
532
533
239
void test(const operation::Schnorr_Sign& op, const std::optional<component::Schnorr_Signature>& result) {
534
239
    if ( result != std::nullopt ) {
535
0
        test_ECC_PrivateKey(op.curveType.Get(), op.priv.ToTrimmedString());
536
537
0
        if (
538
0
                op.UseSpecifiedNonce() == true &&
539
0
                !IsSpecialCurve(op.curveType.Get()) &&
540
0
                op.nonce.ToTrimmedString() == "0"
541
0
           ) {
542
0
            std::cout << "0 is an invalid Schnorr nonce" << std::endl;
543
0
            ::abort();
544
0
        }
545
546
0
        test_BIP340_Schnorr_Signature(op.curveType.Get(),
547
0
                result->signature.first.ToTrimmedString(),
548
0
                result->signature.second.ToTrimmedString());
549
0
    }
550
239
}
551
552
241
void test(const operation::ECCSI_Verify& op, const std::optional<bool>& result) {
553
241
    (void)op;
554
241
    (void)result;
555
241
}
556
557
1.49k
void test(const operation::ECDSA_Verify& op, const std::optional<bool>& result) {
558
1.49k
    if ( result != std::nullopt && *result == true ) {
559
48
        test_ECDSA_Signature(op.curveType.Get(),
560
48
                op.signature.signature.first.ToTrimmedString(),
561
48
                op.signature.signature.second.ToTrimmedString());
562
48
    }
563
1.49k
}
564
565
900
void test(const operation::ECGDSA_Verify& op, const std::optional<bool>& result) {
566
900
    if ( result != std::nullopt && *result == true ) {
567
21
        test_ECDSA_Signature(op.curveType.Get(),
568
21
                op.signature.signature.first.ToTrimmedString(),
569
21
                op.signature.signature.second.ToTrimmedString());
570
21
    }
571
900
}
572
573
235
void test(const operation::ECRDSA_Verify& op, const std::optional<bool>& result) {
574
235
    if ( result != std::nullopt && *result == true ) {
575
0
        test_ECDSA_Signature(op.curveType.Get(),
576
0
                op.signature.signature.first.ToTrimmedString(),
577
0
                op.signature.signature.second.ToTrimmedString());
578
0
    }
579
235
}
580
581
228
void test(const operation::Schnorr_Verify& op, const std::optional<bool>& result) {
582
228
    if ( result != std::nullopt && *result == true ) {
583
0
        test_BIP340_Schnorr_Signature(op.curveType.Get(),
584
0
                op.signature.signature.first.ToTrimmedString(),
585
0
                op.signature.signature.second.ToTrimmedString());
586
0
    }
587
228
}
588
589
2.60k
void test(const operation::ECDSA_Recover& op, const std::optional<component::ECC_PublicKey>& result) {
590
2.60k
    if ( result != std::nullopt ) {
591
986
        if ( op.id > 3 ) {
592
0
            std::cout << "Invalid recovery ID" << std::endl;
593
0
            ::abort();
594
0
        }
595
986
    }
596
2.60k
    if ( result != std::nullopt ) {
597
986
        test_ECDSA_Signature(op.curveType.Get(),
598
986
                op.signature.first.ToTrimmedString(),
599
986
                op.signature.second.ToTrimmedString());
600
986
    }
601
2.60k
}
602
603
1.12k
void test(const operation::DSA_Verify& op, const std::optional<bool>& result) {
604
1.12k
    (void)op;
605
606
1.12k
    if ( result == std::nullopt || *result == false ) {
607
1.09k
        return;
608
1.09k
    }
609
610
24
    if ( !op.signature.first.IsPositive() ) {
611
0
        std::cout << "DSA signature must be rejected if R is smaller than 1" << std::endl;
612
0
        ::abort();
613
0
    }
614
24
    if ( !op.signature.second.IsPositive() ) {
615
0
        std::cout << "DSA signature must be rejected is S is smaller than 1" << std::endl;
616
0
        ::abort();
617
0
    }
618
619
    /* Q > R */
620
24
    if ( op.signature.first.ToTrimmedString().size() > op.parameters.q.ToTrimmedString().size() ) {
621
0
        std::cout << "DSA signature must be rejected if R is larger than Q" << std::endl;
622
0
        ::abort();
623
0
    }
624
    /* Q > S */
625
24
    if ( op.signature.second.ToTrimmedString().size() > op.parameters.q.ToTrimmedString().size() ) {
626
0
        std::cout << "DSA signature must be rejected if S is larger than Q" << std::endl;
627
0
        ::abort();
628
0
    }
629
24
}
630
631
318
void test(const operation::DSA_Sign& op, const std::optional<component::DSA_Signature>& result) {
632
318
    if ( result == std::nullopt ) {
633
318
        return;
634
318
    }
635
636
0
    if ( !result->signature.first.IsPositive() ) {
637
0
        std::cout << "DSA signature R must be larger than 0" << std::endl;
638
0
        ::abort();
639
0
    }
640
0
    if ( !result->signature.second.IsPositive() ) {
641
0
        std::cout << "DSA signature S must be larger than 0" << std::endl;
642
0
        ::abort();
643
0
    }
644
645
    /* Q > R */
646
0
    if ( result->signature.first.ToTrimmedString().size() > op.parameters.q.ToTrimmedString().size() ) {
647
0
        std::cout << "DSA signature R must be smaller than P" << std::endl;
648
0
        ::abort();
649
0
    }
650
    /* Q > S */
651
0
    if ( result->signature.second.ToTrimmedString().size() > op.parameters.q.ToTrimmedString().size() ) {
652
0
        std::cout << "DSA signature S must be smaller than Q" << std::endl;
653
0
        ::abort();
654
0
    }
655
656
    /* R > 0 */
657
0
    if ( !result->signature.first.IsPositive() ) {
658
0
        std::cout << "DSA signature R must be larger than 0" << std::endl;
659
0
        ::abort();
660
0
    }
661
    /* S > 0 */
662
0
    if ( !result->signature.second.IsPositive() ) {
663
0
        std::cout << "DSA signature R must be larger than 0" << std::endl;
664
0
        ::abort();
665
0
    }
666
0
}
667
668
0
static bool isComposite(const std::string &num) {
669
0
    if ( num.size() == 0 ) {
670
0
        return true;
671
0
    }
672
673
0
    size_t sum = 0;
674
0
    for (char c : num) {
675
0
        sum += c - '0';
676
0
    }
677
0
    if (sum % 3 == 0) {
678
0
        return true;
679
0
    }
680
681
0
    return false;
682
0
}
683
684
685
242
void test(const operation::DSA_GenerateParameters& op, const std::optional<component::DSA_Parameters>& result) {
686
242
    (void)op;
687
688
242
    if ( result == std::nullopt ) {
689
242
        return;
690
242
    }
691
692
    /* Larger than 0 */
693
0
    if ( !result->p.IsPositive() ) {
694
0
        std::cout << "DSA P parameter must be larger than 0" << std::endl;
695
0
        ::abort();
696
0
    }
697
0
    if ( !result->q.IsPositive() ) {
698
0
        std::cout << "DSA Q parameter must be larger than 0" << std::endl;
699
0
        ::abort();
700
0
    }
701
0
    if ( !result->g.IsPositive() ) {
702
0
        std::cout << "DSA G parameter must be larger than 0" << std::endl;
703
0
        ::abort();
704
0
    }
705
706
    /* P > Q */
707
0
    if ( result->q.ToTrimmedString().size() > result->p.ToTrimmedString().size() ) {
708
0
        std::cout << "DSA Q must be smaller than P" << std::endl;
709
0
        ::abort();
710
0
    }
711
712
    /* P > G */
713
0
    if ( result->q.ToTrimmedString().size() > result->p.ToTrimmedString().size() ) {
714
0
        std::cout << "DSA G must be smaller than P" << std::endl;
715
0
        ::abort();
716
0
    }
717
718
    /* G != 1 */
719
0
    if ( result->p.ToTrimmedString() == "1" ) {
720
0
        std::cout << "DSA G must not be 1" << std::endl;
721
0
        ::abort();
722
0
    }
723
724
    /* P, Q must be prime */
725
0
    if ( isComposite(result->p.ToTrimmedString()) ) {
726
0
        std::cout << "DSA P must be prime" << std::endl;
727
0
        ::abort();
728
0
    }
729
730
0
    if ( isComposite(result->q.ToTrimmedString()) ) {
731
0
        std::cout << "DSA Q must be prime" << std::endl;
732
0
        ::abort();
733
0
    }
734
0
}
735
736
273
void test(const operation::DSA_PrivateToPublic& op, const std::optional<component::Bignum>& result) {
737
273
    (void)op;
738
273
    (void)result;
739
273
}
740
741
302
void test(const operation::DSA_GenerateKeyPair& op, const std::optional<component::DSA_KeyPair>& result) {
742
302
    if ( result == std::nullopt ) {
743
302
        return;
744
302
    }
745
746
0
    if ( !result->first.IsPositive() ) {
747
0
        std::cout << "Private key must be larger than 0" << std::endl;
748
0
        ::abort();
749
0
    }
750
751
    /* Q > priv */
752
0
    if ( result->first.ToTrimmedString().size() > op.q.ToTrimmedString().size() ) {
753
0
        std::cout << "Q must be larger than private key" << std::endl;
754
0
        ::abort();
755
0
    }
756
0
}
757
758
216
void test(const operation::ECDH_Derive& op, const std::optional<component::Secret>& result) {
759
216
    (void)op;
760
216
    (void)result;
761
216
}
762
763
285
void test(const operation::ECIES_Encrypt& op, const std::optional<component::Ciphertext>& result) {
764
    /* TODO check minimum size? */
765
285
    (void)op;
766
285
    (void)result;
767
285
}
768
769
292
void test(const operation::ECIES_Decrypt& op, const std::optional<component::Cleartext>& result) {
770
292
    (void)op;
771
292
    (void)result;
772
292
}
773
774
460
void test(const operation::ECC_Point_Add& op, const std::optional<component::ECC_Point>& result) {
775
460
    (void)op;
776
460
    (void)result;
777
460
}
778
779
545
void test(const operation::ECC_Point_Sub& op, const std::optional<component::ECC_Point>& result) {
780
545
    if ( result == std::nullopt ) {
781
467
        return;
782
467
    }
783
784
78
    if ( !(op.a.first == op.b.first) ) {
785
67
        return;
786
67
    }
787
788
11
    if ( !(op.a.second == op.b.second) ) {
789
11
        return;
790
11
    }
791
792
0
    if ( !result->first.IsZero() || !result->second.IsZero() ) {
793
0
        std::cout << "Subtracting equal points should result in point at infinity" << std::endl;
794
0
        ::abort();
795
0
    }
796
0
}
797
798
1.91k
void test(const operation::ECC_Point_Mul& op, const std::optional<component::ECC_Point>& result) {
799
1.91k
    (void)op;
800
1.91k
    (void)result;
801
1.91k
}
802
803
430
void test(const operation::ECC_Point_Neg& op, const std::optional<component::ECC_Point>& result) {
804
430
    (void)op;
805
430
    (void)result;
806
430
}
807
808
437
void test(const operation::ECC_Point_Dbl& op, const std::optional<component::ECC_Point>& result) {
809
437
    (void)op;
810
437
    (void)result;
811
437
}
812
813
415
void test(const operation::ECC_Point_Cmp& op, const std::optional<bool>& result) {
814
415
    (void)op;
815
415
    (void)result;
816
415
}
817
818
281
void test(const operation::DH_GenerateKeyPair& op, const std::optional<component::DH_KeyPair>& result) {
819
281
    (void)op;
820
281
    (void)result;
821
281
}
822
823
1.03k
void test(const operation::DH_Derive& op, const std::optional<component::Bignum>& result) {
824
1.03k
    (void)op;
825
1.03k
    (void)result;
826
1.03k
}
827
828
260
void test(const operation::BLS_PrivateToPublic& op, const std::optional<component::BLS_PublicKey>& result) {
829
260
    (void)op;
830
260
    (void)result;
831
260
}
832
833
311
void test(const operation::BLS_PrivateToPublic_G2& op, const std::optional<component::G2>& result) {
834
311
    (void)op;
835
311
    (void)result;
836
311
}
837
838
260
void test(const operation::BLS_Sign& op, const std::optional<component::BLS_Signature>& result) {
839
260
    (void)op;
840
260
    (void)result;
841
260
}
842
843
271
void test(const operation::BLS_Verify& op, const std::optional<bool>& result) {
844
271
    (void)op;
845
271
    (void)result;
846
271
}
847
848
319
void test(const operation::BLS_BatchSign& op, const std::optional<component::BLS_BatchSignature>& result) {
849
319
    (void)op;
850
319
    (void)result;
851
319
}
852
853
290
void test(const operation::BLS_BatchVerify& op, const std::optional<bool>& result) {
854
290
    (void)op;
855
290
    (void)result;
856
290
}
857
858
255
void test(const operation::BLS_Aggregate_G1& op, const std::optional<component::G1>& result) {
859
255
    (void)op;
860
255
    (void)result;
861
255
}
862
863
265
void test(const operation::BLS_Aggregate_G2& op, const std::optional<component::G2>& result) {
864
265
    (void)op;
865
265
    (void)result;
866
265
}
867
868
236
void test(const operation::BLS_Pairing& op, const std::optional<component::Fp12>& result) {
869
236
    (void)op;
870
236
    (void)result;
871
236
}
872
873
247
void test(const operation::BLS_MillerLoop& op, const std::optional<component::Fp12>& result) {
874
247
    (void)op;
875
247
    (void)result;
876
247
}
877
878
290
void test(const operation::BLS_FinalExp& op, const std::optional<component::Fp12>& result) {
879
290
    (void)op;
880
290
    (void)result;
881
290
}
882
883
262
void test(const operation::BLS_HashToG1& op, const std::optional<component::G1>& result) {
884
262
    (void)op;
885
262
    (void)result;
886
262
}
887
888
283
void test(const operation::BLS_HashToG2& op, const std::optional<component::G2>& result) {
889
283
    (void)op;
890
283
    (void)result;
891
283
}
892
893
254
void test(const operation::BLS_MapToG1& op, const std::optional<component::G1>& result) {
894
254
    (void)op;
895
254
    (void)result;
896
254
}
897
898
235
void test(const operation::BLS_MapToG2& op, const std::optional<component::G2>& result) {
899
235
    (void)op;
900
235
    (void)result;
901
235
}
902
903
264
void test(const operation::BLS_IsG1OnCurve& op, const std::optional<bool>& result) {
904
264
    (void)op;
905
264
    (void)result;
906
264
}
907
908
287
void test(const operation::BLS_IsG2OnCurve& op, const std::optional<bool>& result) {
909
287
    (void)op;
910
287
    (void)result;
911
287
}
912
913
268
void test(const operation::BLS_GenerateKeyPair& op, const std::optional<component::BLS_KeyPair>& result) {
914
268
    (void)op;
915
268
    (void)result;
916
268
}
917
918
258
void test(const operation::BLS_Decompress_G1& op, const std::optional<component::G1>& result) {
919
258
    (void)op;
920
258
    (void)result;
921
258
}
922
923
249
void test(const operation::BLS_Compress_G1& op, const std::optional<component::Bignum>& result) {
924
249
    (void)op;
925
249
    (void)result;
926
249
}
927
928
220
void test(const operation::BLS_Decompress_G2& op, const std::optional<component::G2>& result) {
929
220
    (void)op;
930
220
    (void)result;
931
220
}
932
933
211
void test(const operation::BLS_Compress_G2& op, const std::optional<component::G1>& result) {
934
211
    (void)op;
935
211
    (void)result;
936
211
}
937
938
296
void test(const operation::BLS_G1_Add& op, const std::optional<component::G1>& result) {
939
296
    (void)op;
940
296
    (void)result;
941
296
}
942
943
273
void test(const operation::BLS_G1_Mul& op, const std::optional<component::G1>& result) {
944
273
    (void)op;
945
273
    (void)result;
946
273
}
947
948
422
void test(const operation::BLS_G1_IsEq& op, const std::optional<bool>& result) {
949
422
    (void)op;
950
422
    (void)result;
951
422
}
952
953
274
void test(const operation::BLS_G1_Neg& op, const std::optional<component::G1>& result) {
954
274
    (void)op;
955
274
    (void)result;
956
274
}
957
958
471
void test(const operation::BLS_G2_Add& op, const std::optional<component::G2>& result) {
959
471
    (void)op;
960
471
    (void)result;
961
471
}
962
963
261
void test(const operation::BLS_G2_Mul& op, const std::optional<component::G2>& result) {
964
261
    (void)op;
965
261
    (void)result;
966
261
}
967
968
393
void test(const operation::BLS_G2_IsEq& op, const std::optional<bool>& result) {
969
393
    (void)op;
970
393
    (void)result;
971
393
}
972
973
288
void test(const operation::BLS_G2_Neg& op, const std::optional<component::G2>& result) {
974
288
    (void)op;
975
288
    (void)result;
976
288
}
977
978
418
void test(const operation::BLS_G1_MultiExp& op, const std::optional<component::G1>& result) {
979
418
    (void)op;
980
418
    (void)result;
981
418
}
982
983
207
void test(const operation::Misc& op, const std::optional<Buffer>& result) {
984
207
    (void)op;
985
207
    (void)result;
986
207
}
987
988
282
void test(const operation::SR25519_Verify& op, const std::optional<bool>& result) {
989
282
    (void)op;
990
282
    (void)result;
991
282
}
992
993
namespace BignumCalc {
994
0
    static void Abort(const std::string& message, const std::string& opStr) {
995
0
        std::cout << "BignumCalc ( " << opStr << " ): " << message << std::endl;
996
0
        ::abort();
997
0
    }
998
622
    static void AssertBinary(const component::Bignum& result, const std::string& opStr) {
999
622
        const auto resultStr = result.ToTrimmedString();
1000
622
        if ( !(resultStr == "0" || resultStr == "1") ) {
1001
0
            Abort("Result must be 0 or 1", opStr);
1002
0
        }
1003
622
    }
1004
210
    static void AssertTertiary(const component::Bignum& result, const std::string& opStr) {
1005
210
        const auto resultStr = result.ToTrimmedString();
1006
210
        if ( !(resultStr == "0" || resultStr == "1" || resultStr == "-1") ) {
1007
0
            Abort("Result must be 0 or 1 or -1", opStr);
1008
0
        }
1009
210
    }
1010
0
    static bool IsEqual(const component::Bignum& A, const component::Bignum& B) {
1011
0
        return A.ToTrimmedString() == B.ToTrimmedString();
1012
0
    }
1013
894
    static bool IsZero(const component::Bignum& A) {
1014
894
        return A.ToTrimmedString() == "0";
1015
894
    }
1016
558
    static bool SmallerThan(const component::Bignum& A, const component::Bignum& B) {
1017
558
        return A.ToTrimmedString().size() < B.ToTrimmedString().size();
1018
558
    }
1019
803
    static bool LargerThan(const component::Bignum& A, const component::Bignum& B) {
1020
803
        return A.ToTrimmedString().size() > B.ToTrimmedString().size();
1021
803
    }
1022
1.36k
    static bool IsEqualOrLargerThan(const component::Bignum& A, const component::Bignum& B) {
1023
1.36k
        const auto a = A.ToTrimmedString();
1024
1.36k
        const auto b = B.ToTrimmedString();
1025
1.36k
        if ( a.size() > b.size() ) {
1026
0
            return true;
1027
0
        }
1028
1.36k
        if ( a.size() == b.size() ) {
1029
1.05k
            if ( a == b ) {
1030
0
                return true;
1031
0
            }
1032
1.05k
        }
1033
1.36k
        return false;
1034
1.36k
    }
1035
1.36k
    static void AssertModResult(const component::Bignum& result, const component::Bignum& mod, const std::string& opStr) {
1036
1.36k
        if ( IsEqualOrLargerThan(result, mod) ) {
1037
0
            Abort("Result is equal to or larger than modulo", opStr);
1038
0
        }
1039
1.36k
    }
1040
218
    static void AssertNotSmallerThan(const component::Bignum& result, const component::Bignum& A, const std::string& opStr) {
1041
218
        if ( SmallerThan(result, A) ) {
1042
0
            Abort("Result is smaller than the input", opStr);
1043
0
        }
1044
218
    }
1045
    static void AssertNotSmallerThan(
1046
            const component::Bignum& result,
1047
            const component::Bignum& A,
1048
            const component::Bignum& B,
1049
245
            const std::string& opStr) {
1050
245
        if ( SmallerThan(result, A) && SmallerThan(result, B) ) {
1051
0
            Abort("Result is smaller than the input", opStr);
1052
0
        }
1053
245
    }
1054
485
    static void AssertNotLargerThan(const component::Bignum& result, const component::Bignum& A, const std::string& opStr) {
1055
485
        if ( LargerThan(result, A) ) {
1056
0
            Abort("Result is larger than the input", opStr);
1057
0
        }
1058
485
    }
1059
    static void AssertNotLargerThan(
1060
            const component::Bignum& result,
1061
            const component::Bignum& A,
1062
            const component::Bignum& B,
1063
138
            const std::string& opStr) {
1064
138
        if ( LargerThan(result, A) && LargerThan(result, B) ) {
1065
0
            Abort("Result is larger than the input", opStr);
1066
0
        }
1067
138
    }
1068
    static void AssertPositive(
1069
            const component::Bignum& result,
1070
1.22k
            const std::string& opStr) {
1071
1.22k
        if ( !result.IsPositive() ) {
1072
0
            Abort("Result is not positive", opStr);
1073
0
        }
1074
1.22k
    }
1075
    static void AssertOdd(
1076
            const component::Bignum& result,
1077
1.37k
            const std::string& opStr) {
1078
1.37k
        if ( !result.IsOdd() ) {
1079
0
            Abort("Result is not odd", opStr);
1080
0
        }
1081
1.37k
    }
1082
    static void AssertZero(
1083
            const component::Bignum& result,
1084
21
            const std::string& opStr) {
1085
21
        if ( !result.IsZero() ) {
1086
0
            Abort("Result is not zero", opStr);
1087
0
        }
1088
21
    }
1089
}
1090
1091
24.8k
void test(const operation::BignumCalc& op, const std::optional<component::Bignum>& result) {
1092
24.8k
    if ( result == std::nullopt ) {
1093
17.7k
        return;
1094
17.7k
    }
1095
1096
7.14k
    using namespace BignumCalc;
1097
1098
7.14k
    const auto calcOp = op.calcOp.Get();
1099
1100
7.14k
    if (
1101
7.14k
            calcOp != CF_CALCOP("IsPrime(A)") &&
1102
7.14k
            calcOp != CF_CALCOP("Prime()") ) {
1103
        /* Negative numbers are not supported yet */
1104
5.63k
        if (    op.bn0.IsNegative() ||
1105
5.63k
                op.bn1.IsNegative() ||
1106
5.63k
                op.bn2.IsNegative() ) {
1107
0
            return;
1108
0
        }
1109
5.63k
    }
1110
1111
    /* Modular calculations are not supported yet */
1112
7.14k
    if ( op.modulo != std::nullopt ) {
1113
1.38k
        return;
1114
1.38k
    }
1115
1116
5.75k
    switch ( calcOp ) {
1117
37
        case    CF_CALCOP("Add(A,B)"):
1118
37
            if (    SmallerThan(*result, op.bn0) ||
1119
37
                    SmallerThan(*result, op.bn1) ) {
1120
0
                Abort("Result is smaller than its operands", repository::CalcOpToString(calcOp));
1121
0
            }
1122
37
            break;
1123
141
        case    CF_CALCOP("Div(A,B)"):
1124
141
            if ( IsZero(op.bn1) ) {
1125
0
                Abort("Division by zero should not produce a result", repository::CalcOpToString(calcOp));
1126
0
            }
1127
1128
141
            if ( LargerThan(*result, op.bn0) ) {
1129
0
                Abort("Result is larger than the dividend", repository::CalcOpToString(calcOp));
1130
0
            }
1131
141
            break;
1132
61
        case    CF_CALCOP("Mul(A,B)"):
1133
61
            if ( IsZero(op.bn0) || IsZero(op.bn1) ) {
1134
40
                if ( !IsZero(*result) ) {
1135
0
                    Abort("Result of Mul with zero operand is not zero", repository::CalcOpToString(calcOp));
1136
0
                }
1137
40
            }
1138
61
            break;
1139
217
        case    CF_CALCOP("Mod(A,B)"):
1140
217
            BignumCalc::AssertModResult(*result, op.bn1, "Mod");
1141
217
            break;
1142
784
        case    CF_CALCOP("ExpMod(A,B,C)"):
1143
784
            BignumCalc::AssertModResult(*result, op.bn2, "ExpMod");
1144
784
            break;
1145
84
        case    CF_CALCOP("AddMod(A,B,C)"):
1146
84
            BignumCalc::AssertModResult(*result, op.bn2, "AddMod");
1147
84
            break;
1148
121
        case    CF_CALCOP("SubMod(A,B,C)"):
1149
121
            BignumCalc::AssertModResult(*result, op.bn2, "SubMod");
1150
121
            break;
1151
78
        case    CF_CALCOP("MulMod(A,B,C)"):
1152
78
            BignumCalc::AssertModResult(*result, op.bn2, "MulMod");
1153
78
            break;
1154
85
        case    CF_CALCOP("SqrMod(A,B)"):
1155
85
            BignumCalc::AssertModResult(*result, op.bn1, "SqrMod");
1156
85
            break;
1157
0
        case    CF_CALCOP("SqrtMod(A,B)"):
1158
0
            BignumCalc::AssertModResult(*result, op.bn1, "SqrtMod");
1159
0
            break;
1160
0
        case    CF_CALCOP("ModLShift(A,B,C)"):
1161
0
            BignumCalc::AssertModResult(*result, op.bn2, "ModLShift");
1162
0
            break;
1163
41
        case    CF_CALCOP("Bit(A,B)"):
1164
41
            BignumCalc::AssertBinary(*result, "Bit");
1165
41
            break;
1166
0
        case    CF_CALCOP("IsCoprime(A,B)"):
1167
0
            BignumCalc::AssertBinary(*result, "IsCoprime");
1168
0
            break;
1169
23
        case    CF_CALCOP("IsEq(A,B)"):
1170
23
            BignumCalc::AssertBinary(*result, "IsEq");
1171
23
            break;
1172
23
        case    CF_CALCOP("IsGt(A,B)"):
1173
23
            BignumCalc::AssertBinary(*result, "IsGt");
1174
23
            break;
1175
20
        case    CF_CALCOP("IsGte(A,B)"):
1176
20
            BignumCalc::AssertBinary(*result, "IsGte");
1177
20
            break;
1178
21
        case    CF_CALCOP("IsLt(A,B)"):
1179
21
            BignumCalc::AssertBinary(*result, "IsLt");
1180
21
            break;
1181
25
        case    CF_CALCOP("IsLte(A,B)"):
1182
25
            BignumCalc::AssertBinary(*result, "IsLte");
1183
25
            break;
1184
20
        case    CF_CALCOP("IsEven(A)"):
1185
20
            BignumCalc::AssertBinary(*result, "IsEven");
1186
20
            break;
1187
20
        case    CF_CALCOP("IsOdd(A)"):
1188
20
            BignumCalc::AssertBinary(*result, "IsOdd");
1189
20
            break;
1190
20
        case    CF_CALCOP("IsOne(A)"):
1191
20
            BignumCalc::AssertBinary(*result, "IsOne");
1192
20
            break;
1193
0
        case    CF_CALCOP("IsPow2(A)"):
1194
0
            BignumCalc::AssertBinary(*result, "IsPow2");
1195
0
            break;
1196
284
        case    CF_CALCOP("IsPrime(A)"):
1197
284
            BignumCalc::AssertBinary(*result, "IsPrime");
1198
284
            if ( !op.bn0.IsPositive() ) {
1199
21
                BignumCalc::AssertZero(*result, "IsPrime");
1200
21
            }
1201
284
            if ( result->IsOne() ) {
1202
172
                if ( op.bn0.ToTrimmedString() != "2" ) {
1203
151
                    BignumCalc::AssertOdd(op.bn0, "IsPrime");
1204
151
                }
1205
172
            }
1206
284
            break;
1207
13
        case    CF_CALCOP("IsZero(A)"):
1208
13
            BignumCalc::AssertBinary(*result, "IsZero");
1209
13
            break;
1210
74
        case    CF_CALCOP("IsSquare(A)"):
1211
74
            BignumCalc::AssertBinary(*result, "IsSquare");
1212
74
            break;
1213
0
        case    CF_CALCOP("IsPower(A)"):
1214
0
            BignumCalc::AssertBinary(*result, "IsPower");
1215
0
            break;
1216
17
        case    CF_CALCOP("IsNeg(A)"):
1217
17
            BignumCalc::AssertBinary(*result, "IsNeg");
1218
17
            break;
1219
21
        case    CF_CALCOP("IsNotZero(A)"):
1220
21
            BignumCalc::AssertBinary(*result, "IsNotZero");
1221
21
            break;
1222
35
        case    CF_CALCOP("Cmp(A,B)"):
1223
35
            BignumCalc::AssertTertiary(*result, "Cmp");
1224
35
            break;
1225
88
        case    CF_CALCOP("CmpAbs(A,B)"):
1226
88
            BignumCalc::AssertTertiary(*result, "CmpAbs");
1227
88
            break;
1228
87
        case    CF_CALCOP("Jacobi(A,B)"):
1229
87
            BignumCalc::AssertTertiary(*result, "Jacobi");
1230
87
            break;
1231
58
        case    CF_CALCOP("Sqr(A)"):
1232
58
            AssertNotSmallerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
1233
58
            break;
1234
98
        case    CF_CALCOP("RShift(A,B)"):
1235
98
            if ( IsZero(op.bn0) || IsZero(op.bn1) ) {
1236
82
                if ( op.bn0.ToTrimmedString() != result->ToTrimmedString() ) {
1237
0
                    Abort("Zero operand should not alter input", repository::CalcOpToString(calcOp));
1238
0
                }
1239
82
            }
1240
1241
98
            AssertNotLargerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
1242
98
            break;
1243
57
        case    CF_CALCOP("LShift1(A)"):
1244
57
            if ( IsZero(op.bn0) ) {
1245
34
                if ( op.bn0.ToTrimmedString() != result->ToTrimmedString() ) {
1246
0
                    Abort("Zero input should remain zero", repository::CalcOpToString(calcOp));
1247
0
                }
1248
34
            }
1249
1250
57
            AssertNotSmallerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
1251
57
            break;
1252
57
        case    CF_CALCOP("SetBit(A,B)"):
1253
57
            AssertNotSmallerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
1254
57
            break;
1255
55
        case    CF_CALCOP("ClearBit(A,B)"):
1256
55
            AssertNotLargerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
1257
55
            break;
1258
38
        case    CF_CALCOP("Sqrt(A)"):
1259
38
            AssertNotLargerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
1260
38
            break;
1261
0
        case    CF_CALCOP("Cbrt(A)"):
1262
0
            AssertNotLargerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
1263
0
            break;
1264
46
        case    CF_CALCOP("MulAdd(A,B,C)"):
1265
46
            AssertNotSmallerThan(*result, op.bn2, repository::CalcOpToString(calcOp));
1266
46
            break;
1267
0
        case    CF_CALCOP("Min(A,B)"):
1268
0
        case    CF_CALCOP("Max(A,B)"):
1269
0
            if ( !IsEqual(*result, op.bn0) && !IsEqual(*result, op.bn1) ) {
1270
0
                Abort("Result is not an operand", repository::CalcOpToString(calcOp));
1271
0
            }
1272
0
            break;
1273
0
        case    CF_CALCOP("Mask(A,B)"):
1274
0
            if ( LargerThan(*result, op.bn0) ) {
1275
0
                Abort("Result is larger than input", repository::CalcOpToString(calcOp));
1276
0
            }
1277
0
            break;
1278
0
        case    CF_CALCOP("And(A,B)"):
1279
0
            AssertNotLargerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
1280
0
            AssertNotLargerThan(*result, op.bn1, repository::CalcOpToString(calcOp));
1281
0
            break;
1282
0
        case    CF_CALCOP("Or(A,B)"):
1283
0
            AssertNotSmallerThan(*result, op.bn0, repository::CalcOpToString(calcOp));
1284
0
            AssertNotSmallerThan(*result, op.bn1, repository::CalcOpToString(calcOp));
1285
0
            break;
1286
0
        case    CF_CALCOP("Nthrt(A,B)"):
1287
0
        case    CF_CALCOP("NthrtRem(A,B)"):
1288
0
            if ( IsZero(op.bn1) ) {
1289
0
                Abort("Root of zero should not produce a result", repository::CalcOpToString(calcOp));
1290
0
            }
1291
0
            break;
1292
0
        case    CF_CALCOP("Zero()"):
1293
0
            if ( !IsZero(*result) ) {
1294
0
                Abort("Result should be zero", repository::CalcOpToString(calcOp));
1295
0
            }
1296
0
            break;
1297
138
        case    CF_CALCOP("GCD(A,B)"):
1298
138
            AssertNotLargerThan(*result, op.bn0, op.bn1, repository::CalcOpToString(calcOp));
1299
138
            break;
1300
245
        case    CF_CALCOP("LCM(A,B)"):
1301
245
            AssertNotSmallerThan(*result, op.bn0, op.bn1, repository::CalcOpToString(calcOp));
1302
245
            break;
1303
389
        case    CF_CALCOP("InvMod(A,B)"):
1304
389
            if ( !IsZero(*result) ) {
1305
262
                AssertNotLargerThan(*result, op.bn1, repository::CalcOpToString(calcOp));
1306
262
            }
1307
389
            break;
1308
0
        case    CF_CALCOP("Exp(A,B)"):
1309
0
            AssertNotSmallerThan(*result, op.bn0, op.bn1, repository::CalcOpToString(calcOp));
1310
0
            break;
1311
0
        case    CF_CALCOP("RandMod(A)"):
1312
0
            BignumCalc::AssertModResult(*result, op.bn0, "RandMod");
1313
0
            break;
1314
1.22k
        case    CF_CALCOP("Prime()"):
1315
1.22k
            BignumCalc::AssertPositive(*result, repository::CalcOpToString(calcOp));
1316
1.22k
            if ( result->ToTrimmedString() != "2" ) {
1317
1.22k
                BignumCalc::AssertOdd(*result, repository::CalcOpToString(calcOp));
1318
1.22k
            }
1319
1.22k
            break;
1320
32
        case    CF_CALCOP("RandRange(A,B)"):
1321
32
            AssertNotLargerThan(*result, op.bn1, repository::CalcOpToString(calcOp));
1322
32
            break;
1323
5.75k
    }
1324
5.75k
}
1325
1326
455
void test(const operation::BignumCalc_Fp2& op, const std::optional<component::Fp2>& result) {
1327
455
    (void)op;
1328
455
    (void)result;
1329
455
}
1330
1331
1.42k
void test(const operation::BignumCalc_Fp12& op, const std::optional<component::Fp12>& result) {
1332
1.42k
    (void)op;
1333
1.42k
    (void)result;
1334
1.42k
}
1335
1336
} /* namespace tests */
1337
} /* namespace cryptofuzz */