rbsecp256k1 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ad49bf4a099e7afb5cf5ef09af6d61f5019c4378fdc0bda9bc1b7b66d2cbca8b
4
+ data.tar.gz: 8de35376f226a7955feb12c8214a6f023cbed7dde25fc1d98aa49464e6777cb5
5
+ SHA512:
6
+ metadata.gz: 68a48a57862f066da1477de75283e18c20daa80bb8508e5cf39da06885eb12bc38d40f06e35958d13667fac942d31315b6a13a175970bc5e929eff8bcf1a1514
7
+ data.tar.gz: b802bda821e12c398c379b003a4a60956d6d69b8f30fe26e2d799ef23290f228ffca603a30e3c376dfe0b546b2d8b7b9dedc86c6862d963228d67c3f3fbb0efe
@@ -0,0 +1,5 @@
1
+ require "rake/extensiontask"
2
+
3
+ Rake::ExtensionTask.new "rbsecp256k1" do |ext|
4
+ ext.lib_dir = "lib/rbsecp256k1"
5
+ end
@@ -0,0 +1,13 @@
1
+ require 'mkmf'
2
+
3
+ # OpenSSL flags
4
+ print("Looking for OpenSSL")
5
+ results = pkg_config('openssl')
6
+ abort "missing openssl pkg-config information" unless results[1]
7
+
8
+ # Require that libsecp256k1 be installed using `make install` or similar.
9
+ print("Looking for libsecp256k1")
10
+ results = pkg_config('libsecp256k1')
11
+ abort "missing libsecp256k1" unless results[1]
12
+
13
+ create_makefile('rbsecp256k1')
@@ -0,0 +1,896 @@
1
+ // rbsecp256k1.c - Ruby VM interfaces for library.
2
+ //
3
+ // Description:
4
+ // This library provides a low-level and high-performance Ruby wrapper around
5
+ // libsecp256k1. It includes functions for generating key pairs, signing data,
6
+ // and verifying signatures using the library.
7
+ //
8
+ // Dependencies:
9
+ // * libsecp256k1
10
+ // * openssl
11
+ #include <ruby.h>
12
+ #include <stdio.h>
13
+
14
+ #include <openssl/rand.h>
15
+ #include <openssl/sha.h>
16
+ #include <secp256k1.h>
17
+
18
+ // High-level design:
19
+ //
20
+ // The Ruby wrapper is divided into the following hierarchical organization:
21
+ //
22
+ // +- Secp256k1 (Top-level module)
23
+ // |-- Context
24
+ // |-- KeyPair
25
+ // |-- PublicKey
26
+ // |-- PrivateKey
27
+ // |-- Signature
28
+ //
29
+ // The Context class contains most of the methods that invoke libsecp256k1.
30
+ // The KayPair, PublicKey, PrivateKey, and Signature objects act as data
31
+ // objects and are passed to various methods. Contexts are thread safe and can
32
+ // be used across applications. Context initialization is expensive so it is
33
+ // recommended that a single context be initialized and used throughout an
34
+ // application when possible.
35
+
36
+ //
37
+ // The section below contains purely internal methods used exclusively by the
38
+ // C internals of the library.
39
+ //
40
+
41
+ // Globally define our module and its associated classes so we can instantiate
42
+ // objects from anywhere. The use of global variables seems to be inline with
43
+ // how the Ruby project builds its own extension gems.
44
+ static VALUE Secp256k1_module;
45
+ static VALUE Secp256k1_Context_class;
46
+ static VALUE Secp256k1_KeyPair_class;
47
+ static VALUE Secp256k1_PublicKey_class;
48
+ static VALUE Secp256k1_PrivateKey_class;
49
+ static VALUE Secp256k1_Signature_class;
50
+
51
+ // Forward definitions for all structures
52
+ typedef struct Context_dummy {
53
+ secp256k1_context *ctx; // Context used by libsecp256k1 library
54
+ } Context;
55
+
56
+ typedef struct KeyPair_dummy {
57
+ VALUE public_key;
58
+ VALUE private_key;
59
+ } KeyPair;
60
+
61
+ typedef struct PublicKey_dummy {
62
+ secp256k1_pubkey pubkey;
63
+ Context *context;
64
+ } PublicKey;
65
+
66
+ typedef struct PrivateKey_dummy {
67
+ unsigned char data[32]; // Bytes comprising the private key data
68
+ } PrivateKey;
69
+
70
+ typedef struct Signature_dummy {
71
+ secp256k1_ecdsa_signature sig; // Signature object, contains 64-byte signature.
72
+ Context *context;
73
+ } Signature;
74
+
75
+ /**
76
+ * Macro: SUCCESS
77
+ *
78
+ * Determines whether or not the given function result was a success.
79
+ */
80
+ #define SUCCESS(x) ((x) == RESULT_SUCCESS)
81
+
82
+ /**
83
+ * Macro: FAILURE
84
+ *
85
+ * Indicates whether or not the given function result is a failure.
86
+ */
87
+ #define FAILURE(x) !SUCCESS(x)
88
+
89
+ /* Result type for internally defined functions */
90
+ typedef enum ResultT_dummy {
91
+ RESULT_SUCCESS,
92
+ RESULT_FAILURE
93
+ } ResultT;
94
+
95
+ /**
96
+ * Generate a series of cryptographically secure random bytes using OpenSSL.
97
+ *
98
+ * \param out_bytes Desired number of bytes will be written here.
99
+ * \param in_size Number of bytes of random data to be generated.
100
+ * \return RESULT_SUCCESS if the bytes were generated successfully,
101
+ * RESULT_FAILURE otherwise.
102
+ */
103
+ static ResultT
104
+ GenerateRandomBytes(unsigned char *out_bytes, size_t in_size)
105
+ {
106
+ // OpenSSL RNG has not been seeded with enough data and is therefore
107
+ // not usable.
108
+ if (RAND_status() == 0)
109
+ {
110
+ return RESULT_FAILURE;
111
+ }
112
+
113
+ // Attempt to generate random bytes using the OpenSSL RNG
114
+ if (RAND_bytes(out_bytes, in_size) != 1)
115
+ {
116
+ return RESULT_FAILURE;
117
+ }
118
+
119
+ return RESULT_SUCCESS;
120
+ }
121
+
122
+ /**
123
+ * Computes the ECDSA signature of the given data.
124
+ *
125
+ * This method first computes the ECDSA signature of the given data (can be
126
+ * text or binary data) and outputs both the raw libsecp256k1 signature.
127
+ *
128
+ * ECDSA signing involves the following steps:
129
+ * 1. Compute the 32-byte SHA-256 hash of the given data.
130
+ * 2. Sign the 32-byte hash using the private key provided.
131
+ *
132
+ * \param in_context libsecp256k1 context
133
+ * \param in_data Data to be signed
134
+ * \param in_data_len Length of data to be signed
135
+ * \param in_private_key Private key to be used for signing
136
+ * \param out_signature Signature produced during the signing proccess
137
+ * \return RESULT_SUCCESS if the hash and signature were computed successfully,
138
+ * RESULT_FAILURE if signing failed or DER encoding failed.
139
+ */
140
+ static ResultT
141
+ SignData(secp256k1_context *in_context,
142
+ unsigned char *in_data,
143
+ unsigned long in_data_len,
144
+ unsigned char *in_private_key,
145
+ secp256k1_ecdsa_signature *out_signature)
146
+ {
147
+ unsigned char hash[SHA256_DIGEST_LENGTH];
148
+
149
+ // Compute the SHA-256 hash of data
150
+ SHA256(in_data, in_data_len, hash);
151
+
152
+ // Sign the hash of the data
153
+ if (secp256k1_ecdsa_sign(in_context,
154
+ out_signature,
155
+ hash,
156
+ in_private_key,
157
+ NULL,
158
+ NULL) == 1)
159
+ {
160
+ return RESULT_SUCCESS;
161
+ }
162
+
163
+ return RESULT_FAILURE;
164
+ }
165
+
166
+ /**
167
+ * Secp256k1.generate_private_key_bytes
168
+ *
169
+ * Generate cryptographically secure 32 byte private key data.
170
+ *
171
+ * Raises:
172
+ * RuntimeError - If random number generation fails for any reason.
173
+ */
174
+ static VALUE
175
+ Secp256k1_generate_private_key_bytes(VALUE self)
176
+ {
177
+ unsigned char private_key_bytes[32];
178
+
179
+ if (FAILURE(GenerateRandomBytes(private_key_bytes, 32)))
180
+ {
181
+ rb_raise(rb_eRuntimeError, "Random number generation failed.");
182
+ }
183
+
184
+ return rb_str_new((char*)private_key_bytes, 32);
185
+ }
186
+
187
+ //
188
+ // Secp256k1::PrivateKey class interface
189
+ //
190
+
191
+ /* Allocate space for new private key internal data */
192
+ static VALUE
193
+ PrivateKey_alloc(VALUE klass)
194
+ {
195
+ VALUE new_instance;
196
+ PrivateKey *private_key;
197
+
198
+ new_instance = Data_Make_Struct(
199
+ klass, PrivateKey, NULL, free, private_key
200
+ );
201
+ memset(private_key->data, 0, 32);
202
+
203
+ return new_instance;
204
+ }
205
+
206
+ /**
207
+ * PrivateKey.generate
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.
227
+ *
228
+ * \param self allocated class instance
229
+ * \param in_bytes private key data as 32 byte string
230
+ * \raises ArgumentError If private key data is not 32 bytes long.
231
+ */
232
+ static VALUE
233
+ PrivateKey_initialize(VALUE self, VALUE in_bytes)
234
+ {
235
+ PrivateKey *private_key;
236
+
237
+ Check_Type(in_bytes, T_STRING);
238
+
239
+ if (RSTRING_LEN(in_bytes) != 32)
240
+ {
241
+ rb_raise(rb_eArgError, "private key data must be 32 bytes in length");
242
+ return self;
243
+ }
244
+
245
+ Data_Get_Struct(self, PrivateKey, private_key);
246
+ memcpy(private_key->data, RSTRING_PTR(in_bytes), 32);
247
+
248
+ // Set the PrivateKey.data attribute for later reading
249
+ rb_iv_set(self, "@data", in_bytes);
250
+
251
+ return self;
252
+ }
253
+
254
+ //
255
+ // Secp256k1::Signature class interface
256
+ //
257
+
258
+ /* Allocate memory for Signature object */
259
+ static VALUE
260
+ Signature_alloc(VALUE klass)
261
+ {
262
+ VALUE new_instance;
263
+ Signature *signature;
264
+
265
+ new_instance = Data_Make_Struct(klass,
266
+ Signature,
267
+ NULL,
268
+ free,
269
+ signature);
270
+ memset(signature, 0, sizeof(Signature));
271
+
272
+ return new_instance;
273
+ }
274
+
275
+ /**
276
+ * Signature#der_encoded
277
+ *
278
+ * \param self
279
+ * \return DER encoded version of this signature
280
+ */
281
+ static VALUE
282
+ Signature_der_encoded(VALUE self)
283
+ {
284
+ Signature *signature;
285
+ unsigned long der_signature_len;
286
+ unsigned char der_signature[512];
287
+
288
+ Data_Get_Struct(self, Signature, signature);
289
+
290
+ der_signature_len = 512;
291
+ if (secp256k1_ecdsa_signature_serialize_der(signature->context->ctx,
292
+ der_signature,
293
+ &der_signature_len,
294
+ &(signature->sig)) == 1)
295
+ {
296
+ return rb_str_new((char*)der_signature, der_signature_len);
297
+ }
298
+
299
+ rb_raise(rb_eRuntimeError, "Could not compute DER encoded signature");
300
+ }
301
+
302
+ /**
303
+ * Signature#compact
304
+ *
305
+ * Returns the compact (64-byte) representation of this signature.
306
+ *
307
+ * \param self
308
+ * \return Compact encoding of this signature
309
+ */
310
+ static VALUE
311
+ Signature_compact(VALUE self)
312
+ {
313
+ Signature *signature;
314
+ unsigned char compact_signature[65];
315
+
316
+ Data_Get_Struct(self, Signature, signature);
317
+
318
+ if (secp256k1_ecdsa_signature_serialize_compact(signature->context->ctx,
319
+ compact_signature,
320
+ &(signature->sig)) == 1)
321
+ {
322
+ return rb_str_new((char*)compact_signature, 65);
323
+ }
324
+
325
+ rb_raise(rb_eRuntimeError, "Unable to compute compact signature");
326
+ }
327
+
328
+ //
329
+ // Secp256k1::Context class interface
330
+ //
331
+
332
+ /* Deallocate a context when it is garbage collected */
333
+ static void
334
+ Context_free(void* in_context)
335
+ {
336
+ Context *context = (Context*)in_context;
337
+
338
+ secp256k1_context_destroy(context->ctx);
339
+ free(context);
340
+ }
341
+
342
+ /* Allocate a new context object */
343
+ static VALUE
344
+ Context_alloc(VALUE klass)
345
+ {
346
+ VALUE new_instance;
347
+ Context *context;
348
+
349
+ new_instance = Data_Make_Struct(
350
+ klass, Context, NULL, Context_free, context
351
+ );
352
+ context->ctx = NULL;
353
+
354
+ return new_instance;
355
+ }
356
+
357
+ /**
358
+ * Context#initialize
359
+ *
360
+ * Initialize a new libsecp256k1 context.
361
+ *
362
+ * \raises RuntimeError if context randomizatino fails.
363
+ */
364
+ static VALUE
365
+ Context_initialize(VALUE self)
366
+ {
367
+ Context *context;
368
+ unsigned char seed[32];
369
+
370
+ Data_Get_Struct(self, Context, context);
371
+
372
+ context->ctx = secp256k1_context_create(
373
+ SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY
374
+ );
375
+
376
+ // Randomize the context at initialization time rather than before calls so
377
+ // the same context can be used across threads safely.
378
+ GenerateRandomBytes(seed, 32);
379
+ if (secp256k1_context_randomize(context->ctx, seed) != 1)
380
+ {
381
+ rb_raise(rb_eRuntimeError, "Randomization of context failed.");
382
+ }
383
+
384
+ return self;
385
+ }
386
+
387
+ /**
388
+ * Context#generate_key_pair
389
+ *
390
+ * Generate a new (public, private) key pair.
391
+ */
392
+ static VALUE
393
+ Context_generate_key_pair(VALUE self)
394
+ {
395
+ VALUE private_key;
396
+ VALUE public_key;
397
+ VALUE key_pair;
398
+
399
+ private_key = PrivateKey_generate(Secp256k1_PrivateKey_class);
400
+ public_key = rb_funcall(Secp256k1_PublicKey_class,
401
+ rb_intern("new"),
402
+ 2,
403
+ self,
404
+ private_key);
405
+ key_pair = rb_funcall(Secp256k1_KeyPair_class,
406
+ rb_intern("new"),
407
+ 2,
408
+ public_key,
409
+ private_key);
410
+
411
+ return key_pair;
412
+ }
413
+
414
+ /**
415
+ * Context#public_key_from_data
416
+ *
417
+ * Loads a public key from compressed or uncompressed binary data.
418
+ *
419
+ * \param self
420
+ * \param in_public_key_data Compressed or uncompressed binary public key data.
421
+ */
422
+ static VALUE
423
+ Context_public_key_from_data(VALUE self, VALUE in_public_key_data)
424
+ {
425
+ Context *context;
426
+ PublicKey *public_key;
427
+ unsigned char *public_key_data;
428
+ VALUE result;
429
+
430
+ Check_Type(in_public_key_data, T_STRING);
431
+
432
+ Data_Get_Struct(self, Context, context);
433
+ public_key_data = (unsigned char*)StringValuePtr(in_public_key_data);
434
+ result = Data_Make_Struct(Secp256k1_PublicKey_class,
435
+ PublicKey,
436
+ NULL,
437
+ free,
438
+ public_key);
439
+ public_key->context = context;
440
+
441
+ if (secp256k1_ec_pubkey_parse(context->ctx,
442
+ &(public_key->pubkey),
443
+ public_key_data,
444
+ RSTRING_LEN(in_public_key_data)) != 1)
445
+ {
446
+ rb_raise(rb_eRuntimeError, "Invalid public key data");
447
+ }
448
+
449
+ return result;
450
+ }
451
+
452
+ /**
453
+ * Context#key_pair_from_private_key
454
+ *
455
+ * Converts a binary private key into a key pair
456
+ *
457
+ * \param self
458
+ * \param in_private_key_data Binary private key data to be used
459
+ * \return A KeyPair initialized from the given private key data
460
+ * \raises ArgumentError if the private key data is invalid or key derivation
461
+ * fails.
462
+ */
463
+ static VALUE
464
+ Context_key_pair_from_private_key(VALUE self, VALUE in_private_key_data)
465
+ {
466
+ Context *context;
467
+ VALUE public_key;
468
+ VALUE private_key;
469
+ VALUE key_pair;
470
+ unsigned char *private_key_data;
471
+
472
+ // TODO: Move verification into PrivateKey_initialize?
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)
478
+ {
479
+ rb_raise(rb_eRuntimeError, "Invalid private key data.");
480
+ }
481
+
482
+ private_key = rb_funcall(Secp256k1_PrivateKey_class,
483
+ rb_intern("new"),
484
+ 1,
485
+ in_private_key_data);
486
+ public_key = rb_funcall(Secp256k1_PublicKey_class,
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);
496
+
497
+ return key_pair;
498
+ }
499
+
500
+ /**
501
+ * Context#signature_from_der_encoded
502
+ *
503
+ * Converts a DER encoded signature into a Secp256k1::Signature object.
504
+ *
505
+ * \param self
506
+ * \param in_der_encoded_signature DER encoded signature as a binary string
507
+ */
508
+ static VALUE
509
+ Context_signature_from_der_encoded(VALUE self, VALUE in_der_encoded_signature)
510
+ {
511
+ Context *context;
512
+ Signature *signature;
513
+ VALUE signature_result;
514
+ unsigned char *signature_data;
515
+
516
+ Check_Type(in_der_encoded_signature, T_STRING);
517
+
518
+ Data_Get_Struct(self, Context, context);
519
+ signature_data = (unsigned char*)StringValuePtr(in_der_encoded_signature);
520
+
521
+ signature_result = Data_Make_Struct(Secp256k1_Signature_class,
522
+ Signature,
523
+ NULL,
524
+ free,
525
+ signature);
526
+
527
+ if (secp256k1_ecdsa_signature_parse_der(context->ctx,
528
+ &(signature->sig),
529
+ signature_data,
530
+ RSTRING_LEN(in_der_encoded_signature)) != 1)
531
+ {
532
+ rb_raise(rb_eRuntimeError, "Invalid DER encoded signature.");
533
+ }
534
+
535
+ signature->context = context;
536
+ return signature_result;
537
+ }
538
+
539
+ /**
540
+ * Context#signature_from_compact
541
+ *
542
+ * Deserializes a Signature from 64-byte compact signature data.
543
+ *
544
+ * \param self
545
+ * \param in_compact_signature Compact signature to deserialize
546
+ * \return Signature object deserialized from compact signature.
547
+ * \raises RuntimeError if signature deserialization fails
548
+ */
549
+ static VALUE
550
+ Context_signature_from_compact(VALUE self, VALUE in_compact_signature)
551
+ {
552
+ Context *context;
553
+ Signature *signature;
554
+ VALUE signature_result;
555
+ unsigned char *signature_data;
556
+
557
+ Check_Type(in_compact_signature, T_STRING);
558
+
559
+ Data_Get_Struct(self, Context, context);
560
+ signature_data = (unsigned char*)StringValuePtr(in_compact_signature);
561
+
562
+ signature_result = Data_Make_Struct(Secp256k1_Signature_class,
563
+ Signature,
564
+ NULL,
565
+ free,
566
+ signature);
567
+
568
+ if (secp256k1_ecdsa_signature_parse_compact(context->ctx,
569
+ &(signature->sig),
570
+ signature_data) != 1)
571
+ {
572
+ rb_raise(rb_eRuntimeError, "Invalid compact signature.");
573
+ }
574
+
575
+ signature->context = context;
576
+ return signature_result;
577
+ }
578
+
579
+ /**
580
+ * Context#sign
581
+ *
582
+ * Computes the ECDSA signature of the data using the secp256k1 EC.
583
+ *
584
+ * \param self
585
+ * \param in_private_key Private key to use for signing
586
+ * \param in_data Data to be signed
587
+ * \raises RuntimeError if signing fails
588
+ */
589
+ static VALUE
590
+ Context_sign(VALUE self, VALUE in_private_key, VALUE in_data)
591
+ {
592
+ unsigned char *data_ptr;
593
+ PrivateKey *private_key;
594
+ Context *context;
595
+ Signature *signature;
596
+ VALUE signature_result;
597
+
598
+ Check_Type(in_data, T_STRING);
599
+
600
+ Data_Get_Struct(self, Context, context);
601
+ Data_Get_Struct(in_private_key, PrivateKey, private_key);
602
+ data_ptr = (unsigned char*)StringValuePtr(in_data);
603
+
604
+ signature_result = Data_Make_Struct(Secp256k1_Signature_class,
605
+ Signature,
606
+ NULL,
607
+ free,
608
+ signature);
609
+
610
+ // Attempt to sign the hash of the given data
611
+ if (SUCCESS(SignData(context->ctx,
612
+ data_ptr,
613
+ RSTRING_LEN(in_data),
614
+ private_key->data,
615
+ &(signature->sig))))
616
+ {
617
+ signature->context = context;
618
+ return signature_result;
619
+ }
620
+
621
+ rb_raise(rb_eRuntimeError, "Unable to compute signature");
622
+ }
623
+
624
+ /**
625
+ * Context#verify
626
+ *
627
+ * Verifies that the signature by the holder of public key on message.
628
+ *
629
+ * \param self
630
+ * \param in_signature Signature to be verified
631
+ * \param in_pubkey Public key to verify signature against
632
+ * \param in_message Message to verify signature of
633
+ * \return Qtrue if the signature is valid, Qfalse otherwise.
634
+ */
635
+ static VALUE
636
+ Context_verify(VALUE self, VALUE in_signature, VALUE in_pubkey, VALUE in_message)
637
+ {
638
+ Context *context;
639
+ PublicKey *public_key;
640
+ Signature *signature;
641
+ unsigned char *message_ptr;
642
+ unsigned char hash[SHA256_DIGEST_LENGTH];
643
+
644
+ Check_Type(in_message, T_STRING);
645
+
646
+ Data_Get_Struct(self, Context, context);
647
+ Data_Get_Struct(in_pubkey, PublicKey, public_key);
648
+ Data_Get_Struct(in_signature, Signature, signature);
649
+
650
+ message_ptr = (unsigned char*)StringValuePtr(in_message);
651
+ SHA256(message_ptr, RSTRING_LEN(in_message), hash);
652
+
653
+ if (secp256k1_ecdsa_verify(context->ctx,
654
+ &(signature->sig),
655
+ hash,
656
+ &(public_key->pubkey)) == 1)
657
+ {
658
+ return Qtrue;
659
+ }
660
+
661
+ return Qfalse;
662
+ }
663
+
664
+ //
665
+ // Secp256k1::PublicKey class interface
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
+ }
678
+
679
+ /**
680
+ * PublicKey#initialize
681
+ *
682
+ * Initialize a new public key from the given context and private key.
683
+ *
684
+ * \param in_context Context instance to be used in derivation
685
+ * \param in_private_key PrivateKey to derive public key from
686
+ * \return PublicKey instance initialized with data
687
+ * \raises TypeError if private key data is invalid
688
+ */
689
+ static VALUE
690
+ PublicKey_initialize(VALUE self, VALUE in_context, VALUE in_private_key)
691
+ {
692
+ Context *context;
693
+ PublicKey *public_key;
694
+ PrivateKey *private_key;
695
+
696
+ Data_Get_Struct(self, PublicKey, public_key);
697
+ Data_Get_Struct(in_context, Context, context);
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)
703
+ {
704
+ rb_raise(rb_eTypeError, "Invalid private key data");
705
+ return self;
706
+ }
707
+
708
+ public_key->context = context;
709
+
710
+ return self;
711
+ }
712
+
713
+ /* PublicKey#as_uncompressed */
714
+ static VALUE
715
+ PublicKey_as_uncompressed(VALUE self)
716
+ {
717
+ PublicKey *public_key;
718
+ size_t serialized_pubkey_len = 65;
719
+ unsigned char serialized_pubkey[65];
720
+
721
+ Data_Get_Struct(self, PublicKey, public_key);
722
+
723
+ if (public_key->context == NULL || public_key->context->ctx == NULL)
724
+ {
725
+ rb_raise(rb_eRuntimeError, "Public key context is NULL");
726
+ }
727
+
728
+ secp256k1_ec_pubkey_serialize(public_key->context->ctx,
729
+ serialized_pubkey,
730
+ &serialized_pubkey_len,
731
+ &(public_key->pubkey),
732
+ SECP256K1_EC_UNCOMPRESSED);
733
+
734
+ return rb_str_new((char*)serialized_pubkey, serialized_pubkey_len);
735
+ }
736
+
737
+ /* PublicKey#as_compressed */
738
+ static VALUE
739
+ PublicKey_as_compressed(VALUE self)
740
+ {
741
+ PublicKey *public_key;
742
+ size_t serialized_pubkey_len = 65;
743
+ unsigned char serialized_pubkey[65];
744
+
745
+ Data_Get_Struct(self, PublicKey, public_key);
746
+
747
+ secp256k1_ec_pubkey_serialize(public_key->context->ctx,
748
+ serialized_pubkey,
749
+ &serialized_pubkey_len,
750
+ &(public_key->pubkey),
751
+ SECP256K1_EC_COMPRESSED);
752
+
753
+ return rb_str_new((char*)serialized_pubkey, serialized_pubkey_len);
754
+ }
755
+
756
+
757
+ //
758
+ // Secp256k1::KeyPair class interface
759
+ //
760
+
761
+ static VALUE
762
+ KeyPair_alloc(VALUE klass)
763
+ {
764
+ VALUE result;
765
+ KeyPair *key_pair;
766
+ result = Data_Make_Struct(klass, KeyPair, NULL, free, key_pair);
767
+
768
+ return result;
769
+ }
770
+
771
+ static VALUE
772
+ KeyPair_initialize(VALUE self, VALUE public_key, VALUE private_key)
773
+ {
774
+ KeyPair *key_pair;
775
+
776
+ Data_Get_Struct(self, KeyPair, key_pair);
777
+
778
+ key_pair->public_key = public_key;
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;
785
+ }
786
+
787
+ //
788
+ // Library initialization
789
+ //
790
+
791
+ void Init_rbsecp256k1()
792
+ {
793
+ // Secp256k1
794
+ Secp256k1_module = rb_define_module("Secp256k1");
795
+ rb_define_singleton_method(Secp256k1_module,
796
+ "generate_private_key_bytes",
797
+ Secp256k1_generate_private_key_bytes,
798
+ 0);
799
+
800
+ // Secp256k1::Context
801
+ Secp256k1_Context_class = rb_define_class_under(
802
+ Secp256k1_module, "Context", rb_cObject
803
+ );
804
+ rb_define_alloc_func(Secp256k1_Context_class, Context_alloc);
805
+ rb_define_method(Secp256k1_Context_class,
806
+ "initialize",
807
+ Context_initialize,
808
+ 0);
809
+ rb_define_method(Secp256k1_Context_class,
810
+ "generate_key_pair",
811
+ Context_generate_key_pair,
812
+ 0);
813
+ rb_define_method(Secp256k1_Context_class,
814
+ "key_pair_from_private_key",
815
+ Context_key_pair_from_private_key,
816
+ 1);
817
+ rb_define_method(Secp256k1_Context_class,
818
+ "public_key_from_data",
819
+ Context_public_key_from_data,
820
+ 1);
821
+ rb_define_method(Secp256k1_Context_class,
822
+ "sign",
823
+ Context_sign,
824
+ 2);
825
+ rb_define_method(Secp256k1_Context_class,
826
+ "verify",
827
+ Context_verify,
828
+ 3);
829
+ rb_define_method(Secp256k1_Context_class,
830
+ "signature_from_der_encoded",
831
+ Context_signature_from_der_encoded,
832
+ 1);
833
+ rb_define_method(Secp256k1_Context_class,
834
+ "signature_from_compact",
835
+ Context_signature_from_compact,
836
+ 1);
837
+
838
+ // Secp256k1::KeyPair
839
+ Secp256k1_KeyPair_class = rb_define_class_under(Secp256k1_module,
840
+ "KeyPair",
841
+ rb_cObject);
842
+ rb_define_alloc_func(Secp256k1_KeyPair_class, KeyPair_alloc);
843
+ rb_define_attr(Secp256k1_KeyPair_class, "public_key", 1, 0);
844
+ rb_define_attr(Secp256k1_KeyPair_class, "private_key", 1, 0);
845
+ rb_define_method(Secp256k1_KeyPair_class,
846
+ "initialize",
847
+ KeyPair_initialize,
848
+ 2);
849
+
850
+ // Secp256k1::PublicKey
851
+ Secp256k1_PublicKey_class = rb_define_class_under(Secp256k1_module,
852
+ "PublicKey",
853
+ rb_cObject);
854
+ rb_define_alloc_func(Secp256k1_PublicKey_class, PublicKey_alloc);
855
+ rb_define_method(Secp256k1_PublicKey_class,
856
+ "initialize",
857
+ PublicKey_initialize,
858
+ 2);
859
+ rb_define_method(Secp256k1_PublicKey_class,
860
+ "as_compressed",
861
+ PublicKey_as_compressed,
862
+ 0);
863
+ rb_define_method(Secp256k1_PublicKey_class,
864
+ "as_uncompressed",
865
+ PublicKey_as_uncompressed,
866
+ 0);
867
+
868
+ // Secp256k1::PrivateKey
869
+ Secp256k1_PrivateKey_class = rb_define_class_under(
870
+ Secp256k1_module, "PrivateKey", rb_cObject
871
+ );
872
+ 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
+ rb_define_attr(Secp256k1_PrivateKey_class, "data", 1, 0);
878
+ rb_define_method(Secp256k1_PrivateKey_class,
879
+ "initialize",
880
+ PrivateKey_initialize,
881
+ 1);
882
+
883
+ // Secp256k1::Signature
884
+ Secp256k1_Signature_class = rb_define_class_under(Secp256k1_module,
885
+ "Signature",
886
+ rb_cObject);
887
+ rb_define_alloc_func(Secp256k1_Signature_class, Signature_alloc);
888
+ rb_define_method(Secp256k1_Signature_class,
889
+ "der_encoded",
890
+ Signature_der_encoded,
891
+ 0);
892
+ rb_define_method(Secp256k1_Signature_class,
893
+ "compact",
894
+ Signature_compact,
895
+ 0);
896
+ }
@@ -0,0 +1,7 @@
1
+ # Wraps libsecp256k1 in a ruby module and provides object interfaces.
2
+ module Secp256k1
3
+ end
4
+
5
+ require 'rbsecp256k1/util'
6
+ require 'rbsecp256k1/version'
7
+ require 'rbsecp256k1/rbsecp256k1'
@@ -0,0 +1,20 @@
1
+ module Secp256k1
2
+ # Contains utility methods that complement the functionality of the library.
3
+ module Util
4
+ # Converts a binary string to a hex string.
5
+ #
6
+ # @param binary_string [String] binary string to be converted.
7
+ # @return [String] hex string equivalent of the given binary string.
8
+ def self.bin_to_hex(binary_string)
9
+ binary_string.unpack('H*').first
10
+ end
11
+
12
+ # Converts a hex string to a binary string.
13
+ #
14
+ # @param hex_string [String] string with hexadeimcal value.
15
+ # @return [String] binary string equivalent of the given hex string.
16
+ def self.hex_to_bin(hex_string)
17
+ [hex_string].pack('H*')
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module Secp256k1
2
+ VERSION = '1.0.0'.freeze
3
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rbsecp256k1
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Eric Scrivner
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-12-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '12.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '12.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake-compiler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.8'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.61'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.61'
69
+ description:
70
+ email:
71
+ executables: []
72
+ extensions:
73
+ - ext/rbsecp256k1/extconf.rb
74
+ extra_rdoc_files: []
75
+ files:
76
+ - Rakefile
77
+ - ext/rbsecp256k1/extconf.rb
78
+ - ext/rbsecp256k1/rbsecp256k1.c
79
+ - lib/rbsecp256k1.rb
80
+ - lib/rbsecp256k1/util.rb
81
+ - lib/rbsecp256k1/version.rb
82
+ homepage: https://github.com/etscrivner/rbsecp256k1
83
+ licenses:
84
+ - MIT
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - ext
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubyforge_project:
103
+ rubygems_version: 2.7.6
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: Compiled, native ruby extension interfaces to libsecp256k1
107
+ test_files: []