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