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.
- checksums.yaml +4 -4
- data/README.md +6 -34
- data/documentation/context.md +21 -4
- data/documentation/index.md +63 -4
- data/documentation/key_pair.md +4 -7
- data/documentation/public_key.md +4 -0
- data/documentation/schnorr_signature.md +30 -0
- data/documentation/secp256k1.md +5 -0
- data/documentation/shared_secret.md +0 -2
- data/documentation/xonly_public_key.md +29 -0
- data/ext/rbsecp256k1/extconf.rb +19 -14
- data/ext/rbsecp256k1/rbsecp256k1.c +626 -117
- data/lib/rbsecp256k1/context.rb +7 -0
- data/lib/rbsecp256k1/version.rb +1 -1
- metadata +20 -4
@@ -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
|
-
//
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
{
|
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::
|
416
|
+
// Secp256k1::XOnlyPublicKey class interface
|
341
417
|
//
|
342
418
|
|
343
419
|
static VALUE
|
344
|
-
|
420
|
+
XOnlyPublicKey_alloc(VALUE klass)
|
345
421
|
{
|
346
|
-
|
422
|
+
VALUE result;
|
423
|
+
XOnlyPublicKey* xonly_pubkey;
|
347
424
|
|
348
|
-
|
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
|
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
|
-
*
|
451
|
+
* Loads an x-only public key from serialized data.
|
355
452
|
*
|
356
|
-
* @param
|
357
|
-
*
|
358
|
-
* @return [Secp256k1::
|
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
|
-
|
459
|
+
XOnlyPublicKey_from_data(VALUE klass, VALUE in_xonly_public_key_serialized)
|
362
460
|
{
|
363
|
-
|
461
|
+
unsigned char *xonly_pubkey_data;
|
364
462
|
|
365
|
-
|
366
|
-
|
367
|
-
|
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
|
-
|
370
|
-
|
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
|
-
|
373
|
-
rb_iv_set(self, "@private_key", in_private_key);
|
486
|
+
TypedData_Get_Struct(self, XOnlyPublicKey, &XOnlyPublicKey_DataType, xonly_pubkey);
|
374
487
|
|
375
|
-
|
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
|
498
|
+
* Compare two x-only public keys.
|
380
499
|
*
|
381
|
-
*
|
382
|
-
*
|
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
|
-
|
504
|
+
XOnlyPublicKey_equals(VALUE self, VALUE other)
|
389
505
|
{
|
390
|
-
|
391
|
-
|
392
|
-
VALUE public_keys_equal;
|
393
|
-
VALUE private_keys_equal;
|
506
|
+
XOnlyPublicKey *lhs;
|
507
|
+
XOnlyPublicKey *rhs;
|
394
508
|
|
395
|
-
TypedData_Get_Struct(self,
|
396
|
-
TypedData_Get_Struct(other,
|
509
|
+
TypedData_Get_Struct(self, XOnlyPublicKey, &XOnlyPublicKey_DataType, lhs);
|
510
|
+
TypedData_Get_Struct(other, XOnlyPublicKey, &XOnlyPublicKey_DataType, rhs);
|
397
511
|
|
398
|
-
|
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(
|
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(
|
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(
|
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
|
-
|
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
|
-
|
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(
|
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(
|
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(
|
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(
|
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(
|
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
|
-
|
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
|
-
|
1135
|
+
secp256k1_context_static, lhs_compact, &(lhs->sig)
|
885
1136
|
);
|
886
1137
|
secp256k1_ecdsa_signature_serialize_compact(
|
887
|
-
|
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
|
-
|
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
|
-
|
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
|
1211
|
-
|
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
|
-
|
1225
|
-
|
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
|
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
|
-
|
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
|
-
|
1586
|
-
|
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
|
-
|
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
|
}
|