rbsecp256k1 5.1.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,19 +7,39 @@
7
7
  //
8
8
  // Dependencies:
9
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
+
10
22
  #include <ruby.h>
11
23
  #include <secp256k1.h>
12
24
 
13
- // Include recoverable signatures functionality if available
25
+ // Check for optional sub-modules. As a rule any secp256k1 submodule is
26
+ // optional and so should be blocked off using these ifdefs.
14
27
  #ifdef HAVE_SECP256K1_RECOVERY_H
15
28
  #include <secp256k1_recovery.h>
16
29
  #endif // HAVE_SECP256K1_RECOVERY_H
17
30
 
18
- // Include EC Diffie-Hellman functionality
19
31
  #ifdef HAVE_SECP256K1_ECDH_H
20
32
  #include <secp256k1_ecdh.h>
21
33
  #endif // HAVE_SECP256K1_ECDH_H
22
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
+
23
43
  // High-level design:
24
44
  //
25
45
  // The Ruby wrapper is divided into the following hierarchical organization:
@@ -28,13 +48,15 @@
28
48
  // |-- Context
29
49
  // |-- KeyPair
30
50
  // |-- PublicKey
51
+ // |-- XOnlyPublicKey
31
52
  // |-- PrivateKey
32
- // |-- RecoverableSignature
33
- // |-- SharedSecret
53
+ // |-- RecoverableSignature (recovery module)
54
+ // |-- SharedSecret (ecdh module)
34
55
  // |-- Signature
56
+ // |-- SchnorrSignature
35
57
  //
36
58
  // The Context class contains most of the methods that invoke libsecp256k1.
37
- // The KayPair, PublicKey, PrivateKey, RecoverableSignature, SharedSecret, and
59
+ // The KeyPair, PublicKey, PrivateKey, RecoverableSignature, SharedSecret, and
38
60
  // Signature objects act as data objects and are passed to various
39
61
  // methods. Contexts are thread safe and can be used across
40
62
  // applications. Context initialization is expensive so it is recommended that
@@ -58,8 +80,12 @@
58
80
  const size_t UNCOMPRESSED_PUBKEY_SIZE_BYTES = 65;
59
81
  // Size of a compressed public key
60
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;
61
85
  // Size of a compact signature in bytes
62
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;
63
89
 
64
90
  // Globally define our module and its associated classes so we can instantiate
65
91
  // objects from anywhere. The use of global variables seems to be inline with
@@ -73,6 +99,7 @@ static VALUE Secp256k1_KeyPair_class;
73
99
  static VALUE Secp256k1_PublicKey_class;
74
100
  static VALUE Secp256k1_PrivateKey_class;
75
101
  static VALUE Secp256k1_Signature_class;
102
+ static VALUE Secp256k1_XOnlyPublicKey_class;
76
103
 
77
104
  #ifdef HAVE_SECP256K1_RECOVERY_H
78
105
  static VALUE Secp256k1_RecoverableSignature_class;
@@ -82,14 +109,17 @@ static VALUE Secp256k1_RecoverableSignature_class;
82
109
  static VALUE Secp256k1_SharedSecret_class;
83
110
  #endif // HAVE_SECP256K1_ECDH_H
84
111
 
112
+ #ifdef HAVE_SECP256K1_SCHNORRSIG_H
113
+ static VALUE Secp256k1_SchnorrSignature_class;
114
+ #endif // HAVE_SECP256K1_SCHNORRSIG_H
115
+
85
116
  // Forward definitions for all structures
86
117
  typedef struct Context_dummy {
87
118
  secp256k1_context *ctx; // Context used by libsecp256k1 library
88
119
  } Context;
89
120
 
90
121
  typedef struct KeyPair_dummy {
91
- VALUE public_key;
92
- VALUE private_key;
122
+ secp256k1_keypair keypair;
93
123
  } KeyPair;
94
124
 
95
125
  typedef struct PublicKey_dummy {
@@ -100,6 +130,10 @@ typedef struct PrivateKey_dummy {
100
130
  unsigned char data[32]; // Bytes comprising the private key data
101
131
  } PrivateKey;
102
132
 
133
+ typedef struct XOnlyPublicKey_dummy {
134
+ secp256k1_xonly_pubkey pubkey; // Opaque object representing an x-only pubkey.
135
+ } XOnlyPublicKey;
136
+
103
137
  typedef struct Signature_dummy {
104
138
  secp256k1_ecdsa_signature sig; // Signature object, contains 64-byte signature
105
139
  } Signature;
@@ -117,6 +151,11 @@ typedef struct SharedSecret_dummy {
117
151
  } SharedSecret;
118
152
  #endif // HAVE_SECP256K1_ECDH_H
119
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
120
159
  //
121
160
  // Typed data definitions
122
161
  //
@@ -154,12 +193,38 @@ static const rb_data_type_t PublicKey_DataType = {
154
193
  RUBY_TYPED_FREE_IMMEDIATELY
155
194
  };
156
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
+
157
212
  // PrivateKey
158
213
  static void
159
214
  PrivateKey_free(void *in_private_key)
160
215
  {
161
216
  PrivateKey *private_key;
162
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
+
163
228
  xfree(private_key);
164
229
  }
165
230
 
@@ -172,24 +237,16 @@ static const rb_data_type_t PrivateKey_DataType = {
172
237
 
173
238
  // KeyPair
174
239
  static void
175
- KeyPair_mark(void *in_key_pair)
176
- {
177
- KeyPair *key_pair = (KeyPair*)in_key_pair;
178
-
179
- // Mark both contained objects to ensure they are properly garbage collected
180
- rb_gc_mark(key_pair->public_key);
181
- rb_gc_mark(key_pair->private_key);
182
- }
183
-
184
- static void
185
- KeyPair_free(void *self)
240
+ KeyPair_free(void *in_keypair)
186
241
  {
187
- xfree(self);
242
+ KeyPair *keypair;
243
+ keypair = (KeyPair*)in_keypair;
244
+ xfree(keypair);
188
245
  }
189
246
 
190
247
  static const rb_data_type_t KeyPair_DataType = {
191
248
  "KeyPair",
192
- { KeyPair_mark, KeyPair_free, 0 },
249
+ { 0, KeyPair_free, 0 },
193
250
  0, 0,
194
251
  RUBY_TYPED_FREE_IMMEDIATELY
195
252
  };
@@ -249,6 +306,25 @@ static const rb_data_type_t SharedSecret_DataType = {
249
306
  };
250
307
  #endif // HAVE_SECP256K1_ECDH_H
251
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
+
252
328
  /**
253
329
  * Macro: SUCCESS
254
330
  *
@@ -337,72 +413,103 @@ RecoverableSignData(secp256k1_context *in_context,
337
413
  #endif // HAVE_SECP256K1_RECOVERY_H
338
414
 
339
415
  //
340
- // Secp256k1::KeyPair class interface
416
+ // Secp256k1::XOnlyPublicKey class interface
341
417
  //
342
418
 
343
419
  static VALUE
344
- KeyPair_alloc(VALUE klass)
420
+ XOnlyPublicKey_alloc(VALUE klass)
345
421
  {
346
- KeyPair *key_pair;
422
+ VALUE result;
423
+ XOnlyPublicKey* xonly_pubkey;
347
424
 
348
- key_pair = ALLOC(KeyPair);
425
+ xonly_pubkey = ALLOC(XOnlyPublicKey);
426
+ MEMZERO(xonly_pubkey, XOnlyPublicKey, 1);
427
+ result = TypedData_Wrap_Struct(klass, &XOnlyPublicKey_DataType, xonly_pubkey);
349
428
 
350
- return TypedData_Wrap_Struct(klass, &KeyPair_DataType, key_pair);
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;
351
448
  }
352
449
 
353
450
  /**
354
- * Default constructor.
451
+ * Loads an x-only public key from serialized data.
355
452
  *
356
- * @param in_public_key [Secp256k1::PublicKey] public key
357
- * @param in_private_key [Secp256k1::PrivateKey] private key
358
- * @return [Secp256k1::KeyPair] newly initialized key pair.
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
359
457
  */
360
458
  static VALUE
361
- KeyPair_initialize(VALUE self, VALUE in_public_key, VALUE in_private_key)
459
+ XOnlyPublicKey_from_data(VALUE klass, VALUE in_xonly_public_key_serialized)
362
460
  {
363
- KeyPair *key_pair;
461
+ unsigned char *xonly_pubkey_data;
364
462
 
365
- TypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, key_pair);
366
- Check_TypedStruct(in_public_key, &PublicKey_DataType);
367
- Check_TypedStruct(in_private_key, &PrivateKey_DataType);
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
+ }
368
473
 
369
- key_pair->public_key = in_public_key;
370
- key_pair->private_key = in_private_key;
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];
371
485
 
372
- rb_iv_set(self, "@public_key", in_public_key);
373
- rb_iv_set(self, "@private_key", in_private_key);
486
+ TypedData_Get_Struct(self, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
374
487
 
375
- return self;
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);
376
495
  }
377
496
 
378
497
  /**
379
- * Compare two key pairs.
498
+ * Compare two x-only public keys.
380
499
  *
381
- * Two key pairs are equal if they have the same public and private key. The
382
- * keys are compared using their own comparison operators.
383
- *
384
- * @param other [Secp256k1::KeyPair] key pair to compare to.
385
- * @return [Boolean] true if the keys match, false otherwise.
500
+ * @param other [Secp256k1::XOnlyPublicKey] x-only public key to compare.
501
+ * @return [Boolean] true if they are equal, false otherwise.
386
502
  */
387
503
  static VALUE
388
- KeyPair_equals(VALUE self, VALUE other)
504
+ XOnlyPublicKey_equals(VALUE self, VALUE other)
389
505
  {
390
- KeyPair *lhs;
391
- KeyPair *rhs;
392
- VALUE public_keys_equal;
393
- VALUE private_keys_equal;
506
+ XOnlyPublicKey *lhs;
507
+ XOnlyPublicKey *rhs;
394
508
 
395
- TypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, lhs);
396
- TypedData_Get_Struct(other, KeyPair, &KeyPair_DataType, rhs);
509
+ TypedData_Get_Struct(self, XOnlyPublicKey, &XOnlyPublicKey_DataType, lhs);
510
+ TypedData_Get_Struct(other, XOnlyPublicKey, &XOnlyPublicKey_DataType, rhs);
397
511
 
398
- public_keys_equal = rb_funcall(
399
- lhs->public_key, rb_intern("=="), 1, rhs->public_key
400
- );
401
- private_keys_equal = rb_funcall(
402
- lhs->private_key, rb_intern("=="), 1, rhs->private_key
403
- );
404
-
405
- if (public_keys_equal == Qtrue && private_keys_equal == Qtrue)
512
+ if (secp256k1_xonly_pubkey_cmp(secp256k1_context_static, &lhs->pubkey, &rhs->pubkey) == 0)
406
513
  {
407
514
  return Qtrue;
408
515
  }
@@ -427,27 +534,6 @@ PublicKey_alloc(VALUE klass)
427
534
  return result;
428
535
  }
429
536
 
430
- static VALUE
431
- PublicKey_create_from_private_key(Context *in_context,
432
- unsigned char *private_key_data)
433
- {
434
- PublicKey *public_key;
435
- VALUE result;
436
-
437
- result = PublicKey_alloc(Secp256k1_PublicKey_class);
438
- TypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
439
-
440
- if (secp256k1_ec_pubkey_create(
441
- in_context->ctx,
442
- (&public_key->pubkey),
443
- private_key_data) != 1)
444
- {
445
- rb_raise(Secp256k1_DeserializationError_class, "invalid private key data");
446
- }
447
-
448
- return result;
449
- }
450
-
451
537
  static VALUE
452
538
  PublicKey_create_from_data(unsigned char *in_public_key_data,
453
539
  unsigned int in_public_key_data_len)
@@ -458,12 +544,13 @@ PublicKey_create_from_data(unsigned char *in_public_key_data,
458
544
  result = PublicKey_alloc(Secp256k1_PublicKey_class);
459
545
  TypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
460
546
 
461
- if (secp256k1_ec_pubkey_parse(secp256k1_context_no_precomp,
547
+ if (secp256k1_ec_pubkey_parse(secp256k1_context_static,
462
548
  &(public_key->pubkey),
463
549
  in_public_key_data,
464
550
  in_public_key_data_len) != 1)
465
551
  {
466
552
  rb_raise(Secp256k1_DeserializationError_class, "invalid public key data");
553
+ return Qnil;
467
554
  }
468
555
 
469
556
  return result;
@@ -505,7 +592,7 @@ PublicKey_uncompressed(VALUE self)
505
592
 
506
593
  TypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
507
594
 
508
- secp256k1_ec_pubkey_serialize(secp256k1_context_no_precomp,
595
+ secp256k1_ec_pubkey_serialize(secp256k1_context_static,
509
596
  serialized_pubkey,
510
597
  &serialized_pubkey_len,
511
598
  &(public_key->pubkey),
@@ -528,7 +615,7 @@ PublicKey_compressed(VALUE self)
528
615
 
529
616
  TypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
530
617
 
531
- secp256k1_ec_pubkey_serialize(secp256k1_context_no_precomp,
618
+ secp256k1_ec_pubkey_serialize(secp256k1_context_static,
532
619
  serialized_pubkey,
533
620
  &serialized_pubkey_len,
534
621
  &(public_key->pubkey),
@@ -537,6 +624,35 @@ PublicKey_compressed(VALUE self)
537
624
  return rb_str_new((char*)serialized_pubkey, serialized_pubkey_len);
538
625
  }
539
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
+
540
656
  /**
541
657
  * Compares two public keys.
542
658
  *
@@ -562,14 +678,14 @@ PublicKey_equals(VALUE self, VALUE other)
562
678
  TypedData_Get_Struct(other, PublicKey, &PublicKey_DataType, rhs);
563
679
 
564
680
  secp256k1_ec_pubkey_serialize(
565
- secp256k1_context_no_precomp,
681
+ secp256k1_context_static,
566
682
  lhs_compressed,
567
683
  &lhs_len,
568
684
  &(lhs->pubkey),
569
685
  SECP256K1_EC_COMPRESSED
570
686
  );
571
687
  secp256k1_ec_pubkey_serialize(
572
- secp256k1_context_no_precomp,
688
+ secp256k1_context_static,
573
689
  rhs_compressed,
574
690
  &rhs_len,
575
691
  &(rhs->pubkey),
@@ -602,27 +718,42 @@ PrivateKey_alloc(VALUE klass)
602
718
  return new_instance;
603
719
  }
604
720
 
721
+ /* Internal-only method for creating a private key from secret data */
605
722
  static VALUE
606
723
  PrivateKey_create(unsigned char *in_private_key_data)
607
724
  {
608
725
  PrivateKey *private_key;
609
726
  VALUE result;
610
727
 
611
- if (secp256k1_ec_seckey_verify(secp256k1_context_no_precomp,
728
+ if (secp256k1_ec_seckey_verify(secp256k1_context_static,
612
729
  in_private_key_data) != 1)
613
730
  {
614
731
  rb_raise(Secp256k1_Error_class, "invalid private key data");
732
+ return Qnil;
615
733
  }
616
734
 
617
735
  result = PrivateKey_alloc(Secp256k1_PrivateKey_class);
618
736
  TypedData_Get_Struct(result, PrivateKey, &PrivateKey_DataType, private_key);
619
737
  MEMCPY(private_key->data, in_private_key_data, char, 32);
620
738
 
621
- rb_iv_set(result, "@data", rb_str_new((char*)in_private_key_data, 32));
622
-
623
739
  return result;
624
740
  }
625
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
+
626
757
  /**
627
758
  * Load a private key from binary data.
628
759
  *
@@ -643,6 +774,7 @@ PrivateKey_from_data(VALUE klass, VALUE in_private_key_data)
643
774
  Secp256k1_Error_class,
644
775
  "private key data must be 32 bytes in length"
645
776
  );
777
+ return Qnil;
646
778
  }
647
779
 
648
780
  private_key_data = (unsigned char*)StringValuePtr(in_private_key_data);
@@ -674,6 +806,121 @@ PrivateKey_equals(VALUE self, VALUE other)
674
806
  return Qfalse;
675
807
  }
676
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
+
677
924
  //
678
925
  // Secp256k1::Signature class interface
679
926
  //
@@ -718,11 +965,12 @@ Signature_from_compact(VALUE klass, VALUE in_compact_signature)
718
965
  signature_result = Signature_alloc(Secp256k1_Signature_class);
719
966
  TypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
720
967
 
721
- if (secp256k1_ecdsa_signature_parse_compact(secp256k1_context_no_precomp,
968
+ if (secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static,
722
969
  &(signature->sig),
723
970
  signature_data) != 1)
724
971
  {
725
972
  rb_raise(Secp256k1_DeserializationError_class, "invalid compact signature");
973
+ return Qnil;
726
974
  }
727
975
 
728
976
  return signature_result;
@@ -751,12 +999,13 @@ Signature_from_der_encoded(VALUE klass, VALUE in_der_encoded_signature)
751
999
  signature_result = Signature_alloc(Secp256k1_Signature_class);
752
1000
  TypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
753
1001
 
754
- if (secp256k1_ecdsa_signature_parse_der(secp256k1_context_no_precomp,
1002
+ if (secp256k1_ecdsa_signature_parse_der(secp256k1_context_static,
755
1003
  &(signature->sig),
756
1004
  signature_data,
757
1005
  RSTRING_LEN(in_der_encoded_signature)) != 1)
758
1006
  {
759
1007
  rb_raise(Secp256k1_DeserializationError_class, "invalid DER encoded signature");
1008
+ return Qnil;
760
1009
  }
761
1010
 
762
1011
  return signature_result;
@@ -778,7 +1027,7 @@ Signature_der_encoded(VALUE self)
778
1027
  TypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
779
1028
 
780
1029
  der_signature_len = 72;
781
- if (secp256k1_ecdsa_signature_serialize_der(secp256k1_context_no_precomp,
1030
+ if (secp256k1_ecdsa_signature_serialize_der(secp256k1_context_static,
782
1031
  der_signature,
783
1032
  &der_signature_len,
784
1033
  &(signature->sig)) != 1)
@@ -787,6 +1036,7 @@ Signature_der_encoded(VALUE self)
787
1036
  Secp256k1_SerializationError_class,
788
1037
  "could not compute DER encoded signature"
789
1038
  );
1039
+ return Qnil;
790
1040
  }
791
1041
 
792
1042
  return rb_str_new((char*)der_signature, der_signature_len);
@@ -806,7 +1056,7 @@ Signature_compact(VALUE self)
806
1056
 
807
1057
  TypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
808
1058
 
809
- if (secp256k1_ecdsa_signature_serialize_compact(secp256k1_context_no_precomp,
1059
+ if (secp256k1_ecdsa_signature_serialize_compact(secp256k1_context_static,
810
1060
  compact_signature,
811
1061
  &(signature->sig)) != 1)
812
1062
  {
@@ -814,6 +1064,7 @@ Signature_compact(VALUE self)
814
1064
  Secp256k1_SerializationError_class,
815
1065
  "unable to compute compact signature"
816
1066
  );
1067
+ return Qnil;
817
1068
  }
818
1069
 
819
1070
  return rb_str_new((char*)compact_signature, COMPACT_SIG_SIZE_BYTES);
@@ -847,7 +1098,7 @@ Signature_normalized(VALUE self)
847
1098
 
848
1099
  was_normalized = Qfalse;
849
1100
  if (secp256k1_ecdsa_signature_normalize(
850
- secp256k1_context_no_precomp,
1101
+ secp256k1_context_static,
851
1102
  &(normalized_signature->sig),
852
1103
  &(signature->sig)) == 1)
853
1104
  {
@@ -881,10 +1132,10 @@ Signature_equals(VALUE self, VALUE other)
881
1132
  TypedData_Get_Struct(other, Signature, &Signature_DataType, rhs);
882
1133
 
883
1134
  secp256k1_ecdsa_signature_serialize_compact(
884
- secp256k1_context_no_precomp, lhs_compact, &(lhs->sig)
1135
+ secp256k1_context_static, lhs_compact, &(lhs->sig)
885
1136
  );
886
1137
  secp256k1_ecdsa_signature_serialize_compact(
887
- secp256k1_context_no_precomp, rhs_compact, &(rhs->sig)
1138
+ secp256k1_context_static, rhs_compact, &(rhs->sig)
888
1139
  );
889
1140
 
890
1141
  if (memcmp(lhs_compact, rhs_compact, 64) == 0)
@@ -939,7 +1190,7 @@ RecoverableSignature_compact(VALUE self)
939
1190
  );
940
1191
 
941
1192
  if (secp256k1_ecdsa_recoverable_signature_serialize_compact(
942
- secp256k1_context_no_precomp,
1193
+ recoverable_signature->ctx,
943
1194
  compact_sig,
944
1195
  &recovery_id,
945
1196
  &(recoverable_signature->sig)) != 1)
@@ -948,6 +1199,7 @@ RecoverableSignature_compact(VALUE self)
948
1199
  Secp256k1_SerializationError_class,
949
1200
  "unable to serialize recoverable signature"
950
1201
  );
1202
+ return Qnil;
951
1203
  }
952
1204
 
953
1205
  // Create a new array with room for 2 elements and push data onto it
@@ -988,7 +1240,7 @@ RecoverableSignature_to_signature(VALUE self)
988
1240
 
989
1241
  // NOTE: This method cannot fail
990
1242
  secp256k1_ecdsa_recoverable_signature_convert(
991
- secp256k1_context_no_precomp,
1243
+ recoverable_signature->ctx,
992
1244
  &(signature->sig),
993
1245
  &(recoverable_signature->sig));
994
1246
 
@@ -1016,6 +1268,7 @@ RecoverableSignature_recover_public_key(VALUE self, VALUE in_hash32)
1016
1268
  if (RSTRING_LEN(in_hash32) != 32)
1017
1269
  {
1018
1270
  rb_raise(Secp256k1_Error_class, "in_hash32 is not 32 bytes in length");
1271
+ return Qnil;
1019
1272
  }
1020
1273
 
1021
1274
  TypedData_Get_Struct(
@@ -1101,6 +1354,98 @@ SharedSecret_alloc(VALUE klass)
1101
1354
 
1102
1355
  #endif // HAVE_SECP256K1_ECDH_H
1103
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
+
1104
1449
  //
1105
1450
  // Secp256k1::Context class interface
1106
1451
  //
@@ -1207,8 +1552,8 @@ static VALUE
1207
1552
  Context_key_pair_from_private_key(VALUE self, VALUE in_private_key_data)
1208
1553
  {
1209
1554
  Context *context;
1210
- VALUE public_key;
1211
- VALUE private_key;
1555
+ VALUE result;
1556
+ KeyPair *keypair;
1212
1557
  unsigned char *private_key_data;
1213
1558
 
1214
1559
  Check_Type(in_private_key_data, T_STRING);
@@ -1217,20 +1562,20 @@ Context_key_pair_from_private_key(VALUE self, VALUE in_private_key_data)
1217
1562
  if (RSTRING_LEN(in_private_key_data) != 32)
1218
1563
  {
1219
1564
  rb_raise(Secp256k1_Error_class, "private key data must be 32 bytes in length");
1565
+ return Qnil;
1220
1566
  }
1221
1567
 
1568
+ result = KeyPair_alloc(Secp256k1_KeyPair_class);
1569
+ TypedData_Get_Struct(result, KeyPair, &KeyPair_DataType, keypair);
1570
+
1222
1571
  private_key_data = (unsigned char*)StringValuePtr(in_private_key_data);
1223
1572
 
1224
- private_key = PrivateKey_create(private_key_data);
1225
- public_key = PublicKey_create_from_private_key(context, private_key_data);
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
+ }
1226
1577
 
1227
- return rb_funcall(
1228
- Secp256k1_KeyPair_class,
1229
- rb_intern("new"),
1230
- 2,
1231
- public_key,
1232
- private_key
1233
- );
1578
+ return result;
1234
1579
  }
1235
1580
 
1236
1581
  /**
@@ -1257,6 +1602,7 @@ Context_sign(VALUE self, VALUE in_private_key, VALUE in_hash32)
1257
1602
  if (RSTRING_LEN(in_hash32) != 32)
1258
1603
  {
1259
1604
  rb_raise(Secp256k1_Error_class, "in_hash32 is not 32 bytes in length");
1605
+ return Qnil;
1260
1606
  }
1261
1607
 
1262
1608
  TypedData_Get_Struct(self, Context, &Context_DataType, context);
@@ -1276,6 +1622,39 @@ Context_sign(VALUE self, VALUE in_private_key, VALUE in_hash32)
1276
1622
  }
1277
1623
 
1278
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);
1279
1658
  }
1280
1659
 
1281
1660
  /**
@@ -1347,6 +1726,7 @@ Context_sign_recoverable(VALUE self, VALUE in_private_key, VALUE in_hash32)
1347
1726
  if (RSTRING_LEN(in_hash32) != 32)
1348
1727
  {
1349
1728
  rb_raise(Secp256k1_Error_class, "in_hash32 is not 32 bytes in length");
1729
+ return Qnil;
1350
1730
  }
1351
1731
 
1352
1732
  TypedData_Get_Struct(self, Context, &Context_DataType, context);
@@ -1373,6 +1753,7 @@ Context_sign_recoverable(VALUE self, VALUE in_private_key, VALUE in_hash32)
1373
1753
  }
1374
1754
 
1375
1755
  rb_raise(Secp256k1_Error_class, "unable to compute recoverable signature");
1756
+ return Qnil;
1376
1757
  }
1377
1758
 
1378
1759
  /**
@@ -1407,11 +1788,13 @@ Context_recoverable_signature_from_compact(
1407
1788
  if (RSTRING_LEN(in_compact_sig) != 64)
1408
1789
  {
1409
1790
  rb_raise(Secp256k1_Error_class, "compact signature is not 64 bytes");
1791
+ return Qnil;
1410
1792
  }
1411
1793
 
1412
1794
  if (recovery_id < 0 || recovery_id > 3)
1413
1795
  {
1414
1796
  rb_raise(Secp256k1_Error_class, "invalid recovery ID, must be in range [0, 3]");
1797
+ return Qnil;
1415
1798
  }
1416
1799
 
1417
1800
  result = RecoverableSignature_alloc(Secp256k1_RecoverableSignature_class);
@@ -1423,7 +1806,7 @@ Context_recoverable_signature_from_compact(
1423
1806
  );
1424
1807
 
1425
1808
  if (secp256k1_ecdsa_recoverable_signature_parse_compact(
1426
- secp256k1_context_no_precomp,
1809
+ context->ctx,
1427
1810
  &(recoverable_signature->sig),
1428
1811
  compact_sig,
1429
1812
  recovery_id) == 1)
@@ -1433,6 +1816,7 @@ Context_recoverable_signature_from_compact(
1433
1816
  }
1434
1817
 
1435
1818
  rb_raise(Secp256k1_DeserializationError_class, "unable to parse recoverable signature");
1819
+ return Qnil;
1436
1820
  }
1437
1821
 
1438
1822
  #endif // HAVE_SECP256K1_RECOVERY_H
@@ -1476,6 +1860,7 @@ Context_ecdh(VALUE self, VALUE point, VALUE scalar)
1476
1860
  NULL) != 1)
1477
1861
  {
1478
1862
  rb_raise(Secp256k1_Error_class, "invalid scalar provided to ecdh");
1863
+ return Qnil;
1479
1864
  }
1480
1865
 
1481
1866
  rb_iv_set(result, "@data", rb_str_new((char*)shared_secret->data, 32));
@@ -1485,6 +1870,57 @@ Context_ecdh(VALUE self, VALUE point, VALUE scalar)
1485
1870
 
1486
1871
  #endif // HAVE_SECP256K1_ECDH_H
1487
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
+
1488
1924
  //
1489
1925
  // Secp256k1 module methods
1490
1926
  //
@@ -1521,12 +1957,31 @@ Secp256k1_have_ecdh(VALUE module)
1521
1957
  #endif // HAVE_SECP256K1_ECDH_H
1522
1958
  }
1523
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
+
1524
1975
  //
1525
1976
  // Library initialization
1526
1977
  //
1527
1978
 
1528
- void Init_rbsecp256k1()
1979
+ void Init_rbsecp256k1(void)
1529
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
+
1530
1985
  // Secp256k1
1531
1986
  Secp256k1_module = rb_define_module("Secp256k1");
1532
1987
  rb_define_singleton_method(
@@ -1541,6 +1996,12 @@ void Init_rbsecp256k1()
1541
1996
  Secp256k1_have_ecdh,
1542
1997
  0
1543
1998
  );
1999
+ rb_define_singleton_method(
2000
+ Secp256k1_module,
2001
+ "have_schnorr?",
2002
+ Secp256k1_have_schnorr,
2003
+ 0
2004
+ );
1544
2005
 
1545
2006
  // Secp256k1 exception hierarchy
1546
2007
  Secp256k1_Error_class = rb_define_class_under(
@@ -1571,6 +2032,10 @@ void Init_rbsecp256k1()
1571
2032
  "sign",
1572
2033
  Context_sign,
1573
2034
  2);
2035
+ rb_define_method(Secp256k1_Context_class,
2036
+ "tagged_sha256",
2037
+ Context_tagged_sha256,
2038
+ 2);
1574
2039
  rb_define_method(Secp256k1_Context_class,
1575
2040
  "verify",
1576
2041
  Context_verify,
@@ -1582,12 +2047,9 @@ void Init_rbsecp256k1()
1582
2047
  rb_cObject);
1583
2048
  rb_undef_alloc_func(Secp256k1_KeyPair_class);
1584
2049
  rb_define_alloc_func(Secp256k1_KeyPair_class, KeyPair_alloc);
1585
- rb_define_attr(Secp256k1_KeyPair_class, "public_key", 1, 0);
1586
- rb_define_attr(Secp256k1_KeyPair_class, "private_key", 1, 0);
1587
- rb_define_method(Secp256k1_KeyPair_class,
1588
- "initialize",
1589
- KeyPair_initialize,
1590
- 2);
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);
1591
2053
  rb_define_method(Secp256k1_KeyPair_class, "==", KeyPair_equals, 1);
1592
2054
 
1593
2055
  // Secp256k1::PublicKey
@@ -1604,6 +2066,10 @@ void Init_rbsecp256k1()
1604
2066
  "uncompressed",
1605
2067
  PublicKey_uncompressed,
1606
2068
  0);
2069
+ rb_define_method(Secp256k1_PublicKey_class,
2070
+ "to_xonly",
2071
+ PublicKey_to_xonly,
2072
+ 0);
1607
2073
  rb_define_singleton_method(
1608
2074
  Secp256k1_PublicKey_class,
1609
2075
  "from_data",
@@ -1612,13 +2078,31 @@ void Init_rbsecp256k1()
1612
2078
  );
1613
2079
  rb_define_method(Secp256k1_PublicKey_class, "==", PublicKey_equals, 1);
1614
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
+
1615
2099
  // Secp256k1::PrivateKey
1616
2100
  Secp256k1_PrivateKey_class = rb_define_class_under(
1617
2101
  Secp256k1_module, "PrivateKey", rb_cObject
1618
2102
  );
1619
2103
  rb_undef_alloc_func(Secp256k1_PrivateKey_class);
1620
2104
  rb_define_alloc_func(Secp256k1_PrivateKey_class, PrivateKey_alloc);
1621
- rb_define_attr(Secp256k1_PrivateKey_class, "data", 1, 0);
2105
+ rb_define_method(Secp256k1_PrivateKey_class, "data", PrivateKey_data, 0);
1622
2106
  rb_define_method(Secp256k1_PrivateKey_class, "==", PrivateKey_equals, 1);
1623
2107
  rb_define_singleton_method(
1624
2108
  Secp256k1_PrivateKey_class,
@@ -1732,4 +2216,29 @@ void Init_rbsecp256k1()
1732
2216
  2
1733
2217
  );
1734
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
1735
2244
  }