rbsecp256k1 5.1.1 → 6.0.0

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.
@@ -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
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(void)
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(void)
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(void)
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(void)
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(void)
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(void)
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
  }