rbsecp256k1 6.0.1 → 6.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2244 +1,2429 @@
1
- // rbsecp256k1.c - Ruby VM interfaces for library.
2
- //
3
- // Description:
4
- // This library provides a low-level and high-performance Ruby wrapper around
5
- // libsecp256k1. It includes functions for generating key pairs, signing data,
6
- // and verifying signatures using the library.
7
- //
8
- // Dependencies:
9
- // * libsecp256k1
10
-
11
- // Sanity check that we have the basic header file.
12
- #ifndef HAVE_SECP256K1_H
13
- #error missing secp256k1.h during build
14
- #endif // HAVE_SECP256K1_H
15
-
16
- // Sanity check we have extrakeys module as we need it for keypair which is
17
- // used by schnorrsig.
18
- #ifndef HAVE_SECP256K1_EXTRAKEYS_H
19
- #error missing secp256k1_extrakeys.h during build
20
- #endif // HAVE_SECP256K1_EXTRAKEYS_H
21
-
22
- #include <ruby.h>
23
- #include <secp256k1.h>
24
-
25
- // Check for optional sub-modules. As a rule any secp256k1 submodule is
26
- // optional and so should be blocked off using these ifdefs.
27
- #ifdef HAVE_SECP256K1_RECOVERY_H
28
- #include <secp256k1_recovery.h>
29
- #endif // HAVE_SECP256K1_RECOVERY_H
30
-
31
- #ifdef HAVE_SECP256K1_ECDH_H
32
- #include <secp256k1_ecdh.h>
33
- #endif // HAVE_SECP256K1_ECDH_H
34
-
35
- #ifdef HAVE_SECP256K1_EXTRAKEYS_H
36
- #include <secp256k1_extrakeys.h>
37
- #endif // HAVE_SECP256K1_EXTRAKEYS_H
38
-
39
- #ifdef HAVE_SECP256K1_SCHNORRSIG_H
40
- #include <secp256k1_schnorrsig.h>
41
- #endif // HAVE_SECP256K1_SCHNORRSIG_H
42
-
43
- // High-level design:
44
- //
45
- // The Ruby wrapper is divided into the following hierarchical organization:
46
- //
47
- // +- Secp256k1 (Top-level module)
48
- // |-- Context
49
- // |-- KeyPair
50
- // |-- PublicKey
51
- // |-- XOnlyPublicKey
52
- // |-- PrivateKey
53
- // |-- RecoverableSignature (recovery module)
54
- // |-- SharedSecret (ecdh module)
55
- // |-- Signature
56
- // |-- SchnorrSignature
57
- //
58
- // The Context class contains most of the methods that invoke libsecp256k1.
59
- // The KeyPair, PublicKey, PrivateKey, RecoverableSignature, SharedSecret, and
60
- // Signature objects act as data objects and are passed to various
61
- // methods. Contexts are thread safe and can be used across
62
- // applications. Context initialization is expensive so it is recommended that
63
- // a single context be initialized and used throughout an application when
64
- // possible.
65
- //
66
- // Exception Hierarchy:
67
- //
68
- // The following hierarchy is used for exceptions raised from the library:
69
- //
70
- // +- Error (Descends from StandardError)
71
- // |-- SerializationError
72
- // |-- DeserializationError
73
-
74
- //
75
- // The section below contains purely internal methods used exclusively by the
76
- // C internals of the library.
77
- //
78
-
79
- // Size of an uncompressed public key
80
- const size_t UNCOMPRESSED_PUBKEY_SIZE_BYTES = 65;
81
- // Size of a compressed public key
82
- const size_t COMPRESSED_PUBKEY_SIZE_BYTES = 33;
83
- // Size of a serialized x-only public key
84
- const size_t SERIALIZED_XONLY_PUBKEY_SIZE_BYTES = 32;
85
- // Size of a compact signature in bytes
86
- const size_t COMPACT_SIG_SIZE_BYTES = 64;
87
- // Size of a schnorr signature in bytes
88
- const size_t SCHNORR_SIG_SIZE_BYTES = 64;
89
-
90
- // Globally define our module and its associated classes so we can instantiate
91
- // objects from anywhere. The use of global variables seems to be inline with
92
- // how the Ruby project builds its own extension gems.
93
- static VALUE Secp256k1_module;
94
- static VALUE Secp256k1_Error_class;
95
- static VALUE Secp256k1_SerializationError_class;
96
- static VALUE Secp256k1_DeserializationError_class;
97
- static VALUE Secp256k1_Context_class;
98
- static VALUE Secp256k1_KeyPair_class;
99
- static VALUE Secp256k1_PublicKey_class;
100
- static VALUE Secp256k1_PrivateKey_class;
101
- static VALUE Secp256k1_Signature_class;
102
- static VALUE Secp256k1_XOnlyPublicKey_class;
103
-
104
- #ifdef HAVE_SECP256K1_RECOVERY_H
105
- static VALUE Secp256k1_RecoverableSignature_class;
106
- #endif // HAVE_SECP256K1_RECOVERY_H
107
-
108
- #ifdef HAVE_SECP256K1_ECDH_H
109
- static VALUE Secp256k1_SharedSecret_class;
110
- #endif // HAVE_SECP256K1_ECDH_H
111
-
112
- #ifdef HAVE_SECP256K1_SCHNORRSIG_H
113
- static VALUE Secp256k1_SchnorrSignature_class;
114
- #endif // HAVE_SECP256K1_SCHNORRSIG_H
115
-
116
- // Forward definitions for all structures
117
- typedef struct Context_dummy {
118
- secp256k1_context *ctx; // Context used by libsecp256k1 library
119
- } Context;
120
-
121
- typedef struct KeyPair_dummy {
122
- secp256k1_keypair keypair;
123
- } KeyPair;
124
-
125
- typedef struct PublicKey_dummy {
126
- secp256k1_pubkey pubkey; // Opaque object containing public key data
127
- } PublicKey;
128
-
129
- typedef struct PrivateKey_dummy {
130
- unsigned char data[32]; // Bytes comprising the private key data
131
- } PrivateKey;
132
-
133
- typedef struct XOnlyPublicKey_dummy {
134
- secp256k1_xonly_pubkey pubkey; // Opaque object representing an x-only pubkey.
135
- } XOnlyPublicKey;
136
-
137
- typedef struct Signature_dummy {
138
- secp256k1_ecdsa_signature sig; // Signature object, contains 64-byte signature
139
- } Signature;
140
-
141
- #ifdef HAVE_SECP256K1_RECOVERY_H
142
- typedef struct RecoverableSignature_dummy {
143
- secp256k1_ecdsa_recoverable_signature sig; // Recoverable signature object
144
- secp256k1_context *ctx;
145
- } RecoverableSignature;
146
- #endif // HAVE_SECP256K1_RECOVERY_H
147
-
148
- #ifdef HAVE_SECP256K1_ECDH_H
149
- typedef struct SharedSecret_dummy {
150
- unsigned char data[32]; // Shared secret data
151
- } SharedSecret;
152
- #endif // HAVE_SECP256K1_ECDH_H
153
-
154
- #ifdef HAVE_SECP256K1_SCHNORRSIG_H
155
- typedef struct SchnorrSignature_dummy {
156
- unsigned char sig[64]; // Serialized schnorr signature data
157
- } SchnorrSignature;
158
- #endif // HAVE_SECP256K1_SCHNORRSIG_H
159
- //
160
- // Typed data definitions
161
- //
162
-
163
- // Context
164
- static void
165
- Context_free(void* in_context)
166
- {
167
- Context *context;
168
- context = (Context*)in_context;
169
- secp256k1_context_destroy(context->ctx);
170
- xfree(context);
171
- }
172
-
173
- static const rb_data_type_t Context_DataType = {
174
- "Context",
175
- { 0, Context_free, 0 },
176
- 0, 0,
177
- RUBY_TYPED_FREE_IMMEDIATELY
178
- };
179
-
180
- // PublicKey
181
- static void
182
- PublicKey_free(void *in_public_key)
183
- {
184
- PublicKey *public_key;
185
- public_key = (PublicKey*)in_public_key;
186
- xfree(public_key);
187
- }
188
-
189
- static const rb_data_type_t PublicKey_DataType = {
190
- "PublicKey",
191
- { 0, PublicKey_free, 0 },
192
- 0, 0,
193
- RUBY_TYPED_FREE_IMMEDIATELY
194
- };
195
-
196
- // XOnlyPublicKey
197
- static void
198
- XOnlyPublicKey_free(void* in_xonly_pubkey)
199
- {
200
- XOnlyPublicKey *xonly_pubkey;
201
- xonly_pubkey = (XOnlyPublicKey*)in_xonly_pubkey;
202
- xfree(xonly_pubkey);
203
- }
204
-
205
- static const rb_data_type_t XOnlyPublicKey_DataType = {
206
- "XOnlyPublicKey",
207
- { 0, XOnlyPublicKey_free, 0 },
208
- 0, 0,
209
- RUBY_TYPED_FREE_IMMEDIATELY
210
- };
211
-
212
- // PrivateKey
213
- static void
214
- PrivateKey_free(void *in_private_key)
215
- {
216
- PrivateKey *private_key;
217
- private_key = (PrivateKey*)in_private_key;
218
-
219
- /* Take the best practice recommendation from the libsecp256k1 example and
220
- * clear the secret from memory in case there are bugs that might allow an
221
- * attacker to leak memory.
222
- *
223
- * That being said its not clear how much control we actually have over Ruby
224
- * potentially copying the string version of this private key data.
225
- */
226
- memset(private_key->data, 0, 32);
227
-
228
- xfree(private_key);
229
- }
230
-
231
- static const rb_data_type_t PrivateKey_DataType = {
232
- "PrivateKey",
233
- { 0, PrivateKey_free, 0 },
234
- 0, 0,
235
- RUBY_TYPED_FREE_IMMEDIATELY
236
- };
237
-
238
- // KeyPair
239
- static void
240
- KeyPair_free(void *in_keypair)
241
- {
242
- KeyPair *keypair;
243
- keypair = (KeyPair*)in_keypair;
244
- xfree(keypair);
245
- }
246
-
247
- static const rb_data_type_t KeyPair_DataType = {
248
- "KeyPair",
249
- { 0, KeyPair_free, 0 },
250
- 0, 0,
251
- RUBY_TYPED_FREE_IMMEDIATELY
252
- };
253
-
254
- // Signature
255
- static void
256
- Signature_free(void *in_signature)
257
- {
258
- Signature *signature = (Signature*)in_signature;
259
- xfree(signature);
260
- }
261
-
262
- static const rb_data_type_t Signature_DataType = {
263
- "Signature",
264
- { 0, Signature_free, 0 },
265
- 0, 0,
266
- RUBY_TYPED_FREE_IMMEDIATELY
267
- };
268
-
269
- // RecoverableSignature
270
- #ifdef HAVE_SECP256K1_RECOVERY_H
271
- static void
272
- RecoverableSignature_free(void *in_recoverable_signature)
273
- {
274
- RecoverableSignature *recoverable_signature = (
275
- (RecoverableSignature*)in_recoverable_signature
276
- );
277
-
278
- secp256k1_context_destroy(recoverable_signature->ctx);
279
- xfree(recoverable_signature);
280
- }
281
-
282
- static const rb_data_type_t RecoverableSignature_DataType = {
283
- "RecoverableSignature",
284
- { 0, RecoverableSignature_free, 0 },
285
- 0, 0,
286
- RUBY_TYPED_FREE_IMMEDIATELY
287
- };
288
- #endif // HAVE_SECP256K1_RECOVERY_H
289
-
290
- // SharedSecret
291
- #ifdef HAVE_SECP256K1_ECDH_H
292
- static void
293
- SharedSecret_free(void *in_shared_secret)
294
- {
295
- SharedSecret *shared_secret;
296
-
297
- shared_secret = (SharedSecret*)in_shared_secret;
298
- xfree(shared_secret);
299
- }
300
-
301
- static const rb_data_type_t SharedSecret_DataType = {
302
- "SharedSecret",
303
- { 0, SharedSecret_free, 0 },
304
- 0, 0,
305
- RUBY_TYPED_FREE_IMMEDIATELY
306
- };
307
- #endif // HAVE_SECP256K1_ECDH_H
308
-
309
- // SchnorrSignature
310
- #ifdef HAVE_SECP256K1_SCHNORRSIG_H
311
- static void
312
- SchnorrSignature_free(void *in_schnorr_sig)
313
- {
314
- SchnorrSignature *schnorr_sig;
315
-
316
- schnorr_sig = (SchnorrSignature*)in_schnorr_sig;
317
- xfree(schnorr_sig);
318
- }
319
-
320
- static const rb_data_type_t SchnorrSignature_DataType = {
321
- "SchnorrSignature",
322
- { 0, SchnorrSignature_free, 0 },
323
- 0, 0,
324
- RUBY_TYPED_FREE_IMMEDIATELY
325
- };
326
- #endif // HAVE_SECP256K1_SCHNORRSIG_H
327
-
328
- /**
329
- * Macro: SUCCESS
330
- *
331
- * Determines whether or not the given function result was a success.
332
- */
333
- #define SUCCESS(x) ((x) == RESULT_SUCCESS)
334
-
335
- /**
336
- * Macro: FAILURE
337
- *
338
- * Indicates whether or not the given function result is a failure.
339
- */
340
- #define FAILURE(x) !SUCCESS(x)
341
-
342
- /* Result type for internally defined functions */
343
- typedef enum ResultT_dummy {
344
- RESULT_SUCCESS,
345
- RESULT_FAILURE
346
- } ResultT;
347
-
348
- /**
349
- * Computes the ECDSA signature of the given 32-byte SHA-256 hash.
350
- *
351
- * \param in_context libsecp256k1 context
352
- * \param in_hash32 32-byte SHA-256 hash
353
- * \param in_private_key Private key to be used for signing
354
- * \param out_signature Signature produced during the signing proccess
355
- * \return RESULT_SUCCESS if the hash and signature were computed successfully,
356
- * RESULT_FAILURE if signing failed or DER encoding failed.
357
- */
358
- static ResultT
359
- SignData(secp256k1_context *in_context,
360
- unsigned char *in_hash32,
361
- unsigned char *in_private_key,
362
- secp256k1_ecdsa_signature *out_signature)
363
- {
364
- // Sign the hash of the data
365
- if (secp256k1_ecdsa_sign(in_context,
366
- out_signature,
367
- in_hash32,
368
- in_private_key,
369
- NULL,
370
- NULL) == 1)
371
- {
372
- return RESULT_SUCCESS;
373
- }
374
-
375
- return RESULT_FAILURE;
376
- }
377
-
378
- #ifdef HAVE_SECP256K1_RECOVERY_H
379
-
380
- /**
381
- * Computes the recoverable ECDSA signature of the given data.
382
- *
383
- * ECDSA signing involves the following steps:
384
- * 1. Compute the 32-byte SHA-256 hash of the given data.
385
- * 2. Sign the 32-byte hash using the private key provided.
386
- *
387
- * \param in_context libsecp256k1 context
388
- * \param in_hash32 32-byte SHA-256 hash to sign
389
- * \param in_private_key Private key to be used for signing
390
- * \param out_signature Recoverable signature computed
391
- * \return RESULT_SUCCESS if the hash and signature were computed successfully,
392
- * RESULT_FAILURE if signing failed or DER encoding failed.
393
- */
394
- static ResultT
395
- RecoverableSignData(secp256k1_context *in_context,
396
- unsigned char *in_hash32,
397
- unsigned char *in_private_key,
398
- secp256k1_ecdsa_recoverable_signature *out_signature)
399
- {
400
- if (secp256k1_ecdsa_sign_recoverable(in_context,
401
- out_signature,
402
- in_hash32,
403
- in_private_key,
404
- NULL,
405
- NULL) == 1)
406
- {
407
- return RESULT_SUCCESS;
408
- }
409
-
410
- return RESULT_FAILURE;
411
- }
412
-
413
- #endif // HAVE_SECP256K1_RECOVERY_H
414
-
415
- //
416
- // Secp256k1::XOnlyPublicKey class interface
417
- //
418
-
419
- static VALUE
420
- XOnlyPublicKey_alloc(VALUE klass)
421
- {
422
- VALUE result;
423
- XOnlyPublicKey* xonly_pubkey;
424
-
425
- xonly_pubkey = ALLOC(XOnlyPublicKey);
426
- MEMZERO(xonly_pubkey, XOnlyPublicKey, 1);
427
- result = TypedData_Wrap_Struct(klass, &XOnlyPublicKey_DataType, xonly_pubkey);
428
-
429
- return result;
430
- }
431
-
432
- static VALUE
433
- XOnlyPublicKey_create_from_data(unsigned char *in_xonly_pubkey32)
434
- {
435
- XOnlyPublicKey *xonly_pubkey;
436
- VALUE result;
437
-
438
- result = XOnlyPublicKey_alloc(Secp256k1_XOnlyPublicKey_class);
439
- TypedData_Get_Struct(result, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
440
-
441
- if (secp256k1_xonly_pubkey_parse(secp256k1_context_static, &xonly_pubkey->pubkey, in_xonly_pubkey32) != 1)
442
- {
443
- rb_raise(Secp256k1_DeserializationError_class, "invalid x-only public key data");
444
- return Qnil;
445
- }
446
-
447
- return result;
448
- }
449
-
450
- /**
451
- * Loads an x-only public key from serialized data.
452
- *
453
- * @param in_xonly_public_key_serialized [String] binary string with serialized
454
- * data.
455
- * @return [Secp256k1::XOnlyPublicKey] x-only public key derived from data.
456
- * @raise [Secp256k1::DeserializationError] if x-only public key data is invalid
457
- */
458
- static VALUE
459
- XOnlyPublicKey_from_data(VALUE klass, VALUE in_xonly_public_key_serialized)
460
- {
461
- unsigned char *xonly_pubkey_data;
462
-
463
- Check_Type(in_xonly_public_key_serialized, T_STRING);
464
- if (RSTRING_LEN(in_xonly_public_key_serialized) != 32)
465
- {
466
- rb_raise(Secp256k1_DeserializationError_class, "x-only public key data must be 32 bytes in length");
467
- return Qnil;
468
- }
469
-
470
- xonly_pubkey_data = (unsigned char*)StringValuePtr(in_xonly_public_key_serialized);
471
- return XOnlyPublicKey_create_from_data(xonly_pubkey_data);
472
- }
473
-
474
- /**
475
- * Returns the 32-byte serialized version of this x-only public key.
476
- *
477
- * @return [String] 32-byte binary string containing serialized x-only public
478
- * key.
479
- */
480
- static VALUE
481
- XOnlyPublicKey_serialized(VALUE self)
482
- {
483
- XOnlyPublicKey* xonly_pubkey;
484
- unsigned char out[SERIALIZED_XONLY_PUBKEY_SIZE_BYTES];
485
-
486
- TypedData_Get_Struct(self, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
487
-
488
- if (secp256k1_xonly_pubkey_serialize(secp256k1_context_static, out, &xonly_pubkey->pubkey) != 1)
489
- {
490
- rb_raise(Secp256k1_SerializationError_class, "failed to serialize x-only public key");
491
- return Qnil;
492
- }
493
-
494
- return rb_str_new((char*)out, SERIALIZED_XONLY_PUBKEY_SIZE_BYTES);
495
- }
496
-
497
- /**
498
- * Compare two x-only public keys.
499
- *
500
- * @param other [Secp256k1::XOnlyPublicKey] x-only public key to compare.
501
- * @return [Boolean] true if they are equal, false otherwise.
502
- */
503
- static VALUE
504
- XOnlyPublicKey_equals(VALUE self, VALUE other)
505
- {
506
- XOnlyPublicKey *lhs;
507
- XOnlyPublicKey *rhs;
508
-
509
- TypedData_Get_Struct(self, XOnlyPublicKey, &XOnlyPublicKey_DataType, lhs);
510
- TypedData_Get_Struct(other, XOnlyPublicKey, &XOnlyPublicKey_DataType, rhs);
511
-
512
- if (secp256k1_xonly_pubkey_cmp(secp256k1_context_static, &lhs->pubkey, &rhs->pubkey) == 0)
513
- {
514
- return Qtrue;
515
- }
516
-
517
- return Qfalse;
518
- }
519
-
520
- //
521
- // Secp256k1::PublicKey class interface
522
- //
523
-
524
- static VALUE
525
- PublicKey_alloc(VALUE klass)
526
- {
527
- VALUE result;
528
- PublicKey *public_key;
529
-
530
- public_key = ALLOC(PublicKey);
531
- MEMZERO(public_key, PublicKey, 1);
532
- result = TypedData_Wrap_Struct(klass, &PublicKey_DataType, public_key);
533
-
534
- return result;
535
- }
536
-
537
- static VALUE
538
- PublicKey_create_from_data(unsigned char *in_public_key_data,
539
- unsigned int in_public_key_data_len)
540
- {
541
- PublicKey *public_key;
542
- VALUE result;
543
-
544
- result = PublicKey_alloc(Secp256k1_PublicKey_class);
545
- TypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
546
-
547
- if (secp256k1_ec_pubkey_parse(secp256k1_context_static,
548
- &(public_key->pubkey),
549
- in_public_key_data,
550
- in_public_key_data_len) != 1)
551
- {
552
- rb_raise(Secp256k1_DeserializationError_class, "invalid public key data");
553
- return Qnil;
554
- }
555
-
556
- return result;
557
- }
558
-
559
- /**
560
- * Loads a public key from compressed or uncompressed binary data.
561
- *
562
- * @param in_public_key_data [String] binary string with compressed or
563
- * uncompressed public key data.
564
- * @return [Secp256k1::PublicKey] public key derived from data.
565
- * @raise [Secp256k1::DeserializationError] if public key data is invalid.
566
- */
567
- static VALUE
568
- PublicKey_from_data(VALUE klass, VALUE in_public_key_data)
569
- {
570
- unsigned char *public_key_data;
571
-
572
- Check_Type(in_public_key_data, T_STRING);
573
-
574
- public_key_data = (unsigned char*)StringValuePtr(in_public_key_data);
575
- return PublicKey_create_from_data(
576
- public_key_data,
577
- (int)RSTRING_LEN(in_public_key_data)
578
- );
579
- }
580
-
581
- /**
582
- * @return [String] binary string containing the uncompressed representation
583
- * of this public key.
584
- */
585
- static VALUE
586
- PublicKey_uncompressed(VALUE self)
587
- {
588
- // TODO: Cache value after first computation
589
- PublicKey *public_key;
590
- size_t serialized_pubkey_len = UNCOMPRESSED_PUBKEY_SIZE_BYTES;
591
- unsigned char serialized_pubkey[UNCOMPRESSED_PUBKEY_SIZE_BYTES];
592
-
593
- TypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
594
-
595
- secp256k1_ec_pubkey_serialize(secp256k1_context_static,
596
- serialized_pubkey,
597
- &serialized_pubkey_len,
598
- &(public_key->pubkey),
599
- SECP256K1_EC_UNCOMPRESSED);
600
-
601
- return rb_str_new((char*)serialized_pubkey, serialized_pubkey_len);
602
- }
603
-
604
- /**
605
- * @return [String] binary string containing the compressed representation of
606
- * this public key.
607
- */
608
- static VALUE
609
- PublicKey_compressed(VALUE self)
610
- {
611
- // TODO: Cache value after first computation
612
- PublicKey *public_key;
613
- size_t serialized_pubkey_len = COMPRESSED_PUBKEY_SIZE_BYTES;
614
- unsigned char serialized_pubkey[COMPRESSED_PUBKEY_SIZE_BYTES];
615
-
616
- TypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
617
-
618
- secp256k1_ec_pubkey_serialize(secp256k1_context_static,
619
- serialized_pubkey,
620
- &serialized_pubkey_len,
621
- &(public_key->pubkey),
622
- SECP256K1_EC_COMPRESSED);
623
-
624
- return rb_str_new((char*)serialized_pubkey, serialized_pubkey_len);
625
- }
626
-
627
- /**
628
- * Returns the x-only public key equivalent of this public key.
629
- *
630
- * @return [Secp256k1::XOnlyPublicKey] x-only public key
631
- */
632
- static VALUE
633
- PublicKey_to_xonly(VALUE self)
634
- {
635
- PublicKey *public_key;
636
- XOnlyPublicKey *xonly_pubkey;
637
- VALUE result;
638
-
639
- TypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
640
-
641
- result = XOnlyPublicKey_alloc(Secp256k1_XOnlyPublicKey_class);
642
- TypedData_Get_Struct(result, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
643
-
644
- if (secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_static,
645
- &xonly_pubkey->pubkey,
646
- NULL,
647
- &public_key->pubkey) != 1)
648
- {
649
- rb_raise(Secp256k1_Error_class, "failed to convert pubkey to x-only pubkey");
650
- return Qnil;
651
- }
652
-
653
- return result;
654
- }
655
-
656
- /**
657
- * Compares two public keys.
658
- *
659
- * Public keys are considered equal if their compressed representations match.
660
- *
661
- * @param other [Secp256k1::PublicKey] public key to compare.
662
- * @return [Boolean] true if the public keys are identical, false otherwise.
663
- */
664
- static VALUE
665
- PublicKey_equals(VALUE self, VALUE other)
666
- {
667
- PublicKey *lhs;
668
- PublicKey *rhs;
669
- unsigned char lhs_compressed[33];
670
- unsigned char rhs_compressed[33];
671
- size_t lhs_len;
672
- size_t rhs_len;
673
-
674
- lhs_len = 33;
675
- rhs_len = 33;
676
-
677
- TypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, lhs);
678
- TypedData_Get_Struct(other, PublicKey, &PublicKey_DataType, rhs);
679
-
680
- secp256k1_ec_pubkey_serialize(
681
- secp256k1_context_static,
682
- lhs_compressed,
683
- &lhs_len,
684
- &(lhs->pubkey),
685
- SECP256K1_EC_COMPRESSED
686
- );
687
- secp256k1_ec_pubkey_serialize(
688
- secp256k1_context_static,
689
- rhs_compressed,
690
- &rhs_len,
691
- &(rhs->pubkey),
692
- SECP256K1_EC_COMPRESSED
693
- );
694
-
695
- if (lhs_len == rhs_len &&
696
- memcmp(lhs_compressed, rhs_compressed, lhs_len) == 0)
697
- {
698
- return Qtrue;
699
- }
700
-
701
- return Qfalse;
702
- }
703
-
704
- //
705
- // Secp256k1::PrivateKey class interface
706
- //
707
-
708
- static VALUE
709
- PrivateKey_alloc(VALUE klass)
710
- {
711
- VALUE new_instance;
712
- PrivateKey *private_key;
713
-
714
- private_key = ALLOC(PrivateKey);
715
- MEMZERO(private_key, PrivateKey, 1);
716
- new_instance = TypedData_Wrap_Struct(klass, &PrivateKey_DataType, private_key);
717
-
718
- return new_instance;
719
- }
720
-
721
- /* Internal-only method for creating a private key from secret data */
722
- static VALUE
723
- PrivateKey_create(unsigned char *in_private_key_data)
724
- {
725
- PrivateKey *private_key;
726
- VALUE result;
727
-
728
- if (secp256k1_ec_seckey_verify(secp256k1_context_static,
729
- in_private_key_data) != 1)
730
- {
731
- rb_raise(Secp256k1_Error_class, "invalid private key data");
732
- return Qnil;
733
- }
734
-
735
- result = PrivateKey_alloc(Secp256k1_PrivateKey_class);
736
- TypedData_Get_Struct(result, PrivateKey, &PrivateKey_DataType, private_key);
737
- MEMCPY(private_key->data, in_private_key_data, char, 32);
738
-
739
- return result;
740
- }
741
-
742
- /**
743
- * Returns binary string of private key data.
744
- *
745
- * @return [String] 32 byte binary string of private key data.
746
- */
747
- static VALUE
748
- PrivateKey_data(VALUE self)
749
- {
750
- PrivateKey *private_key;
751
-
752
- TypedData_Get_Struct(self, PrivateKey, &PrivateKey_DataType, private_key);
753
-
754
- return(rb_str_new((char*)private_key->data, 32));
755
- }
756
-
757
- /**
758
- * Load a private key from binary data.
759
- *
760
- * @param in_private_key_data [String] 32 byte binary string of private key
761
- * data.
762
- * @return [Secp256k1::PrivateKey] private key loaded from the given data.
763
- * @raise [Secp256k1::Error] if private key data is not 32 bytes or is invalid.
764
- */
765
- static VALUE
766
- PrivateKey_from_data(VALUE klass, VALUE in_private_key_data)
767
- {
768
- unsigned char *private_key_data;
769
-
770
- Check_Type(in_private_key_data, T_STRING);
771
- if (RSTRING_LEN(in_private_key_data) != 32)
772
- {
773
- rb_raise(
774
- Secp256k1_Error_class,
775
- "private key data must be 32 bytes in length"
776
- );
777
- return Qnil;
778
- }
779
-
780
- private_key_data = (unsigned char*)StringValuePtr(in_private_key_data);
781
- return PrivateKey_create(private_key_data);
782
- }
783
-
784
- /**
785
- * Compare two private keys.
786
- *
787
- * Private keys are considered equal if their data fields are identical.
788
- *
789
- * @param other [Secp256k1::PrivateKey] private key to compare.
790
- * @return [Boolean] true if they are equal, false otherwise.
791
- */
792
- static VALUE
793
- PrivateKey_equals(VALUE self, VALUE other)
794
- {
795
- PrivateKey *lhs;
796
- PrivateKey *rhs;
797
-
798
- TypedData_Get_Struct(self, PrivateKey, &PrivateKey_DataType, lhs);
799
- TypedData_Get_Struct(other, PrivateKey, &PrivateKey_DataType, rhs);
800
-
801
- if (memcmp(lhs->data, rhs->data, 32) == 0)
802
- {
803
- return Qtrue;
804
- }
805
-
806
- return Qfalse;
807
- }
808
-
809
- //
810
- // Secp256k1::KeyPair class interface
811
- //
812
-
813
- static VALUE
814
- KeyPair_alloc(VALUE klass)
815
- {
816
- KeyPair *key_pair;
817
-
818
- key_pair = ALLOC(KeyPair);
819
-
820
- return TypedData_Wrap_Struct(klass, &KeyPair_DataType, key_pair);
821
- }
822
-
823
- /**
824
- * Retrieve the public key for the given key pair.
825
- *
826
- * @return [Secp256k1::PublicKey] public key corresponding to private key.
827
- */
828
- static VALUE
829
- KeyPair_public_key(VALUE self)
830
- {
831
- KeyPair *key_pair;
832
- VALUE result;
833
- PublicKey *public_key;
834
-
835
- TypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, key_pair);
836
-
837
- result = PublicKey_alloc(Secp256k1_PublicKey_class);
838
- TypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
839
-
840
- if (secp256k1_keypair_pub(secp256k1_context_static, &public_key->pubkey, &key_pair->keypair) == 0)
841
- {
842
- rb_raise(Secp256k1_Error_class, "failed to derive public key from keypair");
843
- return Qnil;
844
- }
845
-
846
- return result;
847
- }
848
-
849
- /**
850
- * Retrieve the x-only public key for the given key pair.
851
- *
852
- * @return [Secp256k1::XOnlyPublicKey] x-only public key corresponding to
853
- * private key.
854
- */
855
- static VALUE
856
- KeyPair_xonly_public_key(VALUE self)
857
- {
858
- KeyPair *key_pair;
859
- VALUE result;
860
- XOnlyPublicKey *xonly_pubkey;
861
-
862
- TypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, key_pair);
863
-
864
- result = XOnlyPublicKey_alloc(Secp256k1_XOnlyPublicKey_class);
865
- TypedData_Get_Struct(result, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
866
-
867
- if (secp256k1_keypair_xonly_pub(secp256k1_context_static, &xonly_pubkey->pubkey, NULL, &key_pair->keypair) == 0)
868
- {
869
- rb_raise(Secp256k1_Error_class, "failed to derive x-only public key from keypair");
870
- return Qnil;
871
- }
872
-
873
- return result;
874
- }
875
-
876
- /**
877
- * Retrieve the private key for the given key pair.
878
- *
879
- * @return [Secp256k1::PrivateKey] public key corresponding to private key.
880
- */
881
- static VALUE
882
- KeyPair_private_key(VALUE self)
883
- {
884
- KeyPair *key_pair;
885
- unsigned char private_key_data[32];
886
-
887
- TypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, key_pair);
888
-
889
- if (secp256k1_keypair_sec(secp256k1_context_static, private_key_data, &key_pair->keypair) == 0)
890
- {
891
- rb_raise(Secp256k1_Error_class, "failed to derive private key from keypair");
892
- return Qnil;
893
- }
894
-
895
- return PrivateKey_create(private_key_data);
896
- }
897
-
898
- /**
899
- * Compare two key pairs.
900
- *
901
- * Two key pairs are equal if they have the same public and private key. The
902
- * keys are compared using their own comparison operators.
903
- *
904
- * @param other [Secp256k1::KeyPair] key pair to compare to.
905
- * @return [Boolean] true if the keys match, false otherwise.
906
- */
907
- static VALUE
908
- KeyPair_equals(VALUE self, VALUE other)
909
- {
910
- KeyPair *lhs;
911
- KeyPair *rhs;
912
-
913
- TypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, lhs);
914
- TypedData_Get_Struct(other, KeyPair, &KeyPair_DataType, rhs);
915
-
916
- if (memcmp(&lhs->keypair, &rhs->keypair, sizeof(secp256k1_keypair)) == 0)
917
- {
918
- return Qtrue;
919
- }
920
-
921
- return Qfalse;
922
- }
923
-
924
- //
925
- // Secp256k1::Signature class interface
926
- //
927
-
928
- static VALUE
929
- Signature_alloc(VALUE klass)
930
- {
931
- VALUE new_instance;
932
- Signature *signature;
933
-
934
- signature = ALLOC(Signature);
935
- MEMZERO(signature, Signature, 1);
936
- new_instance = TypedData_Wrap_Struct(klass, &Signature_DataType, signature);
937
-
938
- return new_instance;
939
- }
940
-
941
- /**
942
- * Deserializes a Signature from 64-byte compact signature data.
943
- *
944
- * @param in_compact_signature [String] compact signature as 64-byte binary
945
- * string.
946
- * @return [Secp256k1::Signature] object deserialized from compact signature.
947
- * @raise [Secp256k1::DeserializationError] if signature data is invalid.
948
- */
949
- static VALUE
950
- Signature_from_compact(VALUE klass, VALUE in_compact_signature)
951
- {
952
- Signature *signature;
953
- VALUE signature_result;
954
- unsigned char *signature_data;
955
-
956
- Check_Type(in_compact_signature, T_STRING);
957
-
958
- if (RSTRING_LEN(in_compact_signature) != 64)
959
- {
960
- rb_raise(Secp256k1_Error_class, "compact signature must be 64 bytes");
961
- }
962
-
963
- signature_data = (unsigned char*)StringValuePtr(in_compact_signature);
964
-
965
- signature_result = Signature_alloc(Secp256k1_Signature_class);
966
- TypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
967
-
968
- if (secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static,
969
- &(signature->sig),
970
- signature_data) != 1)
971
- {
972
- rb_raise(Secp256k1_DeserializationError_class, "invalid compact signature");
973
- return Qnil;
974
- }
975
-
976
- return signature_result;
977
- }
978
-
979
- /**
980
- * Converts a DER encoded binary signature into a signature object.
981
- *
982
- * @param in_der_encoded_signature [String] DER encoded signature as binary
983
- * string.
984
- * @return [Secp256k1::Signature] signature object initialized using signature
985
- * data.
986
- * @raise [Secp256k1::DeserializationError] if signature data is invalid.
987
- */
988
- static VALUE
989
- Signature_from_der_encoded(VALUE klass, VALUE in_der_encoded_signature)
990
- {
991
- Signature *signature;
992
- VALUE signature_result;
993
- unsigned char *signature_data;
994
-
995
- Check_Type(in_der_encoded_signature, T_STRING);
996
-
997
- signature_data = (unsigned char*)StringValuePtr(in_der_encoded_signature);
998
-
999
- signature_result = Signature_alloc(Secp256k1_Signature_class);
1000
- TypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
1001
-
1002
- if (secp256k1_ecdsa_signature_parse_der(secp256k1_context_static,
1003
- &(signature->sig),
1004
- signature_data,
1005
- RSTRING_LEN(in_der_encoded_signature)) != 1)
1006
- {
1007
- rb_raise(Secp256k1_DeserializationError_class, "invalid DER encoded signature");
1008
- return Qnil;
1009
- }
1010
-
1011
- return signature_result;
1012
- }
1013
-
1014
- /**
1015
- * Return Distinguished Encoding Rules (DER) encoded signature data.
1016
- *
1017
- * @return [String] binary string containing DER-encoded signature data.
1018
- */
1019
- static VALUE
1020
- Signature_der_encoded(VALUE self)
1021
- {
1022
- // TODO: Cache value after first computation
1023
- Signature *signature;
1024
- unsigned long der_signature_len;
1025
- unsigned char der_signature[72];
1026
-
1027
- TypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
1028
-
1029
- der_signature_len = 72;
1030
- if (secp256k1_ecdsa_signature_serialize_der(secp256k1_context_static,
1031
- der_signature,
1032
- &der_signature_len,
1033
- &(signature->sig)) != 1)
1034
- {
1035
- rb_raise(
1036
- Secp256k1_SerializationError_class,
1037
- "could not compute DER encoded signature"
1038
- );
1039
- return Qnil;
1040
- }
1041
-
1042
- return rb_str_new((char*)der_signature, der_signature_len);
1043
- }
1044
-
1045
- /**
1046
- * Returns the 64 byte compact representation of this signature.
1047
- *
1048
- * @return [String] 64 byte binary string containing signature data.
1049
- */
1050
- static VALUE
1051
- Signature_compact(VALUE self)
1052
- {
1053
- // TODO: Cache value after first computation
1054
- Signature *signature;
1055
- unsigned char compact_signature[COMPACT_SIG_SIZE_BYTES];
1056
-
1057
- TypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
1058
-
1059
- if (secp256k1_ecdsa_signature_serialize_compact(secp256k1_context_static,
1060
- compact_signature,
1061
- &(signature->sig)) != 1)
1062
- {
1063
- rb_raise(
1064
- Secp256k1_SerializationError_class,
1065
- "unable to compute compact signature"
1066
- );
1067
- return Qnil;
1068
- }
1069
-
1070
- return rb_str_new((char*)compact_signature, COMPACT_SIG_SIZE_BYTES);
1071
- }
1072
-
1073
- /**
1074
- * Returns the normalized lower-S form of this signature.
1075
- *
1076
- * This can be useful when importing signatures generated by other applications
1077
- * that may not be normalized. Non-normalized signatures are potentially
1078
- * forgeable.
1079
- *
1080
- * @return [Array] first element is a boolean that is `true` if the signature
1081
- * was normalized, false otherwise. The second element is a `Signature`
1082
- * object corresponding to the normalized signature.
1083
- */
1084
- static VALUE
1085
- Signature_normalized(VALUE self)
1086
- {
1087
- VALUE result_sig;
1088
- VALUE was_normalized;
1089
- VALUE result;
1090
- Signature *signature;
1091
- Signature *normalized_signature;
1092
-
1093
- TypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
1094
- result_sig = Signature_alloc(Secp256k1_Signature_class);
1095
- TypedData_Get_Struct(
1096
- result_sig, Signature, &Signature_DataType, normalized_signature
1097
- );
1098
-
1099
- was_normalized = Qfalse;
1100
- if (secp256k1_ecdsa_signature_normalize(
1101
- secp256k1_context_static,
1102
- &(normalized_signature->sig),
1103
- &(signature->sig)) == 1)
1104
- {
1105
- was_normalized = Qtrue;
1106
- }
1107
-
1108
- result = rb_ary_new2(2);
1109
- rb_ary_push(result, was_normalized);
1110
- rb_ary_push(result, result_sig);
1111
-
1112
- return result;
1113
- }
1114
-
1115
- /**
1116
- * Compares two signatures.
1117
- *
1118
- * Two signatures are equal if their compact encodings are identical.
1119
- *
1120
- * @param other [Secp256k1::Signature] signature to compare
1121
- * @return [Boolean] true if signatures match, false otherwise.
1122
- */
1123
- static VALUE
1124
- Signature_equals(VALUE self, VALUE other)
1125
- {
1126
- Signature *lhs;
1127
- Signature *rhs;
1128
- unsigned char lhs_compact[64];
1129
- unsigned char rhs_compact[64];
1130
-
1131
- TypedData_Get_Struct(self, Signature, &Signature_DataType, lhs);
1132
- TypedData_Get_Struct(other, Signature, &Signature_DataType, rhs);
1133
-
1134
- secp256k1_ecdsa_signature_serialize_compact(
1135
- secp256k1_context_static, lhs_compact, &(lhs->sig)
1136
- );
1137
- secp256k1_ecdsa_signature_serialize_compact(
1138
- secp256k1_context_static, rhs_compact, &(rhs->sig)
1139
- );
1140
-
1141
- if (memcmp(lhs_compact, rhs_compact, 64) == 0)
1142
- {
1143
- return Qtrue;
1144
- }
1145
-
1146
- return Qfalse;
1147
- }
1148
-
1149
- //
1150
- // Secp256k1::RecoverableSignature class interface
1151
- //
1152
-
1153
- #ifdef HAVE_SECP256K1_RECOVERY_H
1154
-
1155
- static VALUE
1156
- RecoverableSignature_alloc(VALUE klass)
1157
- {
1158
- VALUE new_instance;
1159
- RecoverableSignature *recoverable_signature;
1160
-
1161
- recoverable_signature = ALLOC(RecoverableSignature);
1162
- MEMZERO(recoverable_signature, RecoverableSignature, 1);
1163
- new_instance = TypedData_Wrap_Struct(
1164
- klass, &RecoverableSignature_DataType, recoverable_signature
1165
- );
1166
-
1167
- return new_instance;
1168
- }
1169
-
1170
- /**
1171
- * Returns the compact encoding of recoverable signature.
1172
- *
1173
- * @return [Array] first element is the 64 byte compact encoding of signature,
1174
- * the second element is the integer recovery ID.
1175
- * @raise [Secp256k1::SerializationError] if signature serialization fails.
1176
- */
1177
- static VALUE
1178
- RecoverableSignature_compact(VALUE self)
1179
- {
1180
- RecoverableSignature *recoverable_signature;
1181
- unsigned char compact_sig[64];
1182
- int recovery_id;
1183
- VALUE result;
1184
-
1185
- TypedData_Get_Struct(
1186
- self,
1187
- RecoverableSignature,
1188
- &RecoverableSignature_DataType,
1189
- recoverable_signature
1190
- );
1191
-
1192
- if (secp256k1_ecdsa_recoverable_signature_serialize_compact(
1193
- recoverable_signature->ctx,
1194
- compact_sig,
1195
- &recovery_id,
1196
- &(recoverable_signature->sig)) != 1)
1197
- {
1198
- rb_raise(
1199
- Secp256k1_SerializationError_class,
1200
- "unable to serialize recoverable signature"
1201
- );
1202
- return Qnil;
1203
- }
1204
-
1205
- // Create a new array with room for 2 elements and push data onto it
1206
- result = rb_ary_new2(2);
1207
- rb_ary_push(result, rb_str_new((char*)compact_sig, 64));
1208
- rb_ary_push(result, rb_int_new(recovery_id));
1209
-
1210
- return result;
1211
- }
1212
-
1213
- /**
1214
- * Convert a recoverable signature to a non-recoverable signature.
1215
- *
1216
- * @return [Secp256k1::Signature] non-recoverable signature derived from this
1217
- * recoverable signature.
1218
- */
1219
- static VALUE
1220
- RecoverableSignature_to_signature(VALUE self)
1221
- {
1222
- RecoverableSignature *recoverable_signature;
1223
- Signature *signature;
1224
- VALUE result;
1225
-
1226
- TypedData_Get_Struct(
1227
- self,
1228
- RecoverableSignature,
1229
- &RecoverableSignature_DataType,
1230
- recoverable_signature
1231
- );
1232
-
1233
- result = Signature_alloc(Secp256k1_Signature_class);
1234
- TypedData_Get_Struct(
1235
- result,
1236
- Signature,
1237
- &Signature_DataType,
1238
- signature
1239
- );
1240
-
1241
- // NOTE: This method cannot fail
1242
- secp256k1_ecdsa_recoverable_signature_convert(
1243
- recoverable_signature->ctx,
1244
- &(signature->sig),
1245
- &(recoverable_signature->sig));
1246
-
1247
- return result;
1248
- }
1249
-
1250
- /**
1251
- * Attempts to recover the public key associated with this signature.
1252
- *
1253
- * @param in_hash32 [String] 32-byte SHA-256 hash of data.
1254
- * @return [Secp256k1::PublicKey] recovered public key.
1255
- * @raise [Secp256k1::Error] if hash given is not 32 bytes.
1256
- * @raise [Secp256k1::DeserializationError] if public key could not be
1257
- * recovered.
1258
- */
1259
- static VALUE
1260
- RecoverableSignature_recover_public_key(VALUE self, VALUE in_hash32)
1261
- {
1262
- RecoverableSignature *recoverable_signature;
1263
- PublicKey *public_key;
1264
- VALUE result;
1265
- unsigned char *hash32;
1266
-
1267
- Check_Type(in_hash32, T_STRING);
1268
- if (RSTRING_LEN(in_hash32) != 32)
1269
- {
1270
- rb_raise(Secp256k1_Error_class, "in_hash32 is not 32 bytes in length");
1271
- return Qnil;
1272
- }
1273
-
1274
- TypedData_Get_Struct(
1275
- self,
1276
- RecoverableSignature,
1277
- &RecoverableSignature_DataType,
1278
- recoverable_signature
1279
- );
1280
- hash32 = (unsigned char*)StringValuePtr(in_hash32);
1281
-
1282
- result = PublicKey_alloc(Secp256k1_PublicKey_class);
1283
- TypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
1284
-
1285
- if (secp256k1_ecdsa_recover(recoverable_signature->ctx,
1286
- &(public_key->pubkey),
1287
- &(recoverable_signature->sig),
1288
- hash32) == 1)
1289
- {
1290
- return result;
1291
- }
1292
-
1293
- rb_raise(Secp256k1_DeserializationError_class, "unable to recover public key");
1294
- }
1295
-
1296
- /**
1297
- * Compares two recoverable signatures.
1298
- *
1299
- * Two recoverable signatures their secp256k1_ecdsa_recoverable_signature data
1300
- * is identical.
1301
- *
1302
- * @param other [Secp256k1::RecoverableSignature] recoverable signature to
1303
- * compare.
1304
- * @return [Boolean] true if the recoverable signatures are identical, false
1305
- * otherwise.
1306
- */
1307
- static VALUE
1308
- RecoverableSignature_equals(VALUE self, VALUE other)
1309
- {
1310
- RecoverableSignature *lhs;
1311
- RecoverableSignature *rhs;
1312
-
1313
- TypedData_Get_Struct(
1314
- self, RecoverableSignature, &RecoverableSignature_DataType, lhs
1315
- );
1316
- TypedData_Get_Struct(
1317
- other, RecoverableSignature, &RecoverableSignature_DataType, rhs
1318
- );
1319
-
1320
- // NOTE: It is safe to directly compare these data structures rather than
1321
- // first serializing and then comparing.
1322
- if (memcmp(&(lhs->sig),
1323
- &(rhs->sig),
1324
- sizeof(secp256k1_ecdsa_recoverable_signature)) == 0)
1325
- {
1326
- return Qtrue;
1327
- }
1328
-
1329
- return Qfalse;
1330
- }
1331
-
1332
- #endif // HAVE_SECP256K1_RECOVERY_H
1333
-
1334
- //
1335
- // Secp256k1::SharedSecret class interface
1336
- //
1337
-
1338
- #ifdef HAVE_SECP256K1_ECDH_H
1339
-
1340
- static VALUE
1341
- SharedSecret_alloc(VALUE klass)
1342
- {
1343
- VALUE new_instance;
1344
- SharedSecret *shared_secret;
1345
-
1346
- shared_secret = ALLOC(SharedSecret);
1347
- MEMZERO(shared_secret, SharedSecret, 1);
1348
- new_instance = TypedData_Wrap_Struct(
1349
- klass, &SharedSecret_DataType, shared_secret
1350
- );
1351
-
1352
- return new_instance;
1353
- }
1354
-
1355
- #endif // HAVE_SECP256K1_ECDH_H
1356
-
1357
- //
1358
- // Secp256k1::SchnorrSignature class interface
1359
- //
1360
-
1361
- #ifdef HAVE_SECP256K1_SCHNORRSIG_H
1362
-
1363
- static VALUE
1364
- SchnorrSignature_alloc(VALUE klass)
1365
- {
1366
- VALUE new_instance;
1367
- SchnorrSignature *schnorr_sig;
1368
-
1369
- schnorr_sig = ALLOC(SchnorrSignature);
1370
- MEMZERO(schnorr_sig, SchnorrSignature, 1);
1371
- new_instance = TypedData_Wrap_Struct(klass, &SchnorrSignature_DataType, schnorr_sig);
1372
-
1373
- return new_instance;
1374
- }
1375
-
1376
- static VALUE
1377
- SchnorrSignature_from_data(VALUE klass, VALUE in_data)
1378
- {
1379
- SchnorrSignature* sig;
1380
- VALUE result;
1381
- unsigned char* schnorr_data;
1382
-
1383
- Check_Type(in_data, T_STRING);
1384
- if (RSTRING_LEN(in_data) != SCHNORR_SIG_SIZE_BYTES)
1385
- {
1386
- rb_raise(Secp256k1_DeserializationError_class, "schnorr signature data must be 64 bytes in length");
1387
- return Qnil;
1388
- }
1389
-
1390
- schnorr_data = (unsigned char*)StringValuePtr(in_data);
1391
-
1392
- result = SchnorrSignature_alloc(Secp256k1_SchnorrSignature_class);
1393
- TypedData_Get_Struct(result, SchnorrSignature, &SchnorrSignature_DataType, sig);
1394
-
1395
- memcpy(sig->sig, schnorr_data, SCHNORR_SIG_SIZE_BYTES);
1396
-
1397
- return result;
1398
- }
1399
-
1400
- static VALUE
1401
- SchnorrSignature_serialized(VALUE self)
1402
- {
1403
- SchnorrSignature *schnorr_sig;
1404
-
1405
- TypedData_Get_Struct(self, SchnorrSignature, &SchnorrSignature_DataType, schnorr_sig);
1406
-
1407
- return rb_str_new((char*)schnorr_sig->sig, SCHNORR_SIG_SIZE_BYTES);
1408
- }
1409
-
1410
- static VALUE
1411
- SchnorrSignature_verify(VALUE self, VALUE in_message, VALUE in_xonly_pubkey)
1412
- {
1413
- XOnlyPublicKey *xonly_pubkey;
1414
- SchnorrSignature *schnorr_sig;
1415
- unsigned char* msg;
1416
-
1417
- TypedData_Get_Struct(self, SchnorrSignature, &SchnorrSignature_DataType, schnorr_sig);
1418
- TypedData_Get_Struct(in_xonly_pubkey, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
1419
- Check_Type(in_message, T_STRING);
1420
-
1421
- msg = (unsigned char*)StringValuePtr(in_message);
1422
- if (secp256k1_schnorrsig_verify(secp256k1_context_static, schnorr_sig->sig, msg, RSTRING_LEN(in_message), &xonly_pubkey->pubkey) != 1)
1423
- {
1424
- return Qfalse;
1425
- }
1426
-
1427
- return Qtrue;
1428
- }
1429
-
1430
- static VALUE
1431
- SchnorrSignature_equals(VALUE self, VALUE other)
1432
- {
1433
- SchnorrSignature *lhs;
1434
- SchnorrSignature *rhs;
1435
-
1436
- TypedData_Get_Struct(self, SchnorrSignature, &SchnorrSignature_DataType, lhs);
1437
- TypedData_Get_Struct(other, SchnorrSignature, &SchnorrSignature_DataType, rhs);
1438
-
1439
- if (memcmp(lhs->sig, rhs->sig, SCHNORR_SIG_SIZE_BYTES) == 0)
1440
- {
1441
- return Qtrue;
1442
- }
1443
-
1444
- return Qfalse;
1445
- }
1446
-
1447
- #endif // HAVE_SECP256K1_SCHNORRSIG_H
1448
-
1449
- //
1450
- // Secp256k1::Context class interface
1451
- //
1452
-
1453
- /* Allocate a new context object */
1454
- static VALUE
1455
- Context_alloc(VALUE klass)
1456
- {
1457
- VALUE new_instance;
1458
- Context *context;
1459
-
1460
- context = ALLOC(Context);
1461
- MEMZERO(context, Context, 1);
1462
-
1463
- new_instance = TypedData_Wrap_Struct(klass, &Context_DataType, context);
1464
-
1465
- return new_instance;
1466
- }
1467
-
1468
- /**
1469
- * Initialize a new context.
1470
- *
1471
- * Context initialization should be infrequent as it is an expensive operation.
1472
- *
1473
- * @param context_randomization_bytes [String,nil] (Optional) 32 bytes of
1474
- * random data used to randomize the context. If omitted then the
1475
- * context remains unrandomized. It is recommended that you provide this
1476
- * argument.
1477
- * @return [Secp256k1::Context]
1478
- * @raise [Secp256k1::Error] if context randomization fails.
1479
- */
1480
- static VALUE
1481
- Context_initialize(int argc, const VALUE* argv, VALUE self)
1482
- {
1483
- Context *context;
1484
- unsigned char *seed32;
1485
- VALUE context_randomization_bytes;
1486
- VALUE opts;
1487
- static ID kwarg_ids;
1488
-
1489
- context_randomization_bytes = Qnil;
1490
- if (!kwarg_ids)
1491
- {
1492
- CONST_ID(kwarg_ids, "context_randomization_bytes");
1493
- }
1494
-
1495
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1496
-
1497
- context->ctx = secp256k1_context_create(
1498
- SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY
1499
- );
1500
-
1501
- // Handle optional second argument containing random bytes to use for
1502
- // randomization. We pass ":" to rb_scan_args to say that we expect keyword
1503
- // arguments. We then parse the opts result of the scan in order to grab
1504
- // context_randomization_bytes from the hash.
1505
- rb_scan_args(argc, argv, ":", &opts);
1506
- rb_get_kwargs(opts, &kwarg_ids, 0, 1, &context_randomization_bytes);
1507
-
1508
- // We need this check because rb_get_kwargs will set the result to Qundef if
1509
- // the keyword argument is not provided. This lets us use the NIL_P
1510
- // predicate.
1511
- if (context_randomization_bytes == Qundef)
1512
- {
1513
- context_randomization_bytes = Qnil;
1514
- }
1515
-
1516
- if (!NIL_P(context_randomization_bytes)) // Random bytes given
1517
- {
1518
- Check_Type(context_randomization_bytes, T_STRING);
1519
- if (RSTRING_LEN(context_randomization_bytes) != 32)
1520
- {
1521
- rb_raise(
1522
- Secp256k1_Error_class,
1523
- "context_randomization_bytes must be 32 bytes in length"
1524
- );
1525
- }
1526
-
1527
- seed32 = (unsigned char*)StringValuePtr(context_randomization_bytes);
1528
-
1529
- // Randomize the context at initialization time rather than before calls so
1530
- // the same context can be used across threads safely.
1531
- if (secp256k1_context_randomize(context->ctx, seed32) != 1)
1532
- {
1533
- rb_raise(
1534
- Secp256k1_Error_class,
1535
- "context randomization failed"
1536
- );
1537
- }
1538
- }
1539
-
1540
- return self;
1541
- }
1542
-
1543
- /**
1544
- * Converts binary private key data into a new key pair.
1545
- *
1546
- * @param in_private_key_data [String] binary private key data
1547
- * @return [Secp256k1::KeyPair] key pair initialized from the private key data.
1548
- * @raise [Secp256k1::Error] if the private key data is invalid or key derivation
1549
- * fails.
1550
- */
1551
- static VALUE
1552
- Context_key_pair_from_private_key(VALUE self, VALUE in_private_key_data)
1553
- {
1554
- Context *context;
1555
- VALUE result;
1556
- KeyPair *keypair;
1557
- unsigned char *private_key_data;
1558
-
1559
- Check_Type(in_private_key_data, T_STRING);
1560
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1561
-
1562
- if (RSTRING_LEN(in_private_key_data) != 32)
1563
- {
1564
- rb_raise(Secp256k1_Error_class, "private key data must be 32 bytes in length");
1565
- return Qnil;
1566
- }
1567
-
1568
- result = KeyPair_alloc(Secp256k1_KeyPair_class);
1569
- TypedData_Get_Struct(result, KeyPair, &KeyPair_DataType, keypair);
1570
-
1571
- private_key_data = (unsigned char*)StringValuePtr(in_private_key_data);
1572
-
1573
- if (secp256k1_keypair_create(context->ctx, &keypair->keypair, private_key_data) == 0)
1574
- {
1575
- rb_raise(Secp256k1_Error_class, "invalid secret when attempting to create keypair");
1576
- }
1577
-
1578
- return result;
1579
- }
1580
-
1581
- /**
1582
- * Computes the ECDSA signature of the data using the secp256k1 elliptic curve.
1583
- *
1584
- * @param in_private_key [Secp256k1::PrivateKey] private key to use for
1585
- * signing.
1586
- * @param in_hash32 [String] 32-byte binary string with SHA-256 hash of data.
1587
- * @return [Secp256k1::Signature] signature resulting from signing data.
1588
- * @raise [Secp256k1::Error] if hash is not 32-bytes in length or signature
1589
- * computation fails.
1590
- */
1591
- static VALUE
1592
- Context_sign(VALUE self, VALUE in_private_key, VALUE in_hash32)
1593
- {
1594
- unsigned char *hash32;
1595
- PrivateKey *private_key;
1596
- Context *context;
1597
- Signature *signature;
1598
- VALUE signature_result;
1599
-
1600
- Check_Type(in_hash32, T_STRING);
1601
-
1602
- if (RSTRING_LEN(in_hash32) != 32)
1603
- {
1604
- rb_raise(Secp256k1_Error_class, "in_hash32 is not 32 bytes in length");
1605
- return Qnil;
1606
- }
1607
-
1608
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1609
- TypedData_Get_Struct(in_private_key, PrivateKey, &PrivateKey_DataType, private_key);
1610
- hash32 = (unsigned char*)StringValuePtr(in_hash32);
1611
-
1612
- signature_result = Signature_alloc(Secp256k1_Signature_class);
1613
- TypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
1614
-
1615
- // Attempt to sign the hash of the given data
1616
- if (SUCCESS(SignData(context->ctx,
1617
- hash32,
1618
- private_key->data,
1619
- &(signature->sig))))
1620
- {
1621
- return signature_result;
1622
- }
1623
-
1624
- rb_raise(Secp256k1_Error_class, "unable to compute signature");
1625
- return Qnil;
1626
- }
1627
-
1628
- /**
1629
- * Computes the tagged hash as defined in BIP-340.
1630
- *
1631
- * @param in_tag [String] tag value included in the hash.
1632
- * @param in_message [String] message to be hashed.
1633
- * @return [String] 32-byte binary hash.
1634
- */
1635
- static VALUE
1636
- Context_tagged_sha256(VALUE self, VALUE in_tag, VALUE in_message)
1637
- {
1638
- Context *context;
1639
- unsigned char* tag;
1640
- unsigned char* msg;
1641
- unsigned char hash32[32];
1642
-
1643
- Check_Type(in_tag, T_STRING);
1644
- Check_Type(in_message, T_STRING);
1645
-
1646
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1647
-
1648
- tag = (unsigned char*)StringValuePtr(in_tag);
1649
- msg = (unsigned char*)StringValuePtr(in_message);
1650
-
1651
- if (secp256k1_tagged_sha256(context->ctx, hash32, tag, RSTRING_LEN(in_tag), msg, RSTRING_LEN(in_message)) != 1)
1652
- {
1653
- rb_raise(Secp256k1_Error_class, "failed to compute tagged SHA256");
1654
- return Qnil;
1655
- }
1656
-
1657
- return rb_str_new((char*)hash32, 32);
1658
- }
1659
-
1660
- /**
1661
- * Verifies that signature matches public key and data.
1662
- *
1663
- * @param in_signature [Secp256k1::Signature] signature to be verified.
1664
- * @param in_pubkey [Secp256k1::PublicKey] public key to verify signature
1665
- * against.
1666
- * @param in_hash32 [String] 32-byte binary string containing SHA-256 hash of
1667
- * data.
1668
- * @return [Boolean] True if the signature is valid, false otherwise.
1669
- * @raise [Secp256k1::Error] if hash is not 32-bytes in length.
1670
- */
1671
- static VALUE
1672
- Context_verify(VALUE self, VALUE in_signature, VALUE in_pubkey, VALUE in_hash32)
1673
- {
1674
- Context *context;
1675
- PublicKey *public_key;
1676
- Signature *signature;
1677
- unsigned char *hash32;
1678
-
1679
- Check_Type(in_hash32, T_STRING);
1680
-
1681
- if (RSTRING_LEN(in_hash32) != 32)
1682
- {
1683
- rb_raise(Secp256k1_Error_class, "in_hash32 is not 32-bytes in length");
1684
- }
1685
-
1686
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1687
- TypedData_Get_Struct(in_pubkey, PublicKey, &PublicKey_DataType, public_key);
1688
- TypedData_Get_Struct(in_signature, Signature, &Signature_DataType, signature);
1689
-
1690
- hash32 = (unsigned char*)StringValuePtr(in_hash32);
1691
-
1692
- if (secp256k1_ecdsa_verify(context->ctx,
1693
- &(signature->sig),
1694
- hash32,
1695
- &(public_key->pubkey)) == 1)
1696
- {
1697
- return Qtrue;
1698
- }
1699
-
1700
- return Qfalse;
1701
- }
1702
-
1703
- // Context recoverable signature methods
1704
- #ifdef HAVE_SECP256K1_RECOVERY_H
1705
-
1706
- /**
1707
- * Computes the recoverable ECDSA signature of data signed with private key.
1708
- *
1709
- * @param in_private_key [Secp256k1::PrivateKey] private key to sign with.
1710
- * @param in_hash32 [String] 32-byte binary string with SHA-256 hash of data.
1711
- * @return [Secp256k1::RecoverableSignature] recoverable signature produced by
1712
- * signing the SHA-256 hash `in_hash32` with `in_private_key`.
1713
- * @raise [Secp256k1::Error] if the hash is not 32 bytes or signature could not
1714
- * be computed.
1715
- */
1716
- static VALUE
1717
- Context_sign_recoverable(VALUE self, VALUE in_private_key, VALUE in_hash32)
1718
- {
1719
- Context *context;
1720
- PrivateKey *private_key;
1721
- RecoverableSignature *recoverable_signature;
1722
- unsigned char *hash32;
1723
- VALUE result;
1724
-
1725
- Check_Type(in_hash32, T_STRING);
1726
- if (RSTRING_LEN(in_hash32) != 32)
1727
- {
1728
- rb_raise(Secp256k1_Error_class, "in_hash32 is not 32 bytes in length");
1729
- return Qnil;
1730
- }
1731
-
1732
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1733
- TypedData_Get_Struct(
1734
- in_private_key, PrivateKey, &PrivateKey_DataType, private_key
1735
- );
1736
- hash32 = (unsigned char*)StringValuePtr(in_hash32);
1737
-
1738
- result = RecoverableSignature_alloc(Secp256k1_RecoverableSignature_class);
1739
- TypedData_Get_Struct(
1740
- result,
1741
- RecoverableSignature,
1742
- &RecoverableSignature_DataType,
1743
- recoverable_signature
1744
- );
1745
-
1746
- if (SUCCESS(RecoverableSignData(context->ctx,
1747
- hash32,
1748
- private_key->data,
1749
- &(recoverable_signature->sig))))
1750
- {
1751
- recoverable_signature->ctx = secp256k1_context_clone(context->ctx);
1752
- return result;
1753
- }
1754
-
1755
- rb_raise(Secp256k1_Error_class, "unable to compute recoverable signature");
1756
- return Qnil;
1757
- }
1758
-
1759
- /**
1760
- * Loads recoverable signature from compact representation and recovery ID.
1761
- *
1762
- * @param in_compact_sig [String] binary string containing compact signature
1763
- * data.
1764
- * @param in_recovery_id [Integer] recovery ID (range [0, 3])
1765
- * @return [Secp256k1::RecoverableSignature] signature parsed from data.
1766
- * @raise [Secp256k1::DeserializationError] if signature data or recovery ID is
1767
- * invalid.
1768
- * @raise [Secp256k1::Error] if compact signature is not 64 bytes or recovery ID
1769
- * is not in range [0, 3].
1770
- */
1771
- static VALUE
1772
- Context_recoverable_signature_from_compact(
1773
- VALUE self, VALUE in_compact_sig, VALUE in_recovery_id)
1774
- {
1775
- Context *context;
1776
- RecoverableSignature *recoverable_signature;
1777
- unsigned char *compact_sig;
1778
- int recovery_id;
1779
- VALUE result;
1780
-
1781
- Check_Type(in_compact_sig, T_STRING);
1782
- Check_Type(in_recovery_id, T_FIXNUM);
1783
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1784
-
1785
- compact_sig = (unsigned char*)StringValuePtr(in_compact_sig);
1786
- recovery_id = FIX2INT(in_recovery_id);
1787
-
1788
- if (RSTRING_LEN(in_compact_sig) != 64)
1789
- {
1790
- rb_raise(Secp256k1_Error_class, "compact signature is not 64 bytes");
1791
- return Qnil;
1792
- }
1793
-
1794
- if (recovery_id < 0 || recovery_id > 3)
1795
- {
1796
- rb_raise(Secp256k1_Error_class, "invalid recovery ID, must be in range [0, 3]");
1797
- return Qnil;
1798
- }
1799
-
1800
- result = RecoverableSignature_alloc(Secp256k1_RecoverableSignature_class);
1801
- TypedData_Get_Struct(
1802
- result,
1803
- RecoverableSignature,
1804
- &RecoverableSignature_DataType,
1805
- recoverable_signature
1806
- );
1807
-
1808
- if (secp256k1_ecdsa_recoverable_signature_parse_compact(
1809
- context->ctx,
1810
- &(recoverable_signature->sig),
1811
- compact_sig,
1812
- recovery_id) == 1)
1813
- {
1814
- recoverable_signature->ctx = secp256k1_context_clone(context->ctx);
1815
- return result;
1816
- }
1817
-
1818
- rb_raise(Secp256k1_DeserializationError_class, "unable to parse recoverable signature");
1819
- return Qnil;
1820
- }
1821
-
1822
- #endif // HAVE_SECP256K1_RECOVERY_H
1823
-
1824
- // Context EC Diffie-Hellman methods
1825
- #ifdef HAVE_SECP256K1_ECDH_H
1826
-
1827
- /**
1828
- * Compute EC Diffie-Hellman secret in constant time.
1829
- *
1830
- * Creates a new shared secret from public_key and private_key.
1831
- *
1832
- * @param point [Secp256k1::PublicKey] public-key representing ECDH point.
1833
- * @param scalar [Secp256k1::PrivateKey] private-key representing ECDH scalar.
1834
- * @return [Secp256k1::SharedSecret] shared secret
1835
- * @raise [Secp256k1::Error] If scalar was invalid (zero or caused overflow).
1836
- */
1837
- static VALUE
1838
- Context_ecdh(VALUE self, VALUE point, VALUE scalar)
1839
- {
1840
- Context *context;
1841
- PublicKey *public_key;
1842
- PrivateKey *private_key;
1843
- SharedSecret *shared_secret;
1844
- VALUE result;
1845
-
1846
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1847
- TypedData_Get_Struct(point, PublicKey, &PublicKey_DataType, public_key);
1848
- TypedData_Get_Struct(scalar, PrivateKey, &PrivateKey_DataType, private_key);
1849
-
1850
- result = SharedSecret_alloc(Secp256k1_SharedSecret_class);
1851
- TypedData_Get_Struct(
1852
- result, SharedSecret, &SharedSecret_DataType, shared_secret
1853
- );
1854
-
1855
- if (secp256k1_ecdh(context->ctx,
1856
- shared_secret->data,
1857
- &(public_key->pubkey),
1858
- (unsigned char*)private_key->data,
1859
- NULL,
1860
- NULL) != 1)
1861
- {
1862
- rb_raise(Secp256k1_Error_class, "invalid scalar provided to ecdh");
1863
- return Qnil;
1864
- }
1865
-
1866
- rb_iv_set(result, "@data", rb_str_new((char*)shared_secret->data, 32));
1867
-
1868
- return result;
1869
- }
1870
-
1871
- #endif // HAVE_SECP256K1_ECDH_H
1872
-
1873
- #ifdef HAVE_SECP256K1_SCHNORRSIG_H
1874
-
1875
- static VALUE
1876
- Context_sign_schnorr_custom(VALUE self, VALUE in_keypair, VALUE in_message, VALUE in_auxrand)
1877
- {
1878
- Context* context;
1879
- KeyPair* keypair;
1880
- SchnorrSignature* schnorr_sig;
1881
- unsigned char* msg;
1882
- unsigned char* auxrand;
1883
- unsigned char sig[64];
1884
- VALUE result;
1885
-
1886
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1887
- TypedData_Get_Struct(in_keypair, KeyPair, &KeyPair_DataType, keypair);
1888
-
1889
- Check_Type(in_message, T_STRING);
1890
- if (RSTRING_LEN(in_message) != 32)
1891
- {
1892
- rb_raise(Secp256k1_Error_class, "schnorr signing message must be 32-bytes in length");
1893
- return Qnil;
1894
- }
1895
-
1896
- if (!NIL_P(in_auxrand))
1897
- {
1898
- Check_Type(in_auxrand, T_STRING);
1899
- if (RSTRING_LEN(in_auxrand) != 32)
1900
- {
1901
- rb_raise(Secp256k1_Error_class, "schnorr signing auxrand must be 32-bytes in length");
1902
- return Qnil;
1903
- }
1904
- }
1905
-
1906
- msg = (unsigned char*)StringValuePtr(in_message);
1907
- auxrand = (unsigned char*)StringValuePtr(in_auxrand);
1908
-
1909
- if (secp256k1_schnorrsig_sign32(context->ctx, sig, msg, &keypair->keypair, auxrand) != 1)
1910
- {
1911
- rb_raise(Secp256k1_Error_class, "schnorr signing failed");
1912
- return Qnil;
1913
- }
1914
-
1915
- result = SchnorrSignature_alloc(Secp256k1_SchnorrSignature_class);
1916
- TypedData_Get_Struct(result, SchnorrSignature, &SchnorrSignature_DataType, schnorr_sig);
1917
- memcpy(schnorr_sig->sig, sig, SCHNORR_SIG_SIZE_BYTES);
1918
-
1919
- return result;
1920
- }
1921
-
1922
- #endif // HAVE_SECP256K1_SCHNORRSIG_H
1923
-
1924
- //
1925
- // Secp256k1 module methods
1926
- //
1927
-
1928
- /**
1929
- * Indicates whether or not the libsecp256k1 recovery module is installed.
1930
- *
1931
- * @return [Boolean] true if libsecp256k1 was built with the recovery module,
1932
- * false otherwise.
1933
- */
1934
- static VALUE
1935
- Secp256k1_have_recovery(VALUE module)
1936
- {
1937
- #ifdef HAVE_SECP256K1_RECOVERY_H
1938
- return Qtrue;
1939
- #else // HAVE_SECP256K1_RECOVERY_H
1940
- return Qfalse;
1941
- #endif // HAVE_SECP256K1_RECOVERY_H
1942
- }
1943
-
1944
- /**
1945
- * Indicates whether or not libsecp256k1 EC Diffie-Hellman module is installed.
1946
- *
1947
- * @return [Boolean] true if libsecp256k1 was build with the ECDH module, false
1948
- * otherwise.
1949
- */
1950
- static VALUE
1951
- Secp256k1_have_ecdh(VALUE module)
1952
- {
1953
- #ifdef HAVE_SECP256K1_ECDH_H
1954
- return Qtrue;
1955
- #else // HAVE_SECP256K1_ECDH_H
1956
- return Qfalse;
1957
- #endif // HAVE_SECP256K1_ECDH_H
1958
- }
1959
-
1960
- /**
1961
- * Indicates whether or not libsecp256k1 Schnorr signature module is installed.
1962
- *
1963
- * @return [Boolean]
1964
- */
1965
- static VALUE
1966
- Secp256k1_have_schnorr(VALUE module)
1967
- {
1968
- #ifdef HAVE_SECP256K1_SCHNORRSIG_H
1969
- return Qtrue;
1970
- #else
1971
- return Qfalse;
1972
- #endif
1973
- }
1974
-
1975
- //
1976
- // Library initialization
1977
- //
1978
-
1979
- void Init_rbsecp256k1(void)
1980
- {
1981
- // Perform selftest to ensure secp256k1_context_static is valid. This will
1982
- // cause the program to abort if the selftest fails.
1983
- secp256k1_selftest();
1984
-
1985
- // Secp256k1
1986
- Secp256k1_module = rb_define_module("Secp256k1");
1987
- rb_define_singleton_method(
1988
- Secp256k1_module,
1989
- "have_recovery?",
1990
- Secp256k1_have_recovery,
1991
- 0
1992
- );
1993
- rb_define_singleton_method(
1994
- Secp256k1_module,
1995
- "have_ecdh?",
1996
- Secp256k1_have_ecdh,
1997
- 0
1998
- );
1999
- rb_define_singleton_method(
2000
- Secp256k1_module,
2001
- "have_schnorr?",
2002
- Secp256k1_have_schnorr,
2003
- 0
2004
- );
2005
-
2006
- // Secp256k1 exception hierarchy
2007
- Secp256k1_Error_class = rb_define_class_under(
2008
- Secp256k1_module, "Error", rb_eStandardError
2009
- );
2010
- Secp256k1_SerializationError_class = rb_define_class_under(
2011
- Secp256k1_module, "SerializationError", Secp256k1_Error_class
2012
- );
2013
- Secp256k1_DeserializationError_class = rb_define_class_under(
2014
- Secp256k1_module, "DeserializationError", Secp256k1_Error_class
2015
- );
2016
-
2017
- // Secp256k1::Context
2018
- Secp256k1_Context_class = rb_define_class_under(
2019
- Secp256k1_module, "Context", rb_cObject
2020
- );
2021
- rb_undef_alloc_func(Secp256k1_Context_class);
2022
- rb_define_alloc_func(Secp256k1_Context_class, Context_alloc);
2023
- rb_define_method(Secp256k1_Context_class,
2024
- "initialize",
2025
- Context_initialize,
2026
- -1);
2027
- rb_define_method(Secp256k1_Context_class,
2028
- "key_pair_from_private_key",
2029
- Context_key_pair_from_private_key,
2030
- 1);
2031
- rb_define_method(Secp256k1_Context_class,
2032
- "sign",
2033
- Context_sign,
2034
- 2);
2035
- rb_define_method(Secp256k1_Context_class,
2036
- "tagged_sha256",
2037
- Context_tagged_sha256,
2038
- 2);
2039
- rb_define_method(Secp256k1_Context_class,
2040
- "verify",
2041
- Context_verify,
2042
- 3);
2043
-
2044
- // Secp256k1::KeyPair
2045
- Secp256k1_KeyPair_class = rb_define_class_under(Secp256k1_module,
2046
- "KeyPair",
2047
- rb_cObject);
2048
- rb_undef_alloc_func(Secp256k1_KeyPair_class);
2049
- rb_define_alloc_func(Secp256k1_KeyPair_class, KeyPair_alloc);
2050
- rb_define_method(Secp256k1_KeyPair_class, "public_key", KeyPair_public_key, 0);
2051
- rb_define_method(Secp256k1_KeyPair_class, "private_key", KeyPair_private_key, 0);
2052
- rb_define_method(Secp256k1_KeyPair_class, "xonly_public_key", KeyPair_xonly_public_key, 0);
2053
- rb_define_method(Secp256k1_KeyPair_class, "==", KeyPair_equals, 1);
2054
-
2055
- // Secp256k1::PublicKey
2056
- Secp256k1_PublicKey_class = rb_define_class_under(Secp256k1_module,
2057
- "PublicKey",
2058
- rb_cObject);
2059
- rb_undef_alloc_func(Secp256k1_PublicKey_class);
2060
- rb_define_alloc_func(Secp256k1_PublicKey_class, PublicKey_alloc);
2061
- rb_define_method(Secp256k1_PublicKey_class,
2062
- "compressed",
2063
- PublicKey_compressed,
2064
- 0);
2065
- rb_define_method(Secp256k1_PublicKey_class,
2066
- "uncompressed",
2067
- PublicKey_uncompressed,
2068
- 0);
2069
- rb_define_method(Secp256k1_PublicKey_class,
2070
- "to_xonly",
2071
- PublicKey_to_xonly,
2072
- 0);
2073
- rb_define_singleton_method(
2074
- Secp256k1_PublicKey_class,
2075
- "from_data",
2076
- PublicKey_from_data,
2077
- 1
2078
- );
2079
- rb_define_method(Secp256k1_PublicKey_class, "==", PublicKey_equals, 1);
2080
-
2081
- // Secp256k1::XOnlyPublicKey
2082
- Secp256k1_XOnlyPublicKey_class = rb_define_class_under(Secp256k1_module,
2083
- "XOnlyPublicKey",
2084
- rb_cObject);
2085
-
2086
- rb_undef_alloc_func(Secp256k1_XOnlyPublicKey_class);
2087
- rb_define_alloc_func(Secp256k1_XOnlyPublicKey_class, XOnlyPublicKey_alloc);
2088
- rb_define_method(Secp256k1_XOnlyPublicKey_class,
2089
- "serialized",
2090
- XOnlyPublicKey_serialized,
2091
- 0);
2092
- rb_define_singleton_method(
2093
- Secp256k1_XOnlyPublicKey_class,
2094
- "from_data",
2095
- XOnlyPublicKey_from_data,
2096
- 1);
2097
- rb_define_method(Secp256k1_XOnlyPublicKey_class, "==", XOnlyPublicKey_equals, 1);
2098
-
2099
- // Secp256k1::PrivateKey
2100
- Secp256k1_PrivateKey_class = rb_define_class_under(
2101
- Secp256k1_module, "PrivateKey", rb_cObject
2102
- );
2103
- rb_undef_alloc_func(Secp256k1_PrivateKey_class);
2104
- rb_define_alloc_func(Secp256k1_PrivateKey_class, PrivateKey_alloc);
2105
- rb_define_method(Secp256k1_PrivateKey_class, "data", PrivateKey_data, 0);
2106
- rb_define_method(Secp256k1_PrivateKey_class, "==", PrivateKey_equals, 1);
2107
- rb_define_singleton_method(
2108
- Secp256k1_PrivateKey_class,
2109
- "from_data",
2110
- PrivateKey_from_data,
2111
- 1
2112
- );
2113
-
2114
- // Secp256k1::Signature
2115
- Secp256k1_Signature_class = rb_define_class_under(Secp256k1_module,
2116
- "Signature",
2117
- rb_cObject);
2118
- rb_undef_alloc_func(Secp256k1_Signature_class);
2119
- rb_define_alloc_func(Secp256k1_Signature_class, Signature_alloc);
2120
- rb_define_method(Secp256k1_Signature_class,
2121
- "der_encoded",
2122
- Signature_der_encoded,
2123
- 0);
2124
- rb_define_method(Secp256k1_Signature_class,
2125
- "compact",
2126
- Signature_compact,
2127
- 0);
2128
- rb_define_method(Secp256k1_Signature_class,
2129
- "normalized",
2130
- Signature_normalized,
2131
- 0);
2132
- rb_define_method(Secp256k1_Signature_class,
2133
- "==",
2134
- Signature_equals,
2135
- 1);
2136
- rb_define_singleton_method(
2137
- Secp256k1_Signature_class,
2138
- "from_compact",
2139
- Signature_from_compact,
2140
- 1
2141
- );
2142
- rb_define_singleton_method(
2143
- Secp256k1_Signature_class,
2144
- "from_der_encoded",
2145
- Signature_from_der_encoded,
2146
- 1
2147
- );
2148
-
2149
- #ifdef HAVE_SECP256K1_RECOVERY_H
2150
- // Secp256k1::RecoverableSignature
2151
- Secp256k1_RecoverableSignature_class = rb_define_class_under(
2152
- Secp256k1_module,
2153
- "RecoverableSignature",
2154
- rb_cObject
2155
- );
2156
- rb_undef_alloc_func(Secp256k1_RecoverableSignature_class);
2157
- rb_define_alloc_func(
2158
- Secp256k1_RecoverableSignature_class,
2159
- RecoverableSignature_alloc
2160
- );
2161
- rb_define_method(
2162
- Secp256k1_RecoverableSignature_class,
2163
- "compact",
2164
- RecoverableSignature_compact,
2165
- 0
2166
- );
2167
- rb_define_method(
2168
- Secp256k1_RecoverableSignature_class,
2169
- "to_signature",
2170
- RecoverableSignature_to_signature,
2171
- 0
2172
- );
2173
- rb_define_method(
2174
- Secp256k1_RecoverableSignature_class,
2175
- "recover_public_key",
2176
- RecoverableSignature_recover_public_key,
2177
- 1
2178
- );
2179
- rb_define_method(
2180
- Secp256k1_RecoverableSignature_class,
2181
- "==",
2182
- RecoverableSignature_equals,
2183
- 1
2184
- );
2185
-
2186
- // Context recoverable signature methods
2187
- rb_define_method(
2188
- Secp256k1_Context_class,
2189
- "sign_recoverable",
2190
- Context_sign_recoverable,
2191
- 2
2192
- );
2193
- rb_define_method(
2194
- Secp256k1_Context_class,
2195
- "recoverable_signature_from_compact",
2196
- Context_recoverable_signature_from_compact,
2197
- 2
2198
- );
2199
- #endif // HAVE_SECP256K1_RECOVERY_H
2200
-
2201
- #ifdef HAVE_SECP256K1_ECDH_H
2202
- Secp256k1_SharedSecret_class = rb_define_class_under(
2203
- Secp256k1_module,
2204
- "SharedSecret",
2205
- rb_cObject
2206
- );
2207
- rb_undef_alloc_func(Secp256k1_SharedSecret_class);
2208
- rb_define_alloc_func(Secp256k1_SharedSecret_class, SharedSecret_alloc);
2209
- rb_define_attr(Secp256k1_SharedSecret_class, "data", 1, 0);
2210
-
2211
- // Context EC Diffie-Hellman methods
2212
- rb_define_method(
2213
- Secp256k1_Context_class,
2214
- "ecdh",
2215
- Context_ecdh,
2216
- 2
2217
- );
2218
- #endif // HAVE_SECP256K1_ECDH_H
2219
-
2220
- #ifdef HAVE_SECP256K1_SCHNORRSIG_H
2221
- Secp256k1_SchnorrSignature_class = rb_define_class_under(
2222
- Secp256k1_module,
2223
- "SchnorrSignature",
2224
- rb_cObject);
2225
- rb_undef_alloc_func(Secp256k1_SchnorrSignature_class);
2226
- rb_define_alloc_func(Secp256k1_SchnorrSignature_class, SchnorrSignature_alloc);
2227
- rb_define_method(Secp256k1_SchnorrSignature_class, "serialized", SchnorrSignature_serialized, 0);
2228
- rb_define_method(Secp256k1_SchnorrSignature_class, "verify", SchnorrSignature_verify, 2);
2229
- rb_define_method(Secp256k1_SchnorrSignature_class, "==", SchnorrSignature_equals, 1);
2230
-
2231
- rb_define_singleton_method(
2232
- Secp256k1_SchnorrSignature_class,
2233
- "from_data",
2234
- SchnorrSignature_from_data,
2235
- 1
2236
- );
2237
-
2238
- rb_define_method(
2239
- Secp256k1_Context_class,
2240
- "sign_schnorr_custom",
2241
- Context_sign_schnorr_custom,
2242
- 3);
2243
- #endif // HAVE_SECP256K1_SCHNORRSIG_H
2244
- }
1
+ // rbsecp256k1.c - Ruby VM interfaces for library.
2
+ //
3
+ // Description:
4
+ // This library provides a low-level and high-performance Ruby wrapper around
5
+ // libsecp256k1. It includes functions for generating key pairs, signing data,
6
+ // and verifying signatures using the library.
7
+ //
8
+ // Dependencies:
9
+ // * libsecp256k1
10
+
11
+ // Sanity check that we have the basic header file.
12
+ #ifndef HAVE_SECP256K1_H
13
+ #error missing secp256k1.h during build
14
+ #endif // HAVE_SECP256K1_H
15
+
16
+ // Sanity check we have extrakeys module as we need it for keypair which is
17
+ // used by schnorrsig.
18
+ #ifndef HAVE_SECP256K1_EXTRAKEYS_H
19
+ #error missing secp256k1_extrakeys.h during build
20
+ #endif // HAVE_SECP256K1_EXTRAKEYS_H
21
+
22
+ #include <ruby.h>
23
+ #include <ruby/missing.h>
24
+ #include <string.h>
25
+ #include <secp256k1.h>
26
+ #include <secp256k1_preallocated.h>
27
+
28
+ // Check for optional sub-modules. As a rule any secp256k1 submodule is
29
+ // optional and so should be blocked off using these ifdefs.
30
+ #ifdef HAVE_SECP256K1_RECOVERY_H
31
+ #include <secp256k1_recovery.h>
32
+ #endif // HAVE_SECP256K1_RECOVERY_H
33
+
34
+ #ifdef HAVE_SECP256K1_ECDH_H
35
+ #include <secp256k1_ecdh.h>
36
+ #endif // HAVE_SECP256K1_ECDH_H
37
+
38
+ #ifdef HAVE_SECP256K1_EXTRAKEYS_H
39
+ #include <secp256k1_extrakeys.h>
40
+ #endif // HAVE_SECP256K1_EXTRAKEYS_H
41
+
42
+ #ifdef HAVE_SECP256K1_SCHNORRSIG_H
43
+ #include <secp256k1_schnorrsig.h>
44
+ #endif // HAVE_SECP256K1_SCHNORRSIG_H
45
+
46
+ // High-level design:
47
+ //
48
+ // The Ruby wrapper is divided into the following hierarchical organization:
49
+ //
50
+ // +- Secp256k1 (Top-level module)
51
+ // |-- Context
52
+ // |-- KeyPair
53
+ // |-- PublicKey
54
+ // |-- XOnlyPublicKey
55
+ // |-- PrivateKey
56
+ // |-- RecoverableSignature (recovery module)
57
+ // |-- SharedSecret (ecdh module)
58
+ // |-- Signature
59
+ // |-- SchnorrSignature
60
+ //
61
+ // The Context class contains most of the methods that invoke libsecp256k1.
62
+ // The KeyPair, PublicKey, PrivateKey, RecoverableSignature, SharedSecret, and
63
+ // Signature objects act as data objects and are passed to various
64
+ // methods. Contexts are thread safe and can be used across
65
+ // applications. Context initialization is expensive so it is recommended that
66
+ // a single context be initialized and used throughout an application when
67
+ // possible.
68
+ //
69
+ // Exception Hierarchy:
70
+ //
71
+ // The following hierarchy is used for exceptions raised from the library:
72
+ //
73
+ // +- Error (Descends from StandardError)
74
+ // |-- SerializationError
75
+ // |-- DeserializationError
76
+
77
+ //
78
+ // The section below contains purely internal methods used exclusively by the
79
+ // C internals of the library.
80
+ //
81
+
82
+ // Size of an uncompressed public key
83
+ const size_t UNCOMPRESSED_PUBKEY_SIZE_BYTES = 65;
84
+ // Size of a compressed public key
85
+ const size_t COMPRESSED_PUBKEY_SIZE_BYTES = 33;
86
+ // Size of a serialized x-only public key
87
+ const size_t SERIALIZED_XONLY_PUBKEY_SIZE_BYTES = 32;
88
+ // Size of a compact signature in bytes
89
+ const size_t COMPACT_SIG_SIZE_BYTES = 64;
90
+ // Size of a schnorr signature in bytes
91
+ const size_t SCHNORR_SIG_SIZE_BYTES = 64;
92
+
93
+ // Globally define our module and its associated classes so we can instantiate
94
+ // objects from anywhere. The use of global variables seems to be inline with
95
+ // how the Ruby project builds its own extension gems.
96
+ static VALUE Secp256k1_module;
97
+ static VALUE Secp256k1_Error_class;
98
+ static VALUE Secp256k1_SerializationError_class;
99
+ static VALUE Secp256k1_DeserializationError_class;
100
+ static VALUE Secp256k1_Context_class;
101
+ static VALUE Secp256k1_KeyPair_class;
102
+ static VALUE Secp256k1_PublicKey_class;
103
+ static VALUE Secp256k1_PrivateKey_class;
104
+ static VALUE Secp256k1_Signature_class;
105
+ static VALUE Secp256k1_XOnlyPublicKey_class;
106
+
107
+ #ifdef HAVE_SECP256K1_RECOVERY_H
108
+ static VALUE Secp256k1_RecoverableSignature_class;
109
+ #endif // HAVE_SECP256K1_RECOVERY_H
110
+
111
+ #ifdef HAVE_SECP256K1_ECDH_H
112
+ static VALUE Secp256k1_SharedSecret_class;
113
+ #endif // HAVE_SECP256K1_ECDH_H
114
+
115
+ #ifdef HAVE_SECP256K1_SCHNORRSIG_H
116
+ static VALUE Secp256k1_SchnorrSignature_class;
117
+ #endif // HAVE_SECP256K1_SCHNORRSIG_H
118
+
119
+ /* Ruby allocates an empty shell before initialize_copy. It must never be
120
+ * usable as a cryptographic value if a subclass skips the copy hook. */
121
+ static void *
122
+ CheckedTypedData_get(VALUE object, const rb_data_type_t *type)
123
+ {
124
+ void *data = rb_check_typeddata(object, type);
125
+ if (data == NULL)
126
+ {
127
+ rb_raise(Secp256k1_Error_class, "native object is not initialized");
128
+ }
129
+ return data;
130
+ }
131
+
132
+ #define CheckedTypedData_Get_Struct(object, type, descriptor, result) \
133
+ ((result) = (type *)CheckedTypedData_get((object), (descriptor)))
134
+
135
+ /* Failed factories remain discoverable through ObjectSpace until GC. Detach
136
+ * their invalid payload before raising, using the normal secret-wiping free
137
+ * callback. Subsequent access and copying then reject the empty shell. */
138
+ static void
139
+ NativeValue_invalidate(VALUE object)
140
+ {
141
+ void *data = RTYPEDDATA_DATA(object);
142
+ const rb_data_type_t *type = RTYPEDDATA_TYPE(object);
143
+ RTYPEDDATA_DATA(object) = NULL;
144
+ if (data != NULL) { type->function.dfree(data); }
145
+ }
146
+
147
+ /* Binary inputs are checked as T_STRING before RSTRING_PTR is used. Borrow
148
+ * their bytes only after Ruby allocations; native calls need no NUL terminator.
149
+ * Native payloads do not move, but their Ruby owners must remain live across
150
+ * allocations. Keep RB_GC_GUARD after the last dependent pointer use. */
151
+
152
+ // Forward definitions for all structures
153
+ typedef struct Context_dummy {
154
+ secp256k1_context *ctx; // Context used by libsecp256k1 library
155
+ } Context;
156
+
157
+ typedef struct KeyPair_dummy {
158
+ secp256k1_keypair keypair;
159
+ } KeyPair;
160
+
161
+ typedef struct PublicKey_dummy {
162
+ secp256k1_pubkey pubkey; // Opaque object containing public key data
163
+ } PublicKey;
164
+
165
+ typedef struct PrivateKey_dummy {
166
+ unsigned char data[32]; // Bytes comprising the private key data
167
+ } PrivateKey;
168
+
169
+ typedef struct XOnlyPublicKey_dummy {
170
+ secp256k1_xonly_pubkey pubkey; // Opaque object representing an x-only pubkey.
171
+ } XOnlyPublicKey;
172
+
173
+ typedef struct Signature_dummy {
174
+ secp256k1_ecdsa_signature sig; // Signature object, contains 64-byte signature
175
+ } Signature;
176
+
177
+ #ifdef HAVE_SECP256K1_RECOVERY_H
178
+ typedef struct RecoverableSignature_dummy {
179
+ secp256k1_ecdsa_recoverable_signature sig; // Recoverable signature object
180
+ secp256k1_context *ctx;
181
+ } RecoverableSignature;
182
+ #endif // HAVE_SECP256K1_RECOVERY_H
183
+
184
+ #ifdef HAVE_SECP256K1_ECDH_H
185
+ typedef struct SharedSecret_dummy {
186
+ unsigned char data[32]; // Shared secret data
187
+ } SharedSecret;
188
+ #endif // HAVE_SECP256K1_ECDH_H
189
+
190
+ #ifdef HAVE_SECP256K1_SCHNORRSIG_H
191
+ typedef struct SchnorrSignature_dummy {
192
+ unsigned char sig[64]; // Serialized schnorr signature data
193
+ } SchnorrSignature;
194
+ #endif // HAVE_SECP256K1_SCHNORRSIG_H
195
+ //
196
+ // Typed data definitions
197
+ // dsize reports owned native storage only; Ruby adds the object itself.
198
+ // This is ObjectSpace reporting, not another charge against Ruby's allocator.
199
+ // Context clone-size queries include the upstream allocation without allocator
200
+ // overhead. No Ruby allocations or exceptions are permitted in these callbacks.
201
+ //
202
+
203
+ // Context
204
+ static void
205
+ Context_free(void* in_context)
206
+ {
207
+ if (in_context == NULL) { return; }
208
+ Context *context;
209
+ context = (Context*)in_context;
210
+ if (context->ctx != NULL) { secp256k1_context_destroy(context->ctx); }
211
+ xfree(context);
212
+ }
213
+
214
+ static size_t
215
+ Context_memsize(const void *data)
216
+ {
217
+ if (data == NULL) { return 0; }
218
+ const Context *object = (const Context *)data;
219
+ return sizeof(*object) + (object->ctx == NULL ? 0 :
220
+ secp256k1_context_preallocated_clone_size(object->ctx));
221
+ }
222
+
223
+ static const rb_data_type_t Context_DataType = {
224
+ "Context",
225
+ { 0, Context_free, Context_memsize },
226
+ 0, 0,
227
+ RUBY_TYPED_FREE_IMMEDIATELY
228
+ };
229
+
230
+ /* Context.allocate and subclasses can bypass initialize. Never pass their
231
+ * NULL context pointers into libsecp256k1. */
232
+ static Context *
233
+ Context_get(VALUE self)
234
+ {
235
+ Context *context;
236
+ CheckedTypedData_Get_Struct(self, Context, &Context_DataType, context);
237
+ if (context->ctx == NULL)
238
+ {
239
+ rb_raise(Secp256k1_Error_class, "context is not initialized");
240
+ }
241
+ return context;
242
+ }
243
+
244
+ static VALUE
245
+ Context_initialize_copy(VALUE self, VALUE other)
246
+ {
247
+ Context *context;
248
+ Context *source;
249
+
250
+ if (self == other)
251
+ {
252
+ return self;
253
+ }
254
+ rb_obj_init_copy(self, other);
255
+ source = Context_get(other);
256
+ CheckedTypedData_Get_Struct(self, Context, &Context_DataType, context);
257
+ if (context->ctx != NULL)
258
+ {
259
+ rb_raise(Secp256k1_Error_class, "context is already initialized");
260
+ }
261
+
262
+ // The copy must own a distinct native allocation so either Ruby object can
263
+ // be collected without invalidating the other or double-freeing its context.
264
+ context->ctx = secp256k1_context_clone(source->ctx);
265
+ return self;
266
+ }
267
+
268
+ // PublicKey
269
+ static void
270
+ PublicKey_free(void *in_public_key)
271
+ {
272
+ PublicKey *public_key;
273
+ public_key = (PublicKey*)in_public_key;
274
+ xfree(public_key);
275
+ }
276
+
277
+ static size_t
278
+ PublicKey_memsize(const void *data)
279
+ {
280
+ return data == NULL ? 0 : sizeof(PublicKey);
281
+ }
282
+
283
+ static const rb_data_type_t PublicKey_DataType = {
284
+ "PublicKey",
285
+ { 0, PublicKey_free, PublicKey_memsize },
286
+ 0, 0,
287
+ RUBY_TYPED_FREE_IMMEDIATELY
288
+ };
289
+
290
+ // XOnlyPublicKey
291
+ static void
292
+ XOnlyPublicKey_free(void* in_xonly_pubkey)
293
+ {
294
+ XOnlyPublicKey *xonly_pubkey;
295
+ xonly_pubkey = (XOnlyPublicKey*)in_xonly_pubkey;
296
+ xfree(xonly_pubkey);
297
+ }
298
+
299
+ static size_t
300
+ XOnlyPublicKey_memsize(const void *data)
301
+ {
302
+ return data == NULL ? 0 : sizeof(XOnlyPublicKey);
303
+ }
304
+
305
+ static const rb_data_type_t XOnlyPublicKey_DataType = {
306
+ "XOnlyPublicKey",
307
+ { 0, XOnlyPublicKey_free, XOnlyPublicKey_memsize },
308
+ 0, 0,
309
+ RUBY_TYPED_FREE_IMMEDIATELY
310
+ };
311
+
312
+ // PrivateKey
313
+ static void
314
+ PrivateKey_free(void *in_private_key)
315
+ {
316
+ if (in_private_key == NULL) { return; }
317
+ PrivateKey *private_key;
318
+ private_key = (PrivateKey*)in_private_key;
319
+
320
+ // Ruby supplies a portable wipe that must not be optimized away. This does
321
+ // not erase Ruby strings or other copies previously returned to callers.
322
+ explicit_bzero(private_key->data, sizeof(private_key->data));
323
+
324
+ xfree(private_key);
325
+ }
326
+
327
+ static size_t
328
+ PrivateKey_memsize(const void *data)
329
+ {
330
+ return data == NULL ? 0 : sizeof(PrivateKey);
331
+ }
332
+
333
+ static const rb_data_type_t PrivateKey_DataType = {
334
+ "PrivateKey",
335
+ { 0, PrivateKey_free, PrivateKey_memsize },
336
+ 0, 0,
337
+ RUBY_TYPED_FREE_IMMEDIATELY
338
+ };
339
+
340
+ // KeyPair
341
+ static void
342
+ KeyPair_free(void *in_keypair)
343
+ {
344
+ if (in_keypair == NULL) { return; }
345
+ KeyPair *keypair;
346
+ keypair = (KeyPair*)in_keypair;
347
+ explicit_bzero(keypair, sizeof(*keypair));
348
+ xfree(keypair);
349
+ }
350
+
351
+ static size_t
352
+ KeyPair_memsize(const void *data)
353
+ {
354
+ return data == NULL ? 0 : sizeof(KeyPair);
355
+ }
356
+
357
+ static const rb_data_type_t KeyPair_DataType = {
358
+ "KeyPair",
359
+ { 0, KeyPair_free, KeyPair_memsize },
360
+ 0, 0,
361
+ RUBY_TYPED_FREE_IMMEDIATELY
362
+ };
363
+
364
+ // Signature
365
+ static void
366
+ Signature_free(void *in_signature)
367
+ {
368
+ Signature *signature = (Signature*)in_signature;
369
+ xfree(signature);
370
+ }
371
+
372
+ static size_t
373
+ Signature_memsize(const void *data)
374
+ {
375
+ return data == NULL ? 0 : sizeof(Signature);
376
+ }
377
+
378
+ static const rb_data_type_t Signature_DataType = {
379
+ "Signature",
380
+ { 0, Signature_free, Signature_memsize },
381
+ 0, 0,
382
+ RUBY_TYPED_FREE_IMMEDIATELY
383
+ };
384
+
385
+ // RecoverableSignature
386
+ #ifdef HAVE_SECP256K1_RECOVERY_H
387
+ static void
388
+ RecoverableSignature_free(void *in_recoverable_signature)
389
+ {
390
+ if (in_recoverable_signature == NULL) { return; }
391
+ RecoverableSignature *recoverable_signature = (
392
+ (RecoverableSignature*)in_recoverable_signature
393
+ );
394
+
395
+ if (recoverable_signature->ctx != NULL) {
396
+ secp256k1_context_destroy(recoverable_signature->ctx);
397
+ }
398
+ xfree(recoverable_signature);
399
+ }
400
+
401
+ static size_t
402
+ RecoverableSignature_memsize(const void *data)
403
+ {
404
+ if (data == NULL) { return 0; }
405
+ const RecoverableSignature *object = (const RecoverableSignature *)data;
406
+ return sizeof(*object) + (object->ctx == NULL ? 0 :
407
+ secp256k1_context_preallocated_clone_size(object->ctx));
408
+ }
409
+
410
+ static const rb_data_type_t RecoverableSignature_DataType = {
411
+ "RecoverableSignature",
412
+ { 0, RecoverableSignature_free, RecoverableSignature_memsize },
413
+ 0, 0,
414
+ RUBY_TYPED_FREE_IMMEDIATELY
415
+ };
416
+ #endif // HAVE_SECP256K1_RECOVERY_H
417
+
418
+ // SharedSecret
419
+ #ifdef HAVE_SECP256K1_ECDH_H
420
+ static void
421
+ SharedSecret_free(void *in_shared_secret)
422
+ {
423
+ if (in_shared_secret == NULL) { return; }
424
+ SharedSecret *shared_secret;
425
+
426
+ shared_secret = (SharedSecret*)in_shared_secret;
427
+ explicit_bzero(shared_secret->data, sizeof(shared_secret->data));
428
+ xfree(shared_secret);
429
+ }
430
+
431
+ static size_t
432
+ SharedSecret_memsize(const void *data)
433
+ {
434
+ return data == NULL ? 0 : sizeof(SharedSecret);
435
+ }
436
+
437
+ static const rb_data_type_t SharedSecret_DataType = {
438
+ "SharedSecret",
439
+ { 0, SharedSecret_free, SharedSecret_memsize },
440
+ 0, 0,
441
+ RUBY_TYPED_FREE_IMMEDIATELY
442
+ };
443
+ #endif // HAVE_SECP256K1_ECDH_H
444
+
445
+ // SchnorrSignature
446
+ #ifdef HAVE_SECP256K1_SCHNORRSIG_H
447
+ static void
448
+ SchnorrSignature_free(void *in_schnorr_sig)
449
+ {
450
+ SchnorrSignature *schnorr_sig;
451
+
452
+ schnorr_sig = (SchnorrSignature*)in_schnorr_sig;
453
+ xfree(schnorr_sig);
454
+ }
455
+
456
+ static size_t
457
+ SchnorrSignature_memsize(const void *data)
458
+ {
459
+ return data == NULL ? 0 : sizeof(SchnorrSignature);
460
+ }
461
+
462
+ static const rb_data_type_t SchnorrSignature_DataType = {
463
+ "SchnorrSignature",
464
+ { 0, SchnorrSignature_free, SchnorrSignature_memsize },
465
+ 0, 0,
466
+ RUBY_TYPED_FREE_IMMEDIATELY
467
+ };
468
+ #endif // HAVE_SECP256K1_SCHNORRSIG_H
469
+
470
+ /**
471
+ * Macro: SUCCESS
472
+ *
473
+ * Determines whether or not the given function result was a success.
474
+ */
475
+ #define SUCCESS(x) ((x) == RESULT_SUCCESS)
476
+
477
+ /**
478
+ * Macro: FAILURE
479
+ *
480
+ * Indicates whether or not the given function result is a failure.
481
+ */
482
+ #define FAILURE(x) !SUCCESS(x)
483
+
484
+ /* Result type for internally defined functions */
485
+ typedef enum ResultT_dummy {
486
+ RESULT_SUCCESS,
487
+ RESULT_FAILURE
488
+ } ResultT;
489
+
490
+ /**
491
+ * Computes the ECDSA signature of the given 32-byte SHA-256 hash.
492
+ *
493
+ * \param in_context libsecp256k1 context
494
+ * \param in_hash32 32-byte SHA-256 hash
495
+ * \param in_private_key Private key to be used for signing
496
+ * \param out_signature Signature produced during the signing proccess
497
+ * \return RESULT_SUCCESS if the hash and signature were computed successfully,
498
+ * RESULT_FAILURE if signing failed or DER encoding failed.
499
+ */
500
+ static ResultT
501
+ SignData(secp256k1_context *in_context,
502
+ unsigned char *in_hash32,
503
+ unsigned char *in_private_key,
504
+ secp256k1_ecdsa_signature *out_signature)
505
+ {
506
+ // Sign the hash of the data
507
+ if (secp256k1_ecdsa_sign(in_context,
508
+ out_signature,
509
+ in_hash32,
510
+ in_private_key,
511
+ NULL,
512
+ NULL) == 1)
513
+ {
514
+ return RESULT_SUCCESS;
515
+ }
516
+
517
+ return RESULT_FAILURE;
518
+ }
519
+
520
+ #ifdef HAVE_SECP256K1_RECOVERY_H
521
+
522
+ /**
523
+ * Computes the recoverable ECDSA signature of the given data.
524
+ *
525
+ * ECDSA signing involves the following steps:
526
+ * 1. Compute the 32-byte SHA-256 hash of the given data.
527
+ * 2. Sign the 32-byte hash using the private key provided.
528
+ *
529
+ * \param in_context libsecp256k1 context
530
+ * \param in_hash32 32-byte SHA-256 hash to sign
531
+ * \param in_private_key Private key to be used for signing
532
+ * \param out_signature Recoverable signature computed
533
+ * \return RESULT_SUCCESS if the hash and signature were computed successfully,
534
+ * RESULT_FAILURE if signing failed or DER encoding failed.
535
+ */
536
+ static ResultT
537
+ RecoverableSignData(secp256k1_context *in_context,
538
+ unsigned char *in_hash32,
539
+ unsigned char *in_private_key,
540
+ secp256k1_ecdsa_recoverable_signature *out_signature)
541
+ {
542
+ if (secp256k1_ecdsa_sign_recoverable(in_context,
543
+ out_signature,
544
+ in_hash32,
545
+ in_private_key,
546
+ NULL,
547
+ NULL) == 1)
548
+ {
549
+ return RESULT_SUCCESS;
550
+ }
551
+
552
+ return RESULT_FAILURE;
553
+ }
554
+
555
+ #endif // HAVE_SECP256K1_RECOVERY_H
556
+
557
+ //
558
+ // Secp256k1::XOnlyPublicKey class interface
559
+ //
560
+
561
+ static VALUE
562
+ XOnlyPublicKey_alloc(VALUE klass)
563
+ {
564
+ // Allocate the Ruby owner first; a failed wrapper allocation must not leak.
565
+ return rb_data_typed_object_zalloc(klass, sizeof(XOnlyPublicKey), &XOnlyPublicKey_DataType);
566
+ }
567
+
568
+ static VALUE
569
+ XOnlyPublicKey_create_from_data(VALUE in_data)
570
+ {
571
+ XOnlyPublicKey *xonly_pubkey;
572
+ VALUE result;
573
+
574
+ result = XOnlyPublicKey_alloc(Secp256k1_XOnlyPublicKey_class);
575
+ CheckedTypedData_Get_Struct(result, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
576
+
577
+ if (secp256k1_xonly_pubkey_parse(secp256k1_context_static, &xonly_pubkey->pubkey, (unsigned char*)RSTRING_PTR(in_data)) != 1)
578
+ {
579
+ NativeValue_invalidate(result);
580
+ rb_raise(Secp256k1_DeserializationError_class, "invalid x-only public key data");
581
+ return Qnil;
582
+ }
583
+
584
+ return result;
585
+ }
586
+
587
+ /**
588
+ * Loads an x-only public key from serialized data.
589
+ *
590
+ * @param in_xonly_public_key_serialized [String] binary string with serialized
591
+ * data.
592
+ * @return [Secp256k1::XOnlyPublicKey] x-only public key derived from data.
593
+ * @raise [Secp256k1::DeserializationError] if x-only public key data is invalid
594
+ */
595
+ static VALUE
596
+ XOnlyPublicKey_from_data(VALUE klass, VALUE in_xonly_public_key_serialized)
597
+ {
598
+ Check_Type(in_xonly_public_key_serialized, T_STRING);
599
+ if (RSTRING_LEN(in_xonly_public_key_serialized) != 32)
600
+ {
601
+ rb_raise(Secp256k1_DeserializationError_class, "x-only public key data must be 32 bytes in length");
602
+ return Qnil;
603
+ }
604
+
605
+ return XOnlyPublicKey_create_from_data(in_xonly_public_key_serialized);
606
+ }
607
+
608
+ /**
609
+ * Returns the 32-byte serialized version of this x-only public key.
610
+ *
611
+ * @return [String] 32-byte binary string containing serialized x-only public
612
+ * key.
613
+ */
614
+ static VALUE
615
+ XOnlyPublicKey_serialized(VALUE self)
616
+ {
617
+ XOnlyPublicKey* xonly_pubkey;
618
+ unsigned char out[SERIALIZED_XONLY_PUBKEY_SIZE_BYTES];
619
+
620
+ CheckedTypedData_Get_Struct(self, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
621
+
622
+ if (secp256k1_xonly_pubkey_serialize(secp256k1_context_static, out, &xonly_pubkey->pubkey) != 1)
623
+ {
624
+ rb_raise(Secp256k1_SerializationError_class, "failed to serialize x-only public key");
625
+ return Qnil;
626
+ }
627
+
628
+ return rb_str_new((char*)out, SERIALIZED_XONLY_PUBKEY_SIZE_BYTES);
629
+ }
630
+
631
+ /**
632
+ * Compare two x-only public keys.
633
+ *
634
+ * @param other [Secp256k1::XOnlyPublicKey] x-only public key to compare.
635
+ * @return [Boolean] true if they are equal, false otherwise.
636
+ */
637
+ static VALUE
638
+ XOnlyPublicKey_equals(VALUE self, VALUE other)
639
+ {
640
+ XOnlyPublicKey *lhs;
641
+ XOnlyPublicKey *rhs;
642
+
643
+ CheckedTypedData_Get_Struct(self, XOnlyPublicKey, &XOnlyPublicKey_DataType, lhs);
644
+ CheckedTypedData_Get_Struct(other, XOnlyPublicKey, &XOnlyPublicKey_DataType, rhs);
645
+
646
+ if (secp256k1_xonly_pubkey_cmp(secp256k1_context_static, &lhs->pubkey, &rhs->pubkey) == 0)
647
+ {
648
+ return Qtrue;
649
+ }
650
+
651
+ return Qfalse;
652
+ }
653
+
654
+ //
655
+ // Secp256k1::PublicKey class interface
656
+ //
657
+
658
+ static VALUE
659
+ PublicKey_alloc(VALUE klass)
660
+ {
661
+ return rb_data_typed_object_zalloc(klass, sizeof(PublicKey), &PublicKey_DataType);
662
+ }
663
+
664
+ static VALUE
665
+ PublicKey_create_from_data(VALUE in_data)
666
+ {
667
+ PublicKey *public_key;
668
+ VALUE result;
669
+
670
+ result = PublicKey_alloc(Secp256k1_PublicKey_class);
671
+ CheckedTypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
672
+
673
+ if (secp256k1_ec_pubkey_parse(secp256k1_context_static,
674
+ &(public_key->pubkey),
675
+ (unsigned char*)RSTRING_PTR(in_data),
676
+ (size_t)RSTRING_LEN(in_data)) != 1)
677
+ {
678
+ NativeValue_invalidate(result);
679
+ rb_raise(Secp256k1_DeserializationError_class, "invalid public key data");
680
+ return Qnil;
681
+ }
682
+
683
+ return result;
684
+ }
685
+
686
+ /**
687
+ * Loads a public key from compressed or uncompressed binary data.
688
+ *
689
+ * @param in_public_key_data [String] binary string with compressed or
690
+ * uncompressed public key data.
691
+ * @return [Secp256k1::PublicKey] public key derived from data.
692
+ * @raise [Secp256k1::DeserializationError] if public key data is invalid.
693
+ */
694
+ static VALUE
695
+ PublicKey_from_data(VALUE klass, VALUE in_public_key_data)
696
+ {
697
+ Check_Type(in_public_key_data, T_STRING);
698
+ return PublicKey_create_from_data(in_public_key_data);
699
+ }
700
+
701
+ /**
702
+ * @return [String] binary string containing the uncompressed representation
703
+ * of this public key.
704
+ */
705
+ static VALUE
706
+ PublicKey_uncompressed(VALUE self)
707
+ {
708
+ // TODO: Cache value after first computation
709
+ PublicKey *public_key;
710
+ size_t serialized_pubkey_len = UNCOMPRESSED_PUBKEY_SIZE_BYTES;
711
+ unsigned char serialized_pubkey[UNCOMPRESSED_PUBKEY_SIZE_BYTES];
712
+
713
+ CheckedTypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
714
+
715
+ secp256k1_ec_pubkey_serialize(secp256k1_context_static,
716
+ serialized_pubkey,
717
+ &serialized_pubkey_len,
718
+ &(public_key->pubkey),
719
+ SECP256K1_EC_UNCOMPRESSED);
720
+
721
+ return rb_str_new((char*)serialized_pubkey, serialized_pubkey_len);
722
+ }
723
+
724
+ /**
725
+ * @return [String] binary string containing the compressed representation of
726
+ * this public key.
727
+ */
728
+ static VALUE
729
+ PublicKey_compressed(VALUE self)
730
+ {
731
+ // TODO: Cache value after first computation
732
+ PublicKey *public_key;
733
+ size_t serialized_pubkey_len = COMPRESSED_PUBKEY_SIZE_BYTES;
734
+ unsigned char serialized_pubkey[COMPRESSED_PUBKEY_SIZE_BYTES];
735
+
736
+ CheckedTypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
737
+
738
+ secp256k1_ec_pubkey_serialize(secp256k1_context_static,
739
+ serialized_pubkey,
740
+ &serialized_pubkey_len,
741
+ &(public_key->pubkey),
742
+ SECP256K1_EC_COMPRESSED);
743
+
744
+ return rb_str_new((char*)serialized_pubkey, serialized_pubkey_len);
745
+ }
746
+
747
+ /**
748
+ * Returns the x-only public key equivalent of this public key.
749
+ *
750
+ * @return [Secp256k1::XOnlyPublicKey] x-only public key
751
+ */
752
+ static VALUE
753
+ PublicKey_to_xonly(VALUE self)
754
+ {
755
+ PublicKey *public_key;
756
+ XOnlyPublicKey *xonly_pubkey;
757
+ VALUE result;
758
+
759
+ CheckedTypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
760
+
761
+ result = XOnlyPublicKey_alloc(Secp256k1_XOnlyPublicKey_class);
762
+ CheckedTypedData_Get_Struct(result, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
763
+
764
+ if (secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_static,
765
+ &xonly_pubkey->pubkey,
766
+ NULL,
767
+ &public_key->pubkey) != 1)
768
+ {
769
+ NativeValue_invalidate(result);
770
+ rb_raise(Secp256k1_Error_class, "failed to convert pubkey to x-only pubkey");
771
+ return Qnil;
772
+ }
773
+
774
+ RB_GC_GUARD(self);
775
+ return result;
776
+ }
777
+
778
+ /**
779
+ * Compares two public keys.
780
+ *
781
+ * Public keys are considered equal if their compressed representations match.
782
+ *
783
+ * @param other [Secp256k1::PublicKey] public key to compare.
784
+ * @return [Boolean] true if the public keys are identical, false otherwise.
785
+ */
786
+ static VALUE
787
+ PublicKey_equals(VALUE self, VALUE other)
788
+ {
789
+ PublicKey *lhs;
790
+ PublicKey *rhs;
791
+ unsigned char lhs_compressed[33];
792
+ unsigned char rhs_compressed[33];
793
+ size_t lhs_len;
794
+ size_t rhs_len;
795
+
796
+ lhs_len = 33;
797
+ rhs_len = 33;
798
+
799
+ CheckedTypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, lhs);
800
+ CheckedTypedData_Get_Struct(other, PublicKey, &PublicKey_DataType, rhs);
801
+
802
+ secp256k1_ec_pubkey_serialize(
803
+ secp256k1_context_static,
804
+ lhs_compressed,
805
+ &lhs_len,
806
+ &(lhs->pubkey),
807
+ SECP256K1_EC_COMPRESSED
808
+ );
809
+ secp256k1_ec_pubkey_serialize(
810
+ secp256k1_context_static,
811
+ rhs_compressed,
812
+ &rhs_len,
813
+ &(rhs->pubkey),
814
+ SECP256K1_EC_COMPRESSED
815
+ );
816
+
817
+ if (lhs_len == rhs_len &&
818
+ memcmp(lhs_compressed, rhs_compressed, lhs_len) == 0)
819
+ {
820
+ return Qtrue;
821
+ }
822
+
823
+ return Qfalse;
824
+ }
825
+
826
+ //
827
+ // Secp256k1::PrivateKey class interface
828
+ //
829
+
830
+ static VALUE
831
+ PrivateKey_alloc(VALUE klass)
832
+ {
833
+ return rb_data_typed_object_zalloc(klass, sizeof(PrivateKey), &PrivateKey_DataType);
834
+ }
835
+
836
+ /* Internal-only method for creating a private key from secret data */
837
+ static VALUE
838
+ PrivateKey_create(VALUE in_private_key_data)
839
+ {
840
+ PrivateKey *private_key;
841
+ VALUE result;
842
+
843
+ if (secp256k1_ec_seckey_verify(secp256k1_context_static,
844
+ (unsigned char*)RSTRING_PTR(in_private_key_data)) != 1)
845
+ {
846
+ rb_raise(Secp256k1_Error_class, "invalid private key data");
847
+ return Qnil;
848
+ }
849
+
850
+ result = PrivateKey_alloc(Secp256k1_PrivateKey_class);
851
+ CheckedTypedData_Get_Struct(result, PrivateKey, &PrivateKey_DataType, private_key);
852
+ MEMCPY(private_key->data, RSTRING_PTR(in_private_key_data), char, 32);
853
+
854
+ return result;
855
+ }
856
+
857
+ /**
858
+ * Returns binary string of private key data.
859
+ *
860
+ * @return [String] 32 byte binary string of private key data.
861
+ */
862
+ static VALUE
863
+ PrivateKey_data(VALUE self)
864
+ {
865
+ PrivateKey *private_key;
866
+ VALUE result;
867
+
868
+ CheckedTypedData_Get_Struct(self, PrivateKey, &PrivateKey_DataType, private_key);
869
+
870
+ result = rb_str_new((char*)private_key->data, 32);
871
+ RB_GC_GUARD(self);
872
+ return result;
873
+ }
874
+
875
+ /**
876
+ * Load a private key from binary data.
877
+ *
878
+ * @param in_private_key_data [String] 32 byte binary string of private key
879
+ * data.
880
+ * @return [Secp256k1::PrivateKey] private key loaded from the given data.
881
+ * @raise [Secp256k1::Error] if private key data is not 32 bytes or is invalid.
882
+ */
883
+ static VALUE
884
+ PrivateKey_from_data(VALUE klass, VALUE in_private_key_data)
885
+ {
886
+ Check_Type(in_private_key_data, T_STRING);
887
+ if (RSTRING_LEN(in_private_key_data) != 32)
888
+ {
889
+ rb_raise(
890
+ Secp256k1_Error_class,
891
+ "private key data must be 32 bytes in length"
892
+ );
893
+ return Qnil;
894
+ }
895
+
896
+ return PrivateKey_create(in_private_key_data);
897
+ }
898
+
899
+ /**
900
+ * Compare two private keys.
901
+ *
902
+ * Private keys are considered equal if their data fields are identical.
903
+ *
904
+ * @param other [Secp256k1::PrivateKey] private key to compare.
905
+ * @return [Boolean] true if they are equal, false otherwise.
906
+ */
907
+ static VALUE
908
+ PrivateKey_equals(VALUE self, VALUE other)
909
+ {
910
+ PrivateKey *lhs;
911
+ PrivateKey *rhs;
912
+
913
+ CheckedTypedData_Get_Struct(self, PrivateKey, &PrivateKey_DataType, lhs);
914
+ CheckedTypedData_Get_Struct(other, PrivateKey, &PrivateKey_DataType, rhs);
915
+
916
+ if (memcmp(lhs->data, rhs->data, 32) == 0)
917
+ {
918
+ return Qtrue;
919
+ }
920
+
921
+ return Qfalse;
922
+ }
923
+
924
+ //
925
+ // Secp256k1::KeyPair class interface
926
+ //
927
+
928
+ static VALUE
929
+ KeyPair_alloc(VALUE klass)
930
+ {
931
+ return rb_data_typed_object_zalloc(klass, sizeof(KeyPair), &KeyPair_DataType);
932
+ }
933
+
934
+ /**
935
+ * Retrieve the public key for the given key pair.
936
+ *
937
+ * @return [Secp256k1::PublicKey] public key corresponding to private key.
938
+ */
939
+ static VALUE
940
+ KeyPair_public_key(VALUE self)
941
+ {
942
+ KeyPair *key_pair;
943
+ VALUE result;
944
+ PublicKey *public_key;
945
+
946
+ CheckedTypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, key_pair);
947
+
948
+ result = PublicKey_alloc(Secp256k1_PublicKey_class);
949
+ CheckedTypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
950
+
951
+ if (secp256k1_keypair_pub(secp256k1_context_static, &public_key->pubkey, &key_pair->keypair) == 0)
952
+ {
953
+ NativeValue_invalidate(result);
954
+ rb_raise(Secp256k1_Error_class, "failed to derive public key from keypair");
955
+ return Qnil;
956
+ }
957
+
958
+ RB_GC_GUARD(self);
959
+ return result;
960
+ }
961
+
962
+ /**
963
+ * Retrieve the x-only public key for the given key pair.
964
+ *
965
+ * @return [Secp256k1::XOnlyPublicKey] x-only public key corresponding to
966
+ * private key.
967
+ */
968
+ static VALUE
969
+ KeyPair_xonly_public_key(VALUE self)
970
+ {
971
+ KeyPair *key_pair;
972
+ VALUE result;
973
+ XOnlyPublicKey *xonly_pubkey;
974
+
975
+ CheckedTypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, key_pair);
976
+
977
+ result = XOnlyPublicKey_alloc(Secp256k1_XOnlyPublicKey_class);
978
+ CheckedTypedData_Get_Struct(result, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
979
+
980
+ if (secp256k1_keypair_xonly_pub(secp256k1_context_static, &xonly_pubkey->pubkey, NULL, &key_pair->keypair) == 0)
981
+ {
982
+ NativeValue_invalidate(result);
983
+ rb_raise(Secp256k1_Error_class, "failed to derive x-only public key from keypair");
984
+ return Qnil;
985
+ }
986
+
987
+ RB_GC_GUARD(self);
988
+ return result;
989
+ }
990
+
991
+ /**
992
+ * Retrieve the private key for the given key pair.
993
+ *
994
+ * @return [Secp256k1::PrivateKey] public key corresponding to private key.
995
+ */
996
+ static VALUE
997
+ KeyPair_private_key(VALUE self)
998
+ {
999
+ KeyPair *key_pair;
1000
+ PrivateKey *private_key;
1001
+ VALUE result;
1002
+
1003
+ // Validate the source before publishing an output object. Keep its owner
1004
+ // live across allocation while extracting directly into owned secret storage.
1005
+ CheckedTypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, key_pair);
1006
+ result = PrivateKey_alloc(Secp256k1_PrivateKey_class);
1007
+ CheckedTypedData_Get_Struct(result, PrivateKey, &PrivateKey_DataType, private_key);
1008
+
1009
+ if (secp256k1_keypair_sec(secp256k1_context_static, private_key->data, &key_pair->keypair) == 0)
1010
+ {
1011
+ NativeValue_invalidate(result);
1012
+ rb_raise(Secp256k1_Error_class, "failed to derive private key from keypair");
1013
+ return Qnil;
1014
+ }
1015
+
1016
+ if (secp256k1_ec_seckey_verify(secp256k1_context_static, private_key->data) != 1)
1017
+ {
1018
+ NativeValue_invalidate(result);
1019
+ rb_raise(Secp256k1_Error_class, "invalid private key data");
1020
+ return Qnil;
1021
+ }
1022
+
1023
+ RB_GC_GUARD(self);
1024
+ return result;
1025
+ }
1026
+
1027
+ /**
1028
+ * Compare two key pairs.
1029
+ *
1030
+ * Two key pairs are equal if they have the same public and private key. The
1031
+ * keys are compared using their own comparison operators.
1032
+ *
1033
+ * @param other [Secp256k1::KeyPair] key pair to compare to.
1034
+ * @return [Boolean] true if the keys match, false otherwise.
1035
+ */
1036
+ static VALUE
1037
+ KeyPair_equals(VALUE self, VALUE other)
1038
+ {
1039
+ KeyPair *lhs;
1040
+ KeyPair *rhs;
1041
+
1042
+ CheckedTypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, lhs);
1043
+ CheckedTypedData_Get_Struct(other, KeyPair, &KeyPair_DataType, rhs);
1044
+
1045
+ if (memcmp(&lhs->keypair, &rhs->keypair, sizeof(secp256k1_keypair)) == 0)
1046
+ {
1047
+ return Qtrue;
1048
+ }
1049
+
1050
+ return Qfalse;
1051
+ }
1052
+
1053
+ //
1054
+ // Secp256k1::Signature class interface
1055
+ //
1056
+
1057
+ static VALUE
1058
+ Signature_alloc(VALUE klass)
1059
+ {
1060
+ return rb_data_typed_object_zalloc(klass, sizeof(Signature), &Signature_DataType);
1061
+ }
1062
+
1063
+ /**
1064
+ * Deserializes a Signature from 64-byte compact signature data.
1065
+ *
1066
+ * @param in_compact_signature [String] compact signature as 64-byte binary
1067
+ * string.
1068
+ * @return [Secp256k1::Signature] object deserialized from compact signature.
1069
+ * @raise [Secp256k1::DeserializationError] if signature data is invalid.
1070
+ */
1071
+ static VALUE
1072
+ Signature_from_compact(VALUE klass, VALUE in_compact_signature)
1073
+ {
1074
+ Signature *signature;
1075
+ VALUE signature_result;
1076
+ unsigned char *signature_data;
1077
+
1078
+ Check_Type(in_compact_signature, T_STRING);
1079
+
1080
+ if (RSTRING_LEN(in_compact_signature) != 64)
1081
+ {
1082
+ rb_raise(Secp256k1_Error_class, "compact signature must be 64 bytes");
1083
+ }
1084
+
1085
+ signature_result = Signature_alloc(Secp256k1_Signature_class);
1086
+ CheckedTypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
1087
+ signature_data = (unsigned char*)RSTRING_PTR(in_compact_signature);
1088
+
1089
+ if (secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static,
1090
+ &(signature->sig),
1091
+ signature_data) != 1)
1092
+ {
1093
+ NativeValue_invalidate(signature_result);
1094
+ rb_raise(Secp256k1_DeserializationError_class, "invalid compact signature");
1095
+ return Qnil;
1096
+ }
1097
+
1098
+ return signature_result;
1099
+ }
1100
+
1101
+ /**
1102
+ * Converts a DER encoded binary signature into a signature object.
1103
+ *
1104
+ * @param in_der_encoded_signature [String] DER encoded signature as binary
1105
+ * string.
1106
+ * @return [Secp256k1::Signature] signature object initialized using signature
1107
+ * data.
1108
+ * @raise [Secp256k1::DeserializationError] if signature data is invalid.
1109
+ */
1110
+ static VALUE
1111
+ Signature_from_der_encoded(VALUE klass, VALUE in_der_encoded_signature)
1112
+ {
1113
+ Signature *signature;
1114
+ VALUE signature_result;
1115
+ unsigned char *signature_data;
1116
+
1117
+ Check_Type(in_der_encoded_signature, T_STRING);
1118
+
1119
+ signature_result = Signature_alloc(Secp256k1_Signature_class);
1120
+ CheckedTypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
1121
+ signature_data = (unsigned char*)RSTRING_PTR(in_der_encoded_signature);
1122
+
1123
+ if (secp256k1_ecdsa_signature_parse_der(secp256k1_context_static,
1124
+ &(signature->sig),
1125
+ signature_data,
1126
+ RSTRING_LEN(in_der_encoded_signature)) != 1)
1127
+ {
1128
+ NativeValue_invalidate(signature_result);
1129
+ rb_raise(Secp256k1_DeserializationError_class, "invalid DER encoded signature");
1130
+ return Qnil;
1131
+ }
1132
+
1133
+ return signature_result;
1134
+ }
1135
+
1136
+ /**
1137
+ * Return Distinguished Encoding Rules (DER) encoded signature data.
1138
+ *
1139
+ * @return [String] binary string containing DER-encoded signature data.
1140
+ */
1141
+ static VALUE
1142
+ Signature_der_encoded(VALUE self)
1143
+ {
1144
+ // TODO: Cache value after first computation
1145
+ Signature *signature;
1146
+ unsigned char der_signature[72];
1147
+ size_t der_signature_len = sizeof(der_signature);
1148
+
1149
+ CheckedTypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
1150
+
1151
+ if (secp256k1_ecdsa_signature_serialize_der(secp256k1_context_static,
1152
+ der_signature,
1153
+ &der_signature_len,
1154
+ &(signature->sig)) != 1)
1155
+ {
1156
+ rb_raise(
1157
+ Secp256k1_SerializationError_class,
1158
+ "could not compute DER encoded signature"
1159
+ );
1160
+ return Qnil;
1161
+ }
1162
+
1163
+ // The serializer's output length is bounded by the 72-byte stack buffer.
1164
+ return rb_str_new((char*)der_signature, (long)der_signature_len);
1165
+ }
1166
+
1167
+ /**
1168
+ * Returns the 64 byte compact representation of this signature.
1169
+ *
1170
+ * @return [String] 64 byte binary string containing signature data.
1171
+ */
1172
+ static VALUE
1173
+ Signature_compact(VALUE self)
1174
+ {
1175
+ // TODO: Cache value after first computation
1176
+ Signature *signature;
1177
+ unsigned char compact_signature[COMPACT_SIG_SIZE_BYTES];
1178
+
1179
+ CheckedTypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
1180
+
1181
+ if (secp256k1_ecdsa_signature_serialize_compact(secp256k1_context_static,
1182
+ compact_signature,
1183
+ &(signature->sig)) != 1)
1184
+ {
1185
+ rb_raise(
1186
+ Secp256k1_SerializationError_class,
1187
+ "unable to compute compact signature"
1188
+ );
1189
+ return Qnil;
1190
+ }
1191
+
1192
+ return rb_str_new((char*)compact_signature, COMPACT_SIG_SIZE_BYTES);
1193
+ }
1194
+
1195
+ /**
1196
+ * Returns the normalized lower-S form of this signature.
1197
+ *
1198
+ * This can be useful when importing signatures generated by other applications
1199
+ * that may not be normalized. Non-normalized signatures are potentially
1200
+ * forgeable.
1201
+ *
1202
+ * @return [Array] first element is a boolean that is `true` if the signature
1203
+ * was normalized, false otherwise. The second element is a `Signature`
1204
+ * object corresponding to the normalized signature.
1205
+ */
1206
+ static VALUE
1207
+ Signature_normalized(VALUE self)
1208
+ {
1209
+ VALUE result_sig;
1210
+ VALUE was_normalized;
1211
+ VALUE result;
1212
+ Signature *signature;
1213
+ Signature *normalized_signature;
1214
+
1215
+ CheckedTypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
1216
+ result_sig = Signature_alloc(Secp256k1_Signature_class);
1217
+ CheckedTypedData_Get_Struct(
1218
+ result_sig, Signature, &Signature_DataType, normalized_signature
1219
+ );
1220
+
1221
+ was_normalized = Qfalse;
1222
+ if (secp256k1_ecdsa_signature_normalize(
1223
+ secp256k1_context_static,
1224
+ &(normalized_signature->sig),
1225
+ &(signature->sig)) == 1)
1226
+ {
1227
+ was_normalized = Qtrue;
1228
+ }
1229
+
1230
+ RB_GC_GUARD(self);
1231
+ result = rb_ary_new2(2);
1232
+ rb_ary_push(result, was_normalized);
1233
+ rb_ary_push(result, result_sig);
1234
+
1235
+ return result;
1236
+ }
1237
+
1238
+ /**
1239
+ * Compares two signatures.
1240
+ *
1241
+ * Two signatures are equal if their compact encodings are identical.
1242
+ *
1243
+ * @param other [Secp256k1::Signature] signature to compare
1244
+ * @return [Boolean] true if signatures match, false otherwise.
1245
+ */
1246
+ static VALUE
1247
+ Signature_equals(VALUE self, VALUE other)
1248
+ {
1249
+ Signature *lhs;
1250
+ Signature *rhs;
1251
+ unsigned char lhs_compact[64];
1252
+ unsigned char rhs_compact[64];
1253
+
1254
+ CheckedTypedData_Get_Struct(self, Signature, &Signature_DataType, lhs);
1255
+ CheckedTypedData_Get_Struct(other, Signature, &Signature_DataType, rhs);
1256
+
1257
+ secp256k1_ecdsa_signature_serialize_compact(
1258
+ secp256k1_context_static, lhs_compact, &(lhs->sig)
1259
+ );
1260
+ secp256k1_ecdsa_signature_serialize_compact(
1261
+ secp256k1_context_static, rhs_compact, &(rhs->sig)
1262
+ );
1263
+
1264
+ if (memcmp(lhs_compact, rhs_compact, 64) == 0)
1265
+ {
1266
+ return Qtrue;
1267
+ }
1268
+
1269
+ return Qfalse;
1270
+ }
1271
+
1272
+ //
1273
+ // Secp256k1::RecoverableSignature class interface
1274
+ //
1275
+
1276
+ #ifdef HAVE_SECP256K1_RECOVERY_H
1277
+
1278
+ static VALUE
1279
+ RecoverableSignature_alloc(VALUE klass)
1280
+ {
1281
+ return rb_data_typed_object_zalloc(klass, sizeof(RecoverableSignature), &RecoverableSignature_DataType);
1282
+ }
1283
+
1284
+ /**
1285
+ * Returns the compact encoding of recoverable signature.
1286
+ *
1287
+ * @return [Array] first element is the 64 byte compact encoding of signature,
1288
+ * the second element is the integer recovery ID.
1289
+ * @raise [Secp256k1::SerializationError] if signature serialization fails.
1290
+ */
1291
+ static VALUE
1292
+ RecoverableSignature_compact(VALUE self)
1293
+ {
1294
+ RecoverableSignature *recoverable_signature;
1295
+ unsigned char compact_sig[64];
1296
+ int recovery_id;
1297
+ VALUE result;
1298
+
1299
+ CheckedTypedData_Get_Struct(
1300
+ self,
1301
+ RecoverableSignature,
1302
+ &RecoverableSignature_DataType,
1303
+ recoverable_signature
1304
+ );
1305
+
1306
+ if (secp256k1_ecdsa_recoverable_signature_serialize_compact(
1307
+ recoverable_signature->ctx,
1308
+ compact_sig,
1309
+ &recovery_id,
1310
+ &(recoverable_signature->sig)) != 1)
1311
+ {
1312
+ rb_raise(
1313
+ Secp256k1_SerializationError_class,
1314
+ "unable to serialize recoverable signature"
1315
+ );
1316
+ return Qnil;
1317
+ }
1318
+
1319
+ // Create a new array with room for 2 elements and push data onto it
1320
+ result = rb_ary_new2(2);
1321
+ rb_ary_push(result, rb_str_new((char*)compact_sig, 64));
1322
+ rb_ary_push(result, rb_int_new(recovery_id));
1323
+
1324
+ return result;
1325
+ }
1326
+
1327
+ /**
1328
+ * Convert a recoverable signature to a non-recoverable signature.
1329
+ *
1330
+ * @return [Secp256k1::Signature] non-recoverable signature derived from this
1331
+ * recoverable signature.
1332
+ */
1333
+ static VALUE
1334
+ RecoverableSignature_to_signature(VALUE self)
1335
+ {
1336
+ RecoverableSignature *recoverable_signature;
1337
+ Signature *signature;
1338
+ VALUE result;
1339
+
1340
+ CheckedTypedData_Get_Struct(
1341
+ self,
1342
+ RecoverableSignature,
1343
+ &RecoverableSignature_DataType,
1344
+ recoverable_signature
1345
+ );
1346
+
1347
+ result = Signature_alloc(Secp256k1_Signature_class);
1348
+ CheckedTypedData_Get_Struct(
1349
+ result,
1350
+ Signature,
1351
+ &Signature_DataType,
1352
+ signature
1353
+ );
1354
+
1355
+ // NOTE: This method cannot fail
1356
+ secp256k1_ecdsa_recoverable_signature_convert(
1357
+ recoverable_signature->ctx,
1358
+ &(signature->sig),
1359
+ &(recoverable_signature->sig));
1360
+
1361
+ RB_GC_GUARD(self);
1362
+ return result;
1363
+ }
1364
+
1365
+ /**
1366
+ * Attempts to recover the public key associated with this signature.
1367
+ *
1368
+ * @param in_hash32 [String] 32-byte SHA-256 hash of data.
1369
+ * @return [Secp256k1::PublicKey] recovered public key.
1370
+ * @raise [Secp256k1::Error] if hash given is not 32 bytes.
1371
+ * @raise [Secp256k1::DeserializationError] if public key could not be
1372
+ * recovered.
1373
+ */
1374
+ static VALUE
1375
+ RecoverableSignature_recover_public_key(VALUE self, VALUE in_hash32)
1376
+ {
1377
+ RecoverableSignature *recoverable_signature;
1378
+ PublicKey *public_key;
1379
+ VALUE result;
1380
+ unsigned char *hash32;
1381
+
1382
+ Check_Type(in_hash32, T_STRING);
1383
+ if (RSTRING_LEN(in_hash32) != 32)
1384
+ {
1385
+ rb_raise(Secp256k1_Error_class, "in_hash32 is not 32 bytes in length");
1386
+ return Qnil;
1387
+ }
1388
+
1389
+ CheckedTypedData_Get_Struct(
1390
+ self,
1391
+ RecoverableSignature,
1392
+ &RecoverableSignature_DataType,
1393
+ recoverable_signature
1394
+ );
1395
+
1396
+ result = PublicKey_alloc(Secp256k1_PublicKey_class);
1397
+ CheckedTypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
1398
+ hash32 = (unsigned char*)RSTRING_PTR(in_hash32);
1399
+
1400
+ if (secp256k1_ecdsa_recover(recoverable_signature->ctx,
1401
+ &(public_key->pubkey),
1402
+ &(recoverable_signature->sig),
1403
+ hash32) == 1)
1404
+ {
1405
+ RB_GC_GUARD(self);
1406
+ return result;
1407
+ }
1408
+
1409
+ NativeValue_invalidate(result);
1410
+ rb_raise(Secp256k1_DeserializationError_class, "unable to recover public key");
1411
+ }
1412
+
1413
+ /**
1414
+ * Compares two recoverable signatures.
1415
+ *
1416
+ * Two recoverable signatures their secp256k1_ecdsa_recoverable_signature data
1417
+ * is identical.
1418
+ *
1419
+ * @param other [Secp256k1::RecoverableSignature] recoverable signature to
1420
+ * compare.
1421
+ * @return [Boolean] true if the recoverable signatures are identical, false
1422
+ * otherwise.
1423
+ */
1424
+ static VALUE
1425
+ RecoverableSignature_equals(VALUE self, VALUE other)
1426
+ {
1427
+ RecoverableSignature *lhs;
1428
+ RecoverableSignature *rhs;
1429
+
1430
+ CheckedTypedData_Get_Struct(
1431
+ self, RecoverableSignature, &RecoverableSignature_DataType, lhs
1432
+ );
1433
+ CheckedTypedData_Get_Struct(
1434
+ other, RecoverableSignature, &RecoverableSignature_DataType, rhs
1435
+ );
1436
+
1437
+ // NOTE: It is safe to directly compare these data structures rather than
1438
+ // first serializing and then comparing.
1439
+ if (memcmp(&(lhs->sig),
1440
+ &(rhs->sig),
1441
+ sizeof(secp256k1_ecdsa_recoverable_signature)) == 0)
1442
+ {
1443
+ return Qtrue;
1444
+ }
1445
+
1446
+ return Qfalse;
1447
+ }
1448
+
1449
+ #endif // HAVE_SECP256K1_RECOVERY_H
1450
+
1451
+ //
1452
+ // Secp256k1::SharedSecret class interface
1453
+ //
1454
+
1455
+ #ifdef HAVE_SECP256K1_ECDH_H
1456
+
1457
+ static VALUE
1458
+ SharedSecret_alloc(VALUE klass)
1459
+ {
1460
+ return rb_data_typed_object_zalloc(klass, sizeof(SharedSecret), &SharedSecret_DataType);
1461
+ }
1462
+
1463
+ #endif // HAVE_SECP256K1_ECDH_H
1464
+
1465
+ //
1466
+ // Secp256k1::SchnorrSignature class interface
1467
+ //
1468
+
1469
+ #ifdef HAVE_SECP256K1_SCHNORRSIG_H
1470
+
1471
+ static VALUE
1472
+ SchnorrSignature_alloc(VALUE klass)
1473
+ {
1474
+ return rb_data_typed_object_zalloc(klass, sizeof(SchnorrSignature), &SchnorrSignature_DataType);
1475
+ }
1476
+
1477
+ static VALUE
1478
+ SchnorrSignature_from_data(VALUE klass, VALUE in_data)
1479
+ {
1480
+ SchnorrSignature* sig;
1481
+ VALUE result;
1482
+ unsigned char* schnorr_data;
1483
+
1484
+ Check_Type(in_data, T_STRING);
1485
+ if (RSTRING_LEN(in_data) != SCHNORR_SIG_SIZE_BYTES)
1486
+ {
1487
+ rb_raise(Secp256k1_DeserializationError_class, "schnorr signature data must be 64 bytes in length");
1488
+ return Qnil;
1489
+ }
1490
+
1491
+ result = SchnorrSignature_alloc(Secp256k1_SchnorrSignature_class);
1492
+ CheckedTypedData_Get_Struct(result, SchnorrSignature, &SchnorrSignature_DataType, sig);
1493
+ schnorr_data = (unsigned char*)RSTRING_PTR(in_data);
1494
+
1495
+ memcpy(sig->sig, schnorr_data, SCHNORR_SIG_SIZE_BYTES);
1496
+
1497
+ return result;
1498
+ }
1499
+
1500
+ static VALUE
1501
+ SchnorrSignature_serialized(VALUE self)
1502
+ {
1503
+ SchnorrSignature *schnorr_sig;
1504
+ VALUE result;
1505
+
1506
+ CheckedTypedData_Get_Struct(self, SchnorrSignature, &SchnorrSignature_DataType, schnorr_sig);
1507
+
1508
+ result = rb_str_new((char*)schnorr_sig->sig, SCHNORR_SIG_SIZE_BYTES);
1509
+ RB_GC_GUARD(self);
1510
+ return result;
1511
+ }
1512
+
1513
+ static VALUE
1514
+ SchnorrSignature_verify(VALUE self, VALUE in_message, VALUE in_xonly_pubkey)
1515
+ {
1516
+ XOnlyPublicKey *xonly_pubkey;
1517
+ SchnorrSignature *schnorr_sig;
1518
+ unsigned char* msg;
1519
+
1520
+ CheckedTypedData_Get_Struct(self, SchnorrSignature, &SchnorrSignature_DataType, schnorr_sig);
1521
+ CheckedTypedData_Get_Struct(in_xonly_pubkey, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
1522
+ Check_Type(in_message, T_STRING);
1523
+
1524
+ msg = (unsigned char*)RSTRING_PTR(in_message);
1525
+ if (secp256k1_schnorrsig_verify(secp256k1_context_static, schnorr_sig->sig, msg, RSTRING_LEN(in_message), &xonly_pubkey->pubkey) != 1)
1526
+ {
1527
+ return Qfalse;
1528
+ }
1529
+
1530
+ return Qtrue;
1531
+ }
1532
+
1533
+ static VALUE
1534
+ SchnorrSignature_equals(VALUE self, VALUE other)
1535
+ {
1536
+ SchnorrSignature *lhs;
1537
+ SchnorrSignature *rhs;
1538
+
1539
+ CheckedTypedData_Get_Struct(self, SchnorrSignature, &SchnorrSignature_DataType, lhs);
1540
+ CheckedTypedData_Get_Struct(other, SchnorrSignature, &SchnorrSignature_DataType, rhs);
1541
+
1542
+ if (memcmp(lhs->sig, rhs->sig, SCHNORR_SIG_SIZE_BYTES) == 0)
1543
+ {
1544
+ return Qtrue;
1545
+ }
1546
+
1547
+ return Qfalse;
1548
+ }
1549
+
1550
+ #endif // HAVE_SECP256K1_SCHNORRSIG_H
1551
+
1552
+ //
1553
+ // Secp256k1::Context class interface
1554
+ //
1555
+
1556
+ /* Allocate a new context object */
1557
+ static VALUE
1558
+ Context_alloc(VALUE klass)
1559
+ {
1560
+ return rb_data_typed_object_zalloc(klass, sizeof(Context), &Context_DataType);
1561
+ }
1562
+
1563
+ /**
1564
+ * Initialize a new context.
1565
+ *
1566
+ * Context initialization should be infrequent as it is an expensive operation.
1567
+ *
1568
+ * @param context_randomization_bytes [String,nil] (Optional) 32 bytes of
1569
+ * random data used to randomize the context. If omitted then the
1570
+ * context remains unrandomized. It is recommended that you provide this
1571
+ * argument.
1572
+ * @return [Secp256k1::Context]
1573
+ * @raise [Secp256k1::Error] if context randomization fails.
1574
+ */
1575
+ static VALUE
1576
+ Context_initialize(int argc, const VALUE* argv, VALUE self)
1577
+ {
1578
+ Context *context;
1579
+ secp256k1_context *new_context;
1580
+ unsigned char *seed32;
1581
+ VALUE context_randomization_bytes;
1582
+ VALUE opts;
1583
+ static ID kwarg_ids;
1584
+
1585
+ context_randomization_bytes = Qnil;
1586
+ if (!kwarg_ids)
1587
+ {
1588
+ CONST_ID(kwarg_ids, "context_randomization_bytes");
1589
+ }
1590
+
1591
+ rb_check_frozen(self);
1592
+ CheckedTypedData_Get_Struct(self, Context, &Context_DataType, context);
1593
+ if (context->ctx != NULL)
1594
+ {
1595
+ rb_raise(Secp256k1_Error_class, "context is already initialized");
1596
+ }
1597
+
1598
+ // Handle optional second argument containing random bytes to use for
1599
+ // randomization. We pass ":" to rb_scan_args to say that we expect keyword
1600
+ // arguments. We then parse the opts result of the scan in order to grab
1601
+ // context_randomization_bytes from the hash.
1602
+ rb_scan_args(argc, argv, ":", &opts);
1603
+ rb_get_kwargs(opts, &kwarg_ids, 0, 1, &context_randomization_bytes);
1604
+
1605
+ // We need this check because rb_get_kwargs will set the result to Qundef if
1606
+ // the keyword argument is not provided. This lets us use the NIL_P
1607
+ // predicate.
1608
+ if (context_randomization_bytes == Qundef)
1609
+ {
1610
+ context_randomization_bytes = Qnil;
1611
+ }
1612
+
1613
+ if (!NIL_P(context_randomization_bytes)) // Random bytes given
1614
+ {
1615
+ Check_Type(context_randomization_bytes, T_STRING);
1616
+ if (RSTRING_LEN(context_randomization_bytes) != 32)
1617
+ {
1618
+ rb_raise(
1619
+ Secp256k1_Error_class,
1620
+ "context_randomization_bytes must be 32 bytes in length"
1621
+ );
1622
+ }
1623
+ }
1624
+
1625
+ new_context = secp256k1_context_create(
1626
+ SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY
1627
+ );
1628
+
1629
+ if (!NIL_P(context_randomization_bytes))
1630
+ {
1631
+ seed32 = (unsigned char*)RSTRING_PTR(context_randomization_bytes);
1632
+
1633
+ // Randomize the context at initialization time rather than before calls so
1634
+ // the same context can be used across threads safely.
1635
+ if (secp256k1_context_randomize(new_context, seed32) != 1)
1636
+ {
1637
+ secp256k1_context_destroy(new_context);
1638
+ rb_raise(
1639
+ Secp256k1_Error_class,
1640
+ "context randomization failed"
1641
+ );
1642
+ }
1643
+ }
1644
+
1645
+ context->ctx = new_context;
1646
+ return self;
1647
+ }
1648
+
1649
+ /**
1650
+ * Converts binary private key data into a new key pair.
1651
+ *
1652
+ * @param in_private_key_data [String] binary private key data
1653
+ * @return [Secp256k1::KeyPair] key pair initialized from the private key data.
1654
+ * @raise [Secp256k1::Error] if the private key data is invalid or key derivation
1655
+ * fails.
1656
+ */
1657
+ static VALUE
1658
+ Context_key_pair_from_private_key(VALUE self, VALUE in_private_key_data)
1659
+ {
1660
+ Context *context;
1661
+ VALUE result;
1662
+ KeyPair *keypair;
1663
+ unsigned char *private_key_data;
1664
+
1665
+ Check_Type(in_private_key_data, T_STRING);
1666
+ context = Context_get(self);
1667
+
1668
+ if (RSTRING_LEN(in_private_key_data) != 32)
1669
+ {
1670
+ rb_raise(Secp256k1_Error_class, "private key data must be 32 bytes in length");
1671
+ return Qnil;
1672
+ }
1673
+
1674
+ result = KeyPair_alloc(Secp256k1_KeyPair_class);
1675
+ CheckedTypedData_Get_Struct(result, KeyPair, &KeyPair_DataType, keypair);
1676
+
1677
+ private_key_data = (unsigned char*)RSTRING_PTR(in_private_key_data);
1678
+
1679
+ if (secp256k1_keypair_create(context->ctx, &keypair->keypair, private_key_data) == 0)
1680
+ {
1681
+ NativeValue_invalidate(result);
1682
+ rb_raise(Secp256k1_Error_class, "invalid secret when attempting to create keypair");
1683
+ }
1684
+
1685
+ RB_GC_GUARD(self);
1686
+ return result;
1687
+ }
1688
+
1689
+ /**
1690
+ * Computes the ECDSA signature of the data using the secp256k1 elliptic curve.
1691
+ *
1692
+ * @param in_private_key [Secp256k1::PrivateKey] private key to use for
1693
+ * signing.
1694
+ * @param in_hash32 [String] 32-byte binary string with SHA-256 hash of data.
1695
+ * @return [Secp256k1::Signature] signature resulting from signing data.
1696
+ * @raise [Secp256k1::Error] if hash is not 32-bytes in length or signature
1697
+ * computation fails.
1698
+ */
1699
+ static VALUE
1700
+ Context_sign(VALUE self, VALUE in_private_key, VALUE in_hash32)
1701
+ {
1702
+ unsigned char *hash32;
1703
+ PrivateKey *private_key;
1704
+ Context *context;
1705
+ Signature *signature;
1706
+ VALUE signature_result;
1707
+
1708
+ Check_Type(in_hash32, T_STRING);
1709
+
1710
+ if (RSTRING_LEN(in_hash32) != 32)
1711
+ {
1712
+ rb_raise(Secp256k1_Error_class, "in_hash32 is not 32 bytes in length");
1713
+ return Qnil;
1714
+ }
1715
+
1716
+ context = Context_get(self);
1717
+ CheckedTypedData_Get_Struct(in_private_key, PrivateKey, &PrivateKey_DataType, private_key);
1718
+
1719
+ signature_result = Signature_alloc(Secp256k1_Signature_class);
1720
+ CheckedTypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
1721
+ hash32 = (unsigned char*)RSTRING_PTR(in_hash32);
1722
+
1723
+ // Attempt to sign the hash of the given data
1724
+ if (SUCCESS(SignData(context->ctx,
1725
+ hash32,
1726
+ private_key->data,
1727
+ &(signature->sig))))
1728
+ {
1729
+ RB_GC_GUARD(self);
1730
+ RB_GC_GUARD(in_private_key);
1731
+ return signature_result;
1732
+ }
1733
+
1734
+ NativeValue_invalidate(signature_result);
1735
+ rb_raise(Secp256k1_Error_class, "unable to compute signature");
1736
+ return Qnil;
1737
+ }
1738
+
1739
+ /**
1740
+ * Computes the tagged hash as defined in BIP-340.
1741
+ *
1742
+ * @param in_tag [String] tag value included in the hash.
1743
+ * @param in_message [String] message to be hashed.
1744
+ * @return [String] 32-byte binary hash.
1745
+ */
1746
+ static VALUE
1747
+ Context_tagged_sha256(VALUE self, VALUE in_tag, VALUE in_message)
1748
+ {
1749
+ Context *context;
1750
+ unsigned char* tag;
1751
+ unsigned char* msg;
1752
+ unsigned char hash32[32];
1753
+
1754
+ Check_Type(in_tag, T_STRING);
1755
+ Check_Type(in_message, T_STRING);
1756
+
1757
+ context = Context_get(self);
1758
+
1759
+ tag = (unsigned char*)RSTRING_PTR(in_tag);
1760
+ msg = (unsigned char*)RSTRING_PTR(in_message);
1761
+
1762
+ if (secp256k1_tagged_sha256(context->ctx, hash32, tag, RSTRING_LEN(in_tag), msg, RSTRING_LEN(in_message)) != 1)
1763
+ {
1764
+ rb_raise(Secp256k1_Error_class, "failed to compute tagged SHA256");
1765
+ return Qnil;
1766
+ }
1767
+
1768
+ return rb_str_new((char*)hash32, 32);
1769
+ }
1770
+
1771
+ /**
1772
+ * Verifies that signature matches public key and data.
1773
+ *
1774
+ * @param in_signature [Secp256k1::Signature] signature to be verified.
1775
+ * @param in_pubkey [Secp256k1::PublicKey] public key to verify signature
1776
+ * against.
1777
+ * @param in_hash32 [String] 32-byte binary string containing SHA-256 hash of
1778
+ * data.
1779
+ * @return [Boolean] True if the signature is valid, false otherwise.
1780
+ * @raise [Secp256k1::Error] if hash is not 32-bytes in length.
1781
+ */
1782
+ static VALUE
1783
+ Context_verify(VALUE self, VALUE in_signature, VALUE in_pubkey, VALUE in_hash32)
1784
+ {
1785
+ Context *context;
1786
+ PublicKey *public_key;
1787
+ Signature *signature;
1788
+ unsigned char *hash32;
1789
+
1790
+ Check_Type(in_hash32, T_STRING);
1791
+
1792
+ if (RSTRING_LEN(in_hash32) != 32)
1793
+ {
1794
+ rb_raise(Secp256k1_Error_class, "in_hash32 is not 32-bytes in length");
1795
+ }
1796
+
1797
+ context = Context_get(self);
1798
+ CheckedTypedData_Get_Struct(in_pubkey, PublicKey, &PublicKey_DataType, public_key);
1799
+ CheckedTypedData_Get_Struct(in_signature, Signature, &Signature_DataType, signature);
1800
+
1801
+ hash32 = (unsigned char*)RSTRING_PTR(in_hash32);
1802
+
1803
+ if (secp256k1_ecdsa_verify(context->ctx,
1804
+ &(signature->sig),
1805
+ hash32,
1806
+ &(public_key->pubkey)) == 1)
1807
+ {
1808
+ return Qtrue;
1809
+ }
1810
+
1811
+ return Qfalse;
1812
+ }
1813
+
1814
+ // Context recoverable signature methods
1815
+ #ifdef HAVE_SECP256K1_RECOVERY_H
1816
+
1817
+ /**
1818
+ * Computes the recoverable ECDSA signature of data signed with private key.
1819
+ *
1820
+ * @param in_private_key [Secp256k1::PrivateKey] private key to sign with.
1821
+ * @param in_hash32 [String] 32-byte binary string with SHA-256 hash of data.
1822
+ * @return [Secp256k1::RecoverableSignature] recoverable signature produced by
1823
+ * signing the SHA-256 hash `in_hash32` with `in_private_key`.
1824
+ * @raise [Secp256k1::Error] if the hash is not 32 bytes or signature could not
1825
+ * be computed.
1826
+ */
1827
+ static VALUE
1828
+ Context_sign_recoverable(VALUE self, VALUE in_private_key, VALUE in_hash32)
1829
+ {
1830
+ Context *context;
1831
+ PrivateKey *private_key;
1832
+ RecoverableSignature *recoverable_signature;
1833
+ unsigned char *hash32;
1834
+ VALUE result;
1835
+
1836
+ Check_Type(in_hash32, T_STRING);
1837
+ if (RSTRING_LEN(in_hash32) != 32)
1838
+ {
1839
+ rb_raise(Secp256k1_Error_class, "in_hash32 is not 32 bytes in length");
1840
+ return Qnil;
1841
+ }
1842
+
1843
+ context = Context_get(self);
1844
+ CheckedTypedData_Get_Struct(
1845
+ in_private_key, PrivateKey, &PrivateKey_DataType, private_key
1846
+ );
1847
+
1848
+ result = RecoverableSignature_alloc(Secp256k1_RecoverableSignature_class);
1849
+ CheckedTypedData_Get_Struct(
1850
+ result,
1851
+ RecoverableSignature,
1852
+ &RecoverableSignature_DataType,
1853
+ recoverable_signature
1854
+ );
1855
+ hash32 = (unsigned char*)RSTRING_PTR(in_hash32);
1856
+
1857
+ if (SUCCESS(RecoverableSignData(context->ctx,
1858
+ hash32,
1859
+ private_key->data,
1860
+ &(recoverable_signature->sig))))
1861
+ {
1862
+ recoverable_signature->ctx = secp256k1_context_clone(context->ctx);
1863
+ RB_GC_GUARD(self);
1864
+ RB_GC_GUARD(in_private_key);
1865
+ return result;
1866
+ }
1867
+
1868
+ NativeValue_invalidate(result);
1869
+ rb_raise(Secp256k1_Error_class, "unable to compute recoverable signature");
1870
+ return Qnil;
1871
+ }
1872
+
1873
+ /**
1874
+ * Loads recoverable signature from compact representation and recovery ID.
1875
+ *
1876
+ * @param in_compact_sig [String] binary string containing compact signature
1877
+ * data.
1878
+ * @param in_recovery_id [Integer] recovery ID (range [0, 3])
1879
+ * @return [Secp256k1::RecoverableSignature] signature parsed from data.
1880
+ * @raise [Secp256k1::DeserializationError] if signature data or recovery ID is
1881
+ * invalid.
1882
+ * @raise [Secp256k1::Error] if compact signature is not 64 bytes or recovery ID
1883
+ * is not in range [0, 3].
1884
+ */
1885
+ static VALUE
1886
+ Context_recoverable_signature_from_compact(
1887
+ VALUE self, VALUE in_compact_sig, VALUE in_recovery_id)
1888
+ {
1889
+ Context *context;
1890
+ RecoverableSignature *recoverable_signature;
1891
+ unsigned char *compact_sig;
1892
+ int recovery_id;
1893
+ VALUE result;
1894
+
1895
+ Check_Type(in_compact_sig, T_STRING);
1896
+ Check_Type(in_recovery_id, T_FIXNUM);
1897
+ context = Context_get(self);
1898
+
1899
+ recovery_id = FIX2INT(in_recovery_id);
1900
+
1901
+ if (RSTRING_LEN(in_compact_sig) != 64)
1902
+ {
1903
+ rb_raise(Secp256k1_Error_class, "compact signature is not 64 bytes");
1904
+ return Qnil;
1905
+ }
1906
+
1907
+ if (recovery_id < 0 || recovery_id > 3)
1908
+ {
1909
+ rb_raise(Secp256k1_Error_class, "invalid recovery ID, must be in range [0, 3]");
1910
+ return Qnil;
1911
+ }
1912
+
1913
+ result = RecoverableSignature_alloc(Secp256k1_RecoverableSignature_class);
1914
+ CheckedTypedData_Get_Struct(
1915
+ result,
1916
+ RecoverableSignature,
1917
+ &RecoverableSignature_DataType,
1918
+ recoverable_signature
1919
+ );
1920
+ compact_sig = (unsigned char*)RSTRING_PTR(in_compact_sig);
1921
+
1922
+ if (secp256k1_ecdsa_recoverable_signature_parse_compact(
1923
+ context->ctx,
1924
+ &(recoverable_signature->sig),
1925
+ compact_sig,
1926
+ recovery_id) == 1)
1927
+ {
1928
+ recoverable_signature->ctx = secp256k1_context_clone(context->ctx);
1929
+ RB_GC_GUARD(self);
1930
+ return result;
1931
+ }
1932
+
1933
+ NativeValue_invalidate(result);
1934
+ rb_raise(Secp256k1_DeserializationError_class, "unable to parse recoverable signature");
1935
+ return Qnil;
1936
+ }
1937
+
1938
+ #endif // HAVE_SECP256K1_RECOVERY_H
1939
+
1940
+ // Context EC Diffie-Hellman methods
1941
+ #ifdef HAVE_SECP256K1_ECDH_H
1942
+
1943
+ /**
1944
+ * Compute EC Diffie-Hellman secret in constant time.
1945
+ *
1946
+ * Creates a new shared secret from public_key and private_key.
1947
+ *
1948
+ * @param point [Secp256k1::PublicKey] public-key representing ECDH point.
1949
+ * @param scalar [Secp256k1::PrivateKey] private-key representing ECDH scalar.
1950
+ * @return [Secp256k1::SharedSecret] shared secret
1951
+ * @raise [Secp256k1::Error] If scalar was invalid (zero or caused overflow).
1952
+ */
1953
+ static VALUE
1954
+ Context_ecdh(VALUE self, VALUE point, VALUE scalar)
1955
+ {
1956
+ Context *context;
1957
+ PublicKey *public_key;
1958
+ PrivateKey *private_key;
1959
+ SharedSecret *shared_secret;
1960
+ VALUE result;
1961
+
1962
+ context = Context_get(self);
1963
+ CheckedTypedData_Get_Struct(point, PublicKey, &PublicKey_DataType, public_key);
1964
+ CheckedTypedData_Get_Struct(scalar, PrivateKey, &PrivateKey_DataType, private_key);
1965
+
1966
+ result = SharedSecret_alloc(Secp256k1_SharedSecret_class);
1967
+ CheckedTypedData_Get_Struct(
1968
+ result, SharedSecret, &SharedSecret_DataType, shared_secret
1969
+ );
1970
+
1971
+ if (secp256k1_ecdh(context->ctx,
1972
+ shared_secret->data,
1973
+ &(public_key->pubkey),
1974
+ (unsigned char*)private_key->data,
1975
+ NULL,
1976
+ NULL) != 1)
1977
+ {
1978
+ NativeValue_invalidate(result);
1979
+ rb_raise(Secp256k1_Error_class, "invalid scalar provided to ecdh");
1980
+ return Qnil;
1981
+ }
1982
+
1983
+ rb_iv_set(result, "@data", rb_str_new((char*)shared_secret->data, 32));
1984
+
1985
+ RB_GC_GUARD(self);
1986
+ RB_GC_GUARD(point);
1987
+ RB_GC_GUARD(scalar);
1988
+ return result;
1989
+ }
1990
+
1991
+ #endif // HAVE_SECP256K1_ECDH_H
1992
+
1993
+ #ifdef HAVE_SECP256K1_SCHNORRSIG_H
1994
+
1995
+ static VALUE
1996
+ Context_sign_schnorr_custom(VALUE self, VALUE in_keypair, VALUE in_message, VALUE in_auxrand)
1997
+ {
1998
+ Context* context;
1999
+ KeyPair* keypair;
2000
+ SchnorrSignature* schnorr_sig;
2001
+ unsigned char* msg;
2002
+ secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
2003
+ unsigned char sig[64];
2004
+ VALUE result;
2005
+
2006
+ context = Context_get(self);
2007
+ CheckedTypedData_Get_Struct(in_keypair, KeyPair, &KeyPair_DataType, keypair);
2008
+
2009
+ Check_Type(in_message, T_STRING);
2010
+
2011
+ if (!NIL_P(in_auxrand))
2012
+ {
2013
+ Check_Type(in_auxrand, T_STRING);
2014
+ if (RSTRING_LEN(in_auxrand) != 32)
2015
+ {
2016
+ rb_raise(Secp256k1_Error_class, "schnorr signing auxrand must be 32-bytes in length");
2017
+ return Qnil;
2018
+ }
2019
+ }
2020
+
2021
+ msg = (unsigned char*)RSTRING_PTR(in_message);
2022
+ extraparams.ndata = NIL_P(in_auxrand) ? NULL : (void*)RSTRING_PTR(in_auxrand);
2023
+
2024
+ if (secp256k1_schnorrsig_sign_custom(context->ctx, sig, msg, (size_t)RSTRING_LEN(in_message), &keypair->keypair, &extraparams) != 1)
2025
+ {
2026
+ rb_raise(Secp256k1_Error_class, "schnorr signing failed");
2027
+ return Qnil;
2028
+ }
2029
+
2030
+ result = SchnorrSignature_alloc(Secp256k1_SchnorrSignature_class);
2031
+ CheckedTypedData_Get_Struct(result, SchnorrSignature, &SchnorrSignature_DataType, schnorr_sig);
2032
+ memcpy(schnorr_sig->sig, sig, SCHNORR_SIG_SIZE_BYTES);
2033
+
2034
+ return result;
2035
+ }
2036
+
2037
+ #endif // HAVE_SECP256K1_SCHNORRSIG_H
2038
+
2039
+ //
2040
+ /* Keep normal Ruby dup/clone machinery (ivars, subclass hooks, singleton
2041
+ * methods and frozen state), while rejecting direct construction. The VM
2042
+ * allocator exposes no native storage until initialize_copy succeeds. */
2043
+ static VALUE
2044
+ NativeValue_reject_construction(int argc, VALUE *argv, VALUE self)
2045
+ {
2046
+ rb_raise(rb_eTypeError, "use a factory to create native objects");
2047
+ return Qnil;
2048
+ }
2049
+
2050
+ /* Upstream guarantees its key/signature value structs can be safely copied.
2051
+ * These wrappers contain inline values only; owned pointers need a deep copy. */
2052
+ #define DEFINE_VALUE_COPY(Type) \
2053
+ static VALUE Type##_copy_alloc(VALUE klass) \
2054
+ { \
2055
+ return TypedData_Wrap_Struct(klass, &Type##_DataType, NULL); \
2056
+ } \
2057
+ static VALUE Type##_initialize_copy(VALUE self, VALUE other) \
2058
+ { \
2059
+ Type *source; \
2060
+ Type *copy; \
2061
+ if (self == other) { return self; } \
2062
+ rb_obj_init_copy(self, other); \
2063
+ CheckedTypedData_Get_Struct(other, Type, &Type##_DataType, source); \
2064
+ if (rb_check_typeddata(self, &Type##_DataType) != NULL) \
2065
+ { \
2066
+ rb_raise(Secp256k1_Error_class, "native object is already initialized"); \
2067
+ } \
2068
+ copy = ALLOC(Type); \
2069
+ *copy = *source; \
2070
+ RB_GC_GUARD(other); \
2071
+ RTYPEDDATA_DATA(self) = copy; \
2072
+ return self; \
2073
+ }
2074
+
2075
+ DEFINE_VALUE_COPY(PublicKey)
2076
+ DEFINE_VALUE_COPY(XOnlyPublicKey)
2077
+ DEFINE_VALUE_COPY(PrivateKey)
2078
+ DEFINE_VALUE_COPY(KeyPair)
2079
+ DEFINE_VALUE_COPY(Signature)
2080
+ #ifdef HAVE_SECP256K1_SCHNORRSIG_H
2081
+ DEFINE_VALUE_COPY(SchnorrSignature)
2082
+ #endif
2083
+
2084
+ #ifdef HAVE_SECP256K1_RECOVERY_H
2085
+ static VALUE
2086
+ RecoverableSignature_copy_alloc(VALUE klass)
2087
+ {
2088
+ return TypedData_Wrap_Struct(klass, &RecoverableSignature_DataType, NULL);
2089
+ }
2090
+
2091
+ static VALUE
2092
+ RecoverableSignature_initialize_copy(VALUE self, VALUE other)
2093
+ {
2094
+ RecoverableSignature *source;
2095
+ RecoverableSignature *copy;
2096
+ if (self == other) { return self; }
2097
+ rb_obj_init_copy(self, other);
2098
+ CheckedTypedData_Get_Struct(other, RecoverableSignature, &RecoverableSignature_DataType, source);
2099
+ if (rb_check_typeddata(self, &RecoverableSignature_DataType) != NULL)
2100
+ {
2101
+ rb_raise(Secp256k1_Error_class, "native object is already initialized");
2102
+ }
2103
+ copy = ALLOC(RecoverableSignature);
2104
+ copy->sig = source->sig;
2105
+ copy->ctx = secp256k1_context_clone(source->ctx);
2106
+ RB_GC_GUARD(other);
2107
+ RTYPEDDATA_DATA(self) = copy;
2108
+ return self;
2109
+ }
2110
+ #endif
2111
+
2112
+ #define ENABLE_VALUE_COPY(Type) \
2113
+ rb_define_alloc_func(Secp256k1_##Type##_class, Type##_copy_alloc); \
2114
+ rb_define_singleton_method(Secp256k1_##Type##_class, "allocate", NativeValue_reject_construction, -1); \
2115
+ rb_define_method(Secp256k1_##Type##_class, "initialize", NativeValue_reject_construction, -1); \
2116
+ rb_define_method(Secp256k1_##Type##_class, "initialize_copy", Type##_initialize_copy, 1)
2117
+
2118
+ // Secp256k1 module methods
2119
+ //
2120
+
2121
+ /**
2122
+ * Indicates whether or not the libsecp256k1 recovery module is installed.
2123
+ *
2124
+ * @return [Boolean] true if libsecp256k1 was built with the recovery module,
2125
+ * false otherwise.
2126
+ */
2127
+ static VALUE
2128
+ Secp256k1_have_recovery(VALUE module)
2129
+ {
2130
+ #ifdef HAVE_SECP256K1_RECOVERY_H
2131
+ return Qtrue;
2132
+ #else // HAVE_SECP256K1_RECOVERY_H
2133
+ return Qfalse;
2134
+ #endif // HAVE_SECP256K1_RECOVERY_H
2135
+ }
2136
+
2137
+ /**
2138
+ * Indicates whether or not libsecp256k1 EC Diffie-Hellman module is installed.
2139
+ *
2140
+ * @return [Boolean] true if libsecp256k1 was build with the ECDH module, false
2141
+ * otherwise.
2142
+ */
2143
+ static VALUE
2144
+ Secp256k1_have_ecdh(VALUE module)
2145
+ {
2146
+ #ifdef HAVE_SECP256K1_ECDH_H
2147
+ return Qtrue;
2148
+ #else // HAVE_SECP256K1_ECDH_H
2149
+ return Qfalse;
2150
+ #endif // HAVE_SECP256K1_ECDH_H
2151
+ }
2152
+
2153
+ /**
2154
+ * Indicates whether or not libsecp256k1 Schnorr signature module is installed.
2155
+ *
2156
+ * @return [Boolean]
2157
+ */
2158
+ static VALUE
2159
+ Secp256k1_have_schnorr(VALUE module)
2160
+ {
2161
+ #ifdef HAVE_SECP256K1_SCHNORRSIG_H
2162
+ return Qtrue;
2163
+ #else
2164
+ return Qfalse;
2165
+ #endif
2166
+ }
2167
+
2168
+ //
2169
+ // Library initialization
2170
+ //
2171
+
2172
+ void Init_rbsecp256k1(void)
2173
+ {
2174
+ // Perform selftest to ensure secp256k1_context_static is valid. This will
2175
+ // cause the program to abort if the selftest fails.
2176
+ secp256k1_selftest();
2177
+
2178
+ // Secp256k1
2179
+ Secp256k1_module = rb_define_module("Secp256k1");
2180
+ rb_define_singleton_method(
2181
+ Secp256k1_module,
2182
+ "have_recovery?",
2183
+ Secp256k1_have_recovery,
2184
+ 0
2185
+ );
2186
+ rb_define_singleton_method(
2187
+ Secp256k1_module,
2188
+ "have_ecdh?",
2189
+ Secp256k1_have_ecdh,
2190
+ 0
2191
+ );
2192
+ rb_define_singleton_method(
2193
+ Secp256k1_module,
2194
+ "have_schnorr?",
2195
+ Secp256k1_have_schnorr,
2196
+ 0
2197
+ );
2198
+
2199
+ // Secp256k1 exception hierarchy
2200
+ Secp256k1_Error_class = rb_define_class_under(
2201
+ Secp256k1_module, "Error", rb_eStandardError
2202
+ );
2203
+ Secp256k1_SerializationError_class = rb_define_class_under(
2204
+ Secp256k1_module, "SerializationError", Secp256k1_Error_class
2205
+ );
2206
+ Secp256k1_DeserializationError_class = rb_define_class_under(
2207
+ Secp256k1_module, "DeserializationError", Secp256k1_Error_class
2208
+ );
2209
+
2210
+ // Secp256k1::Context
2211
+ Secp256k1_Context_class = rb_define_class_under(
2212
+ Secp256k1_module, "Context", rb_cObject
2213
+ );
2214
+ rb_undef_alloc_func(Secp256k1_Context_class);
2215
+ rb_define_alloc_func(Secp256k1_Context_class, Context_alloc);
2216
+ rb_define_method(Secp256k1_Context_class, "initialize_copy", Context_initialize_copy, 1);
2217
+ rb_define_method(Secp256k1_Context_class,
2218
+ "initialize",
2219
+ Context_initialize,
2220
+ -1);
2221
+ rb_define_method(Secp256k1_Context_class,
2222
+ "key_pair_from_private_key",
2223
+ Context_key_pair_from_private_key,
2224
+ 1);
2225
+ rb_define_method(Secp256k1_Context_class,
2226
+ "sign",
2227
+ Context_sign,
2228
+ 2);
2229
+ rb_define_method(Secp256k1_Context_class,
2230
+ "tagged_sha256",
2231
+ Context_tagged_sha256,
2232
+ 2);
2233
+ rb_define_method(Secp256k1_Context_class,
2234
+ "verify",
2235
+ Context_verify,
2236
+ 3);
2237
+
2238
+ // Factories wrap initialized storage directly. Copy allocators create empty,
2239
+ // checked shells for Ruby dup/clone; direct construction is rejected.
2240
+ // Secp256k1::KeyPair
2241
+ Secp256k1_KeyPair_class = rb_define_class_under(Secp256k1_module,
2242
+ "KeyPair",
2243
+ rb_cObject);
2244
+ ENABLE_VALUE_COPY(KeyPair);
2245
+ rb_define_method(Secp256k1_KeyPair_class, "public_key", KeyPair_public_key, 0);
2246
+ rb_define_method(Secp256k1_KeyPair_class, "private_key", KeyPair_private_key, 0);
2247
+ rb_define_method(Secp256k1_KeyPair_class, "xonly_public_key", KeyPair_xonly_public_key, 0);
2248
+ rb_define_method(Secp256k1_KeyPair_class, "==", KeyPair_equals, 1);
2249
+
2250
+ // Secp256k1::PublicKey
2251
+ Secp256k1_PublicKey_class = rb_define_class_under(Secp256k1_module,
2252
+ "PublicKey",
2253
+ rb_cObject);
2254
+ ENABLE_VALUE_COPY(PublicKey);
2255
+ rb_define_method(Secp256k1_PublicKey_class,
2256
+ "compressed",
2257
+ PublicKey_compressed,
2258
+ 0);
2259
+ rb_define_method(Secp256k1_PublicKey_class,
2260
+ "uncompressed",
2261
+ PublicKey_uncompressed,
2262
+ 0);
2263
+ rb_define_method(Secp256k1_PublicKey_class,
2264
+ "to_xonly",
2265
+ PublicKey_to_xonly,
2266
+ 0);
2267
+ rb_define_singleton_method(
2268
+ Secp256k1_PublicKey_class,
2269
+ "from_data",
2270
+ PublicKey_from_data,
2271
+ 1
2272
+ );
2273
+ rb_define_method(Secp256k1_PublicKey_class, "==", PublicKey_equals, 1);
2274
+
2275
+ // Secp256k1::XOnlyPublicKey
2276
+ Secp256k1_XOnlyPublicKey_class = rb_define_class_under(Secp256k1_module,
2277
+ "XOnlyPublicKey",
2278
+ rb_cObject);
2279
+
2280
+ ENABLE_VALUE_COPY(XOnlyPublicKey);
2281
+ rb_define_method(Secp256k1_XOnlyPublicKey_class,
2282
+ "serialized",
2283
+ XOnlyPublicKey_serialized,
2284
+ 0);
2285
+ rb_define_singleton_method(
2286
+ Secp256k1_XOnlyPublicKey_class,
2287
+ "from_data",
2288
+ XOnlyPublicKey_from_data,
2289
+ 1);
2290
+ rb_define_method(Secp256k1_XOnlyPublicKey_class, "==", XOnlyPublicKey_equals, 1);
2291
+
2292
+ // Secp256k1::PrivateKey
2293
+ Secp256k1_PrivateKey_class = rb_define_class_under(
2294
+ Secp256k1_module, "PrivateKey", rb_cObject
2295
+ );
2296
+ ENABLE_VALUE_COPY(PrivateKey);
2297
+ rb_define_method(Secp256k1_PrivateKey_class, "data", PrivateKey_data, 0);
2298
+ rb_define_method(Secp256k1_PrivateKey_class, "==", PrivateKey_equals, 1);
2299
+ rb_define_singleton_method(
2300
+ Secp256k1_PrivateKey_class,
2301
+ "from_data",
2302
+ PrivateKey_from_data,
2303
+ 1
2304
+ );
2305
+
2306
+ // Secp256k1::Signature
2307
+ Secp256k1_Signature_class = rb_define_class_under(Secp256k1_module,
2308
+ "Signature",
2309
+ rb_cObject);
2310
+ ENABLE_VALUE_COPY(Signature);
2311
+ rb_define_method(Secp256k1_Signature_class,
2312
+ "der_encoded",
2313
+ Signature_der_encoded,
2314
+ 0);
2315
+ rb_define_method(Secp256k1_Signature_class,
2316
+ "compact",
2317
+ Signature_compact,
2318
+ 0);
2319
+ rb_define_method(Secp256k1_Signature_class,
2320
+ "normalized",
2321
+ Signature_normalized,
2322
+ 0);
2323
+ rb_define_method(Secp256k1_Signature_class,
2324
+ "==",
2325
+ Signature_equals,
2326
+ 1);
2327
+ rb_define_singleton_method(
2328
+ Secp256k1_Signature_class,
2329
+ "from_compact",
2330
+ Signature_from_compact,
2331
+ 1
2332
+ );
2333
+ rb_define_singleton_method(
2334
+ Secp256k1_Signature_class,
2335
+ "from_der_encoded",
2336
+ Signature_from_der_encoded,
2337
+ 1
2338
+ );
2339
+
2340
+ #ifdef HAVE_SECP256K1_RECOVERY_H
2341
+ // Secp256k1::RecoverableSignature
2342
+ Secp256k1_RecoverableSignature_class = rb_define_class_under(
2343
+ Secp256k1_module,
2344
+ "RecoverableSignature",
2345
+ rb_cObject
2346
+ );
2347
+ ENABLE_VALUE_COPY(RecoverableSignature);
2348
+ rb_define_method(
2349
+ Secp256k1_RecoverableSignature_class,
2350
+ "compact",
2351
+ RecoverableSignature_compact,
2352
+ 0
2353
+ );
2354
+ rb_define_method(
2355
+ Secp256k1_RecoverableSignature_class,
2356
+ "to_signature",
2357
+ RecoverableSignature_to_signature,
2358
+ 0
2359
+ );
2360
+ rb_define_method(
2361
+ Secp256k1_RecoverableSignature_class,
2362
+ "recover_public_key",
2363
+ RecoverableSignature_recover_public_key,
2364
+ 1
2365
+ );
2366
+ rb_define_method(
2367
+ Secp256k1_RecoverableSignature_class,
2368
+ "==",
2369
+ RecoverableSignature_equals,
2370
+ 1
2371
+ );
2372
+
2373
+ // Context recoverable signature methods
2374
+ rb_define_method(
2375
+ Secp256k1_Context_class,
2376
+ "sign_recoverable",
2377
+ Context_sign_recoverable,
2378
+ 2
2379
+ );
2380
+ rb_define_method(
2381
+ Secp256k1_Context_class,
2382
+ "recoverable_signature_from_compact",
2383
+ Context_recoverable_signature_from_compact,
2384
+ 2
2385
+ );
2386
+ #endif // HAVE_SECP256K1_RECOVERY_H
2387
+
2388
+ #ifdef HAVE_SECP256K1_ECDH_H
2389
+ Secp256k1_SharedSecret_class = rb_define_class_under(
2390
+ Secp256k1_module,
2391
+ "SharedSecret",
2392
+ rb_cObject
2393
+ );
2394
+ rb_undef_alloc_func(Secp256k1_SharedSecret_class);
2395
+ rb_define_attr(Secp256k1_SharedSecret_class, "data", 1, 0);
2396
+
2397
+ // Context EC Diffie-Hellman methods
2398
+ rb_define_method(
2399
+ Secp256k1_Context_class,
2400
+ "ecdh",
2401
+ Context_ecdh,
2402
+ 2
2403
+ );
2404
+ #endif // HAVE_SECP256K1_ECDH_H
2405
+
2406
+ #ifdef HAVE_SECP256K1_SCHNORRSIG_H
2407
+ Secp256k1_SchnorrSignature_class = rb_define_class_under(
2408
+ Secp256k1_module,
2409
+ "SchnorrSignature",
2410
+ rb_cObject);
2411
+ ENABLE_VALUE_COPY(SchnorrSignature);
2412
+ rb_define_method(Secp256k1_SchnorrSignature_class, "serialized", SchnorrSignature_serialized, 0);
2413
+ rb_define_method(Secp256k1_SchnorrSignature_class, "verify", SchnorrSignature_verify, 2);
2414
+ rb_define_method(Secp256k1_SchnorrSignature_class, "==", SchnorrSignature_equals, 1);
2415
+
2416
+ rb_define_singleton_method(
2417
+ Secp256k1_SchnorrSignature_class,
2418
+ "from_data",
2419
+ SchnorrSignature_from_data,
2420
+ 1
2421
+ );
2422
+
2423
+ rb_define_method(
2424
+ Secp256k1_Context_class,
2425
+ "sign_schnorr_custom",
2426
+ Context_sign_schnorr_custom,
2427
+ 3);
2428
+ #endif // HAVE_SECP256K1_SCHNORRSIG_H
2429
+ }