rbsecp256k1 6.0.0 → 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.
@@ -20,7 +20,10 @@
20
20
  #endif // HAVE_SECP256K1_EXTRAKEYS_H
21
21
 
22
22
  #include <ruby.h>
23
+ #include <ruby/missing.h>
24
+ #include <string.h>
23
25
  #include <secp256k1.h>
26
+ #include <secp256k1_preallocated.h>
24
27
 
25
28
  // Check for optional sub-modules. As a rule any secp256k1 submodule is
26
29
  // optional and so should be blocked off using these ifdefs.
@@ -113,6 +116,39 @@ static VALUE Secp256k1_SharedSecret_class;
113
116
  static VALUE Secp256k1_SchnorrSignature_class;
114
117
  #endif // HAVE_SECP256K1_SCHNORRSIG_H
115
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
+
116
152
  // Forward definitions for all structures
117
153
  typedef struct Context_dummy {
118
154
  secp256k1_context *ctx; // Context used by libsecp256k1 library
@@ -158,25 +194,77 @@ typedef struct SchnorrSignature_dummy {
158
194
  #endif // HAVE_SECP256K1_SCHNORRSIG_H
159
195
  //
160
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.
161
201
  //
162
202
 
163
203
  // Context
164
204
  static void
165
205
  Context_free(void* in_context)
166
206
  {
207
+ if (in_context == NULL) { return; }
167
208
  Context *context;
168
209
  context = (Context*)in_context;
169
- secp256k1_context_destroy(context->ctx);
210
+ if (context->ctx != NULL) { secp256k1_context_destroy(context->ctx); }
170
211
  xfree(context);
171
212
  }
172
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
+
173
223
  static const rb_data_type_t Context_DataType = {
174
224
  "Context",
175
- { 0, Context_free, 0 },
225
+ { 0, Context_free, Context_memsize },
176
226
  0, 0,
177
227
  RUBY_TYPED_FREE_IMMEDIATELY
178
228
  };
179
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
+
180
268
  // PublicKey
181
269
  static void
182
270
  PublicKey_free(void *in_public_key)
@@ -186,9 +274,15 @@ PublicKey_free(void *in_public_key)
186
274
  xfree(public_key);
187
275
  }
188
276
 
277
+ static size_t
278
+ PublicKey_memsize(const void *data)
279
+ {
280
+ return data == NULL ? 0 : sizeof(PublicKey);
281
+ }
282
+
189
283
  static const rb_data_type_t PublicKey_DataType = {
190
284
  "PublicKey",
191
- { 0, PublicKey_free, 0 },
285
+ { 0, PublicKey_free, PublicKey_memsize },
192
286
  0, 0,
193
287
  RUBY_TYPED_FREE_IMMEDIATELY
194
288
  };
@@ -202,9 +296,15 @@ XOnlyPublicKey_free(void* in_xonly_pubkey)
202
296
  xfree(xonly_pubkey);
203
297
  }
204
298
 
299
+ static size_t
300
+ XOnlyPublicKey_memsize(const void *data)
301
+ {
302
+ return data == NULL ? 0 : sizeof(XOnlyPublicKey);
303
+ }
304
+
205
305
  static const rb_data_type_t XOnlyPublicKey_DataType = {
206
306
  "XOnlyPublicKey",
207
- { 0, XOnlyPublicKey_free, 0 },
307
+ { 0, XOnlyPublicKey_free, XOnlyPublicKey_memsize },
208
308
  0, 0,
209
309
  RUBY_TYPED_FREE_IMMEDIATELY
210
310
  };
@@ -213,24 +313,26 @@ static const rb_data_type_t XOnlyPublicKey_DataType = {
213
313
  static void
214
314
  PrivateKey_free(void *in_private_key)
215
315
  {
316
+ if (in_private_key == NULL) { return; }
216
317
  PrivateKey *private_key;
217
318
  private_key = (PrivateKey*)in_private_key;
218
319
 
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);
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));
227
323
 
228
324
  xfree(private_key);
229
325
  }
230
326
 
327
+ static size_t
328
+ PrivateKey_memsize(const void *data)
329
+ {
330
+ return data == NULL ? 0 : sizeof(PrivateKey);
331
+ }
332
+
231
333
  static const rb_data_type_t PrivateKey_DataType = {
232
334
  "PrivateKey",
233
- { 0, PrivateKey_free, 0 },
335
+ { 0, PrivateKey_free, PrivateKey_memsize },
234
336
  0, 0,
235
337
  RUBY_TYPED_FREE_IMMEDIATELY
236
338
  };
@@ -239,14 +341,22 @@ static const rb_data_type_t PrivateKey_DataType = {
239
341
  static void
240
342
  KeyPair_free(void *in_keypair)
241
343
  {
344
+ if (in_keypair == NULL) { return; }
242
345
  KeyPair *keypair;
243
346
  keypair = (KeyPair*)in_keypair;
347
+ explicit_bzero(keypair, sizeof(*keypair));
244
348
  xfree(keypair);
245
349
  }
246
350
 
351
+ static size_t
352
+ KeyPair_memsize(const void *data)
353
+ {
354
+ return data == NULL ? 0 : sizeof(KeyPair);
355
+ }
356
+
247
357
  static const rb_data_type_t KeyPair_DataType = {
248
358
  "KeyPair",
249
- { 0, KeyPair_free, 0 },
359
+ { 0, KeyPair_free, KeyPair_memsize },
250
360
  0, 0,
251
361
  RUBY_TYPED_FREE_IMMEDIATELY
252
362
  };
@@ -259,9 +369,15 @@ Signature_free(void *in_signature)
259
369
  xfree(signature);
260
370
  }
261
371
 
372
+ static size_t
373
+ Signature_memsize(const void *data)
374
+ {
375
+ return data == NULL ? 0 : sizeof(Signature);
376
+ }
377
+
262
378
  static const rb_data_type_t Signature_DataType = {
263
379
  "Signature",
264
- { 0, Signature_free, 0 },
380
+ { 0, Signature_free, Signature_memsize },
265
381
  0, 0,
266
382
  RUBY_TYPED_FREE_IMMEDIATELY
267
383
  };
@@ -271,17 +387,29 @@ static const rb_data_type_t Signature_DataType = {
271
387
  static void
272
388
  RecoverableSignature_free(void *in_recoverable_signature)
273
389
  {
390
+ if (in_recoverable_signature == NULL) { return; }
274
391
  RecoverableSignature *recoverable_signature = (
275
392
  (RecoverableSignature*)in_recoverable_signature
276
393
  );
277
394
 
278
- secp256k1_context_destroy(recoverable_signature->ctx);
395
+ if (recoverable_signature->ctx != NULL) {
396
+ secp256k1_context_destroy(recoverable_signature->ctx);
397
+ }
279
398
  xfree(recoverable_signature);
280
399
  }
281
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
+
282
410
  static const rb_data_type_t RecoverableSignature_DataType = {
283
411
  "RecoverableSignature",
284
- { 0, RecoverableSignature_free, 0 },
412
+ { 0, RecoverableSignature_free, RecoverableSignature_memsize },
285
413
  0, 0,
286
414
  RUBY_TYPED_FREE_IMMEDIATELY
287
415
  };
@@ -292,15 +420,23 @@ static const rb_data_type_t RecoverableSignature_DataType = {
292
420
  static void
293
421
  SharedSecret_free(void *in_shared_secret)
294
422
  {
423
+ if (in_shared_secret == NULL) { return; }
295
424
  SharedSecret *shared_secret;
296
425
 
297
426
  shared_secret = (SharedSecret*)in_shared_secret;
427
+ explicit_bzero(shared_secret->data, sizeof(shared_secret->data));
298
428
  xfree(shared_secret);
299
429
  }
300
430
 
431
+ static size_t
432
+ SharedSecret_memsize(const void *data)
433
+ {
434
+ return data == NULL ? 0 : sizeof(SharedSecret);
435
+ }
436
+
301
437
  static const rb_data_type_t SharedSecret_DataType = {
302
438
  "SharedSecret",
303
- { 0, SharedSecret_free, 0 },
439
+ { 0, SharedSecret_free, SharedSecret_memsize },
304
440
  0, 0,
305
441
  RUBY_TYPED_FREE_IMMEDIATELY
306
442
  };
@@ -317,9 +453,15 @@ SchnorrSignature_free(void *in_schnorr_sig)
317
453
  xfree(schnorr_sig);
318
454
  }
319
455
 
456
+ static size_t
457
+ SchnorrSignature_memsize(const void *data)
458
+ {
459
+ return data == NULL ? 0 : sizeof(SchnorrSignature);
460
+ }
461
+
320
462
  static const rb_data_type_t SchnorrSignature_DataType = {
321
463
  "SchnorrSignature",
322
- { 0, SchnorrSignature_free, 0 },
464
+ { 0, SchnorrSignature_free, SchnorrSignature_memsize },
323
465
  0, 0,
324
466
  RUBY_TYPED_FREE_IMMEDIATELY
325
467
  };
@@ -419,27 +561,22 @@ RecoverableSignData(secp256k1_context *in_context,
419
561
  static VALUE
420
562
  XOnlyPublicKey_alloc(VALUE klass)
421
563
  {
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;
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);
430
566
  }
431
567
 
432
568
  static VALUE
433
- XOnlyPublicKey_create_from_data(unsigned char *in_xonly_pubkey32)
569
+ XOnlyPublicKey_create_from_data(VALUE in_data)
434
570
  {
435
571
  XOnlyPublicKey *xonly_pubkey;
436
572
  VALUE result;
437
573
 
438
574
  result = XOnlyPublicKey_alloc(Secp256k1_XOnlyPublicKey_class);
439
- TypedData_Get_Struct(result, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
575
+ CheckedTypedData_Get_Struct(result, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
440
576
 
441
- if (secp256k1_xonly_pubkey_parse(secp256k1_context_static, &xonly_pubkey->pubkey, in_xonly_pubkey32) != 1)
577
+ if (secp256k1_xonly_pubkey_parse(secp256k1_context_static, &xonly_pubkey->pubkey, (unsigned char*)RSTRING_PTR(in_data)) != 1)
442
578
  {
579
+ NativeValue_invalidate(result);
443
580
  rb_raise(Secp256k1_DeserializationError_class, "invalid x-only public key data");
444
581
  return Qnil;
445
582
  }
@@ -458,8 +595,6 @@ XOnlyPublicKey_create_from_data(unsigned char *in_xonly_pubkey32)
458
595
  static VALUE
459
596
  XOnlyPublicKey_from_data(VALUE klass, VALUE in_xonly_public_key_serialized)
460
597
  {
461
- unsigned char *xonly_pubkey_data;
462
-
463
598
  Check_Type(in_xonly_public_key_serialized, T_STRING);
464
599
  if (RSTRING_LEN(in_xonly_public_key_serialized) != 32)
465
600
  {
@@ -467,8 +602,7 @@ XOnlyPublicKey_from_data(VALUE klass, VALUE in_xonly_public_key_serialized)
467
602
  return Qnil;
468
603
  }
469
604
 
470
- xonly_pubkey_data = (unsigned char*)StringValuePtr(in_xonly_public_key_serialized);
471
- return XOnlyPublicKey_create_from_data(xonly_pubkey_data);
605
+ return XOnlyPublicKey_create_from_data(in_xonly_public_key_serialized);
472
606
  }
473
607
 
474
608
  /**
@@ -483,7 +617,7 @@ XOnlyPublicKey_serialized(VALUE self)
483
617
  XOnlyPublicKey* xonly_pubkey;
484
618
  unsigned char out[SERIALIZED_XONLY_PUBKEY_SIZE_BYTES];
485
619
 
486
- TypedData_Get_Struct(self, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
620
+ CheckedTypedData_Get_Struct(self, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
487
621
 
488
622
  if (secp256k1_xonly_pubkey_serialize(secp256k1_context_static, out, &xonly_pubkey->pubkey) != 1)
489
623
  {
@@ -506,8 +640,8 @@ XOnlyPublicKey_equals(VALUE self, VALUE other)
506
640
  XOnlyPublicKey *lhs;
507
641
  XOnlyPublicKey *rhs;
508
642
 
509
- TypedData_Get_Struct(self, XOnlyPublicKey, &XOnlyPublicKey_DataType, lhs);
510
- TypedData_Get_Struct(other, XOnlyPublicKey, &XOnlyPublicKey_DataType, rhs);
643
+ CheckedTypedData_Get_Struct(self, XOnlyPublicKey, &XOnlyPublicKey_DataType, lhs);
644
+ CheckedTypedData_Get_Struct(other, XOnlyPublicKey, &XOnlyPublicKey_DataType, rhs);
511
645
 
512
646
  if (secp256k1_xonly_pubkey_cmp(secp256k1_context_static, &lhs->pubkey, &rhs->pubkey) == 0)
513
647
  {
@@ -524,31 +658,24 @@ XOnlyPublicKey_equals(VALUE self, VALUE other)
524
658
  static VALUE
525
659
  PublicKey_alloc(VALUE klass)
526
660
  {
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;
661
+ return rb_data_typed_object_zalloc(klass, sizeof(PublicKey), &PublicKey_DataType);
535
662
  }
536
663
 
537
664
  static VALUE
538
- PublicKey_create_from_data(unsigned char *in_public_key_data,
539
- unsigned int in_public_key_data_len)
665
+ PublicKey_create_from_data(VALUE in_data)
540
666
  {
541
667
  PublicKey *public_key;
542
668
  VALUE result;
543
669
 
544
670
  result = PublicKey_alloc(Secp256k1_PublicKey_class);
545
- TypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
671
+ CheckedTypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
546
672
 
547
673
  if (secp256k1_ec_pubkey_parse(secp256k1_context_static,
548
674
  &(public_key->pubkey),
549
- in_public_key_data,
550
- in_public_key_data_len) != 1)
675
+ (unsigned char*)RSTRING_PTR(in_data),
676
+ (size_t)RSTRING_LEN(in_data)) != 1)
551
677
  {
678
+ NativeValue_invalidate(result);
552
679
  rb_raise(Secp256k1_DeserializationError_class, "invalid public key data");
553
680
  return Qnil;
554
681
  }
@@ -567,15 +694,8 @@ PublicKey_create_from_data(unsigned char *in_public_key_data,
567
694
  static VALUE
568
695
  PublicKey_from_data(VALUE klass, VALUE in_public_key_data)
569
696
  {
570
- unsigned char *public_key_data;
571
-
572
697
  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
- );
698
+ return PublicKey_create_from_data(in_public_key_data);
579
699
  }
580
700
 
581
701
  /**
@@ -590,7 +710,7 @@ PublicKey_uncompressed(VALUE self)
590
710
  size_t serialized_pubkey_len = UNCOMPRESSED_PUBKEY_SIZE_BYTES;
591
711
  unsigned char serialized_pubkey[UNCOMPRESSED_PUBKEY_SIZE_BYTES];
592
712
 
593
- TypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
713
+ CheckedTypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
594
714
 
595
715
  secp256k1_ec_pubkey_serialize(secp256k1_context_static,
596
716
  serialized_pubkey,
@@ -613,7 +733,7 @@ PublicKey_compressed(VALUE self)
613
733
  size_t serialized_pubkey_len = COMPRESSED_PUBKEY_SIZE_BYTES;
614
734
  unsigned char serialized_pubkey[COMPRESSED_PUBKEY_SIZE_BYTES];
615
735
 
616
- TypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
736
+ CheckedTypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
617
737
 
618
738
  secp256k1_ec_pubkey_serialize(secp256k1_context_static,
619
739
  serialized_pubkey,
@@ -636,20 +756,22 @@ PublicKey_to_xonly(VALUE self)
636
756
  XOnlyPublicKey *xonly_pubkey;
637
757
  VALUE result;
638
758
 
639
- TypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
759
+ CheckedTypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
640
760
 
641
761
  result = XOnlyPublicKey_alloc(Secp256k1_XOnlyPublicKey_class);
642
- TypedData_Get_Struct(result, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
762
+ CheckedTypedData_Get_Struct(result, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
643
763
 
644
764
  if (secp256k1_xonly_pubkey_from_pubkey(secp256k1_context_static,
645
765
  &xonly_pubkey->pubkey,
646
766
  NULL,
647
767
  &public_key->pubkey) != 1)
648
768
  {
769
+ NativeValue_invalidate(result);
649
770
  rb_raise(Secp256k1_Error_class, "failed to convert pubkey to x-only pubkey");
650
771
  return Qnil;
651
772
  }
652
773
 
774
+ RB_GC_GUARD(self);
653
775
  return result;
654
776
  }
655
777
 
@@ -674,8 +796,8 @@ PublicKey_equals(VALUE self, VALUE other)
674
796
  lhs_len = 33;
675
797
  rhs_len = 33;
676
798
 
677
- TypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, lhs);
678
- TypedData_Get_Struct(other, PublicKey, &PublicKey_DataType, rhs);
799
+ CheckedTypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, lhs);
800
+ CheckedTypedData_Get_Struct(other, PublicKey, &PublicKey_DataType, rhs);
679
801
 
680
802
  secp256k1_ec_pubkey_serialize(
681
803
  secp256k1_context_static,
@@ -708,33 +830,26 @@ PublicKey_equals(VALUE self, VALUE other)
708
830
  static VALUE
709
831
  PrivateKey_alloc(VALUE klass)
710
832
  {
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;
833
+ return rb_data_typed_object_zalloc(klass, sizeof(PrivateKey), &PrivateKey_DataType);
719
834
  }
720
835
 
721
836
  /* Internal-only method for creating a private key from secret data */
722
837
  static VALUE
723
- PrivateKey_create(unsigned char *in_private_key_data)
838
+ PrivateKey_create(VALUE in_private_key_data)
724
839
  {
725
840
  PrivateKey *private_key;
726
841
  VALUE result;
727
842
 
728
843
  if (secp256k1_ec_seckey_verify(secp256k1_context_static,
729
- in_private_key_data) != 1)
844
+ (unsigned char*)RSTRING_PTR(in_private_key_data)) != 1)
730
845
  {
731
846
  rb_raise(Secp256k1_Error_class, "invalid private key data");
732
847
  return Qnil;
733
848
  }
734
849
 
735
850
  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);
851
+ CheckedTypedData_Get_Struct(result, PrivateKey, &PrivateKey_DataType, private_key);
852
+ MEMCPY(private_key->data, RSTRING_PTR(in_private_key_data), char, 32);
738
853
 
739
854
  return result;
740
855
  }
@@ -748,10 +863,13 @@ static VALUE
748
863
  PrivateKey_data(VALUE self)
749
864
  {
750
865
  PrivateKey *private_key;
866
+ VALUE result;
751
867
 
752
- TypedData_Get_Struct(self, PrivateKey, &PrivateKey_DataType, private_key);
868
+ CheckedTypedData_Get_Struct(self, PrivateKey, &PrivateKey_DataType, private_key);
753
869
 
754
- return(rb_str_new((char*)private_key->data, 32));
870
+ result = rb_str_new((char*)private_key->data, 32);
871
+ RB_GC_GUARD(self);
872
+ return result;
755
873
  }
756
874
 
757
875
  /**
@@ -765,8 +883,6 @@ PrivateKey_data(VALUE self)
765
883
  static VALUE
766
884
  PrivateKey_from_data(VALUE klass, VALUE in_private_key_data)
767
885
  {
768
- unsigned char *private_key_data;
769
-
770
886
  Check_Type(in_private_key_data, T_STRING);
771
887
  if (RSTRING_LEN(in_private_key_data) != 32)
772
888
  {
@@ -777,8 +893,7 @@ PrivateKey_from_data(VALUE klass, VALUE in_private_key_data)
777
893
  return Qnil;
778
894
  }
779
895
 
780
- private_key_data = (unsigned char*)StringValuePtr(in_private_key_data);
781
- return PrivateKey_create(private_key_data);
896
+ return PrivateKey_create(in_private_key_data);
782
897
  }
783
898
 
784
899
  /**
@@ -795,8 +910,8 @@ PrivateKey_equals(VALUE self, VALUE other)
795
910
  PrivateKey *lhs;
796
911
  PrivateKey *rhs;
797
912
 
798
- TypedData_Get_Struct(self, PrivateKey, &PrivateKey_DataType, lhs);
799
- TypedData_Get_Struct(other, PrivateKey, &PrivateKey_DataType, rhs);
913
+ CheckedTypedData_Get_Struct(self, PrivateKey, &PrivateKey_DataType, lhs);
914
+ CheckedTypedData_Get_Struct(other, PrivateKey, &PrivateKey_DataType, rhs);
800
915
 
801
916
  if (memcmp(lhs->data, rhs->data, 32) == 0)
802
917
  {
@@ -813,11 +928,7 @@ PrivateKey_equals(VALUE self, VALUE other)
813
928
  static VALUE
814
929
  KeyPair_alloc(VALUE klass)
815
930
  {
816
- KeyPair *key_pair;
817
-
818
- key_pair = ALLOC(KeyPair);
819
-
820
- return TypedData_Wrap_Struct(klass, &KeyPair_DataType, key_pair);
931
+ return rb_data_typed_object_zalloc(klass, sizeof(KeyPair), &KeyPair_DataType);
821
932
  }
822
933
 
823
934
  /**
@@ -832,17 +943,19 @@ KeyPair_public_key(VALUE self)
832
943
  VALUE result;
833
944
  PublicKey *public_key;
834
945
 
835
- TypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, key_pair);
946
+ CheckedTypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, key_pair);
836
947
 
837
948
  result = PublicKey_alloc(Secp256k1_PublicKey_class);
838
- TypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
949
+ CheckedTypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
839
950
 
840
951
  if (secp256k1_keypair_pub(secp256k1_context_static, &public_key->pubkey, &key_pair->keypair) == 0)
841
952
  {
953
+ NativeValue_invalidate(result);
842
954
  rb_raise(Secp256k1_Error_class, "failed to derive public key from keypair");
843
955
  return Qnil;
844
956
  }
845
957
 
958
+ RB_GC_GUARD(self);
846
959
  return result;
847
960
  }
848
961
 
@@ -859,17 +972,19 @@ KeyPair_xonly_public_key(VALUE self)
859
972
  VALUE result;
860
973
  XOnlyPublicKey *xonly_pubkey;
861
974
 
862
- TypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, key_pair);
975
+ CheckedTypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, key_pair);
863
976
 
864
977
  result = XOnlyPublicKey_alloc(Secp256k1_XOnlyPublicKey_class);
865
- TypedData_Get_Struct(result, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
978
+ CheckedTypedData_Get_Struct(result, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
866
979
 
867
980
  if (secp256k1_keypair_xonly_pub(secp256k1_context_static, &xonly_pubkey->pubkey, NULL, &key_pair->keypair) == 0)
868
981
  {
982
+ NativeValue_invalidate(result);
869
983
  rb_raise(Secp256k1_Error_class, "failed to derive x-only public key from keypair");
870
984
  return Qnil;
871
985
  }
872
986
 
987
+ RB_GC_GUARD(self);
873
988
  return result;
874
989
  }
875
990
 
@@ -882,17 +997,31 @@ static VALUE
882
997
  KeyPair_private_key(VALUE self)
883
998
  {
884
999
  KeyPair *key_pair;
885
- unsigned char private_key_data[32];
1000
+ PrivateKey *private_key;
1001
+ VALUE result;
886
1002
 
887
- TypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, key_pair);
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);
888
1008
 
889
- if (secp256k1_keypair_sec(secp256k1_context_static, private_key_data, &key_pair->keypair) == 0)
1009
+ if (secp256k1_keypair_sec(secp256k1_context_static, private_key->data, &key_pair->keypair) == 0)
890
1010
  {
1011
+ NativeValue_invalidate(result);
891
1012
  rb_raise(Secp256k1_Error_class, "failed to derive private key from keypair");
892
1013
  return Qnil;
893
1014
  }
894
1015
 
895
- return PrivateKey_create(private_key_data);
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;
896
1025
  }
897
1026
 
898
1027
  /**
@@ -910,8 +1039,8 @@ KeyPair_equals(VALUE self, VALUE other)
910
1039
  KeyPair *lhs;
911
1040
  KeyPair *rhs;
912
1041
 
913
- TypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, lhs);
914
- TypedData_Get_Struct(other, KeyPair, &KeyPair_DataType, rhs);
1042
+ CheckedTypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, lhs);
1043
+ CheckedTypedData_Get_Struct(other, KeyPair, &KeyPair_DataType, rhs);
915
1044
 
916
1045
  if (memcmp(&lhs->keypair, &rhs->keypair, sizeof(secp256k1_keypair)) == 0)
917
1046
  {
@@ -928,14 +1057,7 @@ KeyPair_equals(VALUE self, VALUE other)
928
1057
  static VALUE
929
1058
  Signature_alloc(VALUE klass)
930
1059
  {
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;
1060
+ return rb_data_typed_object_zalloc(klass, sizeof(Signature), &Signature_DataType);
939
1061
  }
940
1062
 
941
1063
  /**
@@ -960,15 +1082,15 @@ Signature_from_compact(VALUE klass, VALUE in_compact_signature)
960
1082
  rb_raise(Secp256k1_Error_class, "compact signature must be 64 bytes");
961
1083
  }
962
1084
 
963
- signature_data = (unsigned char*)StringValuePtr(in_compact_signature);
964
-
965
1085
  signature_result = Signature_alloc(Secp256k1_Signature_class);
966
- TypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
1086
+ CheckedTypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
1087
+ signature_data = (unsigned char*)RSTRING_PTR(in_compact_signature);
967
1088
 
968
1089
  if (secp256k1_ecdsa_signature_parse_compact(secp256k1_context_static,
969
1090
  &(signature->sig),
970
1091
  signature_data) != 1)
971
1092
  {
1093
+ NativeValue_invalidate(signature_result);
972
1094
  rb_raise(Secp256k1_DeserializationError_class, "invalid compact signature");
973
1095
  return Qnil;
974
1096
  }
@@ -994,16 +1116,16 @@ Signature_from_der_encoded(VALUE klass, VALUE in_der_encoded_signature)
994
1116
 
995
1117
  Check_Type(in_der_encoded_signature, T_STRING);
996
1118
 
997
- signature_data = (unsigned char*)StringValuePtr(in_der_encoded_signature);
998
-
999
1119
  signature_result = Signature_alloc(Secp256k1_Signature_class);
1000
- TypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
1120
+ CheckedTypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
1121
+ signature_data = (unsigned char*)RSTRING_PTR(in_der_encoded_signature);
1001
1122
 
1002
1123
  if (secp256k1_ecdsa_signature_parse_der(secp256k1_context_static,
1003
1124
  &(signature->sig),
1004
1125
  signature_data,
1005
1126
  RSTRING_LEN(in_der_encoded_signature)) != 1)
1006
1127
  {
1128
+ NativeValue_invalidate(signature_result);
1007
1129
  rb_raise(Secp256k1_DeserializationError_class, "invalid DER encoded signature");
1008
1130
  return Qnil;
1009
1131
  }
@@ -1021,12 +1143,11 @@ Signature_der_encoded(VALUE self)
1021
1143
  {
1022
1144
  // TODO: Cache value after first computation
1023
1145
  Signature *signature;
1024
- unsigned long der_signature_len;
1025
1146
  unsigned char der_signature[72];
1147
+ size_t der_signature_len = sizeof(der_signature);
1026
1148
 
1027
- TypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
1149
+ CheckedTypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
1028
1150
 
1029
- der_signature_len = 72;
1030
1151
  if (secp256k1_ecdsa_signature_serialize_der(secp256k1_context_static,
1031
1152
  der_signature,
1032
1153
  &der_signature_len,
@@ -1039,7 +1160,8 @@ Signature_der_encoded(VALUE self)
1039
1160
  return Qnil;
1040
1161
  }
1041
1162
 
1042
- return rb_str_new((char*)der_signature, der_signature_len);
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);
1043
1165
  }
1044
1166
 
1045
1167
  /**
@@ -1054,7 +1176,7 @@ Signature_compact(VALUE self)
1054
1176
  Signature *signature;
1055
1177
  unsigned char compact_signature[COMPACT_SIG_SIZE_BYTES];
1056
1178
 
1057
- TypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
1179
+ CheckedTypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
1058
1180
 
1059
1181
  if (secp256k1_ecdsa_signature_serialize_compact(secp256k1_context_static,
1060
1182
  compact_signature,
@@ -1090,9 +1212,9 @@ Signature_normalized(VALUE self)
1090
1212
  Signature *signature;
1091
1213
  Signature *normalized_signature;
1092
1214
 
1093
- TypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
1215
+ CheckedTypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
1094
1216
  result_sig = Signature_alloc(Secp256k1_Signature_class);
1095
- TypedData_Get_Struct(
1217
+ CheckedTypedData_Get_Struct(
1096
1218
  result_sig, Signature, &Signature_DataType, normalized_signature
1097
1219
  );
1098
1220
 
@@ -1105,6 +1227,7 @@ Signature_normalized(VALUE self)
1105
1227
  was_normalized = Qtrue;
1106
1228
  }
1107
1229
 
1230
+ RB_GC_GUARD(self);
1108
1231
  result = rb_ary_new2(2);
1109
1232
  rb_ary_push(result, was_normalized);
1110
1233
  rb_ary_push(result, result_sig);
@@ -1128,8 +1251,8 @@ Signature_equals(VALUE self, VALUE other)
1128
1251
  unsigned char lhs_compact[64];
1129
1252
  unsigned char rhs_compact[64];
1130
1253
 
1131
- TypedData_Get_Struct(self, Signature, &Signature_DataType, lhs);
1132
- TypedData_Get_Struct(other, Signature, &Signature_DataType, rhs);
1254
+ CheckedTypedData_Get_Struct(self, Signature, &Signature_DataType, lhs);
1255
+ CheckedTypedData_Get_Struct(other, Signature, &Signature_DataType, rhs);
1133
1256
 
1134
1257
  secp256k1_ecdsa_signature_serialize_compact(
1135
1258
  secp256k1_context_static, lhs_compact, &(lhs->sig)
@@ -1155,16 +1278,7 @@ Signature_equals(VALUE self, VALUE other)
1155
1278
  static VALUE
1156
1279
  RecoverableSignature_alloc(VALUE klass)
1157
1280
  {
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;
1281
+ return rb_data_typed_object_zalloc(klass, sizeof(RecoverableSignature), &RecoverableSignature_DataType);
1168
1282
  }
1169
1283
 
1170
1284
  /**
@@ -1182,7 +1296,7 @@ RecoverableSignature_compact(VALUE self)
1182
1296
  int recovery_id;
1183
1297
  VALUE result;
1184
1298
 
1185
- TypedData_Get_Struct(
1299
+ CheckedTypedData_Get_Struct(
1186
1300
  self,
1187
1301
  RecoverableSignature,
1188
1302
  &RecoverableSignature_DataType,
@@ -1223,7 +1337,7 @@ RecoverableSignature_to_signature(VALUE self)
1223
1337
  Signature *signature;
1224
1338
  VALUE result;
1225
1339
 
1226
- TypedData_Get_Struct(
1340
+ CheckedTypedData_Get_Struct(
1227
1341
  self,
1228
1342
  RecoverableSignature,
1229
1343
  &RecoverableSignature_DataType,
@@ -1231,7 +1345,7 @@ RecoverableSignature_to_signature(VALUE self)
1231
1345
  );
1232
1346
 
1233
1347
  result = Signature_alloc(Secp256k1_Signature_class);
1234
- TypedData_Get_Struct(
1348
+ CheckedTypedData_Get_Struct(
1235
1349
  result,
1236
1350
  Signature,
1237
1351
  &Signature_DataType,
@@ -1244,6 +1358,7 @@ RecoverableSignature_to_signature(VALUE self)
1244
1358
  &(signature->sig),
1245
1359
  &(recoverable_signature->sig));
1246
1360
 
1361
+ RB_GC_GUARD(self);
1247
1362
  return result;
1248
1363
  }
1249
1364
 
@@ -1271,25 +1386,27 @@ RecoverableSignature_recover_public_key(VALUE self, VALUE in_hash32)
1271
1386
  return Qnil;
1272
1387
  }
1273
1388
 
1274
- TypedData_Get_Struct(
1389
+ CheckedTypedData_Get_Struct(
1275
1390
  self,
1276
1391
  RecoverableSignature,
1277
1392
  &RecoverableSignature_DataType,
1278
1393
  recoverable_signature
1279
1394
  );
1280
- hash32 = (unsigned char*)StringValuePtr(in_hash32);
1281
1395
 
1282
1396
  result = PublicKey_alloc(Secp256k1_PublicKey_class);
1283
- TypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
1397
+ CheckedTypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
1398
+ hash32 = (unsigned char*)RSTRING_PTR(in_hash32);
1284
1399
 
1285
1400
  if (secp256k1_ecdsa_recover(recoverable_signature->ctx,
1286
1401
  &(public_key->pubkey),
1287
1402
  &(recoverable_signature->sig),
1288
1403
  hash32) == 1)
1289
1404
  {
1405
+ RB_GC_GUARD(self);
1290
1406
  return result;
1291
1407
  }
1292
1408
 
1409
+ NativeValue_invalidate(result);
1293
1410
  rb_raise(Secp256k1_DeserializationError_class, "unable to recover public key");
1294
1411
  }
1295
1412
 
@@ -1310,10 +1427,10 @@ RecoverableSignature_equals(VALUE self, VALUE other)
1310
1427
  RecoverableSignature *lhs;
1311
1428
  RecoverableSignature *rhs;
1312
1429
 
1313
- TypedData_Get_Struct(
1430
+ CheckedTypedData_Get_Struct(
1314
1431
  self, RecoverableSignature, &RecoverableSignature_DataType, lhs
1315
1432
  );
1316
- TypedData_Get_Struct(
1433
+ CheckedTypedData_Get_Struct(
1317
1434
  other, RecoverableSignature, &RecoverableSignature_DataType, rhs
1318
1435
  );
1319
1436
 
@@ -1340,16 +1457,7 @@ RecoverableSignature_equals(VALUE self, VALUE other)
1340
1457
  static VALUE
1341
1458
  SharedSecret_alloc(VALUE klass)
1342
1459
  {
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;
1460
+ return rb_data_typed_object_zalloc(klass, sizeof(SharedSecret), &SharedSecret_DataType);
1353
1461
  }
1354
1462
 
1355
1463
  #endif // HAVE_SECP256K1_ECDH_H
@@ -1363,14 +1471,7 @@ SharedSecret_alloc(VALUE klass)
1363
1471
  static VALUE
1364
1472
  SchnorrSignature_alloc(VALUE klass)
1365
1473
  {
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;
1474
+ return rb_data_typed_object_zalloc(klass, sizeof(SchnorrSignature), &SchnorrSignature_DataType);
1374
1475
  }
1375
1476
 
1376
1477
  static VALUE
@@ -1387,10 +1488,9 @@ SchnorrSignature_from_data(VALUE klass, VALUE in_data)
1387
1488
  return Qnil;
1388
1489
  }
1389
1490
 
1390
- schnorr_data = (unsigned char*)StringValuePtr(in_data);
1391
-
1392
1491
  result = SchnorrSignature_alloc(Secp256k1_SchnorrSignature_class);
1393
- TypedData_Get_Struct(result, SchnorrSignature, &SchnorrSignature_DataType, sig);
1492
+ CheckedTypedData_Get_Struct(result, SchnorrSignature, &SchnorrSignature_DataType, sig);
1493
+ schnorr_data = (unsigned char*)RSTRING_PTR(in_data);
1394
1494
 
1395
1495
  memcpy(sig->sig, schnorr_data, SCHNORR_SIG_SIZE_BYTES);
1396
1496
 
@@ -1401,10 +1501,13 @@ static VALUE
1401
1501
  SchnorrSignature_serialized(VALUE self)
1402
1502
  {
1403
1503
  SchnorrSignature *schnorr_sig;
1504
+ VALUE result;
1404
1505
 
1405
- TypedData_Get_Struct(self, SchnorrSignature, &SchnorrSignature_DataType, schnorr_sig);
1506
+ CheckedTypedData_Get_Struct(self, SchnorrSignature, &SchnorrSignature_DataType, schnorr_sig);
1406
1507
 
1407
- return rb_str_new((char*)schnorr_sig->sig, SCHNORR_SIG_SIZE_BYTES);
1508
+ result = rb_str_new((char*)schnorr_sig->sig, SCHNORR_SIG_SIZE_BYTES);
1509
+ RB_GC_GUARD(self);
1510
+ return result;
1408
1511
  }
1409
1512
 
1410
1513
  static VALUE
@@ -1414,11 +1517,11 @@ SchnorrSignature_verify(VALUE self, VALUE in_message, VALUE in_xonly_pubkey)
1414
1517
  SchnorrSignature *schnorr_sig;
1415
1518
  unsigned char* msg;
1416
1519
 
1417
- TypedData_Get_Struct(self, SchnorrSignature, &SchnorrSignature_DataType, schnorr_sig);
1418
- TypedData_Get_Struct(in_xonly_pubkey, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
1520
+ CheckedTypedData_Get_Struct(self, SchnorrSignature, &SchnorrSignature_DataType, schnorr_sig);
1521
+ CheckedTypedData_Get_Struct(in_xonly_pubkey, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
1419
1522
  Check_Type(in_message, T_STRING);
1420
1523
 
1421
- msg = (unsigned char*)StringValuePtr(in_message);
1524
+ msg = (unsigned char*)RSTRING_PTR(in_message);
1422
1525
  if (secp256k1_schnorrsig_verify(secp256k1_context_static, schnorr_sig->sig, msg, RSTRING_LEN(in_message), &xonly_pubkey->pubkey) != 1)
1423
1526
  {
1424
1527
  return Qfalse;
@@ -1433,8 +1536,8 @@ SchnorrSignature_equals(VALUE self, VALUE other)
1433
1536
  SchnorrSignature *lhs;
1434
1537
  SchnorrSignature *rhs;
1435
1538
 
1436
- TypedData_Get_Struct(self, SchnorrSignature, &SchnorrSignature_DataType, lhs);
1437
- TypedData_Get_Struct(other, SchnorrSignature, &SchnorrSignature_DataType, rhs);
1539
+ CheckedTypedData_Get_Struct(self, SchnorrSignature, &SchnorrSignature_DataType, lhs);
1540
+ CheckedTypedData_Get_Struct(other, SchnorrSignature, &SchnorrSignature_DataType, rhs);
1438
1541
 
1439
1542
  if (memcmp(lhs->sig, rhs->sig, SCHNORR_SIG_SIZE_BYTES) == 0)
1440
1543
  {
@@ -1454,15 +1557,7 @@ SchnorrSignature_equals(VALUE self, VALUE other)
1454
1557
  static VALUE
1455
1558
  Context_alloc(VALUE klass)
1456
1559
  {
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;
1560
+ return rb_data_typed_object_zalloc(klass, sizeof(Context), &Context_DataType);
1466
1561
  }
1467
1562
 
1468
1563
  /**
@@ -1481,6 +1576,7 @@ static VALUE
1481
1576
  Context_initialize(int argc, const VALUE* argv, VALUE self)
1482
1577
  {
1483
1578
  Context *context;
1579
+ secp256k1_context *new_context;
1484
1580
  unsigned char *seed32;
1485
1581
  VALUE context_randomization_bytes;
1486
1582
  VALUE opts;
@@ -1492,11 +1588,12 @@ Context_initialize(int argc, const VALUE* argv, VALUE self)
1492
1588
  CONST_ID(kwarg_ids, "context_randomization_bytes");
1493
1589
  }
1494
1590
 
1495
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1496
-
1497
- context->ctx = secp256k1_context_create(
1498
- SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY
1499
- );
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
+ }
1500
1597
 
1501
1598
  // Handle optional second argument containing random bytes to use for
1502
1599
  // randomization. We pass ":" to rb_scan_args to say that we expect keyword
@@ -1523,13 +1620,21 @@ Context_initialize(int argc, const VALUE* argv, VALUE self)
1523
1620
  "context_randomization_bytes must be 32 bytes in length"
1524
1621
  );
1525
1622
  }
1623
+ }
1526
1624
 
1527
- seed32 = (unsigned char*)StringValuePtr(context_randomization_bytes);
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);
1528
1632
 
1529
1633
  // Randomize the context at initialization time rather than before calls so
1530
1634
  // the same context can be used across threads safely.
1531
- if (secp256k1_context_randomize(context->ctx, seed32) != 1)
1635
+ if (secp256k1_context_randomize(new_context, seed32) != 1)
1532
1636
  {
1637
+ secp256k1_context_destroy(new_context);
1533
1638
  rb_raise(
1534
1639
  Secp256k1_Error_class,
1535
1640
  "context randomization failed"
@@ -1537,6 +1642,7 @@ Context_initialize(int argc, const VALUE* argv, VALUE self)
1537
1642
  }
1538
1643
  }
1539
1644
 
1645
+ context->ctx = new_context;
1540
1646
  return self;
1541
1647
  }
1542
1648
 
@@ -1557,7 +1663,7 @@ Context_key_pair_from_private_key(VALUE self, VALUE in_private_key_data)
1557
1663
  unsigned char *private_key_data;
1558
1664
 
1559
1665
  Check_Type(in_private_key_data, T_STRING);
1560
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1666
+ context = Context_get(self);
1561
1667
 
1562
1668
  if (RSTRING_LEN(in_private_key_data) != 32)
1563
1669
  {
@@ -1566,15 +1672,17 @@ Context_key_pair_from_private_key(VALUE self, VALUE in_private_key_data)
1566
1672
  }
1567
1673
 
1568
1674
  result = KeyPair_alloc(Secp256k1_KeyPair_class);
1569
- TypedData_Get_Struct(result, KeyPair, &KeyPair_DataType, keypair);
1675
+ CheckedTypedData_Get_Struct(result, KeyPair, &KeyPair_DataType, keypair);
1570
1676
 
1571
- private_key_data = (unsigned char*)StringValuePtr(in_private_key_data);
1677
+ private_key_data = (unsigned char*)RSTRING_PTR(in_private_key_data);
1572
1678
 
1573
1679
  if (secp256k1_keypair_create(context->ctx, &keypair->keypair, private_key_data) == 0)
1574
1680
  {
1681
+ NativeValue_invalidate(result);
1575
1682
  rb_raise(Secp256k1_Error_class, "invalid secret when attempting to create keypair");
1576
1683
  }
1577
1684
 
1685
+ RB_GC_GUARD(self);
1578
1686
  return result;
1579
1687
  }
1580
1688
 
@@ -1605,12 +1713,12 @@ Context_sign(VALUE self, VALUE in_private_key, VALUE in_hash32)
1605
1713
  return Qnil;
1606
1714
  }
1607
1715
 
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);
1716
+ context = Context_get(self);
1717
+ CheckedTypedData_Get_Struct(in_private_key, PrivateKey, &PrivateKey_DataType, private_key);
1611
1718
 
1612
1719
  signature_result = Signature_alloc(Secp256k1_Signature_class);
1613
- TypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
1720
+ CheckedTypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
1721
+ hash32 = (unsigned char*)RSTRING_PTR(in_hash32);
1614
1722
 
1615
1723
  // Attempt to sign the hash of the given data
1616
1724
  if (SUCCESS(SignData(context->ctx,
@@ -1618,9 +1726,12 @@ Context_sign(VALUE self, VALUE in_private_key, VALUE in_hash32)
1618
1726
  private_key->data,
1619
1727
  &(signature->sig))))
1620
1728
  {
1729
+ RB_GC_GUARD(self);
1730
+ RB_GC_GUARD(in_private_key);
1621
1731
  return signature_result;
1622
1732
  }
1623
1733
 
1734
+ NativeValue_invalidate(signature_result);
1624
1735
  rb_raise(Secp256k1_Error_class, "unable to compute signature");
1625
1736
  return Qnil;
1626
1737
  }
@@ -1643,10 +1754,10 @@ Context_tagged_sha256(VALUE self, VALUE in_tag, VALUE in_message)
1643
1754
  Check_Type(in_tag, T_STRING);
1644
1755
  Check_Type(in_message, T_STRING);
1645
1756
 
1646
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1757
+ context = Context_get(self);
1647
1758
 
1648
- tag = (unsigned char*)StringValuePtr(in_tag);
1649
- msg = (unsigned char*)StringValuePtr(in_message);
1759
+ tag = (unsigned char*)RSTRING_PTR(in_tag);
1760
+ msg = (unsigned char*)RSTRING_PTR(in_message);
1650
1761
 
1651
1762
  if (secp256k1_tagged_sha256(context->ctx, hash32, tag, RSTRING_LEN(in_tag), msg, RSTRING_LEN(in_message)) != 1)
1652
1763
  {
@@ -1683,11 +1794,11 @@ Context_verify(VALUE self, VALUE in_signature, VALUE in_pubkey, VALUE in_hash32)
1683
1794
  rb_raise(Secp256k1_Error_class, "in_hash32 is not 32-bytes in length");
1684
1795
  }
1685
1796
 
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);
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);
1689
1800
 
1690
- hash32 = (unsigned char*)StringValuePtr(in_hash32);
1801
+ hash32 = (unsigned char*)RSTRING_PTR(in_hash32);
1691
1802
 
1692
1803
  if (secp256k1_ecdsa_verify(context->ctx,
1693
1804
  &(signature->sig),
@@ -1729,19 +1840,19 @@ Context_sign_recoverable(VALUE self, VALUE in_private_key, VALUE in_hash32)
1729
1840
  return Qnil;
1730
1841
  }
1731
1842
 
1732
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1733
- TypedData_Get_Struct(
1843
+ context = Context_get(self);
1844
+ CheckedTypedData_Get_Struct(
1734
1845
  in_private_key, PrivateKey, &PrivateKey_DataType, private_key
1735
1846
  );
1736
- hash32 = (unsigned char*)StringValuePtr(in_hash32);
1737
1847
 
1738
1848
  result = RecoverableSignature_alloc(Secp256k1_RecoverableSignature_class);
1739
- TypedData_Get_Struct(
1849
+ CheckedTypedData_Get_Struct(
1740
1850
  result,
1741
1851
  RecoverableSignature,
1742
1852
  &RecoverableSignature_DataType,
1743
1853
  recoverable_signature
1744
1854
  );
1855
+ hash32 = (unsigned char*)RSTRING_PTR(in_hash32);
1745
1856
 
1746
1857
  if (SUCCESS(RecoverableSignData(context->ctx,
1747
1858
  hash32,
@@ -1749,9 +1860,12 @@ Context_sign_recoverable(VALUE self, VALUE in_private_key, VALUE in_hash32)
1749
1860
  &(recoverable_signature->sig))))
1750
1861
  {
1751
1862
  recoverable_signature->ctx = secp256k1_context_clone(context->ctx);
1863
+ RB_GC_GUARD(self);
1864
+ RB_GC_GUARD(in_private_key);
1752
1865
  return result;
1753
1866
  }
1754
1867
 
1868
+ NativeValue_invalidate(result);
1755
1869
  rb_raise(Secp256k1_Error_class, "unable to compute recoverable signature");
1756
1870
  return Qnil;
1757
1871
  }
@@ -1780,9 +1894,8 @@ Context_recoverable_signature_from_compact(
1780
1894
 
1781
1895
  Check_Type(in_compact_sig, T_STRING);
1782
1896
  Check_Type(in_recovery_id, T_FIXNUM);
1783
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1897
+ context = Context_get(self);
1784
1898
 
1785
- compact_sig = (unsigned char*)StringValuePtr(in_compact_sig);
1786
1899
  recovery_id = FIX2INT(in_recovery_id);
1787
1900
 
1788
1901
  if (RSTRING_LEN(in_compact_sig) != 64)
@@ -1798,12 +1911,13 @@ Context_recoverable_signature_from_compact(
1798
1911
  }
1799
1912
 
1800
1913
  result = RecoverableSignature_alloc(Secp256k1_RecoverableSignature_class);
1801
- TypedData_Get_Struct(
1914
+ CheckedTypedData_Get_Struct(
1802
1915
  result,
1803
1916
  RecoverableSignature,
1804
1917
  &RecoverableSignature_DataType,
1805
1918
  recoverable_signature
1806
1919
  );
1920
+ compact_sig = (unsigned char*)RSTRING_PTR(in_compact_sig);
1807
1921
 
1808
1922
  if (secp256k1_ecdsa_recoverable_signature_parse_compact(
1809
1923
  context->ctx,
@@ -1812,9 +1926,11 @@ Context_recoverable_signature_from_compact(
1812
1926
  recovery_id) == 1)
1813
1927
  {
1814
1928
  recoverable_signature->ctx = secp256k1_context_clone(context->ctx);
1929
+ RB_GC_GUARD(self);
1815
1930
  return result;
1816
1931
  }
1817
1932
 
1933
+ NativeValue_invalidate(result);
1818
1934
  rb_raise(Secp256k1_DeserializationError_class, "unable to parse recoverable signature");
1819
1935
  return Qnil;
1820
1936
  }
@@ -1843,12 +1959,12 @@ Context_ecdh(VALUE self, VALUE point, VALUE scalar)
1843
1959
  SharedSecret *shared_secret;
1844
1960
  VALUE result;
1845
1961
 
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);
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);
1849
1965
 
1850
1966
  result = SharedSecret_alloc(Secp256k1_SharedSecret_class);
1851
- TypedData_Get_Struct(
1967
+ CheckedTypedData_Get_Struct(
1852
1968
  result, SharedSecret, &SharedSecret_DataType, shared_secret
1853
1969
  );
1854
1970
 
@@ -1859,12 +1975,16 @@ Context_ecdh(VALUE self, VALUE point, VALUE scalar)
1859
1975
  NULL,
1860
1976
  NULL) != 1)
1861
1977
  {
1978
+ NativeValue_invalidate(result);
1862
1979
  rb_raise(Secp256k1_Error_class, "invalid scalar provided to ecdh");
1863
1980
  return Qnil;
1864
1981
  }
1865
1982
 
1866
1983
  rb_iv_set(result, "@data", rb_str_new((char*)shared_secret->data, 32));
1867
1984
 
1985
+ RB_GC_GUARD(self);
1986
+ RB_GC_GUARD(point);
1987
+ RB_GC_GUARD(scalar);
1868
1988
  return result;
1869
1989
  }
1870
1990
 
@@ -1879,19 +1999,14 @@ Context_sign_schnorr_custom(VALUE self, VALUE in_keypair, VALUE in_message, VALU
1879
1999
  KeyPair* keypair;
1880
2000
  SchnorrSignature* schnorr_sig;
1881
2001
  unsigned char* msg;
1882
- unsigned char* auxrand;
2002
+ secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
1883
2003
  unsigned char sig[64];
1884
2004
  VALUE result;
1885
2005
 
1886
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1887
- TypedData_Get_Struct(in_keypair, KeyPair, &KeyPair_DataType, keypair);
2006
+ context = Context_get(self);
2007
+ CheckedTypedData_Get_Struct(in_keypair, KeyPair, &KeyPair_DataType, keypair);
1888
2008
 
1889
2009
  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
2010
 
1896
2011
  if (!NIL_P(in_auxrand))
1897
2012
  {
@@ -1903,17 +2018,17 @@ Context_sign_schnorr_custom(VALUE self, VALUE in_keypair, VALUE in_message, VALU
1903
2018
  }
1904
2019
  }
1905
2020
 
1906
- msg = (unsigned char*)StringValuePtr(in_message);
1907
- auxrand = (unsigned char*)StringValuePtr(in_auxrand);
2021
+ msg = (unsigned char*)RSTRING_PTR(in_message);
2022
+ extraparams.ndata = NIL_P(in_auxrand) ? NULL : (void*)RSTRING_PTR(in_auxrand);
1908
2023
 
1909
- if (secp256k1_schnorrsig_sign32(context->ctx, sig, msg, &keypair->keypair, auxrand) != 1)
2024
+ if (secp256k1_schnorrsig_sign_custom(context->ctx, sig, msg, (size_t)RSTRING_LEN(in_message), &keypair->keypair, &extraparams) != 1)
1910
2025
  {
1911
2026
  rb_raise(Secp256k1_Error_class, "schnorr signing failed");
1912
2027
  return Qnil;
1913
2028
  }
1914
2029
 
1915
2030
  result = SchnorrSignature_alloc(Secp256k1_SchnorrSignature_class);
1916
- TypedData_Get_Struct(result, SchnorrSignature, &SchnorrSignature_DataType, schnorr_sig);
2031
+ CheckedTypedData_Get_Struct(result, SchnorrSignature, &SchnorrSignature_DataType, schnorr_sig);
1917
2032
  memcpy(schnorr_sig->sig, sig, SCHNORR_SIG_SIZE_BYTES);
1918
2033
 
1919
2034
  return result;
@@ -1922,6 +2037,84 @@ Context_sign_schnorr_custom(VALUE self, VALUE in_keypair, VALUE in_message, VALU
1922
2037
  #endif // HAVE_SECP256K1_SCHNORRSIG_H
1923
2038
 
1924
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
+
1925
2118
  // Secp256k1 module methods
1926
2119
  //
1927
2120
 
@@ -2020,6 +2213,7 @@ void Init_rbsecp256k1(void)
2020
2213
  );
2021
2214
  rb_undef_alloc_func(Secp256k1_Context_class);
2022
2215
  rb_define_alloc_func(Secp256k1_Context_class, Context_alloc);
2216
+ rb_define_method(Secp256k1_Context_class, "initialize_copy", Context_initialize_copy, 1);
2023
2217
  rb_define_method(Secp256k1_Context_class,
2024
2218
  "initialize",
2025
2219
  Context_initialize,
@@ -2041,12 +2235,13 @@ void Init_rbsecp256k1(void)
2041
2235
  Context_verify,
2042
2236
  3);
2043
2237
 
2238
+ // Factories wrap initialized storage directly. Copy allocators create empty,
2239
+ // checked shells for Ruby dup/clone; direct construction is rejected.
2044
2240
  // Secp256k1::KeyPair
2045
2241
  Secp256k1_KeyPair_class = rb_define_class_under(Secp256k1_module,
2046
2242
  "KeyPair",
2047
2243
  rb_cObject);
2048
- rb_undef_alloc_func(Secp256k1_KeyPair_class);
2049
- rb_define_alloc_func(Secp256k1_KeyPair_class, KeyPair_alloc);
2244
+ ENABLE_VALUE_COPY(KeyPair);
2050
2245
  rb_define_method(Secp256k1_KeyPair_class, "public_key", KeyPair_public_key, 0);
2051
2246
  rb_define_method(Secp256k1_KeyPair_class, "private_key", KeyPair_private_key, 0);
2052
2247
  rb_define_method(Secp256k1_KeyPair_class, "xonly_public_key", KeyPair_xonly_public_key, 0);
@@ -2056,8 +2251,7 @@ void Init_rbsecp256k1(void)
2056
2251
  Secp256k1_PublicKey_class = rb_define_class_under(Secp256k1_module,
2057
2252
  "PublicKey",
2058
2253
  rb_cObject);
2059
- rb_undef_alloc_func(Secp256k1_PublicKey_class);
2060
- rb_define_alloc_func(Secp256k1_PublicKey_class, PublicKey_alloc);
2254
+ ENABLE_VALUE_COPY(PublicKey);
2061
2255
  rb_define_method(Secp256k1_PublicKey_class,
2062
2256
  "compressed",
2063
2257
  PublicKey_compressed,
@@ -2083,8 +2277,7 @@ void Init_rbsecp256k1(void)
2083
2277
  "XOnlyPublicKey",
2084
2278
  rb_cObject);
2085
2279
 
2086
- rb_undef_alloc_func(Secp256k1_XOnlyPublicKey_class);
2087
- rb_define_alloc_func(Secp256k1_XOnlyPublicKey_class, XOnlyPublicKey_alloc);
2280
+ ENABLE_VALUE_COPY(XOnlyPublicKey);
2088
2281
  rb_define_method(Secp256k1_XOnlyPublicKey_class,
2089
2282
  "serialized",
2090
2283
  XOnlyPublicKey_serialized,
@@ -2100,8 +2293,7 @@ void Init_rbsecp256k1(void)
2100
2293
  Secp256k1_PrivateKey_class = rb_define_class_under(
2101
2294
  Secp256k1_module, "PrivateKey", rb_cObject
2102
2295
  );
2103
- rb_undef_alloc_func(Secp256k1_PrivateKey_class);
2104
- rb_define_alloc_func(Secp256k1_PrivateKey_class, PrivateKey_alloc);
2296
+ ENABLE_VALUE_COPY(PrivateKey);
2105
2297
  rb_define_method(Secp256k1_PrivateKey_class, "data", PrivateKey_data, 0);
2106
2298
  rb_define_method(Secp256k1_PrivateKey_class, "==", PrivateKey_equals, 1);
2107
2299
  rb_define_singleton_method(
@@ -2115,8 +2307,7 @@ void Init_rbsecp256k1(void)
2115
2307
  Secp256k1_Signature_class = rb_define_class_under(Secp256k1_module,
2116
2308
  "Signature",
2117
2309
  rb_cObject);
2118
- rb_undef_alloc_func(Secp256k1_Signature_class);
2119
- rb_define_alloc_func(Secp256k1_Signature_class, Signature_alloc);
2310
+ ENABLE_VALUE_COPY(Signature);
2120
2311
  rb_define_method(Secp256k1_Signature_class,
2121
2312
  "der_encoded",
2122
2313
  Signature_der_encoded,
@@ -2153,11 +2344,7 @@ void Init_rbsecp256k1(void)
2153
2344
  "RecoverableSignature",
2154
2345
  rb_cObject
2155
2346
  );
2156
- rb_undef_alloc_func(Secp256k1_RecoverableSignature_class);
2157
- rb_define_alloc_func(
2158
- Secp256k1_RecoverableSignature_class,
2159
- RecoverableSignature_alloc
2160
- );
2347
+ ENABLE_VALUE_COPY(RecoverableSignature);
2161
2348
  rb_define_method(
2162
2349
  Secp256k1_RecoverableSignature_class,
2163
2350
  "compact",
@@ -2205,7 +2392,6 @@ void Init_rbsecp256k1(void)
2205
2392
  rb_cObject
2206
2393
  );
2207
2394
  rb_undef_alloc_func(Secp256k1_SharedSecret_class);
2208
- rb_define_alloc_func(Secp256k1_SharedSecret_class, SharedSecret_alloc);
2209
2395
  rb_define_attr(Secp256k1_SharedSecret_class, "data", 1, 0);
2210
2396
 
2211
2397
  // Context EC Diffie-Hellman methods
@@ -2222,8 +2408,7 @@ void Init_rbsecp256k1(void)
2222
2408
  Secp256k1_module,
2223
2409
  "SchnorrSignature",
2224
2410
  rb_cObject);
2225
- rb_undef_alloc_func(Secp256k1_SchnorrSignature_class);
2226
- rb_define_alloc_func(Secp256k1_SchnorrSignature_class, SchnorrSignature_alloc);
2411
+ ENABLE_VALUE_COPY(SchnorrSignature);
2227
2412
  rb_define_method(Secp256k1_SchnorrSignature_class, "serialized", SchnorrSignature_serialized, 0);
2228
2413
  rb_define_method(Secp256k1_SchnorrSignature_class, "verify", SchnorrSignature_verify, 2);
2229
2414
  rb_define_method(Secp256k1_SchnorrSignature_class, "==", SchnorrSignature_equals, 1);