rbsecp256k1 1.0.0 → 2.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/ext/rbsecp256k1/extconf.rb +8 -2
- data/ext/rbsecp256k1/rbsecp256k1.c +1211 -381
- data/lib/rbsecp256k1/util.rb +6 -0
- data/lib/rbsecp256k1/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5549a7ec71d1bddbefe1ea360d9316ea1bbe74f015e6676cfc7495a7b852831a
|
4
|
+
data.tar.gz: dada9673b8fdf01e29ca2a2479ac3ce92ff43ba736f577feb6e58515ae3ab240
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ac13a464fd1e0c5ee4378cea9f6b9c557d65b08e00a00f4dc94b64fc43822cec9c5e69463a450daa6725d12679a5e9440bb0e60a20f282346551099b64e2802
|
7
|
+
data.tar.gz: 58f2932b693056f4051094d43d68636c2a3d99c71d475c5c1e7ca9c062a4e5d956e844209956e7e4041351677e4c4b376bd4b4a0e9dbdc13dab7e52c099302d0
|
data/ext/rbsecp256k1/extconf.rb
CHANGED
@@ -1,13 +1,19 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
|
3
3
|
# OpenSSL flags
|
4
|
-
print("
|
4
|
+
print("checking for OpenSSL\n")
|
5
5
|
results = pkg_config('openssl')
|
6
6
|
abort "missing openssl pkg-config information" unless results[1]
|
7
7
|
|
8
8
|
# Require that libsecp256k1 be installed using `make install` or similar.
|
9
|
-
print("
|
9
|
+
print("checking for libsecp256k1\n")
|
10
10
|
results = pkg_config('libsecp256k1')
|
11
11
|
abort "missing libsecp256k1" unless results[1]
|
12
12
|
|
13
|
+
# Check if we have the libsecp256k1 recoverable signature header.
|
14
|
+
have_header('secp256k1_recovery.h')
|
15
|
+
|
16
|
+
# Check if we have EC Diffie-Hellman functionality
|
17
|
+
have_header('secp256k1_ecdh.h')
|
18
|
+
|
13
19
|
create_makefile('rbsecp256k1')
|
@@ -9,12 +9,21 @@
|
|
9
9
|
// * libsecp256k1
|
10
10
|
// * openssl
|
11
11
|
#include <ruby.h>
|
12
|
-
#include <stdio.h>
|
13
12
|
|
14
13
|
#include <openssl/rand.h>
|
15
|
-
|
14
|
+
|
16
15
|
#include <secp256k1.h>
|
17
16
|
|
17
|
+
// Include recoverable signatures functionality if available
|
18
|
+
#ifdef HAVE_SECP256K1_RECOVERY_H
|
19
|
+
#include <secp256k1_recovery.h>
|
20
|
+
#endif // HAVE_SECP256K1_RECOVERY_H
|
21
|
+
|
22
|
+
// Include EC Diffie-Hellman functionality
|
23
|
+
#ifdef HAVE_SECP256K1_ECDH_H
|
24
|
+
#include <secp256k1_ecdh.h>
|
25
|
+
#endif // HAVE_SECP256K1_ECDH_H
|
26
|
+
|
18
27
|
// High-level design:
|
19
28
|
//
|
20
29
|
// The Ruby wrapper is divided into the following hierarchical organization:
|
@@ -24,20 +33,30 @@
|
|
24
33
|
// |-- KeyPair
|
25
34
|
// |-- PublicKey
|
26
35
|
// |-- PrivateKey
|
36
|
+
// |-- RecoverableSignature
|
37
|
+
// |-- SharedSecret
|
27
38
|
// |-- Signature
|
28
39
|
//
|
29
40
|
// The Context class contains most of the methods that invoke libsecp256k1.
|
30
|
-
// The KayPair, PublicKey, PrivateKey,
|
31
|
-
// objects and are passed to various
|
32
|
-
//
|
33
|
-
//
|
34
|
-
// application when
|
41
|
+
// The KayPair, PublicKey, PrivateKey, RecoverableSignature, SharedSecret, and
|
42
|
+
// Signature objects act as data objects and are passed to various
|
43
|
+
// methods. Contexts are thread safe and can be used across
|
44
|
+
// applications. Context initialization is expensive so it is recommended that
|
45
|
+
// a single context be initialized and used throughout an application when
|
46
|
+
// possible.
|
35
47
|
|
36
48
|
//
|
37
49
|
// The section below contains purely internal methods used exclusively by the
|
38
50
|
// C internals of the library.
|
39
51
|
//
|
40
52
|
|
53
|
+
// Size of an uncompressed public key
|
54
|
+
const size_t UNCOMPRESSED_PUBKEY_SIZE_BYTES = 65;
|
55
|
+
// Size of a compressed public key
|
56
|
+
const size_t COMPRESSED_PUBKEY_SIZE_BYTES = 33;
|
57
|
+
// Size of a compact signature in bytes
|
58
|
+
const size_t COMPACT_SIG_SIZE_BYTES = 64;
|
59
|
+
|
41
60
|
// Globally define our module and its associated classes so we can instantiate
|
42
61
|
// objects from anywhere. The use of global variables seems to be inline with
|
43
62
|
// how the Ruby project builds its own extension gems.
|
@@ -48,6 +67,14 @@ static VALUE Secp256k1_PublicKey_class;
|
|
48
67
|
static VALUE Secp256k1_PrivateKey_class;
|
49
68
|
static VALUE Secp256k1_Signature_class;
|
50
69
|
|
70
|
+
#ifdef HAVE_SECP256K1_RECOVERY_H
|
71
|
+
static VALUE Secp256k1_RecoverableSignature_class;
|
72
|
+
#endif // HAVE_SECP256K1_RECOVERY_H
|
73
|
+
|
74
|
+
#ifdef HAVE_SECP256K1_ECDH_H
|
75
|
+
static VALUE Secp256k1_SharedSecret_class;
|
76
|
+
#endif // HAVE_SECP256K1_ECDH_H
|
77
|
+
|
51
78
|
// Forward definitions for all structures
|
52
79
|
typedef struct Context_dummy {
|
53
80
|
secp256k1_context *ctx; // Context used by libsecp256k1 library
|
@@ -59,19 +86,168 @@ typedef struct KeyPair_dummy {
|
|
59
86
|
} KeyPair;
|
60
87
|
|
61
88
|
typedef struct PublicKey_dummy {
|
62
|
-
secp256k1_pubkey pubkey;
|
63
|
-
|
89
|
+
secp256k1_pubkey pubkey; // Opaque object containing public key data
|
90
|
+
secp256k1_context *ctx;
|
64
91
|
} PublicKey;
|
65
92
|
|
66
93
|
typedef struct PrivateKey_dummy {
|
67
94
|
unsigned char data[32]; // Bytes comprising the private key data
|
95
|
+
secp256k1_context *ctx;
|
68
96
|
} PrivateKey;
|
69
97
|
|
70
98
|
typedef struct Signature_dummy {
|
71
|
-
secp256k1_ecdsa_signature sig; // Signature object, contains 64-byte signature
|
72
|
-
|
99
|
+
secp256k1_ecdsa_signature sig; // Signature object, contains 64-byte signature
|
100
|
+
secp256k1_context *ctx;
|
73
101
|
} Signature;
|
74
102
|
|
103
|
+
#ifdef HAVE_SECP256K1_RECOVERY_H
|
104
|
+
typedef struct RecoverableSignature_dummy {
|
105
|
+
secp256k1_ecdsa_recoverable_signature sig; // Recoverable signature object
|
106
|
+
secp256k1_context *ctx;
|
107
|
+
} RecoverableSignature;
|
108
|
+
#endif // HAVE_SECP256K1_RECOVERY_H
|
109
|
+
|
110
|
+
#ifdef HAVE_SECP256K1_ECDH_H
|
111
|
+
typedef struct SharedSecret_dummy {
|
112
|
+
unsigned char data[32]; // Shared secret data
|
113
|
+
} SharedSecret;
|
114
|
+
#endif // HAVE_SECP256K1_ECDH_H
|
115
|
+
|
116
|
+
//
|
117
|
+
// Typed data definitions
|
118
|
+
//
|
119
|
+
|
120
|
+
// Context
|
121
|
+
static void
|
122
|
+
Context_free(void* in_context)
|
123
|
+
{
|
124
|
+
Context *context;
|
125
|
+
context = (Context*)in_context;
|
126
|
+
secp256k1_context_destroy(context->ctx);
|
127
|
+
xfree(context);
|
128
|
+
}
|
129
|
+
|
130
|
+
static const rb_data_type_t Context_DataType = {
|
131
|
+
"Context",
|
132
|
+
{ 0, Context_free, 0 },
|
133
|
+
0, 0,
|
134
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
135
|
+
};
|
136
|
+
|
137
|
+
// PublicKey
|
138
|
+
static void
|
139
|
+
PublicKey_free(void *in_public_key)
|
140
|
+
{
|
141
|
+
PublicKey *public_key;
|
142
|
+
public_key = (PublicKey*)in_public_key;
|
143
|
+
secp256k1_context_destroy(public_key->ctx);
|
144
|
+
xfree(public_key);
|
145
|
+
}
|
146
|
+
|
147
|
+
static const rb_data_type_t PublicKey_DataType = {
|
148
|
+
"PublicKey",
|
149
|
+
{ 0, PublicKey_free, 0 },
|
150
|
+
0, 0,
|
151
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
152
|
+
};
|
153
|
+
|
154
|
+
// PrivateKey
|
155
|
+
static void
|
156
|
+
PrivateKey_free(void *in_private_key)
|
157
|
+
{
|
158
|
+
PrivateKey *private_key;
|
159
|
+
private_key = (PrivateKey*)in_private_key;
|
160
|
+
secp256k1_context_destroy(private_key->ctx);
|
161
|
+
xfree(private_key);
|
162
|
+
}
|
163
|
+
|
164
|
+
static const rb_data_type_t PrivateKey_DataType = {
|
165
|
+
"PrivateKey",
|
166
|
+
{ 0, PrivateKey_free, 0 },
|
167
|
+
0, 0,
|
168
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
169
|
+
};
|
170
|
+
|
171
|
+
// KeyPair
|
172
|
+
static void
|
173
|
+
KeyPair_mark(void *in_key_pair)
|
174
|
+
{
|
175
|
+
KeyPair *key_pair = (KeyPair*)in_key_pair;
|
176
|
+
|
177
|
+
// Mark both contained objects to ensure they are properly garbage collected
|
178
|
+
rb_gc_mark(key_pair->public_key);
|
179
|
+
rb_gc_mark(key_pair->private_key);
|
180
|
+
}
|
181
|
+
|
182
|
+
static void
|
183
|
+
KeyPair_free(void *self)
|
184
|
+
{
|
185
|
+
xfree(self);
|
186
|
+
}
|
187
|
+
|
188
|
+
static const rb_data_type_t KeyPair_DataType = {
|
189
|
+
"KeyPair",
|
190
|
+
{ KeyPair_mark, KeyPair_free, 0 },
|
191
|
+
0, 0,
|
192
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
193
|
+
};
|
194
|
+
|
195
|
+
// Signature
|
196
|
+
static void
|
197
|
+
Signature_free(void *in_signature)
|
198
|
+
{
|
199
|
+
Signature *signature = (Signature*)in_signature;
|
200
|
+
secp256k1_context_destroy(signature->ctx);
|
201
|
+
xfree(signature);
|
202
|
+
}
|
203
|
+
|
204
|
+
static const rb_data_type_t Signature_DataType = {
|
205
|
+
"Signature",
|
206
|
+
{ 0, Signature_free, 0 },
|
207
|
+
0, 0,
|
208
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
209
|
+
};
|
210
|
+
|
211
|
+
// RecoverableSignature
|
212
|
+
#ifdef HAVE_SECP256K1_RECOVERY_H
|
213
|
+
static void
|
214
|
+
RecoverableSignature_free(void *in_recoverable_signature)
|
215
|
+
{
|
216
|
+
RecoverableSignature *recoverable_signature = (
|
217
|
+
(RecoverableSignature*)in_recoverable_signature
|
218
|
+
);
|
219
|
+
|
220
|
+
secp256k1_context_destroy(recoverable_signature->ctx);
|
221
|
+
xfree(recoverable_signature);
|
222
|
+
}
|
223
|
+
|
224
|
+
static const rb_data_type_t RecoverableSignature_DataType = {
|
225
|
+
"RecoverableSignature",
|
226
|
+
{ 0, RecoverableSignature_free, 0 },
|
227
|
+
0, 0,
|
228
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
229
|
+
};
|
230
|
+
#endif // HAVE_SECP256K1_RECOVERY_H
|
231
|
+
|
232
|
+
// SharedSecret
|
233
|
+
#ifdef HAVE_SECP256K1_ECDH_H
|
234
|
+
static void
|
235
|
+
SharedSecret_free(void *in_shared_secret)
|
236
|
+
{
|
237
|
+
SharedSecret *shared_secret;
|
238
|
+
|
239
|
+
shared_secret = (SharedSecret*)in_shared_secret;
|
240
|
+
xfree(shared_secret);
|
241
|
+
}
|
242
|
+
|
243
|
+
static const rb_data_type_t SharedSecret_DataType = {
|
244
|
+
"SharedSecret",
|
245
|
+
{ 0, SharedSecret_free, 0 },
|
246
|
+
0, 0,
|
247
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
248
|
+
};
|
249
|
+
#endif // HAVE_SECP256K1_ECDH_H
|
250
|
+
|
75
251
|
/**
|
76
252
|
* Macro: SUCCESS
|
77
253
|
*
|
@@ -120,225 +296,718 @@ GenerateRandomBytes(unsigned char *out_bytes, size_t in_size)
|
|
120
296
|
}
|
121
297
|
|
122
298
|
/**
|
123
|
-
* Computes the ECDSA signature of the given
|
299
|
+
* Computes the ECDSA signature of the given 32-byte SHA-256 hash.
|
124
300
|
*
|
125
|
-
*
|
126
|
-
*
|
301
|
+
* \param in_context libsecp256k1 context
|
302
|
+
* \param in_hash32 32-byte SHA-256 hash
|
303
|
+
* \param in_private_key Private key to be used for signing
|
304
|
+
* \param out_signature Signature produced during the signing proccess
|
305
|
+
* \return RESULT_SUCCESS if the hash and signature were computed successfully,
|
306
|
+
* RESULT_FAILURE if signing failed or DER encoding failed.
|
307
|
+
*/
|
308
|
+
static ResultT
|
309
|
+
SignData(secp256k1_context *in_context,
|
310
|
+
unsigned char *in_hash32,
|
311
|
+
unsigned char *in_private_key,
|
312
|
+
secp256k1_ecdsa_signature *out_signature)
|
313
|
+
{
|
314
|
+
// Sign the hash of the data
|
315
|
+
if (secp256k1_ecdsa_sign(in_context,
|
316
|
+
out_signature,
|
317
|
+
in_hash32,
|
318
|
+
in_private_key,
|
319
|
+
NULL,
|
320
|
+
NULL) == 1)
|
321
|
+
{
|
322
|
+
return RESULT_SUCCESS;
|
323
|
+
}
|
324
|
+
|
325
|
+
return RESULT_FAILURE;
|
326
|
+
}
|
327
|
+
|
328
|
+
#ifdef HAVE_SECP256K1_RECOVERY_H
|
329
|
+
|
330
|
+
/**
|
331
|
+
* Computes the recoverable ECDSA signature of the given data.
|
127
332
|
*
|
128
333
|
* ECDSA signing involves the following steps:
|
129
334
|
* 1. Compute the 32-byte SHA-256 hash of the given data.
|
130
335
|
* 2. Sign the 32-byte hash using the private key provided.
|
131
336
|
*
|
132
337
|
* \param in_context libsecp256k1 context
|
133
|
-
* \param
|
134
|
-
* \param in_data_len Length of data to be signed
|
338
|
+
* \param in_hash32 32-byte SHA-256 hash to sign
|
135
339
|
* \param in_private_key Private key to be used for signing
|
136
|
-
* \param out_signature
|
340
|
+
* \param out_signature Recoverable signature computed
|
137
341
|
* \return RESULT_SUCCESS if the hash and signature were computed successfully,
|
138
342
|
* RESULT_FAILURE if signing failed or DER encoding failed.
|
139
343
|
*/
|
140
|
-
static ResultT
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
344
|
+
static ResultT
|
345
|
+
RecoverableSignData(secp256k1_context *in_context,
|
346
|
+
unsigned char *in_hash32,
|
347
|
+
unsigned char *in_private_key,
|
348
|
+
secp256k1_ecdsa_recoverable_signature *out_signature)
|
349
|
+
{
|
350
|
+
if (secp256k1_ecdsa_sign_recoverable(in_context,
|
351
|
+
out_signature,
|
352
|
+
in_hash32,
|
353
|
+
in_private_key,
|
354
|
+
NULL,
|
355
|
+
NULL) == 1)
|
356
|
+
{
|
357
|
+
return RESULT_SUCCESS;
|
358
|
+
}
|
359
|
+
|
360
|
+
return RESULT_FAILURE;
|
361
|
+
}
|
362
|
+
|
363
|
+
#endif // HAVE_SECP256K1_RECOVERY_H
|
364
|
+
|
365
|
+
//
|
366
|
+
// Secp256k1::KeyPair class interface
|
367
|
+
//
|
368
|
+
|
369
|
+
static VALUE
|
370
|
+
KeyPair_alloc(VALUE klass)
|
371
|
+
{
|
372
|
+
KeyPair *key_pair;
|
373
|
+
|
374
|
+
key_pair = ALLOC(KeyPair);
|
375
|
+
|
376
|
+
return TypedData_Wrap_Struct(klass, &KeyPair_DataType, key_pair);
|
377
|
+
}
|
378
|
+
|
379
|
+
/**
|
380
|
+
* Default constructor.
|
381
|
+
*
|
382
|
+
* @param in_public_key [Secp256k1::PublicKey] public key
|
383
|
+
* @param in_private_key [Secp256k1::PrivateKey] private key
|
384
|
+
* @return [Secp256k1::KeyPair] newly initialized key pair.
|
385
|
+
*/
|
386
|
+
static VALUE
|
387
|
+
KeyPair_initialize(VALUE self, VALUE in_public_key, VALUE in_private_key)
|
388
|
+
{
|
389
|
+
KeyPair *key_pair;
|
390
|
+
|
391
|
+
TypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, key_pair);
|
392
|
+
Check_TypedStruct(in_public_key, &PublicKey_DataType);
|
393
|
+
Check_TypedStruct(in_private_key, &PrivateKey_DataType);
|
394
|
+
|
395
|
+
key_pair->public_key = in_public_key;
|
396
|
+
key_pair->private_key = in_private_key;
|
397
|
+
|
398
|
+
rb_iv_set(self, "@public_key", in_public_key);
|
399
|
+
rb_iv_set(self, "@private_key", in_private_key);
|
400
|
+
|
401
|
+
return self;
|
402
|
+
}
|
403
|
+
|
404
|
+
/**
|
405
|
+
* Compare two key pairs.
|
406
|
+
*
|
407
|
+
* Two key pairs are equal if they have the same public and private key. The
|
408
|
+
* keys are compared using their own comparison operators.
|
409
|
+
*
|
410
|
+
* @param other [Secp256k1::KeyPair] key pair to compare to.
|
411
|
+
* @return [Boolean] true if the keys match, false otherwise.
|
412
|
+
*/
|
413
|
+
static VALUE
|
414
|
+
KeyPair_equals(VALUE self, VALUE other)
|
415
|
+
{
|
416
|
+
KeyPair *lhs;
|
417
|
+
KeyPair *rhs;
|
418
|
+
VALUE public_keys_equal;
|
419
|
+
VALUE private_keys_equal;
|
420
|
+
|
421
|
+
TypedData_Get_Struct(self, KeyPair, &KeyPair_DataType, lhs);
|
422
|
+
TypedData_Get_Struct(other, KeyPair, &KeyPair_DataType, rhs);
|
423
|
+
|
424
|
+
public_keys_equal = rb_funcall(
|
425
|
+
lhs->public_key, rb_intern("=="), 1, rhs->public_key
|
426
|
+
);
|
427
|
+
private_keys_equal = rb_funcall(
|
428
|
+
lhs->private_key, rb_intern("=="), 1, rhs->private_key
|
429
|
+
);
|
430
|
+
|
431
|
+
if (public_keys_equal == Qtrue && private_keys_equal == Qtrue)
|
432
|
+
{
|
433
|
+
return Qtrue;
|
434
|
+
}
|
435
|
+
|
436
|
+
return Qfalse;
|
437
|
+
}
|
438
|
+
|
439
|
+
//
|
440
|
+
// Secp256k1::PublicKey class interface
|
441
|
+
//
|
442
|
+
|
443
|
+
static VALUE
|
444
|
+
PublicKey_alloc(VALUE klass)
|
445
|
+
{
|
446
|
+
VALUE result;
|
447
|
+
PublicKey *public_key;
|
448
|
+
|
449
|
+
public_key = ALLOC(PublicKey);
|
450
|
+
MEMZERO(public_key, PublicKey, 1);
|
451
|
+
result = TypedData_Wrap_Struct(klass, &PublicKey_DataType, public_key);
|
452
|
+
|
453
|
+
return result;
|
454
|
+
}
|
455
|
+
|
456
|
+
static VALUE
|
457
|
+
PublicKey_create_from_private_key(Context *in_context,
|
458
|
+
unsigned char *private_key_data)
|
459
|
+
{
|
460
|
+
PublicKey *public_key;
|
461
|
+
VALUE result;
|
462
|
+
|
463
|
+
result = PublicKey_alloc(Secp256k1_PublicKey_class);
|
464
|
+
TypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
|
465
|
+
|
466
|
+
if (secp256k1_ec_pubkey_create(
|
467
|
+
in_context->ctx,
|
468
|
+
(&public_key->pubkey),
|
469
|
+
private_key_data) != 1)
|
470
|
+
{
|
471
|
+
rb_raise(rb_eTypeError, "invalid private key data");
|
472
|
+
}
|
473
|
+
|
474
|
+
public_key->ctx = secp256k1_context_clone(in_context->ctx);
|
475
|
+
return result;
|
476
|
+
}
|
477
|
+
|
478
|
+
static VALUE
|
479
|
+
PublicKey_create_from_data(Context *in_context,
|
480
|
+
unsigned char *in_public_key_data,
|
481
|
+
unsigned int in_public_key_data_len)
|
482
|
+
{
|
483
|
+
PublicKey *public_key;
|
484
|
+
VALUE result;
|
485
|
+
|
486
|
+
result = PublicKey_alloc(Secp256k1_PublicKey_class);
|
487
|
+
TypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
|
488
|
+
|
489
|
+
if (secp256k1_ec_pubkey_parse(in_context->ctx,
|
490
|
+
&(public_key->pubkey),
|
491
|
+
in_public_key_data,
|
492
|
+
in_public_key_data_len) != 1)
|
493
|
+
{
|
494
|
+
rb_raise(rb_eRuntimeError, "invalid public key data");
|
495
|
+
}
|
496
|
+
|
497
|
+
public_key->ctx = secp256k1_context_clone(in_context->ctx);
|
498
|
+
return result;
|
499
|
+
}
|
500
|
+
|
501
|
+
/**
|
502
|
+
* @return [String] binary string containing the uncompressed representation
|
503
|
+
* of this public key.
|
504
|
+
*/
|
505
|
+
static VALUE
|
506
|
+
PublicKey_uncompressed(VALUE self)
|
507
|
+
{
|
508
|
+
// TODO: Cache value after first computation
|
509
|
+
PublicKey *public_key;
|
510
|
+
size_t serialized_pubkey_len = UNCOMPRESSED_PUBKEY_SIZE_BYTES;
|
511
|
+
unsigned char serialized_pubkey[UNCOMPRESSED_PUBKEY_SIZE_BYTES];
|
512
|
+
|
513
|
+
TypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
|
514
|
+
|
515
|
+
secp256k1_ec_pubkey_serialize(public_key->ctx,
|
516
|
+
serialized_pubkey,
|
517
|
+
&serialized_pubkey_len,
|
518
|
+
&(public_key->pubkey),
|
519
|
+
SECP256K1_EC_UNCOMPRESSED);
|
520
|
+
|
521
|
+
return rb_str_new((char*)serialized_pubkey, serialized_pubkey_len);
|
522
|
+
}
|
523
|
+
|
524
|
+
/**
|
525
|
+
* @return [String] binary string containing the compressed representation of
|
526
|
+
* this public key.
|
527
|
+
*/
|
528
|
+
static VALUE
|
529
|
+
PublicKey_compressed(VALUE self)
|
530
|
+
{
|
531
|
+
// TODO: Cache value after first computation
|
532
|
+
PublicKey *public_key;
|
533
|
+
size_t serialized_pubkey_len = COMPRESSED_PUBKEY_SIZE_BYTES;
|
534
|
+
unsigned char serialized_pubkey[COMPRESSED_PUBKEY_SIZE_BYTES];
|
535
|
+
|
536
|
+
TypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, public_key);
|
537
|
+
|
538
|
+
secp256k1_ec_pubkey_serialize(public_key->ctx,
|
539
|
+
serialized_pubkey,
|
540
|
+
&serialized_pubkey_len,
|
541
|
+
&(public_key->pubkey),
|
542
|
+
SECP256K1_EC_COMPRESSED);
|
543
|
+
|
544
|
+
return rb_str_new((char*)serialized_pubkey, serialized_pubkey_len);
|
545
|
+
}
|
546
|
+
|
547
|
+
/**
|
548
|
+
* Compares two public keys.
|
549
|
+
*
|
550
|
+
* Public keys are considered equal if their compressed representations match.
|
551
|
+
*
|
552
|
+
* @param other [Secp256k1::PublicKey] public key to compare.
|
553
|
+
* @return [Boolean] true if the public keys are identical, false otherwise.
|
554
|
+
*/
|
555
|
+
static VALUE
|
556
|
+
PublicKey_equals(VALUE self, VALUE other)
|
557
|
+
{
|
558
|
+
PublicKey *lhs;
|
559
|
+
PublicKey *rhs;
|
560
|
+
unsigned char lhs_compressed[33];
|
561
|
+
unsigned char rhs_compressed[33];
|
562
|
+
size_t lhs_len;
|
563
|
+
size_t rhs_len;
|
564
|
+
|
565
|
+
lhs_len = 33;
|
566
|
+
rhs_len = 33;
|
567
|
+
|
568
|
+
TypedData_Get_Struct(self, PublicKey, &PublicKey_DataType, lhs);
|
569
|
+
TypedData_Get_Struct(other, PublicKey, &PublicKey_DataType, rhs);
|
570
|
+
|
571
|
+
secp256k1_ec_pubkey_serialize(
|
572
|
+
lhs->ctx,
|
573
|
+
lhs_compressed,
|
574
|
+
&lhs_len,
|
575
|
+
&(lhs->pubkey),
|
576
|
+
SECP256K1_EC_COMPRESSED
|
577
|
+
);
|
578
|
+
secp256k1_ec_pubkey_serialize(
|
579
|
+
rhs->ctx,
|
580
|
+
rhs_compressed,
|
581
|
+
&rhs_len,
|
582
|
+
&(rhs->pubkey),
|
583
|
+
SECP256K1_EC_COMPRESSED
|
584
|
+
);
|
585
|
+
|
586
|
+
if (lhs_len == rhs_len &&
|
587
|
+
memcmp(lhs_compressed, rhs_compressed, lhs_len) == 0)
|
588
|
+
{
|
589
|
+
return Qtrue;
|
590
|
+
}
|
591
|
+
|
592
|
+
return Qfalse;
|
593
|
+
}
|
594
|
+
|
595
|
+
//
|
596
|
+
// Secp256k1::PrivateKey class interface
|
597
|
+
//
|
598
|
+
|
599
|
+
static VALUE
|
600
|
+
PrivateKey_alloc(VALUE klass)
|
601
|
+
{
|
602
|
+
VALUE new_instance;
|
603
|
+
PrivateKey *private_key;
|
604
|
+
|
605
|
+
private_key = ALLOC(PrivateKey);
|
606
|
+
MEMZERO(private_key, PrivateKey, 1);
|
607
|
+
new_instance = TypedData_Wrap_Struct(klass, &PrivateKey_DataType, private_key);
|
608
|
+
|
609
|
+
return new_instance;
|
610
|
+
}
|
611
|
+
|
612
|
+
static VALUE
|
613
|
+
PrivateKey_create(Context *in_context, unsigned char *in_private_key_data)
|
614
|
+
{
|
615
|
+
PrivateKey *private_key;
|
616
|
+
VALUE result;
|
617
|
+
|
618
|
+
if (secp256k1_ec_seckey_verify(in_context->ctx, in_private_key_data) != 1)
|
619
|
+
{
|
620
|
+
rb_raise(rb_eArgError, "invalid private key data");
|
621
|
+
}
|
622
|
+
|
623
|
+
result = PrivateKey_alloc(Secp256k1_PrivateKey_class);
|
624
|
+
TypedData_Get_Struct(result, PrivateKey, &PrivateKey_DataType, private_key);
|
625
|
+
MEMCPY(private_key->data, in_private_key_data, char, 32);
|
626
|
+
private_key->ctx = secp256k1_context_clone(in_context->ctx);
|
627
|
+
|
628
|
+
rb_iv_set(result, "@data", rb_str_new((char*)in_private_key_data, 32));
|
629
|
+
|
630
|
+
return result;
|
631
|
+
}
|
632
|
+
|
633
|
+
/**
|
634
|
+
* Compare two private keys.
|
635
|
+
*
|
636
|
+
* Private keys are considered equal if their data fields are identical.
|
637
|
+
*
|
638
|
+
* @param other [Secp256k1::PrivateKey] private key to compare.
|
639
|
+
* @return [Boolean] true if they are equal, false otherwise.
|
640
|
+
*/
|
641
|
+
static VALUE
|
642
|
+
PrivateKey_equals(VALUE self, VALUE other)
|
643
|
+
{
|
644
|
+
PrivateKey *lhs;
|
645
|
+
PrivateKey *rhs;
|
646
|
+
|
647
|
+
TypedData_Get_Struct(self, PrivateKey, &PrivateKey_DataType, lhs);
|
648
|
+
TypedData_Get_Struct(other, PrivateKey, &PrivateKey_DataType, rhs);
|
649
|
+
|
650
|
+
if (memcmp(lhs->data, rhs->data, 32) == 0)
|
651
|
+
{
|
652
|
+
return Qtrue;
|
653
|
+
}
|
654
|
+
|
655
|
+
return Qfalse;
|
656
|
+
}
|
657
|
+
|
658
|
+
//
|
659
|
+
// Secp256k1::Signature class interface
|
660
|
+
//
|
661
|
+
|
662
|
+
static VALUE
|
663
|
+
Signature_alloc(VALUE klass)
|
664
|
+
{
|
665
|
+
VALUE new_instance;
|
666
|
+
Signature *signature;
|
667
|
+
|
668
|
+
signature = ALLOC(Signature);
|
669
|
+
MEMZERO(signature, Signature, 1);
|
670
|
+
new_instance = TypedData_Wrap_Struct(klass, &Signature_DataType, signature);
|
671
|
+
|
672
|
+
return new_instance;
|
673
|
+
}
|
674
|
+
|
675
|
+
/**
|
676
|
+
* Return Distinguished Encoding Rules (DER) encoded signature data.
|
677
|
+
*
|
678
|
+
* @return [String] binary string containing DER-encoded signature data.
|
679
|
+
*/
|
680
|
+
static VALUE
|
681
|
+
Signature_der_encoded(VALUE self)
|
682
|
+
{
|
683
|
+
// TODO: Cache value after first computation
|
684
|
+
Signature *signature;
|
685
|
+
unsigned long der_signature_len;
|
686
|
+
unsigned char der_signature[72];
|
687
|
+
|
688
|
+
TypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
|
689
|
+
|
690
|
+
der_signature_len = 72;
|
691
|
+
if (secp256k1_ecdsa_signature_serialize_der(signature->ctx,
|
692
|
+
der_signature,
|
693
|
+
&der_signature_len,
|
694
|
+
&(signature->sig)) != 1)
|
695
|
+
{
|
696
|
+
rb_raise(rb_eRuntimeError, "could not compute DER encoded signature");
|
697
|
+
}
|
698
|
+
|
699
|
+
return rb_str_new((char*)der_signature, der_signature_len);
|
700
|
+
}
|
701
|
+
|
702
|
+
/**
|
703
|
+
* Returns the 64 byte compact representation of this signature.
|
704
|
+
*
|
705
|
+
* @return [String] 64 byte binary string containing signature data.
|
706
|
+
*/
|
707
|
+
static VALUE
|
708
|
+
Signature_compact(VALUE self)
|
709
|
+
{
|
710
|
+
// TODO: Cache value after first computation
|
711
|
+
Signature *signature;
|
712
|
+
unsigned char compact_signature[COMPACT_SIG_SIZE_BYTES];
|
713
|
+
|
714
|
+
TypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
|
715
|
+
|
716
|
+
if (secp256k1_ecdsa_signature_serialize_compact(signature->ctx,
|
717
|
+
compact_signature,
|
718
|
+
&(signature->sig)) != 1)
|
719
|
+
{
|
720
|
+
rb_raise(rb_eRuntimeError, "unable to compute compact signature");
|
721
|
+
}
|
722
|
+
|
723
|
+
return rb_str_new((char*)compact_signature, COMPACT_SIG_SIZE_BYTES);
|
724
|
+
}
|
725
|
+
|
726
|
+
/**
|
727
|
+
* Returns the normalized lower-S form of this signature.
|
728
|
+
*
|
729
|
+
* This can be useful when importing signatures generated by other applications
|
730
|
+
* that may not be normalized. Non-normalized signatures are potentially
|
731
|
+
* forgeable.
|
732
|
+
*
|
733
|
+
* @return [Array] first element is a boolean that is `true` if the signature
|
734
|
+
* was normalized, false otherwise. The second element is a `Signature`
|
735
|
+
* object corresponding to the normalized signature.
|
736
|
+
*/
|
737
|
+
static VALUE
|
738
|
+
Signature_normalized(VALUE self)
|
146
739
|
{
|
147
|
-
|
740
|
+
VALUE result_sig;
|
741
|
+
VALUE was_normalized;
|
742
|
+
VALUE result;
|
743
|
+
Signature *signature;
|
744
|
+
Signature *normalized_signature;
|
148
745
|
|
149
|
-
|
150
|
-
|
746
|
+
TypedData_Get_Struct(self, Signature, &Signature_DataType, signature);
|
747
|
+
result_sig = Signature_alloc(Secp256k1_Signature_class);
|
748
|
+
TypedData_Get_Struct(
|
749
|
+
result_sig, Signature, &Signature_DataType, normalized_signature
|
750
|
+
);
|
151
751
|
|
152
|
-
|
153
|
-
if (
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
NULL,
|
158
|
-
NULL) == 1)
|
752
|
+
was_normalized = Qfalse;
|
753
|
+
if (secp256k1_ecdsa_signature_normalize(
|
754
|
+
signature->ctx,
|
755
|
+
&(normalized_signature->sig),
|
756
|
+
&(signature->sig)) == 1)
|
159
757
|
{
|
160
|
-
|
758
|
+
was_normalized = Qtrue;
|
161
759
|
}
|
162
760
|
|
163
|
-
|
761
|
+
normalized_signature->ctx = secp256k1_context_clone(signature->ctx);
|
762
|
+
|
763
|
+
result = rb_ary_new2(2);
|
764
|
+
rb_ary_push(result, was_normalized);
|
765
|
+
rb_ary_push(result, result_sig);
|
766
|
+
|
767
|
+
return result;
|
164
768
|
}
|
165
769
|
|
166
770
|
/**
|
167
|
-
*
|
771
|
+
* Compares two signatures.
|
168
772
|
*
|
169
|
-
*
|
773
|
+
* Two signatures are equal if their compact encodings are identical.
|
170
774
|
*
|
171
|
-
*
|
172
|
-
*
|
775
|
+
* @param other [Secp256k1::Signature] signature to compare
|
776
|
+
* @return [Boolean] true if signatures match, false otherwise.
|
173
777
|
*/
|
174
778
|
static VALUE
|
175
|
-
|
779
|
+
Signature_equals(VALUE self, VALUE other)
|
176
780
|
{
|
177
|
-
|
781
|
+
Signature *lhs;
|
782
|
+
Signature *rhs;
|
783
|
+
unsigned char lhs_compact[64];
|
784
|
+
unsigned char rhs_compact[64];
|
178
785
|
|
179
|
-
|
786
|
+
TypedData_Get_Struct(self, Signature, &Signature_DataType, lhs);
|
787
|
+
TypedData_Get_Struct(other, Signature, &Signature_DataType, rhs);
|
788
|
+
|
789
|
+
secp256k1_ecdsa_signature_serialize_compact(
|
790
|
+
lhs->ctx, lhs_compact, &(lhs->sig)
|
791
|
+
);
|
792
|
+
secp256k1_ecdsa_signature_serialize_compact(
|
793
|
+
rhs->ctx, rhs_compact, &(rhs->sig)
|
794
|
+
);
|
795
|
+
|
796
|
+
if (memcmp(lhs_compact, rhs_compact, 64) == 0)
|
180
797
|
{
|
181
|
-
|
798
|
+
return Qtrue;
|
182
799
|
}
|
183
800
|
|
184
|
-
return
|
801
|
+
return Qfalse;
|
185
802
|
}
|
186
803
|
|
187
804
|
//
|
188
|
-
// Secp256k1::
|
805
|
+
// Secp256k1::RecoverableSignature class interface
|
189
806
|
//
|
190
807
|
|
191
|
-
|
808
|
+
#ifdef HAVE_SECP256K1_RECOVERY_H
|
809
|
+
|
192
810
|
static VALUE
|
193
|
-
|
811
|
+
RecoverableSignature_alloc(VALUE klass)
|
194
812
|
{
|
195
813
|
VALUE new_instance;
|
196
|
-
|
814
|
+
RecoverableSignature *recoverable_signature;
|
197
815
|
|
198
|
-
|
199
|
-
|
816
|
+
recoverable_signature = ALLOC(RecoverableSignature);
|
817
|
+
MEMZERO(recoverable_signature, RecoverableSignature, 1);
|
818
|
+
new_instance = TypedData_Wrap_Struct(
|
819
|
+
klass, &RecoverableSignature_DataType, recoverable_signature
|
200
820
|
);
|
201
|
-
memset(private_key->data, 0, 32);
|
202
821
|
|
203
822
|
return new_instance;
|
204
823
|
}
|
205
824
|
|
206
825
|
/**
|
207
|
-
*
|
208
|
-
*
|
209
|
-
* Generates a new random private key.
|
210
|
-
*
|
211
|
-
* \return PrivateKey instance populated with randomly generated key.
|
212
|
-
*/
|
213
|
-
static VALUE
|
214
|
-
PrivateKey_generate(VALUE klass)
|
215
|
-
{
|
216
|
-
VALUE result = rb_funcall(klass,
|
217
|
-
rb_intern("new"),
|
218
|
-
1,
|
219
|
-
Secp256k1_generate_private_key_bytes(Secp256k1_module));
|
220
|
-
return result;
|
221
|
-
}
|
222
|
-
|
223
|
-
/**
|
224
|
-
* PrivateKey#initialize
|
225
|
-
*
|
226
|
-
* Initialize a new private key with the given private key data.
|
826
|
+
* Returns the compact encoding of recoverable signature.
|
227
827
|
*
|
228
|
-
*
|
229
|
-
*
|
230
|
-
*
|
828
|
+
* @return [Array] first element is the 64 byte compact encoding of signature,
|
829
|
+
* the second element is the integer recovery ID.
|
830
|
+
* @raise [RuntimeError] if signature serialization fails.
|
231
831
|
*/
|
232
832
|
static VALUE
|
233
|
-
|
833
|
+
RecoverableSignature_compact(VALUE self)
|
234
834
|
{
|
235
|
-
|
835
|
+
RecoverableSignature *recoverable_signature;
|
836
|
+
unsigned char compact_sig[64];
|
837
|
+
int recovery_id;
|
838
|
+
VALUE result;
|
236
839
|
|
237
|
-
|
840
|
+
TypedData_Get_Struct(
|
841
|
+
self,
|
842
|
+
RecoverableSignature,
|
843
|
+
&RecoverableSignature_DataType,
|
844
|
+
recoverable_signature
|
845
|
+
);
|
238
846
|
|
239
|
-
if (
|
847
|
+
if (secp256k1_ecdsa_recoverable_signature_serialize_compact(
|
848
|
+
recoverable_signature->ctx,
|
849
|
+
compact_sig,
|
850
|
+
&recovery_id,
|
851
|
+
&(recoverable_signature->sig)) != 1)
|
240
852
|
{
|
241
|
-
rb_raise(
|
242
|
-
return self;
|
853
|
+
rb_raise(rb_eRuntimeError, "unable to serialize recoverable signature");
|
243
854
|
}
|
244
855
|
|
245
|
-
|
246
|
-
|
856
|
+
// Create a new array with room for 2 elements and push data onto it
|
857
|
+
result = rb_ary_new2(2);
|
858
|
+
rb_ary_push(result, rb_str_new((char*)compact_sig, 64));
|
859
|
+
rb_ary_push(result, rb_int_new(recovery_id));
|
247
860
|
|
248
|
-
|
249
|
-
rb_iv_set(self, "@data", in_bytes);
|
250
|
-
|
251
|
-
return self;
|
861
|
+
return result;
|
252
862
|
}
|
253
863
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
864
|
+
/**
|
865
|
+
* Convert a recoverable signature to a non-recoverable signature.
|
866
|
+
*
|
867
|
+
* @return [Secp256k1::Signature] non-recoverable signature derived from this
|
868
|
+
* recoverable signature.
|
869
|
+
*/
|
259
870
|
static VALUE
|
260
|
-
|
871
|
+
RecoverableSignature_to_signature(VALUE self)
|
261
872
|
{
|
262
|
-
|
873
|
+
RecoverableSignature *recoverable_signature;
|
263
874
|
Signature *signature;
|
875
|
+
VALUE result;
|
264
876
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
877
|
+
TypedData_Get_Struct(
|
878
|
+
self,
|
879
|
+
RecoverableSignature,
|
880
|
+
&RecoverableSignature_DataType,
|
881
|
+
recoverable_signature
|
882
|
+
);
|
271
883
|
|
272
|
-
|
884
|
+
result = Signature_alloc(Secp256k1_Signature_class);
|
885
|
+
TypedData_Get_Struct(
|
886
|
+
result,
|
887
|
+
Signature,
|
888
|
+
&Signature_DataType,
|
889
|
+
signature
|
890
|
+
);
|
891
|
+
|
892
|
+
// NOTE: This method cannot fail
|
893
|
+
secp256k1_ecdsa_recoverable_signature_convert(
|
894
|
+
recoverable_signature->ctx,
|
895
|
+
&(signature->sig),
|
896
|
+
&(recoverable_signature->sig));
|
897
|
+
|
898
|
+
signature->ctx = secp256k1_context_clone(recoverable_signature->ctx);
|
899
|
+
return result;
|
273
900
|
}
|
274
901
|
|
275
902
|
/**
|
276
|
-
*
|
903
|
+
* Attempts to recover the public key associated with this signature.
|
277
904
|
*
|
278
|
-
*
|
279
|
-
*
|
905
|
+
* @param in_hash32 [String] 32-byte SHA-256 hash of data.
|
906
|
+
* @return [Secp256k1::PublicKey] recovered public key.
|
907
|
+
* @raise [RuntimeError] if the public key could not be recovered.
|
280
908
|
*/
|
281
909
|
static VALUE
|
282
|
-
|
910
|
+
RecoverableSignature_recover_public_key(VALUE self, VALUE in_hash32)
|
283
911
|
{
|
284
|
-
|
285
|
-
|
286
|
-
|
912
|
+
RecoverableSignature *recoverable_signature;
|
913
|
+
PublicKey *public_key;
|
914
|
+
VALUE result;
|
915
|
+
unsigned char *hash32;
|
287
916
|
|
288
|
-
|
917
|
+
Check_Type(in_hash32, T_STRING);
|
918
|
+
if (RSTRING_LEN(in_hash32) != 32)
|
919
|
+
{
|
920
|
+
rb_raise(rb_eArgError, "in_hash32 is not 32 bytes in length");
|
921
|
+
}
|
289
922
|
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
923
|
+
TypedData_Get_Struct(
|
924
|
+
self,
|
925
|
+
RecoverableSignature,
|
926
|
+
&RecoverableSignature_DataType,
|
927
|
+
recoverable_signature
|
928
|
+
);
|
929
|
+
hash32 = (unsigned char*)StringValuePtr(in_hash32);
|
930
|
+
|
931
|
+
result = PublicKey_alloc(Secp256k1_PublicKey_class);
|
932
|
+
TypedData_Get_Struct(result, PublicKey, &PublicKey_DataType, public_key);
|
933
|
+
|
934
|
+
if (secp256k1_ecdsa_recover(recoverable_signature->ctx,
|
935
|
+
&(public_key->pubkey),
|
936
|
+
&(recoverable_signature->sig),
|
937
|
+
hash32) == 1)
|
295
938
|
{
|
296
|
-
|
939
|
+
public_key->ctx = secp256k1_context_clone(recoverable_signature->ctx);
|
940
|
+
return result;
|
297
941
|
}
|
298
942
|
|
299
|
-
rb_raise(rb_eRuntimeError, "
|
943
|
+
rb_raise(rb_eRuntimeError, "unable to recover public key");
|
300
944
|
}
|
301
945
|
|
302
946
|
/**
|
303
|
-
*
|
947
|
+
* Compares two recoverable signatures.
|
304
948
|
*
|
305
|
-
*
|
949
|
+
* Two recoverable signatures their secp256k1_ecdsa_recoverable_signature data
|
950
|
+
* is identical.
|
306
951
|
*
|
307
|
-
*
|
308
|
-
*
|
952
|
+
* @param other [Secp256k1::RecoverableSignature] recoverable signature to
|
953
|
+
* compare.
|
954
|
+
* @return [Boolean] true if the recoverable signatures are identical, false
|
955
|
+
* otherwise.
|
309
956
|
*/
|
310
957
|
static VALUE
|
311
|
-
|
958
|
+
RecoverableSignature_equals(VALUE self, VALUE other)
|
312
959
|
{
|
313
|
-
|
314
|
-
|
960
|
+
RecoverableSignature *lhs;
|
961
|
+
RecoverableSignature *rhs;
|
315
962
|
|
316
|
-
|
963
|
+
TypedData_Get_Struct(
|
964
|
+
self, RecoverableSignature, &RecoverableSignature_DataType, lhs
|
965
|
+
);
|
966
|
+
TypedData_Get_Struct(
|
967
|
+
other, RecoverableSignature, &RecoverableSignature_DataType, rhs
|
968
|
+
);
|
317
969
|
|
318
|
-
|
319
|
-
|
320
|
-
|
970
|
+
// NOTE: It is safe to directly compare these data structures rather than
|
971
|
+
// first serializing and then comparing.
|
972
|
+
if (memcmp(&(lhs->sig),
|
973
|
+
&(rhs->sig),
|
974
|
+
sizeof(secp256k1_ecdsa_recoverable_signature)) == 0)
|
321
975
|
{
|
322
|
-
return
|
976
|
+
return Qtrue;
|
323
977
|
}
|
324
978
|
|
325
|
-
|
979
|
+
return Qfalse;
|
326
980
|
}
|
327
981
|
|
982
|
+
#endif // HAVE_SECP256K1_RECOVERY_H
|
983
|
+
|
328
984
|
//
|
329
|
-
// Secp256k1::
|
985
|
+
// Secp256k1::SharedSecret class interface
|
330
986
|
//
|
331
987
|
|
332
|
-
|
333
|
-
|
334
|
-
|
988
|
+
#ifdef HAVE_SECP256K1_ECDH_H
|
989
|
+
|
990
|
+
static VALUE
|
991
|
+
SharedSecret_alloc(VALUE klass)
|
335
992
|
{
|
336
|
-
|
993
|
+
VALUE new_instance;
|
994
|
+
SharedSecret *shared_secret;
|
337
995
|
|
338
|
-
|
339
|
-
|
996
|
+
shared_secret = ALLOC(SharedSecret);
|
997
|
+
MEMZERO(shared_secret, SharedSecret, 1);
|
998
|
+
new_instance = TypedData_Wrap_Struct(
|
999
|
+
klass, &SharedSecret_DataType, shared_secret
|
1000
|
+
);
|
1001
|
+
|
1002
|
+
return new_instance;
|
340
1003
|
}
|
341
1004
|
|
1005
|
+
#endif // HAVE_SECP256K1_ECDH_H
|
1006
|
+
|
1007
|
+
//
|
1008
|
+
// Secp256k1::Context class interface
|
1009
|
+
//
|
1010
|
+
|
342
1011
|
/* Allocate a new context object */
|
343
1012
|
static VALUE
|
344
1013
|
Context_alloc(VALUE klass)
|
@@ -346,20 +1015,21 @@ Context_alloc(VALUE klass)
|
|
346
1015
|
VALUE new_instance;
|
347
1016
|
Context *context;
|
348
1017
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
1018
|
+
context = ALLOC(Context);
|
1019
|
+
MEMZERO(context, Context, 1);
|
1020
|
+
|
1021
|
+
new_instance = TypedData_Wrap_Struct(klass, &Context_DataType, context);
|
353
1022
|
|
354
1023
|
return new_instance;
|
355
1024
|
}
|
356
1025
|
|
357
1026
|
/**
|
358
|
-
*
|
1027
|
+
* Initialize a new context.
|
359
1028
|
*
|
360
|
-
*
|
1029
|
+
* Context initialization should be infrequent as it is an expensive operation.
|
361
1030
|
*
|
362
|
-
*
|
1031
|
+
* @return [Secp256k1::Context]
|
1032
|
+
* @raise [RuntimeError] if context randomization fails.
|
363
1033
|
*/
|
364
1034
|
static VALUE
|
365
1035
|
Context_initialize(VALUE self)
|
@@ -367,7 +1037,7 @@ Context_initialize(VALUE self)
|
|
367
1037
|
Context *context;
|
368
1038
|
unsigned char seed[32];
|
369
1039
|
|
370
|
-
|
1040
|
+
TypedData_Get_Struct(self, Context, &Context_DataType, context);
|
371
1041
|
|
372
1042
|
context->ctx = secp256k1_context_create(
|
373
1043
|
SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY
|
@@ -378,86 +1048,104 @@ Context_initialize(VALUE self)
|
|
378
1048
|
GenerateRandomBytes(seed, 32);
|
379
1049
|
if (secp256k1_context_randomize(context->ctx, seed) != 1)
|
380
1050
|
{
|
381
|
-
rb_raise(rb_eRuntimeError, "
|
1051
|
+
rb_raise(rb_eRuntimeError, "context randomization failed");
|
382
1052
|
}
|
383
1053
|
|
384
1054
|
return self;
|
385
1055
|
}
|
386
1056
|
|
387
1057
|
/**
|
388
|
-
*
|
1058
|
+
* Generate a new public-private key pair.
|
389
1059
|
*
|
390
|
-
*
|
1060
|
+
* @return [Secp256k1::KeyPair] newly generated key pair.
|
1061
|
+
* @raise [RuntimeError] if private key generation fails.
|
391
1062
|
*/
|
392
1063
|
static VALUE
|
393
1064
|
Context_generate_key_pair(VALUE self)
|
394
1065
|
{
|
1066
|
+
Context *context;
|
395
1067
|
VALUE private_key;
|
396
1068
|
VALUE public_key;
|
397
|
-
VALUE
|
1069
|
+
VALUE result;
|
1070
|
+
unsigned char private_key_bytes[32];
|
1071
|
+
|
1072
|
+
if (FAILURE(GenerateRandomBytes(private_key_bytes, 32)))
|
1073
|
+
{
|
1074
|
+
rb_raise(rb_eRuntimeError, "unable to generate private key bytes.");
|
1075
|
+
}
|
1076
|
+
|
1077
|
+
TypedData_Get_Struct(self, Context, &Context_DataType, context);
|
398
1078
|
|
399
|
-
private_key =
|
400
|
-
public_key =
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
public_key,
|
409
|
-
private_key);
|
1079
|
+
private_key = PrivateKey_create(context, private_key_bytes);
|
1080
|
+
public_key = PublicKey_create_from_private_key(context, private_key_bytes);
|
1081
|
+
result = rb_funcall(
|
1082
|
+
Secp256k1_KeyPair_class,
|
1083
|
+
rb_intern("new"),
|
1084
|
+
2,
|
1085
|
+
public_key,
|
1086
|
+
private_key
|
1087
|
+
);
|
410
1088
|
|
411
|
-
return
|
1089
|
+
return result;
|
412
1090
|
}
|
413
1091
|
|
414
1092
|
/**
|
415
|
-
* Context#public_key_from_data
|
416
|
-
*
|
417
1093
|
* Loads a public key from compressed or uncompressed binary data.
|
418
1094
|
*
|
419
|
-
*
|
420
|
-
*
|
1095
|
+
* @param in_public_key_data [String] binary string with compressed or
|
1096
|
+
* uncompressed public key data.
|
1097
|
+
* @return [Secp256k1::PublicKey] public key derived from data.
|
1098
|
+
* @raise [RuntimeError] if public key data is invalid.
|
421
1099
|
*/
|
422
1100
|
static VALUE
|
423
1101
|
Context_public_key_from_data(VALUE self, VALUE in_public_key_data)
|
424
1102
|
{
|
425
1103
|
Context *context;
|
426
|
-
PublicKey *public_key;
|
427
1104
|
unsigned char *public_key_data;
|
428
|
-
VALUE result;
|
429
1105
|
|
430
1106
|
Check_Type(in_public_key_data, T_STRING);
|
431
1107
|
|
432
|
-
|
1108
|
+
TypedData_Get_Struct(self, Context, &Context_DataType, context);
|
433
1109
|
public_key_data = (unsigned char*)StringValuePtr(in_public_key_data);
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
1110
|
+
return PublicKey_create_from_data(
|
1111
|
+
context,
|
1112
|
+
public_key_data,
|
1113
|
+
RSTRING_LEN(in_public_key_data)
|
1114
|
+
);
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
/**
|
1118
|
+
* Load a private key from binary data.
|
1119
|
+
*
|
1120
|
+
* @param in_private_key_data [String] 32 byte binary string of private key
|
1121
|
+
* data.
|
1122
|
+
* @return [Secp256k1::PrivateKey] private key loaded from the given data.
|
1123
|
+
* @raise [ArgumentError] if private key data is not 32 bytes or is invalid.
|
1124
|
+
*/
|
1125
|
+
static VALUE
|
1126
|
+
Context_private_key_from_data(VALUE self, VALUE in_private_key_data)
|
1127
|
+
{
|
1128
|
+
Context *context;
|
1129
|
+
unsigned char *private_key_data;
|
1130
|
+
|
1131
|
+
Check_Type(in_private_key_data, T_STRING);
|
1132
|
+
TypedData_Get_Struct(self, Context, &Context_DataType, context);
|
1133
|
+
private_key_data = (unsigned char*)StringValuePtr(in_private_key_data);
|
1134
|
+
|
1135
|
+
if (RSTRING_LEN(in_private_key_data) != 32)
|
445
1136
|
{
|
446
|
-
rb_raise(
|
1137
|
+
rb_raise(rb_eArgError, "private key data must be 32 bytes in length");
|
447
1138
|
}
|
448
1139
|
|
449
|
-
return
|
1140
|
+
return PrivateKey_create(context, private_key_data);
|
450
1141
|
}
|
451
1142
|
|
452
1143
|
/**
|
453
|
-
*
|
454
|
-
*
|
455
|
-
* Converts a binary private key into a key pair
|
1144
|
+
* Converts binary private key data into a new key pair.
|
456
1145
|
*
|
457
|
-
*
|
458
|
-
*
|
459
|
-
*
|
460
|
-
* \raises ArgumentError if the private key data is invalid or key derivation
|
1146
|
+
* @param in_private_key_data [String] binary private key data
|
1147
|
+
* @return [Secp256k1::KeyPair] key pair initialized from the private key data.
|
1148
|
+
* @raise [ArgumentError] if the private key data is invalid or key derivation
|
461
1149
|
* fails.
|
462
1150
|
*/
|
463
1151
|
static VALUE
|
@@ -466,44 +1154,36 @@ Context_key_pair_from_private_key(VALUE self, VALUE in_private_key_data)
|
|
466
1154
|
Context *context;
|
467
1155
|
VALUE public_key;
|
468
1156
|
VALUE private_key;
|
469
|
-
VALUE key_pair;
|
470
1157
|
unsigned char *private_key_data;
|
471
1158
|
|
472
|
-
|
473
|
-
// Verify secret key data before attempting to recover key pair
|
474
|
-
Data_Get_Struct(self, Context, context);
|
475
|
-
private_key_data = (unsigned char*)StringValuePtr(in_private_key_data);
|
476
|
-
|
477
|
-
if (secp256k1_ec_seckey_verify(context->ctx, private_key_data) != 1)
|
1159
|
+
if (RSTRING_LEN(in_private_key_data) != 32)
|
478
1160
|
{
|
479
|
-
rb_raise(
|
1161
|
+
rb_raise(rb_eArgError, "private key data must be 32 bytes in length");
|
480
1162
|
}
|
481
1163
|
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
public_key =
|
487
|
-
rb_intern("new"),
|
488
|
-
2,
|
489
|
-
self,
|
490
|
-
private_key);
|
491
|
-
key_pair = rb_funcall(Secp256k1_KeyPair_class,
|
492
|
-
rb_intern("new"),
|
493
|
-
2,
|
494
|
-
public_key,
|
495
|
-
private_key);
|
1164
|
+
TypedData_Get_Struct(self, Context, &Context_DataType, context);
|
1165
|
+
private_key_data = (unsigned char*)StringValuePtr(in_private_key_data);
|
1166
|
+
|
1167
|
+
private_key = PrivateKey_create(context, private_key_data);
|
1168
|
+
public_key = PublicKey_create_from_private_key(context, private_key_data);
|
496
1169
|
|
497
|
-
return
|
1170
|
+
return rb_funcall(
|
1171
|
+
Secp256k1_KeyPair_class,
|
1172
|
+
rb_intern("new"),
|
1173
|
+
2,
|
1174
|
+
public_key,
|
1175
|
+
private_key
|
1176
|
+
);
|
498
1177
|
}
|
499
1178
|
|
500
1179
|
/**
|
501
|
-
*
|
1180
|
+
* Converts a DER encoded binary signature into a signature object.
|
502
1181
|
*
|
503
|
-
*
|
504
|
-
*
|
505
|
-
*
|
506
|
-
*
|
1182
|
+
* @param in_der_encoded_signature [String] DER encoded signature as binary
|
1183
|
+
* string.
|
1184
|
+
* @return [Secp256k1::Signature] signature object initialized using signature
|
1185
|
+
* data.
|
1186
|
+
* @raise [ArgumentError] if signature data is invalid.
|
507
1187
|
*/
|
508
1188
|
static VALUE
|
509
1189
|
Context_signature_from_der_encoded(VALUE self, VALUE in_der_encoded_signature)
|
@@ -515,36 +1195,31 @@ Context_signature_from_der_encoded(VALUE self, VALUE in_der_encoded_signature)
|
|
515
1195
|
|
516
1196
|
Check_Type(in_der_encoded_signature, T_STRING);
|
517
1197
|
|
518
|
-
|
1198
|
+
TypedData_Get_Struct(self, Context, &Context_DataType, context);
|
519
1199
|
signature_data = (unsigned char*)StringValuePtr(in_der_encoded_signature);
|
520
1200
|
|
521
|
-
signature_result =
|
522
|
-
|
523
|
-
NULL,
|
524
|
-
free,
|
525
|
-
signature);
|
1201
|
+
signature_result = Signature_alloc(Secp256k1_Signature_class);
|
1202
|
+
TypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
|
526
1203
|
|
527
1204
|
if (secp256k1_ecdsa_signature_parse_der(context->ctx,
|
528
1205
|
&(signature->sig),
|
529
1206
|
signature_data,
|
530
1207
|
RSTRING_LEN(in_der_encoded_signature)) != 1)
|
531
1208
|
{
|
532
|
-
rb_raise(
|
1209
|
+
rb_raise(rb_eArgError, "invalid DER encoded signature");
|
533
1210
|
}
|
534
1211
|
|
535
|
-
signature->
|
1212
|
+
signature->ctx = secp256k1_context_clone(context->ctx);
|
536
1213
|
return signature_result;
|
537
1214
|
}
|
538
1215
|
|
539
1216
|
/**
|
540
|
-
* Context#signature_from_compact
|
541
|
-
*
|
542
1217
|
* Deserializes a Signature from 64-byte compact signature data.
|
543
1218
|
*
|
544
|
-
*
|
545
|
-
*
|
546
|
-
*
|
547
|
-
*
|
1219
|
+
* @param in_compact_signature [String] compact signature as 64-byte binary
|
1220
|
+
* string.
|
1221
|
+
* @return [Secp256k1::Signature] object deserialized from compact signature.
|
1222
|
+
* @raise [ArgumentError] if signature data is invalid.
|
548
1223
|
*/
|
549
1224
|
static VALUE
|
550
1225
|
Context_signature_from_compact(VALUE self, VALUE in_compact_signature)
|
@@ -554,105 +1229,104 @@ Context_signature_from_compact(VALUE self, VALUE in_compact_signature)
|
|
554
1229
|
VALUE signature_result;
|
555
1230
|
unsigned char *signature_data;
|
556
1231
|
|
557
|
-
|
558
|
-
|
559
|
-
Data_Get_Struct(self, Context, context);
|
1232
|
+
TypedData_Get_Struct(self, Context, &Context_DataType, context);
|
560
1233
|
signature_data = (unsigned char*)StringValuePtr(in_compact_signature);
|
561
1234
|
|
562
|
-
signature_result =
|
563
|
-
|
564
|
-
NULL,
|
565
|
-
free,
|
566
|
-
signature);
|
1235
|
+
signature_result = Signature_alloc(Secp256k1_Signature_class);
|
1236
|
+
TypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
|
567
1237
|
|
568
1238
|
if (secp256k1_ecdsa_signature_parse_compact(context->ctx,
|
569
1239
|
&(signature->sig),
|
570
1240
|
signature_data) != 1)
|
571
1241
|
{
|
572
|
-
rb_raise(
|
1242
|
+
rb_raise(rb_eArgError, "invalid compact signature");
|
573
1243
|
}
|
574
1244
|
|
575
|
-
signature->
|
1245
|
+
signature->ctx = secp256k1_context_clone(context->ctx);
|
576
1246
|
return signature_result;
|
577
1247
|
}
|
578
1248
|
|
579
1249
|
/**
|
580
|
-
*
|
581
|
-
*
|
582
|
-
* Computes the ECDSA signature of the data using the secp256k1 EC.
|
1250
|
+
* Computes the ECDSA signature of the data using the secp256k1 elliptic curve.
|
583
1251
|
*
|
584
|
-
*
|
585
|
-
*
|
586
|
-
*
|
587
|
-
*
|
1252
|
+
* @param in_private_key [Secp256k1::PrivateKey] private key to use for
|
1253
|
+
* signing.
|
1254
|
+
* @param in_hash32 [String] 32-byte binary string with SHA-256 hash of data.
|
1255
|
+
* @return [Secp256k1::Signature] signature resulting from signing data.
|
1256
|
+
* @raise [RuntimeError] if signature computation fails.
|
1257
|
+
* @raise [ArgumentError] if hash is not 32-bytes in length.
|
588
1258
|
*/
|
589
1259
|
static VALUE
|
590
|
-
Context_sign(VALUE self, VALUE in_private_key, VALUE
|
1260
|
+
Context_sign(VALUE self, VALUE in_private_key, VALUE in_hash32)
|
591
1261
|
{
|
592
|
-
unsigned char *
|
1262
|
+
unsigned char *hash32;
|
593
1263
|
PrivateKey *private_key;
|
594
1264
|
Context *context;
|
595
1265
|
Signature *signature;
|
596
1266
|
VALUE signature_result;
|
597
1267
|
|
598
|
-
Check_Type(
|
1268
|
+
Check_Type(in_hash32, T_STRING);
|
599
1269
|
|
600
|
-
|
601
|
-
|
602
|
-
|
1270
|
+
if (RSTRING_LEN(in_hash32) != 32)
|
1271
|
+
{
|
1272
|
+
rb_raise(rb_eArgError, "in_hash32 is not 32 bytes in length");
|
1273
|
+
}
|
603
1274
|
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
free,
|
608
|
-
signature);
|
1275
|
+
TypedData_Get_Struct(self, Context, &Context_DataType, context);
|
1276
|
+
TypedData_Get_Struct(in_private_key, PrivateKey, &PrivateKey_DataType, private_key);
|
1277
|
+
hash32 = (unsigned char*)StringValuePtr(in_hash32);
|
609
1278
|
|
1279
|
+
signature_result = Signature_alloc(Secp256k1_Signature_class);
|
1280
|
+
TypedData_Get_Struct(signature_result, Signature, &Signature_DataType, signature);
|
1281
|
+
|
610
1282
|
// Attempt to sign the hash of the given data
|
611
1283
|
if (SUCCESS(SignData(context->ctx,
|
612
|
-
|
613
|
-
RSTRING_LEN(in_data),
|
1284
|
+
hash32,
|
614
1285
|
private_key->data,
|
615
1286
|
&(signature->sig))))
|
616
1287
|
{
|
617
|
-
signature->
|
1288
|
+
signature->ctx = secp256k1_context_clone(context->ctx);
|
618
1289
|
return signature_result;
|
619
1290
|
}
|
620
1291
|
|
621
|
-
rb_raise(rb_eRuntimeError, "
|
1292
|
+
rb_raise(rb_eRuntimeError, "unable to compute signature");
|
622
1293
|
}
|
623
1294
|
|
624
1295
|
/**
|
625
|
-
*
|
1296
|
+
* Verifies that signature matches public key and data.
|
626
1297
|
*
|
627
|
-
*
|
628
|
-
*
|
629
|
-
*
|
630
|
-
*
|
631
|
-
*
|
632
|
-
*
|
633
|
-
*
|
1298
|
+
* @param in_signature [Secp256k1::Signature] signature to be verified.
|
1299
|
+
* @param in_pubkey [Secp256k1::PublicKey] public key to verify signature
|
1300
|
+
* against.
|
1301
|
+
* @param in_hash32 [String] 32-byte binary string containing SHA-256 hash of
|
1302
|
+
* data.
|
1303
|
+
* @return [Boolean] True if the signature is valid, false otherwise.
|
1304
|
+
* @raise [ArgumentError] if hash is not 32-bytes in length.
|
634
1305
|
*/
|
635
1306
|
static VALUE
|
636
|
-
Context_verify(VALUE self, VALUE in_signature, VALUE in_pubkey, VALUE
|
1307
|
+
Context_verify(VALUE self, VALUE in_signature, VALUE in_pubkey, VALUE in_hash32)
|
637
1308
|
{
|
638
1309
|
Context *context;
|
639
1310
|
PublicKey *public_key;
|
640
1311
|
Signature *signature;
|
641
|
-
unsigned char *
|
642
|
-
|
1312
|
+
unsigned char *hash32;
|
1313
|
+
|
1314
|
+
Check_Type(in_hash32, T_STRING);
|
643
1315
|
|
644
|
-
|
1316
|
+
if (RSTRING_LEN(in_hash32) != 32)
|
1317
|
+
{
|
1318
|
+
rb_raise(rb_eArgError, "in_hash32 is not 32-bytes in length");
|
1319
|
+
}
|
645
1320
|
|
646
|
-
|
647
|
-
|
648
|
-
|
1321
|
+
TypedData_Get_Struct(self, Context, &Context_DataType, context);
|
1322
|
+
TypedData_Get_Struct(in_pubkey, PublicKey, &PublicKey_DataType, public_key);
|
1323
|
+
TypedData_Get_Struct(in_signature, Signature, &Signature_DataType, signature);
|
649
1324
|
|
650
|
-
|
651
|
-
SHA256(message_ptr, RSTRING_LEN(in_message), hash);
|
1325
|
+
hash32 = (unsigned char*)StringValuePtr(in_hash32);
|
652
1326
|
|
653
1327
|
if (secp256k1_ecdsa_verify(context->ctx,
|
654
1328
|
&(signature->sig),
|
655
|
-
|
1329
|
+
hash32,
|
656
1330
|
&(public_key->pubkey)) == 1)
|
657
1331
|
{
|
658
1332
|
return Qtrue;
|
@@ -661,127 +1335,196 @@ Context_verify(VALUE self, VALUE in_signature, VALUE in_pubkey, VALUE in_message
|
|
661
1335
|
return Qfalse;
|
662
1336
|
}
|
663
1337
|
|
664
|
-
//
|
665
|
-
|
666
|
-
//
|
667
|
-
|
668
|
-
static VALUE
|
669
|
-
PublicKey_alloc(VALUE klass)
|
670
|
-
{
|
671
|
-
VALUE result;
|
672
|
-
PublicKey *public_key;
|
673
|
-
|
674
|
-
result = Data_Make_Struct(klass, PublicKey, NULL, free, public_key);
|
675
|
-
|
676
|
-
return result;
|
677
|
-
}
|
1338
|
+
// Context recoverable signature methods
|
1339
|
+
#ifdef HAVE_SECP256K1_RECOVERY_H
|
678
1340
|
|
679
1341
|
/**
|
680
|
-
*
|
681
|
-
*
|
682
|
-
* Initialize a new public key from the given context and private key.
|
1342
|
+
* Computes the recoverable ECDSA signature of data signed with private key.
|
683
1343
|
*
|
684
|
-
*
|
685
|
-
*
|
686
|
-
*
|
687
|
-
*
|
1344
|
+
* @param in_private_key [Secp256k1::PrivateKey] private key to sign with.
|
1345
|
+
* @param in_hash32 [String] 32-byte binary string with SHA-256 hash of data.
|
1346
|
+
* @return [Secp256k1::RecoverableSignature] recoverable signature produced by
|
1347
|
+
* signing the SHA-256 hash `in_hash32` with `in_private_key`.
|
1348
|
+
* @raise [ArgumentError] if the hash is not 32 bytes
|
688
1349
|
*/
|
689
1350
|
static VALUE
|
690
|
-
|
1351
|
+
Context_sign_recoverable(VALUE self, VALUE in_private_key, VALUE in_hash32)
|
691
1352
|
{
|
692
1353
|
Context *context;
|
693
|
-
PublicKey *public_key;
|
694
1354
|
PrivateKey *private_key;
|
1355
|
+
RecoverableSignature *recoverable_signature;
|
1356
|
+
unsigned char *hash32;
|
1357
|
+
VALUE result;
|
695
1358
|
|
696
|
-
|
697
|
-
|
698
|
-
Data_Get_Struct(in_private_key, PrivateKey, private_key);
|
699
|
-
|
700
|
-
if (secp256k1_ec_pubkey_create(context->ctx,
|
701
|
-
&(public_key->pubkey),
|
702
|
-
private_key->data) == 0)
|
1359
|
+
Check_Type(in_hash32, T_STRING);
|
1360
|
+
if (RSTRING_LEN(in_hash32) != 32)
|
703
1361
|
{
|
704
|
-
rb_raise(
|
705
|
-
return self;
|
1362
|
+
rb_raise(rb_eArgError, "in_hash32 is not 32 bytes in length");
|
706
1363
|
}
|
707
1364
|
|
708
|
-
|
1365
|
+
TypedData_Get_Struct(self, Context, &Context_DataType, context);
|
1366
|
+
TypedData_Get_Struct(
|
1367
|
+
in_private_key, PrivateKey, &PrivateKey_DataType, private_key
|
1368
|
+
);
|
1369
|
+
hash32 = (unsigned char*)StringValuePtr(in_hash32);
|
1370
|
+
|
1371
|
+
result = RecoverableSignature_alloc(Secp256k1_RecoverableSignature_class);
|
1372
|
+
TypedData_Get_Struct(
|
1373
|
+
result,
|
1374
|
+
RecoverableSignature,
|
1375
|
+
&RecoverableSignature_DataType,
|
1376
|
+
recoverable_signature
|
1377
|
+
);
|
1378
|
+
|
1379
|
+
if (SUCCESS(RecoverableSignData(context->ctx,
|
1380
|
+
hash32,
|
1381
|
+
private_key->data,
|
1382
|
+
&(recoverable_signature->sig))))
|
1383
|
+
{
|
1384
|
+
recoverable_signature->ctx = secp256k1_context_clone(context->ctx);
|
1385
|
+
return result;
|
1386
|
+
}
|
709
1387
|
|
710
|
-
|
1388
|
+
rb_raise(rb_eRuntimeError, "unable to compute recoverable signature");
|
711
1389
|
}
|
712
1390
|
|
713
|
-
|
1391
|
+
/**
|
1392
|
+
* Loads recoverable signature from compact representation and recovery ID.
|
1393
|
+
*
|
1394
|
+
* @param in_compact_sig [String] binary string containing compact signature
|
1395
|
+
* data.
|
1396
|
+
* @param in_recovery_id [Integer] recovery ID.
|
1397
|
+
* @return [Secp256k1::RecoverableSignature] signature parsed from data.
|
1398
|
+
* @raise [RuntimeError] if signature data or recovery ID is invalid.
|
1399
|
+
* @raise [ArgumentError] if compact signature is not 64 bytes.
|
1400
|
+
*/
|
714
1401
|
static VALUE
|
715
|
-
|
1402
|
+
Context_recoverable_signature_from_compact(
|
1403
|
+
VALUE self, VALUE in_compact_sig, VALUE in_recovery_id)
|
716
1404
|
{
|
717
|
-
|
718
|
-
|
719
|
-
unsigned char
|
1405
|
+
Context *context;
|
1406
|
+
RecoverableSignature *recoverable_signature;
|
1407
|
+
unsigned char *compact_sig;
|
1408
|
+
int recovery_id;
|
1409
|
+
VALUE result;
|
1410
|
+
|
1411
|
+
Check_Type(in_compact_sig, T_STRING);
|
1412
|
+
Check_Type(in_recovery_id, T_FIXNUM);
|
1413
|
+
TypedData_Get_Struct(self, Context, &Context_DataType, context);
|
720
1414
|
|
721
|
-
|
1415
|
+
compact_sig = (unsigned char*)StringValuePtr(in_compact_sig);
|
1416
|
+
recovery_id = FIX2INT(in_recovery_id);
|
722
1417
|
|
723
|
-
if (
|
1418
|
+
if (RSTRING_LEN(in_compact_sig) != 64)
|
724
1419
|
{
|
725
|
-
rb_raise(
|
1420
|
+
rb_raise(rb_eArgError, "compact signature is not 64 bytes");
|
726
1421
|
}
|
727
1422
|
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
1423
|
+
result = RecoverableSignature_alloc(Secp256k1_RecoverableSignature_class);
|
1424
|
+
TypedData_Get_Struct(
|
1425
|
+
result,
|
1426
|
+
RecoverableSignature,
|
1427
|
+
&RecoverableSignature_DataType,
|
1428
|
+
recoverable_signature
|
1429
|
+
);
|
733
1430
|
|
734
|
-
|
1431
|
+
if (secp256k1_ecdsa_recoverable_signature_parse_compact(
|
1432
|
+
context->ctx,
|
1433
|
+
&(recoverable_signature->sig),
|
1434
|
+
compact_sig,
|
1435
|
+
recovery_id) == 1)
|
1436
|
+
{
|
1437
|
+
recoverable_signature->ctx = secp256k1_context_clone(context->ctx);
|
1438
|
+
return result;
|
1439
|
+
}
|
1440
|
+
|
1441
|
+
rb_raise(rb_eRuntimeError, "unable to parse recoverable signature");
|
735
1442
|
}
|
736
1443
|
|
737
|
-
|
1444
|
+
#endif // HAVE_SECP256K1_RECOVERY_H
|
1445
|
+
|
1446
|
+
// Context EC Diffie-Hellman methods
|
1447
|
+
#ifdef HAVE_SECP256K1_ECDH_H
|
1448
|
+
|
1449
|
+
/**
|
1450
|
+
* Compute EC Diffie-Hellman secret in constant time.
|
1451
|
+
*
|
1452
|
+
* Creates a new shared secret from public_key and private_key.
|
1453
|
+
*
|
1454
|
+
* @param point [Secp256k1::PublicKey] public-key representing ECDH point.
|
1455
|
+
* @param scalar [Secp256k1::PrivateKey] private-key representing ECDH scalar.
|
1456
|
+
* @return [Secp256k1::SharedSecret] shared secret
|
1457
|
+
* @raise [RuntimeError] If scalar was invalid (zero or caused overflow).
|
1458
|
+
*/
|
738
1459
|
static VALUE
|
739
|
-
|
1460
|
+
Context_ecdh(VALUE self, VALUE point, VALUE scalar)
|
740
1461
|
{
|
1462
|
+
Context *context;
|
741
1463
|
PublicKey *public_key;
|
742
|
-
|
743
|
-
|
1464
|
+
PrivateKey *private_key;
|
1465
|
+
SharedSecret *shared_secret;
|
1466
|
+
VALUE result;
|
744
1467
|
|
745
|
-
|
1468
|
+
TypedData_Get_Struct(self, Context, &Context_DataType, context);
|
1469
|
+
TypedData_Get_Struct(point, PublicKey, &PublicKey_DataType, public_key);
|
1470
|
+
TypedData_Get_Struct(scalar, PrivateKey, &PrivateKey_DataType, private_key);
|
746
1471
|
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
SECP256K1_EC_COMPRESSED);
|
1472
|
+
result = SharedSecret_alloc(Secp256k1_SharedSecret_class);
|
1473
|
+
TypedData_Get_Struct(
|
1474
|
+
result, SharedSecret, &SharedSecret_DataType, shared_secret
|
1475
|
+
);
|
752
1476
|
|
753
|
-
|
1477
|
+
if (secp256k1_ecdh(context->ctx,
|
1478
|
+
shared_secret->data,
|
1479
|
+
&(public_key->pubkey),
|
1480
|
+
(unsigned char*)private_key->data,
|
1481
|
+
NULL,
|
1482
|
+
NULL) != 1)
|
1483
|
+
{
|
1484
|
+
rb_raise(rb_eRuntimeError, "invalid scalar provided to ecdh");
|
1485
|
+
}
|
1486
|
+
|
1487
|
+
rb_iv_set(result, "@data", rb_str_new((char*)shared_secret->data, 32));
|
1488
|
+
|
1489
|
+
return result;
|
754
1490
|
}
|
755
1491
|
|
1492
|
+
#endif // HAVE_SECP256K1_ECDH_H
|
756
1493
|
|
757
1494
|
//
|
758
|
-
// Secp256k1
|
1495
|
+
// Secp256k1 module methods
|
759
1496
|
//
|
760
1497
|
|
1498
|
+
/**
|
1499
|
+
* Indicates whether or not the libsecp256k1 recovery module is installed.
|
1500
|
+
*
|
1501
|
+
* @return [Boolean] true if libsecp256k1 was built with the recovery module,
|
1502
|
+
* false otherwise.
|
1503
|
+
*/
|
761
1504
|
static VALUE
|
762
|
-
|
1505
|
+
Secp256k1_have_recovery(VALUE module)
|
763
1506
|
{
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
1507
|
+
#ifdef HAVE_SECP256K1_RECOVERY_H
|
1508
|
+
return Qtrue;
|
1509
|
+
#else // HAVE_SECP256K1_RECOVERY_H
|
1510
|
+
return Qfalse;
|
1511
|
+
#endif // HAVE_SECP256K1_RECOVERY_H
|
769
1512
|
}
|
770
1513
|
|
1514
|
+
/**
|
1515
|
+
* Indicates whether or not libsecp256k1 EC Diffie-Hellman module is installed.
|
1516
|
+
*
|
1517
|
+
* @return [Boolean] true if libsecp256k1 was build with the ECDH module, false
|
1518
|
+
* otherwise.
|
1519
|
+
*/
|
771
1520
|
static VALUE
|
772
|
-
|
1521
|
+
Secp256k1_have_ecdh(VALUE module)
|
773
1522
|
{
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
key_pair->private_key = private_key;
|
780
|
-
|
781
|
-
rb_iv_set(self, "@public_key", public_key);
|
782
|
-
rb_iv_set(self, "@private_key", private_key);
|
783
|
-
|
784
|
-
return self;
|
1523
|
+
#ifdef HAVE_SECP256K1_ECDH_H
|
1524
|
+
return Qtrue;
|
1525
|
+
#else // HAVE_SECP256K1_ECDH_H
|
1526
|
+
return Qfalse;
|
1527
|
+
#endif // HAVE_SECP256K1_ECDH_H
|
785
1528
|
}
|
786
1529
|
|
787
1530
|
//
|
@@ -790,16 +1533,31 @@ KeyPair_initialize(VALUE self, VALUE public_key, VALUE private_key)
|
|
790
1533
|
|
791
1534
|
void Init_rbsecp256k1()
|
792
1535
|
{
|
1536
|
+
// NOTE: All classes derive from Data (rb_cData) rather than Object
|
1537
|
+
// (rb_cObject). This makes it so we don't have to call rb_undef_alloc_func
|
1538
|
+
// for each class and can instead simply define the allocation methods for
|
1539
|
+
// each class.
|
1540
|
+
//
|
1541
|
+
// See: https://github.com/ruby/ruby/blob/trunk/doc/extension.rdoc#encapsulate-c-data-into-a-ruby-object
|
1542
|
+
|
793
1543
|
// Secp256k1
|
794
1544
|
Secp256k1_module = rb_define_module("Secp256k1");
|
795
|
-
rb_define_singleton_method(
|
796
|
-
|
797
|
-
|
798
|
-
|
1545
|
+
rb_define_singleton_method(
|
1546
|
+
Secp256k1_module,
|
1547
|
+
"have_recovery?",
|
1548
|
+
Secp256k1_have_recovery,
|
1549
|
+
0
|
1550
|
+
);
|
1551
|
+
rb_define_singleton_method(
|
1552
|
+
Secp256k1_module,
|
1553
|
+
"have_ecdh?",
|
1554
|
+
Secp256k1_have_ecdh,
|
1555
|
+
0
|
1556
|
+
);
|
799
1557
|
|
800
1558
|
// Secp256k1::Context
|
801
1559
|
Secp256k1_Context_class = rb_define_class_under(
|
802
|
-
Secp256k1_module, "Context",
|
1560
|
+
Secp256k1_module, "Context", rb_cData
|
803
1561
|
);
|
804
1562
|
rb_define_alloc_func(Secp256k1_Context_class, Context_alloc);
|
805
1563
|
rb_define_method(Secp256k1_Context_class,
|
@@ -818,6 +1576,10 @@ void Init_rbsecp256k1()
|
|
818
1576
|
"public_key_from_data",
|
819
1577
|
Context_public_key_from_data,
|
820
1578
|
1);
|
1579
|
+
rb_define_method(Secp256k1_Context_class,
|
1580
|
+
"private_key_from_data",
|
1581
|
+
Context_private_key_from_data,
|
1582
|
+
1);
|
821
1583
|
rb_define_method(Secp256k1_Context_class,
|
822
1584
|
"sign",
|
823
1585
|
Context_sign,
|
@@ -838,7 +1600,7 @@ void Init_rbsecp256k1()
|
|
838
1600
|
// Secp256k1::KeyPair
|
839
1601
|
Secp256k1_KeyPair_class = rb_define_class_under(Secp256k1_module,
|
840
1602
|
"KeyPair",
|
841
|
-
|
1603
|
+
rb_cData);
|
842
1604
|
rb_define_alloc_func(Secp256k1_KeyPair_class, KeyPair_alloc);
|
843
1605
|
rb_define_attr(Secp256k1_KeyPair_class, "public_key", 1, 0);
|
844
1606
|
rb_define_attr(Secp256k1_KeyPair_class, "private_key", 1, 0);
|
@@ -846,44 +1608,35 @@ void Init_rbsecp256k1()
|
|
846
1608
|
"initialize",
|
847
1609
|
KeyPair_initialize,
|
848
1610
|
2);
|
1611
|
+
rb_define_method(Secp256k1_KeyPair_class, "==", KeyPair_equals, 1);
|
849
1612
|
|
850
1613
|
// Secp256k1::PublicKey
|
851
1614
|
Secp256k1_PublicKey_class = rb_define_class_under(Secp256k1_module,
|
852
1615
|
"PublicKey",
|
853
|
-
|
1616
|
+
rb_cData);
|
854
1617
|
rb_define_alloc_func(Secp256k1_PublicKey_class, PublicKey_alloc);
|
855
1618
|
rb_define_method(Secp256k1_PublicKey_class,
|
856
|
-
"
|
857
|
-
|
858
|
-
2);
|
859
|
-
rb_define_method(Secp256k1_PublicKey_class,
|
860
|
-
"as_compressed",
|
861
|
-
PublicKey_as_compressed,
|
1619
|
+
"compressed",
|
1620
|
+
PublicKey_compressed,
|
862
1621
|
0);
|
863
1622
|
rb_define_method(Secp256k1_PublicKey_class,
|
864
|
-
"
|
865
|
-
|
1623
|
+
"uncompressed",
|
1624
|
+
PublicKey_uncompressed,
|
866
1625
|
0);
|
1626
|
+
rb_define_method(Secp256k1_PublicKey_class, "==", PublicKey_equals, 1);
|
867
1627
|
|
868
1628
|
// Secp256k1::PrivateKey
|
869
1629
|
Secp256k1_PrivateKey_class = rb_define_class_under(
|
870
|
-
Secp256k1_module, "PrivateKey",
|
1630
|
+
Secp256k1_module, "PrivateKey", rb_cData
|
871
1631
|
);
|
872
1632
|
rb_define_alloc_func(Secp256k1_PrivateKey_class, PrivateKey_alloc);
|
873
|
-
rb_define_singleton_method(Secp256k1_PrivateKey_class,
|
874
|
-
"generate",
|
875
|
-
PrivateKey_generate,
|
876
|
-
0);
|
877
1633
|
rb_define_attr(Secp256k1_PrivateKey_class, "data", 1, 0);
|
878
|
-
rb_define_method(Secp256k1_PrivateKey_class,
|
879
|
-
"initialize",
|
880
|
-
PrivateKey_initialize,
|
881
|
-
1);
|
1634
|
+
rb_define_method(Secp256k1_PrivateKey_class, "==", PrivateKey_equals, 1);
|
882
1635
|
|
883
1636
|
// Secp256k1::Signature
|
884
1637
|
Secp256k1_Signature_class = rb_define_class_under(Secp256k1_module,
|
885
1638
|
"Signature",
|
886
|
-
|
1639
|
+
rb_cData);
|
887
1640
|
rb_define_alloc_func(Secp256k1_Signature_class, Signature_alloc);
|
888
1641
|
rb_define_method(Secp256k1_Signature_class,
|
889
1642
|
"der_encoded",
|
@@ -893,4 +1646,81 @@ void Init_rbsecp256k1()
|
|
893
1646
|
"compact",
|
894
1647
|
Signature_compact,
|
895
1648
|
0);
|
1649
|
+
rb_define_method(Secp256k1_Signature_class,
|
1650
|
+
"normalized",
|
1651
|
+
Signature_normalized,
|
1652
|
+
0);
|
1653
|
+
rb_define_method(Secp256k1_Signature_class,
|
1654
|
+
"==",
|
1655
|
+
Signature_equals,
|
1656
|
+
1);
|
1657
|
+
|
1658
|
+
#ifdef HAVE_SECP256K1_RECOVERY_H
|
1659
|
+
// Secp256k1::RecoverableSignature
|
1660
|
+
Secp256k1_RecoverableSignature_class = rb_define_class_under(
|
1661
|
+
Secp256k1_module,
|
1662
|
+
"RecoverableSignature",
|
1663
|
+
rb_cData
|
1664
|
+
);
|
1665
|
+
rb_define_alloc_func(
|
1666
|
+
Secp256k1_RecoverableSignature_class,
|
1667
|
+
RecoverableSignature_alloc
|
1668
|
+
);
|
1669
|
+
rb_define_method(
|
1670
|
+
Secp256k1_RecoverableSignature_class,
|
1671
|
+
"compact",
|
1672
|
+
RecoverableSignature_compact,
|
1673
|
+
0
|
1674
|
+
);
|
1675
|
+
rb_define_method(
|
1676
|
+
Secp256k1_RecoverableSignature_class,
|
1677
|
+
"to_signature",
|
1678
|
+
RecoverableSignature_to_signature,
|
1679
|
+
0
|
1680
|
+
);
|
1681
|
+
rb_define_method(
|
1682
|
+
Secp256k1_RecoverableSignature_class,
|
1683
|
+
"recover_public_key",
|
1684
|
+
RecoverableSignature_recover_public_key,
|
1685
|
+
1
|
1686
|
+
);
|
1687
|
+
rb_define_method(
|
1688
|
+
Secp256k1_RecoverableSignature_class,
|
1689
|
+
"==",
|
1690
|
+
RecoverableSignature_equals,
|
1691
|
+
1
|
1692
|
+
);
|
1693
|
+
|
1694
|
+
// Context recoverable signature methods
|
1695
|
+
rb_define_method(
|
1696
|
+
Secp256k1_Context_class,
|
1697
|
+
"sign_recoverable",
|
1698
|
+
Context_sign_recoverable,
|
1699
|
+
2
|
1700
|
+
);
|
1701
|
+
rb_define_method(
|
1702
|
+
Secp256k1_Context_class,
|
1703
|
+
"recoverable_signature_from_compact",
|
1704
|
+
Context_recoverable_signature_from_compact,
|
1705
|
+
2
|
1706
|
+
);
|
1707
|
+
#endif // HAVE_SECP256K1_RECOVERY_H
|
1708
|
+
|
1709
|
+
#ifdef HAVE_SECP256K1_ECDH_H
|
1710
|
+
Secp256k1_SharedSecret_class = rb_define_class_under(
|
1711
|
+
Secp256k1_module,
|
1712
|
+
"SharedSecret",
|
1713
|
+
rb_cData
|
1714
|
+
);
|
1715
|
+
rb_define_alloc_func(Secp256k1_SharedSecret_class, SharedSecret_alloc);
|
1716
|
+
rb_define_attr(Secp256k1_SharedSecret_class, "data", 1, 0);
|
1717
|
+
|
1718
|
+
// Context EC Diffie-Hellman methods
|
1719
|
+
rb_define_method(
|
1720
|
+
Secp256k1_Context_class,
|
1721
|
+
"ecdh",
|
1722
|
+
Context_ecdh,
|
1723
|
+
2
|
1724
|
+
);
|
1725
|
+
#endif // HAVE_SECP256K1_ECDH_H
|
896
1726
|
}
|