rbsecp256k1 4.0.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0bda0a3b5513e2716322c5bd47668b1fe17493ee6a542848d4d3add50cabd67
4
- data.tar.gz: 45d1d8dccfa8303b5d750f270dd65331ae6c72948982863e430628cfe9ce2b9a
3
+ metadata.gz: '09bce1370a196e16d15f8d923add9097a24e54cd16d6966252eaef876b43e8e2'
4
+ data.tar.gz: 59c16c569f2ea9a18d67f041b0a6bcd4b334d747a165e8801192094518a0a11b
5
5
  SHA512:
6
- metadata.gz: 980d07a3fb920d7c873aca6969dc7102896379005e5a30741f637387fd43c06efdfddb09905e5c24a1dd1bb780211ebe9d46e3a8d16f02f95bf0a180cc6a7652
7
- data.tar.gz: acb8d3284c484d946a5e22ebb4f4f2fb2c72f4e0e1e3b9bdb5b8beed2890283c361a14eda2453817401c0a8d98ace34219208f10d8997d98d21ef49766843d0c
6
+ metadata.gz: 457122cce9314f5f6af45c73fc2b55977e98765d5aa13e18e6a7f6ea614f0af0559857a6a735c4c066760b62af9fa970200645fb93f1f4fd333a6f3412297ad5
7
+ data.tar.gz: 4f503461cc54439ea891b4c0827d93a8e403abac1e9503f5be7b422c09abfae59917507d029ea0a3d6bb2cde10c64c256e9c6463ef0e1faace5e568d4d7d6282
data/README.md CHANGED
@@ -2,10 +2,11 @@
2
2
 
3
3
  [![Build Status](https://travis-ci.com/etscrivner/rbsecp256k1.svg?branch=master)](https://travis-ci.com/etscrivner/rbsecp256k1) [![Gem Version](https://badge.fury.io/rb/rbsecp256k1.svg)](https://badge.fury.io/rb/rbsecp256k1)
4
4
 
5
- Compiled Ruby extension gem for [libsecp256k1](https://github.com/bitcoin-core/secp256k1). In rbsecp256k1 3.0.0
6
- and later libsecp256k1 is bundled with the gem.
5
+ Native extension gem for secp256k1 ECDSA. Wraps [libsecp256k1](https://github.com/bitcoin-core/secp256k1). In
6
+ rbsecp256k1 3.0.0 and later libsecp256k1 is bundled with the gem.
7
7
 
8
- [Documentation](documentation/index.md)
8
+ * [Documentation](documentation/index.md)
9
+ * [Examples](examples/README.md)
9
10
 
10
11
  ### Why wrap libsecp256k1?
11
12
 
@@ -16,6 +17,9 @@ faster than the OpenSSL implementation of the same curve. It is the only library
16
17
  that provides constant time signing of this curve and has been deployed as part
17
18
  of Bitcoin since [v0.10.0](https://bitcoin.org/en/release/v0.10.0#improved-signing-security)
18
19
 
20
+ Natively wrapping the library in an extension gem means users don't have to
21
+ worry about compiling or locating the library, unlike many [FFI](https://github.com/ffi/ffi) based gems.
22
+
19
23
  ## Installation
20
24
 
21
25
  The simplest installation:
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rake/extensiontask"
2
4
 
3
5
  Rake::ExtensionTask.new "rbsecp256k1" do |ext|
@@ -10,10 +10,25 @@ for multiple operations as much as possible.
10
10
  Initializers
11
11
  ------------
12
12
 
13
- #### new
13
+ #### new(context_randomization_bytes: nil)
14
14
 
15
15
  Returns a newly initialized libsecp256k1 context. The context is randomized at
16
- initialization.
16
+ initialization if given `context_randomization_bytes`. The
17
+ `context_randomization_bytes` argument can optionally take a string containing
18
+ 32 bytes of random data, if not provided then the Context is not randomized and
19
+ may be vulnerable to side-channel attacks.
20
+
21
+ Class Methods
22
+ -------------
23
+
24
+ #### create
25
+
26
+ Creates and returns a new randomized `Context` using `SecureRandom` for the
27
+ random initialization bytes. This is the recommended method for initialization.
28
+
29
+ #### create_unrandomized
30
+
31
+ Creates a new unrandomized `Context`.
17
32
 
18
33
  Instance Methods
19
34
  ----------------
@@ -23,7 +38,7 @@ Instance Methods
23
38
  **Requires:** libsecp256k1 was built with the experimental ECDH module.
24
39
 
25
40
  Takes a `point` ([PublicKey](public_key.md)) and a `scalar` ([PrivateKey](private_key.md)) and returns a new
26
- [SharedSecret](shared_secret.md) containing the 32-byte shared secret. Raises a `RuntimeError` if
41
+ [SharedSecret](shared_secret.md) containing the 32-byte shared secret. Raises a `Secp256k1::Error` if
27
42
  the `scalar` is invalid (zero or causes an overflow).
28
43
 
29
44
  #### generate_key_pair
@@ -34,7 +49,7 @@ secure random number generator (CSRNG) provided by OpenSSL.
34
49
  #### key_pair_from_private_key(private_key_data)
35
50
 
36
51
  Returns a new [KeyPair](key_pair.md) from the given `private_key_data`. The
37
- `private_key_data` is expected to be a binary string. Raises a `RuntimeError`
52
+ `private_key_data` is expected to be a binary string. Raises a `Secp256k1::Error`
38
53
  if the private key is invalid or key derivation fails.
39
54
 
40
55
  #### recoverable_signature_from_compact(compact_signature, recovery_id)
@@ -42,7 +57,7 @@ if the private key is invalid or key derivation fails.
42
57
  **Requires:** libsecp256k1 was build with recovery module.
43
58
 
44
59
  Attempts to load a [RecoverableSignature](recoverable_signature.md) from the given `compact_signature`
45
- and `recovery_id`. Raises a RuntimeError if the signature data or recovery ID are invalid.
60
+ and `recovery_id`. Raises a `Secp256k1::DeserializationError` if the signature data or recovery ID are invalid.
46
61
 
47
62
  #### sign(private_key, hash32)
48
63
 
@@ -48,7 +48,7 @@ This example demonstrates how to create a new libsecp256k1 context. This is the
48
48
  first step of using this library:
49
49
 
50
50
  ```ruby
51
- context = Secp256k1::Context.new
51
+ context = Secp256k1::Context.create
52
52
  # => #<Secp256k1::Context:0x0000559b0bd8f5d0>
53
53
  ```
54
54
 
@@ -57,7 +57,7 @@ context = Secp256k1::Context.new
57
57
  This example shows how to generate a new public-private key pair:
58
58
 
59
59
  ```ruby
60
- context = Secp256k1::Context.new
60
+ context = Secp256k1::Context.create
61
61
  key_pair = context.generate_key_pair
62
62
  # => #<Secp256k1::KeyPair:0x0000559b0bc876b0 @public_key=#<Secp256k1::PublicKey:0x0000559b0bc876d8>, @private_key=#<Secp256k1::PrivateKey:0x0000559b0bc87700 @data="\r\xA7\xB3<\x92\xCDw\xC1\xDB\xEB[BB;=\x80\xB83\xA8]\x06\xD9\x90\xF8v\xFFi\xF0/\x1E\x96\xF9">>
63
63
  ```
@@ -67,7 +67,7 @@ key_pair = context.generate_key_pair
67
67
  This example shows how to generate compressed and uncompressed public keys:
68
68
 
69
69
  ```ruby
70
- context = Secp256k1::Context.new
70
+ context = Secp256k1::Context.create
71
71
  key_pair = context.generate_key_pair
72
72
 
73
73
  # 1. Get the binary representation of compressed public key
@@ -94,7 +94,7 @@ This example shows how to sign a message using your private key:
94
94
  ```ruby
95
95
  require 'digest'
96
96
 
97
- context = Secp256k1::Context.new
97
+ context = Secp256k1::Context.create
98
98
  key_pair = context.generate_key_pair
99
99
 
100
100
  signature = context.sign(key_pair.private_key, Digest::SHA256.digest("test message"))
@@ -109,7 +109,7 @@ representations of a signature:
109
109
  ```ruby
110
110
  require 'digest'
111
111
 
112
- context = Secp256k1::Context.new
112
+ context = Secp256k1::Context.create
113
113
  key_pair = context.generate_key_pair
114
114
 
115
115
  signature = context.sign(key_pair.private_key, Digest::SHA256.digest("test message"))
@@ -138,7 +138,7 @@ This example shows how to verify a signature using a public key:
138
138
  ```ruby
139
139
  require 'digest'
140
140
 
141
- context = Secp256k1::Context.new
141
+ context = Secp256k1::Context.create
142
142
  key_pair = context.generate_key_pair
143
143
  hash = Digest::SHA256.digest("test message")
144
144
 
@@ -158,7 +158,7 @@ context.verify(signature, key_pair.public_key, hash)
158
158
  This example shows how to load a key pair from raw binary private key data:
159
159
 
160
160
  ```ruby
161
- context = Secp256k1::Context.new
161
+ context = Secp256k1::Context.create
162
162
 
163
163
  #1. Load private key alone
164
164
  private_key = Secp256k1::PrivateKey.from_data("I\nX\x85\xAEz}\n\x9B\xA4\\\x81)\xD4\x9Aq\xFDH\t\xBE\x8EP\xC5.\xC6\x1F7-\x86\xA0\xCB\xF9")
@@ -218,7 +218,7 @@ You can sign data producing a recoverable signature as follows:
218
218
  require 'digest'
219
219
 
220
220
  hash = Digest::SHA256.digest('test message')
221
- context = Secp256k1::Context.new
221
+ context = Secp256k1::Context.create
222
222
  key_pair = context.generate_key_pair
223
223
 
224
224
  signature = context.sign_recoverable(key_pair.private_key, hash)
@@ -233,7 +233,7 @@ You can produce the compact binary serialization of a recoverable signature:
233
233
  require 'digest'
234
234
 
235
235
  hash = Digest::SHA256.digest('test message')
236
- context = Secp256k1::Context.new
236
+ context = Secp256k1::Context.create
237
237
  key_pair = context.generate_key_pair
238
238
 
239
239
  signature = context.sign_recoverable(key_pair.private_key, hash)
@@ -247,7 +247,7 @@ You can load a recoverable signature give its compact representation and
247
247
  recovery ID:
248
248
 
249
249
  ```ruby
250
- context = Secp256k1::Context.new
250
+ context = Secp256k1::Context.create
251
251
 
252
252
  compact_data = "D,\x9C\xA6%I\x14-\xCA\xC0\x11\x0F\xEB\x1E\xB0\xB6\\-\xE2\b\x98\xFB\xEA\xD5\x9BZ\xE6\xDF#\xC1\x1A\xEEL\xF02\xB1\xE9{\r\xEBhh<\\\xCF\xB6\x98\xEA\x8F\xF65\xF2\xBF\x84\xD8\xE5x\xF0\xA5)\xA2Wb\x9D"
253
253
  recovery_id = 1
@@ -265,7 +265,7 @@ for use by all methods that take a [Signature](signature.md) object:
265
265
  require 'digest'
266
266
 
267
267
  hash = Digest::SHA256.digest('test message')
268
- context = Secp256k1::Context.new
268
+ context = Secp256k1::Context.create
269
269
  key_pair = context.generate_key_pair
270
270
 
271
271
  recoverable_signature = context.sign_recoverable(key_pair.private_key, hash)
@@ -281,7 +281,7 @@ You can recover the [PublicKey](public_key.md) associated with a recoverable sig
281
281
  require 'digest'
282
282
 
283
283
  hash = Digest::SHA256.digest('test message')
284
- context = Secp256k1::Context.new
284
+ context = Secp256k1::Context.create
285
285
  key_pair = context.generate_key_pair
286
286
 
287
287
  recoverable_signature = context.sign_recoverable(key_pair.private_key, hash)
@@ -310,7 +310,7 @@ Secp256k1.have_ecdh?
310
310
  To generate a shared secret run the following:
311
311
 
312
312
  ```ruby
313
- context = Secp256k1::Context.new
313
+ context = Secp256k1::Context.create
314
314
  key_pair = context.generate_key_pair
315
315
 
316
316
  shared_secret = context.ecdh(key_pair.public_key, key_pair.private_key)
@@ -11,7 +11,7 @@ Class Methods
11
11
  #### from_data(private_key_data)
12
12
 
13
13
  Loads new private key from the given binary `private_key_data` string. Raises
14
- `ArgumentError` if the given data is invalid.
14
+ `Secp256k1::Error` if the given data is invalid.
15
15
 
16
16
  Instance Methods
17
17
  ----------------
@@ -13,8 +13,8 @@ Class Methods
13
13
  #### from_data(public_key_data)
14
14
 
15
15
  Parses compressed or uncompressed from binary string `public_key_data` and
16
- creates and returns a new public key from it. Raises a `RuntimeError` if the
17
- given public key data is invalid.
16
+ creates and returns a new public key from it. Raises a `Secp256k1::DeserializationError`
17
+ if the given public key data is invalid.
18
18
 
19
19
  Instance Methods
20
20
  ----------------
@@ -12,12 +12,12 @@ Class Methods
12
12
  #### from_compact(compact_signature)
13
13
 
14
14
  Parses a signature from binary string `compact_signature`. Raises a
15
- `RuntimeError` ig the signature data is invalid.
15
+ `Secp256k1::DeserializationError` if the signature data is invalid.
16
16
 
17
17
  #### from_der_encoded(der_encoded_signature)
18
18
 
19
19
  Parses a signature from binary string `der_encoded_signature`. Raises a
20
- `RuntimeError` ig the signature data is invalid.
20
+ `Secp256k1::DeserializationError` if the signature data is invalid.
21
21
 
22
22
  Instance Methods
23
23
  ----------------
@@ -1,27 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'mini_portile2'
2
4
  require 'mkmf'
3
5
  require 'zip'
4
6
 
5
- # Indicates the platform on which the package is being installed
6
- INSTALLING_OS =
7
- if RUBY_PLATFORM =~ /darwin/
8
- :macos
9
- elsif RUBY_PLATFORM =~ /linux/
10
- :linux
11
- else
12
- :unknown
13
- end
14
-
15
- # Fixed path to Homebrew OpenSSL pkgconfig file
16
- HOMEBREW_OPENSSL_PKGCONFIG = '/usr/local/opt/openssl/lib/pkgconfig'.freeze
17
-
18
7
  # Recipe for downloading and building libsecp256k1 as part of installation
19
8
  class Secp256k1Recipe < MiniPortile
20
9
  # Hard-coded URL for libsecp256k1 zipfile (HEAD of master as of 26-11-2018)
21
- LIBSECP256K1_ZIP_URL = 'https://github.com/bitcoin-core/secp256k1/archive/e34ceb333b1c0e6f4115ecbb80c632ac1042fa49.zip'.freeze
10
+ LIBSECP256K1_ZIP_URL = 'https://github.com/bitcoin-core/secp256k1/archive/e34ceb333b1c0e6f4115ecbb80c632ac1042fa49.zip'
22
11
 
23
12
  # Expected SHA-256 of the zipfile above (computed using sha256sum)
24
- LIBSECP256K1_SHA256 = 'd87d3ca7ebc42edbabb0f38e79205040b24b09b3e6d1c9ac89585de9bf302143'.freeze
13
+ LIBSECP256K1_SHA256 = 'd87d3ca7ebc42edbabb0f38e79205040b24b09b3e6d1c9ac89585de9bf302143'
25
14
 
26
15
  WITH_RECOVERY = ENV.fetch('WITH_RECOVERY', '1') == '1'
27
16
  WITH_ECDH = ENV.fetch('WITH_ECDH', '1') == '1'
@@ -82,46 +71,6 @@ class Secp256k1Recipe < MiniPortile
82
71
  end
83
72
  end
84
73
 
85
- # OpenSSL flags
86
- message("checking for OpenSSL\n")
87
- results = pkg_config('openssl')
88
-
89
- # Failed to find package OpenSSL
90
- unless results && results[1]
91
- # Check if the user happens to have OpenSSL installed via Homebrew on a path
92
- # we know about.
93
- # rubocop:disable Style/GlobalVars
94
- if INSTALLING_OS == :macos && File.exist?(HOMEBREW_OPENSSL_PKGCONFIG)
95
- begin
96
- require 'rubygems'
97
- gem 'pkg-config', (gem_ver = '~> 1.3')
98
- require 'pkg-config'
99
- rescue LoadError
100
- message(
101
- "pkg-config could not be used to find openssl\n" \
102
- "Please install either `pkg-config` or the pkg-config gem via\n" \
103
- "gem install pkg-config -v #{gem_ver.inspect}\n\n"
104
- )
105
- else
106
- message("Initial check failed. Trying homebrew openssl path...\n")
107
- message("Using pkg-config gem version #{PKGConfig::VERSION}\n")
108
- PKGConfig.add_path(HOMEBREW_OPENSSL_PKGCONFIG)
109
-
110
- cflags = PKGConfig.cflags('openssl')
111
- ldflags = PKGConfig.libs_only_L('openssl')
112
- libs = PKGConfig.libs_only_l('openssl')
113
-
114
- $CFLAGS += " " << cflags if cflags
115
- $libs += " " << libs if libs
116
- $LDFLAGS = [$LDFLAGS, ldflags].join(' ')
117
-
118
- results = [cflags, libs, ldflags]
119
- end
120
- end
121
- # rubocop:enable Style/GlobalVars
122
- end
123
- abort "missing openssl pkg-config information" unless results && results[1]
124
-
125
74
  if with_config('system-library')
126
75
  # Require that libsecp256k1 be installed using `make install` or similar.
127
76
  message("checking for libsecp256k1\n")
@@ -142,6 +91,11 @@ else
142
91
  "-Wall"
143
92
  ]
144
93
  )
94
+ append_ldflags(
95
+ [
96
+ "-Wl,--no-as-needed"
97
+ ]
98
+ )
145
99
  # rubocop:disable Style/GlobalVars
146
100
  $LIBPATH = ["#{recipe.path}/lib"] | $LIBPATH
147
101
  # rubocop:enable Style/GlobalVars
@@ -6,12 +6,8 @@
6
6
  // and verifying signatures using the library.
7
7
  //
8
8
  // Dependencies:
9
- // * libsecp256k1
10
- // * openssl
9
+ // * libsecp256k1
11
10
  #include <ruby.h>
12
-
13
- #include <openssl/rand.h>
14
-
15
11
  #include <secp256k1.h>
16
12
 
17
13
  // Include recoverable signatures functionality if available
@@ -44,6 +40,14 @@
44
40
  // applications. Context initialization is expensive so it is recommended that
45
41
  // a single context be initialized and used throughout an application when
46
42
  // possible.
43
+ //
44
+ // Exception Hierarchy:
45
+ //
46
+ // The following hierarchy is used for exceptions raised from the library:
47
+ //
48
+ // +- Error (Descends from StandardError)
49
+ // |-- SerializationError
50
+ // |-- DeserializationError
47
51
 
48
52
  //
49
53
  // The section below contains purely internal methods used exclusively by the
@@ -61,6 +65,9 @@ const size_t COMPACT_SIG_SIZE_BYTES = 64;
61
65
  // objects from anywhere. The use of global variables seems to be inline with
62
66
  // how the Ruby project builds its own extension gems.
63
67
  static VALUE Secp256k1_module;
68
+ static VALUE Secp256k1_Error_class;
69
+ static VALUE Secp256k1_SerializationError_class;
70
+ static VALUE Secp256k1_DeserializationError_class;
64
71
  static VALUE Secp256k1_Context_class;
65
72
  static VALUE Secp256k1_KeyPair_class;
66
73
  static VALUE Secp256k1_PublicKey_class;
@@ -262,33 +269,6 @@ typedef enum ResultT_dummy {
262
269
  RESULT_FAILURE
263
270
  } ResultT;
264
271
 
265
- /**
266
- * Generate a series of cryptographically secure random bytes using OpenSSL.
267
- *
268
- * \param out_bytes Desired number of bytes will be written here.
269
- * \param in_size Number of bytes of random data to be generated.
270
- * \return RESULT_SUCCESS if the bytes were generated successfully,
271
- * RESULT_FAILURE otherwise.
272
- */
273
- static ResultT
274
- GenerateRandomBytes(unsigned char *out_bytes, int in_size)
275
- {
276
- // OpenSSL RNG has not been seeded with enough data and is therefore
277
- // not usable.
278
- if (RAND_status() == 0)
279
- {
280
- return RESULT_FAILURE;
281
- }
282
-
283
- // Attempt to generate random bytes using the OpenSSL RNG
284
- if (RAND_bytes(out_bytes, in_size) != 1)
285
- {
286
- return RESULT_FAILURE;
287
- }
288
-
289
- return RESULT_SUCCESS;
290
- }
291
-
292
272
  /**
293
273
  * Computes the ECDSA signature of the given 32-byte SHA-256 hash.
294
274
  *
@@ -462,7 +442,7 @@ PublicKey_create_from_private_key(Context *in_context,
462
442
  (&public_key->pubkey),
463
443
  private_key_data) != 1)
464
444
  {
465
- rb_raise(rb_eTypeError, "invalid private key data");
445
+ rb_raise(Secp256k1_DeserializationError_class, "invalid private key data");
466
446
  }
467
447
 
468
448
  return result;
@@ -483,7 +463,7 @@ PublicKey_create_from_data(unsigned char *in_public_key_data,
483
463
  in_public_key_data,
484
464
  in_public_key_data_len) != 1)
485
465
  {
486
- rb_raise(rb_eRuntimeError, "invalid public key data");
466
+ rb_raise(Secp256k1_DeserializationError_class, "invalid public key data");
487
467
  }
488
468
 
489
469
  return result;
@@ -495,7 +475,7 @@ PublicKey_create_from_data(unsigned char *in_public_key_data,
495
475
  * @param in_public_key_data [String] binary string with compressed or
496
476
  * uncompressed public key data.
497
477
  * @return [Secp256k1::PublicKey] public key derived from data.
498
- * @raise [RuntimeError] if public key data is invalid.
478
+ * @raise [Secp256k1::DeserializationError] if public key data is invalid.
499
479
  */
500
480
  static VALUE
501
481
  PublicKey_from_data(VALUE klass, VALUE in_public_key_data)
@@ -631,7 +611,7 @@ PrivateKey_create(unsigned char *in_private_key_data)
631
611
  if (secp256k1_ec_seckey_verify(secp256k1_context_no_precomp,
632
612
  in_private_key_data) != 1)
633
613
  {
634
- rb_raise(rb_eArgError, "invalid private key data");
614
+ rb_raise(Secp256k1_Error_class, "invalid private key data");
635
615
  }
636
616
 
637
617
  result = PrivateKey_alloc(Secp256k1_PrivateKey_class);
@@ -649,7 +629,7 @@ PrivateKey_create(unsigned char *in_private_key_data)
649
629
  * @param in_private_key_data [String] 32 byte binary string of private key
650
630
  * data.
651
631
  * @return [Secp256k1::PrivateKey] private key loaded from the given data.
652
- * @raise [ArgumentError] if private key data is not 32 bytes or is invalid.
632
+ * @raise [Secp256k1::Error] if private key data is not 32 bytes or is invalid.
653
633
  */
654
634
  static VALUE
655
635
  PrivateKey_from_data(VALUE klass, VALUE in_private_key_data)
@@ -659,7 +639,10 @@ PrivateKey_from_data(VALUE klass, VALUE in_private_key_data)
659
639
  Check_Type(in_private_key_data, T_STRING);
660
640
  if (RSTRING_LEN(in_private_key_data) != 32)
661
641
  {
662
- rb_raise(rb_eArgError, "private key data must be 32 bytes in length");
642
+ rb_raise(
643
+ Secp256k1_Error_class,
644
+ "private key data must be 32 bytes in length"
645
+ );
663
646
  }
664
647
 
665
648
  private_key_data = (unsigned char*)StringValuePtr(in_private_key_data);
@@ -714,7 +697,7 @@ Signature_alloc(VALUE klass)
714
697
  * @param in_compact_signature [String] compact signature as 64-byte binary
715
698
  * string.
716
699
  * @return [Secp256k1::Signature] object deserialized from compact signature.
717
- * @raise [ArgumentError] if signature data is invalid.
700
+ * @raise [Secp256k1::DeserializationError] if signature data is invalid.
718
701
  */
719
702
  static VALUE
720
703
  Signature_from_compact(VALUE klass, VALUE in_compact_signature)
@@ -727,7 +710,7 @@ Signature_from_compact(VALUE klass, VALUE in_compact_signature)
727
710
 
728
711
  if (RSTRING_LEN(in_compact_signature) != 64)
729
712
  {
730
- rb_raise(rb_eArgError, "compact signature must be 64 bytes");
713
+ rb_raise(Secp256k1_Error_class, "compact signature must be 64 bytes");
731
714
  }
732
715
 
733
716
  signature_data = (unsigned char*)StringValuePtr(in_compact_signature);
@@ -739,7 +722,7 @@ Signature_from_compact(VALUE klass, VALUE in_compact_signature)
739
722
  &(signature->sig),
740
723
  signature_data) != 1)
741
724
  {
742
- rb_raise(rb_eArgError, "invalid compact signature");
725
+ rb_raise(Secp256k1_DeserializationError_class, "invalid compact signature");
743
726
  }
744
727
 
745
728
  return signature_result;
@@ -752,7 +735,7 @@ Signature_from_compact(VALUE klass, VALUE in_compact_signature)
752
735
  * string.
753
736
  * @return [Secp256k1::Signature] signature object initialized using signature
754
737
  * data.
755
- * @raise [ArgumentError] if signature data is invalid.
738
+ * @raise [Secp256k1::DeserializationError] if signature data is invalid.
756
739
  */
757
740
  static VALUE
758
741
  Signature_from_der_encoded(VALUE klass, VALUE in_der_encoded_signature)
@@ -773,7 +756,7 @@ Signature_from_der_encoded(VALUE klass, VALUE in_der_encoded_signature)
773
756
  signature_data,
774
757
  RSTRING_LEN(in_der_encoded_signature)) != 1)
775
758
  {
776
- rb_raise(rb_eArgError, "invalid DER encoded signature");
759
+ rb_raise(Secp256k1_DeserializationError_class, "invalid DER encoded signature");
777
760
  }
778
761
 
779
762
  return signature_result;
@@ -800,7 +783,10 @@ Signature_der_encoded(VALUE self)
800
783
  &der_signature_len,
801
784
  &(signature->sig)) != 1)
802
785
  {
803
- rb_raise(rb_eRuntimeError, "could not compute DER encoded signature");
786
+ rb_raise(
787
+ Secp256k1_SerializationError_class,
788
+ "could not compute DER encoded signature"
789
+ );
804
790
  }
805
791
 
806
792
  return rb_str_new((char*)der_signature, der_signature_len);
@@ -824,7 +810,10 @@ Signature_compact(VALUE self)
824
810
  compact_signature,
825
811
  &(signature->sig)) != 1)
826
812
  {
827
- rb_raise(rb_eRuntimeError, "unable to compute compact signature");
813
+ rb_raise(
814
+ Secp256k1_SerializationError_class,
815
+ "unable to compute compact signature"
816
+ );
828
817
  }
829
818
 
830
819
  return rb_str_new((char*)compact_signature, COMPACT_SIG_SIZE_BYTES);
@@ -932,7 +921,7 @@ RecoverableSignature_alloc(VALUE klass)
932
921
  *
933
922
  * @return [Array] first element is the 64 byte compact encoding of signature,
934
923
  * the second element is the integer recovery ID.
935
- * @raise [RuntimeError] if signature serialization fails.
924
+ * @raise [Secp256k1::SerializationError] if signature serialization fails.
936
925
  */
937
926
  static VALUE
938
927
  RecoverableSignature_compact(VALUE self)
@@ -955,7 +944,10 @@ RecoverableSignature_compact(VALUE self)
955
944
  &recovery_id,
956
945
  &(recoverable_signature->sig)) != 1)
957
946
  {
958
- rb_raise(rb_eRuntimeError, "unable to serialize recoverable signature");
947
+ rb_raise(
948
+ Secp256k1_SerializationError_class,
949
+ "unable to serialize recoverable signature"
950
+ );
959
951
  }
960
952
 
961
953
  // Create a new array with room for 2 elements and push data onto it
@@ -1008,7 +1000,9 @@ RecoverableSignature_to_signature(VALUE self)
1008
1000
  *
1009
1001
  * @param in_hash32 [String] 32-byte SHA-256 hash of data.
1010
1002
  * @return [Secp256k1::PublicKey] recovered public key.
1011
- * @raise [RuntimeError] if the public key could not be recovered.
1003
+ * @raise [Secp256k1::Error] if hash given is not 32 bytes.
1004
+ * @raise [Secp256k1::DeserializationError] if public key could not be
1005
+ * recovered.
1012
1006
  */
1013
1007
  static VALUE
1014
1008
  RecoverableSignature_recover_public_key(VALUE self, VALUE in_hash32)
@@ -1021,7 +1015,7 @@ RecoverableSignature_recover_public_key(VALUE self, VALUE in_hash32)
1021
1015
  Check_Type(in_hash32, T_STRING);
1022
1016
  if (RSTRING_LEN(in_hash32) != 32)
1023
1017
  {
1024
- rb_raise(rb_eArgError, "in_hash32 is not 32 bytes in length");
1018
+ rb_raise(Secp256k1_Error_class, "in_hash32 is not 32 bytes in length");
1025
1019
  }
1026
1020
 
1027
1021
  TypedData_Get_Struct(
@@ -1043,7 +1037,7 @@ RecoverableSignature_recover_public_key(VALUE self, VALUE in_hash32)
1043
1037
  return result;
1044
1038
  }
1045
1039
 
1046
- rb_raise(rb_eRuntimeError, "unable to recover public key");
1040
+ rb_raise(Secp256k1_DeserializationError_class, "unable to recover public key");
1047
1041
  }
1048
1042
 
1049
1043
  /**
@@ -1131,14 +1125,27 @@ Context_alloc(VALUE klass)
1131
1125
  *
1132
1126
  * Context initialization should be infrequent as it is an expensive operation.
1133
1127
  *
1128
+ * @param context_randomization_bytes [String,nil] (Optional) 32 bytes of
1129
+ * random data used to randomize the context. If omitted then the
1130
+ * context remains unrandomized. It is recommended that you provide this
1131
+ * argument.
1134
1132
  * @return [Secp256k1::Context]
1135
- * @raise [RuntimeError] if context randomization fails.
1133
+ * @raise [Secp256k1::Error] if context randomization fails.
1136
1134
  */
1137
1135
  static VALUE
1138
- Context_initialize(VALUE self)
1136
+ Context_initialize(int argc, const VALUE* argv, VALUE self)
1139
1137
  {
1140
1138
  Context *context;
1141
- unsigned char seed[32];
1139
+ unsigned char *seed32;
1140
+ VALUE context_randomization_bytes;
1141
+ VALUE opts;
1142
+ static ID kwarg_ids;
1143
+
1144
+ context_randomization_bytes = Qnil;
1145
+ if (!kwarg_ids)
1146
+ {
1147
+ CONST_ID(kwarg_ids, "context_randomization_bytes");
1148
+ }
1142
1149
 
1143
1150
  TypedData_Get_Struct(self, Context, &Context_DataType, context);
1144
1151
 
@@ -1146,50 +1153,46 @@ Context_initialize(VALUE self)
1146
1153
  SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY
1147
1154
  );
1148
1155
 
1149
- // Randomize the context at initialization time rather than before calls so
1150
- // the same context can be used across threads safely.
1151
- GenerateRandomBytes(seed, 32);
1152
- if (secp256k1_context_randomize(context->ctx, seed) != 1)
1156
+ // Handle optional second argument containing random bytes to use for
1157
+ // randomization. We pass ":" to rb_scan_args to say that we expect keyword
1158
+ // arguments. We then parse the opts result of the scan in order to grab
1159
+ // context_randomization_bytes from the hash.
1160
+ rb_scan_args(argc, argv, ":", &opts);
1161
+ rb_get_kwargs(opts, &kwarg_ids, 0, 1, &context_randomization_bytes);
1162
+
1163
+ // We need this check because rb_get_kwargs will set the result to Qundef if
1164
+ // the keyword argument is not provided. This lets us use the NIL_P
1165
+ // predicate.
1166
+ if (context_randomization_bytes == Qundef)
1153
1167
  {
1154
- rb_raise(rb_eRuntimeError, "context randomization failed");
1168
+ context_randomization_bytes = Qnil;
1155
1169
  }
1156
1170
 
1157
- return self;
1158
- }
1159
-
1160
- /**
1161
- * Generate a new public-private key pair.
1162
- *
1163
- * @return [Secp256k1::KeyPair] newly generated key pair.
1164
- * @raise [RuntimeError] if private key generation fails.
1165
- */
1166
- static VALUE
1167
- Context_generate_key_pair(VALUE self)
1168
- {
1169
- Context *context;
1170
- VALUE private_key;
1171
- VALUE public_key;
1172
- VALUE result;
1173
- unsigned char private_key_bytes[32];
1174
-
1175
- if (FAILURE(GenerateRandomBytes(private_key_bytes, 32)))
1171
+ if (!NIL_P(context_randomization_bytes)) // Random bytes given
1176
1172
  {
1177
- rb_raise(rb_eRuntimeError, "unable to generate private key bytes.");
1173
+ Check_Type(context_randomization_bytes, T_STRING);
1174
+ if (RSTRING_LEN(context_randomization_bytes) != 32)
1175
+ {
1176
+ rb_raise(
1177
+ Secp256k1_Error_class,
1178
+ "context_randomization_bytes must be 32 bytes in length"
1179
+ );
1180
+ }
1181
+
1182
+ seed32 = (unsigned char*)StringValuePtr(context_randomization_bytes);
1183
+
1184
+ // Randomize the context at initialization time rather than before calls so
1185
+ // the same context can be used across threads safely.
1186
+ if (secp256k1_context_randomize(context->ctx, seed32) != 1)
1187
+ {
1188
+ rb_raise(
1189
+ Secp256k1_Error_class,
1190
+ "context randomization failed"
1191
+ );
1192
+ }
1178
1193
  }
1179
1194
 
1180
- TypedData_Get_Struct(self, Context, &Context_DataType, context);
1181
-
1182
- private_key = PrivateKey_create(private_key_bytes);
1183
- public_key = PublicKey_create_from_private_key(context, private_key_bytes);
1184
- result = rb_funcall(
1185
- Secp256k1_KeyPair_class,
1186
- rb_intern("new"),
1187
- 2,
1188
- public_key,
1189
- private_key
1190
- );
1191
-
1192
- return result;
1195
+ return self;
1193
1196
  }
1194
1197
 
1195
1198
  /**
@@ -1197,7 +1200,7 @@ Context_generate_key_pair(VALUE self)
1197
1200
  *
1198
1201
  * @param in_private_key_data [String] binary private key data
1199
1202
  * @return [Secp256k1::KeyPair] key pair initialized from the private key data.
1200
- * @raise [ArgumentError] if the private key data is invalid or key derivation
1203
+ * @raise [Secp256k1::Error] if the private key data is invalid or key derivation
1201
1204
  * fails.
1202
1205
  */
1203
1206
  static VALUE
@@ -1213,7 +1216,7 @@ Context_key_pair_from_private_key(VALUE self, VALUE in_private_key_data)
1213
1216
 
1214
1217
  if (RSTRING_LEN(in_private_key_data) != 32)
1215
1218
  {
1216
- rb_raise(rb_eArgError, "private key data must be 32 bytes in length");
1219
+ rb_raise(Secp256k1_Error_class, "private key data must be 32 bytes in length");
1217
1220
  }
1218
1221
 
1219
1222
  private_key_data = (unsigned char*)StringValuePtr(in_private_key_data);
@@ -1237,8 +1240,8 @@ Context_key_pair_from_private_key(VALUE self, VALUE in_private_key_data)
1237
1240
  * signing.
1238
1241
  * @param in_hash32 [String] 32-byte binary string with SHA-256 hash of data.
1239
1242
  * @return [Secp256k1::Signature] signature resulting from signing data.
1240
- * @raise [RuntimeError] if signature computation fails.
1241
- * @raise [ArgumentError] if hash is not 32-bytes in length.
1243
+ * @raise [Secp256k1::Error] if hash is not 32-bytes in length or signature
1244
+ * computation fails.
1242
1245
  */
1243
1246
  static VALUE
1244
1247
  Context_sign(VALUE self, VALUE in_private_key, VALUE in_hash32)
@@ -1253,7 +1256,7 @@ Context_sign(VALUE self, VALUE in_private_key, VALUE in_hash32)
1253
1256
 
1254
1257
  if (RSTRING_LEN(in_hash32) != 32)
1255
1258
  {
1256
- rb_raise(rb_eArgError, "in_hash32 is not 32 bytes in length");
1259
+ rb_raise(Secp256k1_Error_class, "in_hash32 is not 32 bytes in length");
1257
1260
  }
1258
1261
 
1259
1262
  TypedData_Get_Struct(self, Context, &Context_DataType, context);
@@ -1272,7 +1275,7 @@ Context_sign(VALUE self, VALUE in_private_key, VALUE in_hash32)
1272
1275
  return signature_result;
1273
1276
  }
1274
1277
 
1275
- rb_raise(rb_eRuntimeError, "unable to compute signature");
1278
+ rb_raise(Secp256k1_Error_class, "unable to compute signature");
1276
1279
  }
1277
1280
 
1278
1281
  /**
@@ -1284,7 +1287,7 @@ Context_sign(VALUE self, VALUE in_private_key, VALUE in_hash32)
1284
1287
  * @param in_hash32 [String] 32-byte binary string containing SHA-256 hash of
1285
1288
  * data.
1286
1289
  * @return [Boolean] True if the signature is valid, false otherwise.
1287
- * @raise [ArgumentError] if hash is not 32-bytes in length.
1290
+ * @raise [Secp256k1::Error] if hash is not 32-bytes in length.
1288
1291
  */
1289
1292
  static VALUE
1290
1293
  Context_verify(VALUE self, VALUE in_signature, VALUE in_pubkey, VALUE in_hash32)
@@ -1298,7 +1301,7 @@ Context_verify(VALUE self, VALUE in_signature, VALUE in_pubkey, VALUE in_hash32)
1298
1301
 
1299
1302
  if (RSTRING_LEN(in_hash32) != 32)
1300
1303
  {
1301
- rb_raise(rb_eArgError, "in_hash32 is not 32-bytes in length");
1304
+ rb_raise(Secp256k1_Error_class, "in_hash32 is not 32-bytes in length");
1302
1305
  }
1303
1306
 
1304
1307
  TypedData_Get_Struct(self, Context, &Context_DataType, context);
@@ -1328,7 +1331,8 @@ Context_verify(VALUE self, VALUE in_signature, VALUE in_pubkey, VALUE in_hash32)
1328
1331
  * @param in_hash32 [String] 32-byte binary string with SHA-256 hash of data.
1329
1332
  * @return [Secp256k1::RecoverableSignature] recoverable signature produced by
1330
1333
  * signing the SHA-256 hash `in_hash32` with `in_private_key`.
1331
- * @raise [ArgumentError] if the hash is not 32 bytes
1334
+ * @raise [Secp256k1::Error] if the hash is not 32 bytes or signature could not
1335
+ * be computed.
1332
1336
  */
1333
1337
  static VALUE
1334
1338
  Context_sign_recoverable(VALUE self, VALUE in_private_key, VALUE in_hash32)
@@ -1342,7 +1346,7 @@ Context_sign_recoverable(VALUE self, VALUE in_private_key, VALUE in_hash32)
1342
1346
  Check_Type(in_hash32, T_STRING);
1343
1347
  if (RSTRING_LEN(in_hash32) != 32)
1344
1348
  {
1345
- rb_raise(rb_eArgError, "in_hash32 is not 32 bytes in length");
1349
+ rb_raise(Secp256k1_Error_class, "in_hash32 is not 32 bytes in length");
1346
1350
  }
1347
1351
 
1348
1352
  TypedData_Get_Struct(self, Context, &Context_DataType, context);
@@ -1368,7 +1372,7 @@ Context_sign_recoverable(VALUE self, VALUE in_private_key, VALUE in_hash32)
1368
1372
  return result;
1369
1373
  }
1370
1374
 
1371
- rb_raise(rb_eRuntimeError, "unable to compute recoverable signature");
1375
+ rb_raise(Secp256k1_Error_class, "unable to compute recoverable signature");
1372
1376
  }
1373
1377
 
1374
1378
  /**
@@ -1378,8 +1382,9 @@ Context_sign_recoverable(VALUE self, VALUE in_private_key, VALUE in_hash32)
1378
1382
  * data.
1379
1383
  * @param in_recovery_id [Integer] recovery ID (range [0, 3])
1380
1384
  * @return [Secp256k1::RecoverableSignature] signature parsed from data.
1381
- * @raise [RuntimeError] if signature data or recovery ID is invalid.
1382
- * @raise [ArgumentError] if compact signature is not 64 bytes or recovery ID
1385
+ * @raise [Secp256k1::DeserializationError] if signature data or recovery ID is
1386
+ * invalid.
1387
+ * @raise [Secp256k1::Error] if compact signature is not 64 bytes or recovery ID
1383
1388
  * is not in range [0, 3].
1384
1389
  */
1385
1390
  static VALUE
@@ -1401,12 +1406,12 @@ Context_recoverable_signature_from_compact(
1401
1406
 
1402
1407
  if (RSTRING_LEN(in_compact_sig) != 64)
1403
1408
  {
1404
- rb_raise(rb_eArgError, "compact signature is not 64 bytes");
1409
+ rb_raise(Secp256k1_Error_class, "compact signature is not 64 bytes");
1405
1410
  }
1406
1411
 
1407
1412
  if (recovery_id < 0 || recovery_id > 3)
1408
1413
  {
1409
- rb_raise(rb_eArgError, "invalid recovery ID, must be in range [0, 3]");
1414
+ rb_raise(Secp256k1_Error_class, "invalid recovery ID, must be in range [0, 3]");
1410
1415
  }
1411
1416
 
1412
1417
  result = RecoverableSignature_alloc(Secp256k1_RecoverableSignature_class);
@@ -1427,7 +1432,7 @@ Context_recoverable_signature_from_compact(
1427
1432
  return result;
1428
1433
  }
1429
1434
 
1430
- rb_raise(rb_eRuntimeError, "unable to parse recoverable signature");
1435
+ rb_raise(Secp256k1_DeserializationError_class, "unable to parse recoverable signature");
1431
1436
  }
1432
1437
 
1433
1438
  #endif // HAVE_SECP256K1_RECOVERY_H
@@ -1443,7 +1448,7 @@ Context_recoverable_signature_from_compact(
1443
1448
  * @param point [Secp256k1::PublicKey] public-key representing ECDH point.
1444
1449
  * @param scalar [Secp256k1::PrivateKey] private-key representing ECDH scalar.
1445
1450
  * @return [Secp256k1::SharedSecret] shared secret
1446
- * @raise [RuntimeError] If scalar was invalid (zero or caused overflow).
1451
+ * @raise [Secp256k1::Error] If scalar was invalid (zero or caused overflow).
1447
1452
  */
1448
1453
  static VALUE
1449
1454
  Context_ecdh(VALUE self, VALUE point, VALUE scalar)
@@ -1470,7 +1475,7 @@ Context_ecdh(VALUE self, VALUE point, VALUE scalar)
1470
1475
  NULL,
1471
1476
  NULL) != 1)
1472
1477
  {
1473
- rb_raise(rb_eRuntimeError, "invalid scalar provided to ecdh");
1478
+ rb_raise(Secp256k1_Error_class, "invalid scalar provided to ecdh");
1474
1479
  }
1475
1480
 
1476
1481
  rb_iv_set(result, "@data", rb_str_new((char*)shared_secret->data, 32));
@@ -1522,13 +1527,6 @@ Secp256k1_have_ecdh(VALUE module)
1522
1527
 
1523
1528
  void Init_rbsecp256k1()
1524
1529
  {
1525
- // NOTE: All classes derive from Data (rb_cData) rather than Object
1526
- // (rb_cObject). This makes it so we don't have to call rb_undef_alloc_func
1527
- // for each class and can instead simply define the allocation methods for
1528
- // each class.
1529
- //
1530
- // See: https://github.com/ruby/ruby/blob/trunk/doc/extension.rdoc#encapsulate-c-data-into-a-ruby-object
1531
-
1532
1530
  // Secp256k1
1533
1531
  Secp256k1_module = rb_define_module("Secp256k1");
1534
1532
  rb_define_singleton_method(
@@ -1544,19 +1542,27 @@ void Init_rbsecp256k1()
1544
1542
  0
1545
1543
  );
1546
1544
 
1545
+ // Secp256k1 exception hierarchy
1546
+ Secp256k1_Error_class = rb_define_class_under(
1547
+ Secp256k1_module, "Error", rb_eStandardError
1548
+ );
1549
+ Secp256k1_SerializationError_class = rb_define_class_under(
1550
+ Secp256k1_module, "SerializationError", Secp256k1_Error_class
1551
+ );
1552
+ Secp256k1_DeserializationError_class = rb_define_class_under(
1553
+ Secp256k1_module, "DeserializationError", Secp256k1_Error_class
1554
+ );
1555
+
1547
1556
  // Secp256k1::Context
1548
1557
  Secp256k1_Context_class = rb_define_class_under(
1549
- Secp256k1_module, "Context", rb_cData
1558
+ Secp256k1_module, "Context", rb_cObject
1550
1559
  );
1560
+ rb_undef_alloc_func(Secp256k1_Context_class);
1551
1561
  rb_define_alloc_func(Secp256k1_Context_class, Context_alloc);
1552
1562
  rb_define_method(Secp256k1_Context_class,
1553
1563
  "initialize",
1554
1564
  Context_initialize,
1555
- 0);
1556
- rb_define_method(Secp256k1_Context_class,
1557
- "generate_key_pair",
1558
- Context_generate_key_pair,
1559
- 0);
1565
+ -1);
1560
1566
  rb_define_method(Secp256k1_Context_class,
1561
1567
  "key_pair_from_private_key",
1562
1568
  Context_key_pair_from_private_key,
@@ -1573,7 +1579,8 @@ void Init_rbsecp256k1()
1573
1579
  // Secp256k1::KeyPair
1574
1580
  Secp256k1_KeyPair_class = rb_define_class_under(Secp256k1_module,
1575
1581
  "KeyPair",
1576
- rb_cData);
1582
+ rb_cObject);
1583
+ rb_undef_alloc_func(Secp256k1_KeyPair_class);
1577
1584
  rb_define_alloc_func(Secp256k1_KeyPair_class, KeyPair_alloc);
1578
1585
  rb_define_attr(Secp256k1_KeyPair_class, "public_key", 1, 0);
1579
1586
  rb_define_attr(Secp256k1_KeyPair_class, "private_key", 1, 0);
@@ -1586,7 +1593,8 @@ void Init_rbsecp256k1()
1586
1593
  // Secp256k1::PublicKey
1587
1594
  Secp256k1_PublicKey_class = rb_define_class_under(Secp256k1_module,
1588
1595
  "PublicKey",
1589
- rb_cData);
1596
+ rb_cObject);
1597
+ rb_undef_alloc_func(Secp256k1_PublicKey_class);
1590
1598
  rb_define_alloc_func(Secp256k1_PublicKey_class, PublicKey_alloc);
1591
1599
  rb_define_method(Secp256k1_PublicKey_class,
1592
1600
  "compressed",
@@ -1606,8 +1614,9 @@ void Init_rbsecp256k1()
1606
1614
 
1607
1615
  // Secp256k1::PrivateKey
1608
1616
  Secp256k1_PrivateKey_class = rb_define_class_under(
1609
- Secp256k1_module, "PrivateKey", rb_cData
1617
+ Secp256k1_module, "PrivateKey", rb_cObject
1610
1618
  );
1619
+ rb_undef_alloc_func(Secp256k1_PrivateKey_class);
1611
1620
  rb_define_alloc_func(Secp256k1_PrivateKey_class, PrivateKey_alloc);
1612
1621
  rb_define_attr(Secp256k1_PrivateKey_class, "data", 1, 0);
1613
1622
  rb_define_method(Secp256k1_PrivateKey_class, "==", PrivateKey_equals, 1);
@@ -1621,7 +1630,8 @@ void Init_rbsecp256k1()
1621
1630
  // Secp256k1::Signature
1622
1631
  Secp256k1_Signature_class = rb_define_class_under(Secp256k1_module,
1623
1632
  "Signature",
1624
- rb_cData);
1633
+ rb_cObject);
1634
+ rb_undef_alloc_func(Secp256k1_Signature_class);
1625
1635
  rb_define_alloc_func(Secp256k1_Signature_class, Signature_alloc);
1626
1636
  rb_define_method(Secp256k1_Signature_class,
1627
1637
  "der_encoded",
@@ -1657,8 +1667,9 @@ void Init_rbsecp256k1()
1657
1667
  Secp256k1_RecoverableSignature_class = rb_define_class_under(
1658
1668
  Secp256k1_module,
1659
1669
  "RecoverableSignature",
1660
- rb_cData
1670
+ rb_cObject
1661
1671
  );
1672
+ rb_undef_alloc_func(Secp256k1_RecoverableSignature_class);
1662
1673
  rb_define_alloc_func(
1663
1674
  Secp256k1_RecoverableSignature_class,
1664
1675
  RecoverableSignature_alloc
@@ -1707,8 +1718,9 @@ void Init_rbsecp256k1()
1707
1718
  Secp256k1_SharedSecret_class = rb_define_class_under(
1708
1719
  Secp256k1_module,
1709
1720
  "SharedSecret",
1710
- rb_cData
1721
+ rb_cObject
1711
1722
  );
1723
+ rb_undef_alloc_func(Secp256k1_SharedSecret_class);
1712
1724
  rb_define_alloc_func(Secp256k1_SharedSecret_class, SharedSecret_alloc);
1713
1725
  rb_define_attr(Secp256k1_SharedSecret_class, "data", 1, 0);
1714
1726
 
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Wraps libsecp256k1 in a ruby module and provides object interfaces.
2
4
  module Secp256k1
3
5
  end
4
6
 
7
+ require 'rbsecp256k1/context'
5
8
  require 'rbsecp256k1/util'
6
9
  require 'rbsecp256k1/version'
7
10
  require 'rbsecp256k1/rbsecp256k1'
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Secp256k1
6
+ # Wrapper around a secp256k1_context object.
7
+ class Context
8
+ # Create a new randomized context.
9
+ #
10
+ # @return [Secp256k1::Context] randomized context
11
+ def self.create
12
+ new(context_randomization_bytes: SecureRandom.random_bytes(32))
13
+ end
14
+
15
+ # Create a new non-randomized context.
16
+ #
17
+ # @return [Secp256k1::Context] non-randomized context
18
+ def self.create_unrandomized
19
+ new
20
+ end
21
+
22
+ # Generates a new random key pair.
23
+ #
24
+ # @return [Secp256k1::KeyPair] public-private key pair.
25
+ def generate_key_pair
26
+ key_pair_from_private_key(SecureRandom.random_bytes(32))
27
+ end
28
+ end
29
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Secp256k1
2
4
  # Contains utility methods that complement the functionality of the library.
3
5
  module Util
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Secp256k1
2
- VERSION = '4.0.0'.freeze
4
+ VERSION = '5.0.0'
3
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbsecp256k1
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Scrivner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-05 00:00:00.000000000 Z
11
+ date: 2019-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mini_portile2
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0.61'
103
+ version: '0.7'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0.61'
110
+ version: '0.7'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: yard
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -144,6 +144,7 @@ files:
144
144
  - ext/rbsecp256k1/extconf.rb
145
145
  - ext/rbsecp256k1/rbsecp256k1.c
146
146
  - lib/rbsecp256k1.rb
147
+ - lib/rbsecp256k1/context.rb
147
148
  - lib/rbsecp256k1/util.rb
148
149
  - lib/rbsecp256k1/version.rb
149
150
  homepage: https://github.com/etscrivner/rbsecp256k1
@@ -170,6 +171,6 @@ rubyforge_project:
170
171
  rubygems_version: 2.7.6
171
172
  signing_key:
172
173
  specification_version: 4
173
- summary: Compiled, native ruby extension interfaces to libsecp256k1. In rbsecp256k1
174
+ summary: Native extension gem for secp256k1 ECDSA. Wraps libsecp256k1. In rbsecp256k1
174
175
  3.0.0 and later libsecp256k1 is bundled with the gem.
175
176
  test_files: []