bitcoin-ruby 0.0.9 → 0.0.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ac6c9d01c48a263a569a401541007093dbd82e33
4
- data.tar.gz: a27f352d83e4a7958004d8d6ff1eee46d12656b2
3
+ metadata.gz: fa1430d4dfa8bcf7f4e23a098341ef1803797d8b
4
+ data.tar.gz: 1d4f1c0a5b163c7d42d07e4056d6a497719167b4
5
5
  SHA512:
6
- metadata.gz: dfcdaf331ed1a47de70e8557c7de2acdd04e255da1fb5ffbd787f83c4f84ba7963b122924e4a7c61f9e36a407dbcc57294ebf122a614afc9134f118b388811f0
7
- data.tar.gz: c7909f9e27da531aa015701342559ec39a742c73171e3f8c8bc5de82f699d57c3be1318bce9f0b71caae24b5226d6f48d002cddcc32ed37bc33d5b430d98029e
6
+ metadata.gz: a790a81f8a5bd8a94e8794e599b0ab5ca62f2b4568efce9924ffbc1fabd2805307ef9e8695cb2c9383907eff3ab62081fc8dd798d1985bcd11623e0155070c84
7
+ data.tar.gz: 5ab37c03ed8b4ba6f15a95c1ab29d564c2b5200309b75ef5667f9dc9f3003e267f8bf7c14ddf42fe9b56f53c6e26e221850e0f74af81e1fa731cfdd88e87218f
data/.travis.yml CHANGED
@@ -1,5 +1,4 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.0.0
4
- - 2.1.2
5
3
  - 2.2.0
4
+ - 2.3.2
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bitcoin-ruby (0.0.9)
4
+ bitcoin-ruby (0.0.8)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -277,6 +277,8 @@ module OpenSSL_EC
277
277
  end
278
278
 
279
279
  def self.sign_compact(hash, private_key, public_key_hex = nil, pubkey_compressed = nil)
280
+ msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hash)
281
+
280
282
  private_key = [private_key].pack("H*") if private_key.bytesize >= 64
281
283
  private_key_hex = private_key.unpack("H*")[0]
282
284
 
@@ -295,7 +297,7 @@ module OpenSSL_EC
295
297
  EC_KEY_set_private_key(eckey, priv_key)
296
298
  EC_KEY_set_public_key(eckey, pub_key)
297
299
 
298
- signature = ECDSA_do_sign(hash, hash.bytesize, eckey)
300
+ signature = ECDSA_do_sign(msg32, msg32.size, eckey)
299
301
 
300
302
  BN_free(order)
301
303
  BN_CTX_free(ctx)
@@ -309,7 +311,7 @@ module OpenSSL_EC
309
311
  if signature.get_array_of_pointer(0, 2).all?{|i| BN_num_bits(i) <= 256 }
310
312
  4.times{|i|
311
313
  head = [ 27 + i + (pubkey_compressed ? 4 : 0) ].pack("C")
312
- if public_key_hex == recover_public_key_from_signature(hash, [head, r, s].join, i, pubkey_compressed)
314
+ if public_key_hex == recover_public_key_from_signature(msg32.read_string(32), [head, r, s].join, i, pubkey_compressed)
313
315
  rec_id = i; break
314
316
  end
315
317
  }
@@ -322,14 +324,13 @@ module OpenSSL_EC
322
324
 
323
325
  def self.recover_compact(hash, signature)
324
326
  return false if signature.bytesize != 65
325
- #i = signature.unpack("C")[0] - 27
326
- #pubkey = recover_public_key_from_signature(hash, signature, (i & ~4), i >= 4)
327
+ msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, hash)
327
328
 
328
329
  version = signature.unpack('C')[0]
329
330
  return false if version < 27 or version > 34
330
331
 
331
332
  compressed = (version >= 31) ? (version -= 4; true) : false
332
- pubkey = recover_public_key_from_signature(hash, signature, version-27, compressed)
333
+ pubkey = recover_public_key_from_signature(msg32.read_string(32), signature, version-27, compressed)
333
334
  end
334
335
 
335
336
  # lifted from https://github.com/GemHQ/money-tree
@@ -1,8 +1,15 @@
1
1
  # encoding: ascii-8bit
2
2
 
3
- # bindings for secp256k1 inside bitcoin (https://github.com/bitcoin/bitcoin/tree/v0.11.0/src/secp256k1)
4
- # tag: v0.11.0
5
- # commit: d26f951802c762de04fb68e1a112d611929920ba
3
+ # bindings for secp256k1 inside bitcoin (https://github.com/bitcoin/bitcoin/tree/v0.13.1/src/secp256k1)
4
+ # tag: v0.13.1
5
+ # commit: 03422e564b552c1d3c16ae854f8471f7cb39e25d
6
+ # bitcoin@master% git checkout v0.13.1
7
+ # bitcoin@tags/v0.13.1^0% cd src/secp256k1
8
+ # bitcoin@tags/v0.13.1^0 src/secp256k1% ./autogen.sh
9
+ # bitcoin@tags/v0.13.1^0 src/secp256k1% ./configure --enable-module-recovery
10
+ # bitcoin@tags/v0.13.1^0 src/secp256k1% make libsecp256k1.la
11
+ # bitcoin@tags/v0.13.1^0 src/secp256k1% nm -D .libs/libsecp256k1.so.0.0.0 | grep secp
12
+ # export SECP256K1_LIB_PATH=/path/to/bitcoin/src/secp256k1/.libs/libsecp256k1.so.0.0.0
6
13
 
7
14
  require 'ffi'
8
15
 
@@ -10,70 +17,82 @@ module Bitcoin
10
17
  module Secp256k1
11
18
  extend FFI::Library
12
19
 
13
- SECP256K1_START_VERIFY = (1 << 0)
14
- SECP256K1_START_SIGN = (1 << 1)
20
+ SECP256K1_FLAGS_TYPE_MASK = ((1 << 8) - 1)
21
+ SECP256K1_FLAGS_TYPE_CONTEXT = (1 << 0)
22
+ SECP256K1_FLAGS_TYPE_COMPRESSION = (1 << 1)
23
+
24
+ # The higher bits contain the actual data. Do not use directly.
25
+ SECP256K1_FLAGS_BIT_CONTEXT_VERIFY = (1 << 8)
26
+ SECP256K1_FLAGS_BIT_CONTEXT_SIGN = (1 << 9)
27
+ SECP256K1_FLAGS_BIT_COMPRESSION = (1 << 8)
28
+
29
+ # Flags to pass to secp256k1_context_create.
30
+ SECP256K1_CONTEXT_VERIFY = (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
31
+ SECP256K1_CONTEXT_SIGN = (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
32
+
33
+ # Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export.
34
+ SECP256K1_EC_COMPRESSED = (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
35
+ SECP256K1_EC_UNCOMPRESSED = (SECP256K1_FLAGS_TYPE_COMPRESSION)
15
36
 
16
37
  def self.ffi_load_functions(file)
17
38
  class_eval <<-RUBY
18
39
  ffi_lib [ %[#{file}] ]
19
40
 
20
41
  ##
21
- # source: https://github.com/bitcoin/bitcoin/blob/v0.11.0/src/secp256k1/include/secp256k1.h
42
+ # source: https://github.com/bitcoin/bitcoin/blob/v0.13.1/src/secp256k1/include/secp256k1.h
22
43
  ##
23
44
 
24
- # secp256k1_context_t* secp256k1_context_create(int flags)
25
- attach_function :secp256k1_context_create, [:int], :pointer
45
+ # secp256k1_context* secp256k1_context_create(unsigned int flags)
46
+ attach_function :secp256k1_context_create, [:uint], :pointer
26
47
 
27
- # secp256k1_context_t* secp256k1_context_clone(const secp256k1_context_t* ctx)
28
- attach_function :secp256k1_context_clone, [:pointer], :pointer
29
-
30
- # void secp256k1_context_destroy(secp256k1_context_t* ctx)
48
+ # void secp256k1_context_destroy(secp256k1_context* ctx)
31
49
  attach_function :secp256k1_context_destroy, [:pointer], :void
32
50
 
33
- # int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen)
34
- attach_function :secp256k1_ecdsa_verify, [:pointer, :pointer, :pointer, :int, :pointer, :int], :int
51
+ # int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32)
52
+ attach_function :secp256k1_context_randomize, [:pointer, :pointer], :int
35
53
 
36
- # int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig, int *siglen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void *ndata)
37
- attach_function :secp256k1_ecdsa_sign, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int
54
+ # int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey)
55
+ attach_function :secp256k1_ec_seckey_verify, [:pointer, :pointer], :int
38
56
 
39
- # int secp256k1_ecdsa_sign_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void *ndata, int *recid)
40
- attach_function :secp256k1_ecdsa_sign_compact, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int
57
+ # int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey)
58
+ attach_function :secp256k1_ec_pubkey_create, [:pointer, :pointer, :pointer], :int
41
59
 
42
- # int secp256k1_ecdsa_recover_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid)
43
- attach_function :secp256k1_ecdsa_recover_compact, [:pointer, :pointer, :pointer, :pointer, :pointer, :int, :int], :int
60
+ # int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags)
61
+ attach_function :secp256k1_ec_pubkey_serialize, [:pointer, :pointer, :pointer, :pointer, :uint], :int
44
62
 
45
- # int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey)
46
- attach_function :secp256k1_ec_seckey_verify, [:pointer, :pointer], :int
63
+ # int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *sig, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void *ndata)
64
+ attach_function :secp256k1_ecdsa_sign_recoverable, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int
47
65
 
48
- # int secp256k1_ec_pubkey_verify(const secp256k1_context_t* ctx, const unsigned char *pubkey, int pubkeylen)
49
- attach_function :secp256k1_ec_pubkey_verify, [:pointer, :pointer, :int], :int
66
+ # int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig)
67
+ attach_function :secp256k1_ecdsa_recoverable_signature_serialize_compact, [:pointer, :pointer, :pointer, :pointer], :int
50
68
 
51
- # int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed)
52
- attach_function :secp256k1_ec_pubkey_create, [:pointer, :pointer, :pointer, :pointer, :int], :int
69
+ # int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid)
70
+ attach_function :secp256k1_ecdsa_recoverable_signature_parse_compact, [:pointer, :pointer, :pointer, :int], :int
53
71
 
54
- # int secp256k1_ec_pubkey_decompress(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen)
55
- attach_function :secp256k1_ec_pubkey_decompress, [:pointer, :pointer, :pointer], :int
72
+ # int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *sig, const unsigned char *msg32)
73
+ attach_function :secp256k1_ecdsa_recover, [:pointer, :pointer, :pointer, :pointer], :int
56
74
 
57
- # int secp256k1_ec_privkey_export(const secp256k1_context_t* ctx, const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed)
58
- attach_function :secp256k1_ec_privkey_export, [:pointer, :pointer, :pointer, :pointer, :int], :int
75
+ # int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void *ndata)
76
+ attach_function :secp256k1_ecdsa_sign, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :int
59
77
 
60
- # int secp256k1_ec_privkey_import(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *privkey, int privkeylen)
61
- attach_function :secp256k1_ec_privkey_import, [:pointer, :pointer, :pointer, :pointer], :int
78
+ # int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig)
79
+ attach_function :secp256k1_ecdsa_signature_serialize_der, [:pointer, :pointer, :pointer, :pointer], :int
62
80
 
63
- # int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak)
64
- attach_function :secp256k1_ec_privkey_tweak_add, [:pointer, :pointer, :pointer], :int
81
+ # int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen)
82
+ attach_function :secp256k1_ec_pubkey_parse, [:pointer, :pointer, :pointer, :size_t], :int
65
83
 
66
- # int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak)
67
- attach_function :secp256k1_ec_pubkey_tweak_add, [:pointer, :pointer, :int, :pointer], :int
84
+ # int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin)
85
+ attach_function :secp256k1_ecdsa_signature_normalize, [:pointer, :pointer, :pointer], :int
68
86
 
69
- # int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak)
70
- attach_function :secp256k1_ec_privkey_tweak_mul, [:pointer, :pointer, :pointer], :int
87
+ # int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey)
88
+ attach_function :secp256k1_ecdsa_verify, [:pointer, :pointer, :pointer, :pointer], :int
71
89
 
72
- # int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak)
73
- attach_function :secp256k1_ec_pubkey_tweak_mul, [:pointer, :pointer, :int, :pointer], :int
90
+ # int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen)
91
+ attach_function :secp256k1_ecdsa_signature_parse_der, [:pointer, :pointer, :pointer, :size_t], :int
74
92
 
75
- # int secp256k1_context_randomize(secp256k1_context_t* ctx, const unsigned char *seed32)
76
- attach_function :secp256k1_context_randomize, [:pointer, :pointer], :int
93
+ # TODO: add or port
94
+ # # int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen)
95
+ # attach_function :ecdsa_signature_parse_der_lax, [:pointer, :pointer, :pointer, :size_t], :int
77
96
  RUBY
78
97
  end
79
98
 
@@ -86,7 +105,7 @@ module Bitcoin
86
105
 
87
106
  def self.with_context(flags=nil, seed=nil)
88
107
  init
89
- flags = flags || (SECP256K1_START_VERIFY | SECP256K1_START_SIGN )
108
+ flags = flags || (SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN)
90
109
  context = secp256k1_context_create(flags)
91
110
 
92
111
  ret, tries, max = 0, 0, 20
@@ -109,15 +128,25 @@ module Bitcoin
109
128
  raise "secp256k1_ec_seckey_verify in generate_key_pair failed." if tries >= max
110
129
  tries += 1
111
130
 
112
- priv_key = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, SecureRandom.random_bytes(32))
113
- ret = secp256k1_ec_seckey_verify(context, priv_key)
131
+ seckey = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, SecureRandom.random_bytes(32))
132
+ ret = secp256k1_ec_seckey_verify(context, seckey)
114
133
  end
115
134
 
116
- pub_key, pub_key_length = FFI::MemoryPointer.new(:uchar, 65), FFI::MemoryPointer.new(:int)
117
- result = secp256k1_ec_pubkey_create(context, pub_key, pub_key_length, priv_key, compressed ? 1 : 0)
135
+ internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
136
+ result = secp256k1_ec_pubkey_create(context, internal_pubkey, seckey)
118
137
  raise "error creating pubkey" unless result
119
138
 
120
- [ priv_key.read_string(32), pub_key.read_string(pub_key_length.read_int) ]
139
+ pubkey, pubkey_len = FFI::MemoryPointer.new(:uchar, 65), FFI::MemoryPointer.new(:uint64)
140
+ result = if compressed
141
+ pubkey_len.put_uint64(0, 33)
142
+ secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_COMPRESSED)
143
+ else
144
+ pubkey_len.put_uint64(0, 65)
145
+ secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_UNCOMPRESSED)
146
+ end
147
+ raise "error serialize pubkey" unless result || pubkey_len.read_uint64 > 0
148
+
149
+ [ seckey.read_string(32), pubkey.read_string(pubkey_len.read_uint64) ]
121
150
  end
122
151
  end
123
152
 
@@ -128,53 +157,77 @@ module Bitcoin
128
157
 
129
158
  def self.sign(data, priv_key)
130
159
  with_context do |context|
131
- msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
132
160
  seckey = FFI::MemoryPointer.new(:uchar, priv_key.bytesize).put_bytes(0, priv_key)
133
161
  raise "priv_key invalid" unless secp256k1_ec_seckey_verify(context, seckey)
134
162
 
135
- sig, siglen = FFI::MemoryPointer.new(:uchar, 72), FFI::MemoryPointer.new(:int).write_int(72)
163
+ internal_signature = FFI::MemoryPointer.new(:uchar, 64)
164
+ msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
136
165
 
137
- while true do
138
- break if secp256k1_ecdsa_sign(context, msg32, sig, siglen, seckey, nil, nil)
166
+ ret, tries, max = 0, 0, 20
167
+ while ret != 1
168
+ raise "secp256k1_ecdsa_sign failed." if tries >= max
169
+ tries += 1
170
+
171
+ ret = secp256k1_ecdsa_sign(context, internal_signature, msg32, seckey, nil, nil)
139
172
  end
140
173
 
141
- sig.read_string(siglen.read_int)
174
+ signature, signature_len = FFI::MemoryPointer.new(:uchar, 72), FFI::MemoryPointer.new(:uint64).put_uint64(0, 72)
175
+ result = secp256k1_ecdsa_signature_serialize_der(context, signature, signature_len, internal_signature)
176
+ raise "secp256k1_ecdsa_signature_serialize_der failed" unless result
177
+
178
+ signature.read_string(signature_len.read_uint64)
142
179
  end
143
180
  end
144
181
 
145
- def self.verify(data, signature, pub_key)
182
+ def self.verify(data, sig, pub_key)
146
183
  with_context do |context|
147
- data_buf = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
148
- sig_buf = FFI::MemoryPointer.new(:uchar, signature.bytesize).put_bytes(0, signature)
149
- pub_buf = FFI::MemoryPointer.new(:uchar, pub_key.bytesize).put_bytes(0, pub_key)
150
-
151
- result = secp256k1_ecdsa_verify(context, data_buf, sig_buf, sig_buf.size, pub_buf, pub_buf.size)
152
-
153
- case result
154
- when 0; false
155
- when 1; true
156
- when -1; raise "error invalid pubkey"
157
- when -2; raise "error invalid signature"
158
- else ; raise "error invalid result"
159
- end
184
+ return false if data.bytesize == 0
185
+
186
+ pubkey = FFI::MemoryPointer.new(:uchar, pub_key.bytesize).put_bytes(0, pub_key)
187
+ internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
188
+ result = secp256k1_ec_pubkey_parse(context, internal_pubkey, pubkey, pubkey.size)
189
+ return false unless result
190
+
191
+ signature = FFI::MemoryPointer.new(:uchar, sig.bytesize).put_bytes(0, sig)
192
+ internal_signature = FFI::MemoryPointer.new(:uchar, 64)
193
+ result = secp256k1_ecdsa_signature_parse_der(context, internal_signature, signature, signature.size)
194
+ #result = ecdsa_signature_parse_der_lax(context, internal_signature, signature, signature.size)
195
+ return false unless result
196
+
197
+ # libsecp256k1's ECDSA verification requires lower-S signatures, which have not historically been enforced in Bitcoin, so normalize them first.
198
+ secp256k1_ecdsa_signature_normalize(context, internal_signature, internal_signature)
199
+
200
+ msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, data)
201
+ result = secp256k1_ecdsa_verify(context, internal_signature, msg32, internal_pubkey)
202
+
203
+ return result ? true : false
160
204
  end
161
205
  end
162
206
 
163
207
  def self.sign_compact(message, priv_key, compressed=true)
164
208
  with_context do |context|
165
- msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, message)
166
- sig64 = FFI::MemoryPointer.new(:uchar, 64)
167
- rec_id = FFI::MemoryPointer.new(:int)
168
-
169
209
  seckey = FFI::MemoryPointer.new(:uchar, priv_key.bytesize).put_bytes(0, priv_key)
170
210
  raise "priv_key invalid" unless secp256k1_ec_seckey_verify(context, seckey)
171
211
 
172
- while true do
173
- break if secp256k1_ecdsa_sign_compact(context, msg32, sig64, seckey, nil, nil, rec_id)
212
+ msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, message)
213
+ internal_recoverable_signature = FFI::MemoryPointer.new(:uchar, 65)
214
+ rec_id = FFI::MemoryPointer.new(:int).put_int(0, -1)
215
+
216
+ ret, tries, max = 0, 0, 20
217
+ while ret != 1
218
+ raise "secp256k1_ecdsa_sign_recoverable failed." if tries >= max
219
+ tries += 1
220
+
221
+ ret = secp256k1_ecdsa_sign_recoverable(context, internal_recoverable_signature, msg32, seckey, nil, nil)
174
222
  end
175
223
 
224
+ recoverable_signature = FFI::MemoryPointer.new(:uchar, 64)
225
+ result = secp256k1_ecdsa_recoverable_signature_serialize_compact(context, recoverable_signature, rec_id, internal_recoverable_signature)
226
+ raise "secp256k1_ecdsa_recoverable_signature_serialize_compact failed" unless result
227
+ raise "secp256k1_ecdsa_recoverable_signature_serialize_compact failed" unless rec_id.read_int != -1
228
+
176
229
  header = [27 + rec_id.read_int + (compressed ? 4 : 0)].pack("C")
177
- [ header, sig64.read_string(64) ].join
230
+ [ header, recoverable_signature.read_string(64) ].join
178
231
  end
179
232
  end
180
233
 
@@ -186,19 +239,26 @@ module Bitcoin
186
239
  return nil if version < 27 || version > 34
187
240
 
188
241
  compressed = version >= 31 ? true : false
242
+ flag = compressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED
189
243
  version -= 4 if compressed
190
244
 
191
245
  recid = version - 27
192
246
  msg32 = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, message)
193
- sig64 = FFI::MemoryPointer.new(:uchar, 64).put_bytes(0, signature[1..-1])
194
- pubkey = FFI::MemoryPointer.new(:uchar, pub_key_len = compressed ? 33 : 65)
195
- pubkeylen = FFI::MemoryPointer.new(:int).write_int(pub_key_len)
247
+ recoverable_signature = FFI::MemoryPointer.new(:uchar, 64).put_bytes(0, signature[1..-1])
196
248
 
197
- result = secp256k1_ecdsa_recover_compact(context, msg32, sig64, pubkey, pubkeylen, (compressed ? 1 : 0), recid)
249
+ internal_recoverable_signature = FFI::MemoryPointer.new(:uchar, 65)
250
+ result = secp256k1_ecdsa_recoverable_signature_parse_compact(context, internal_recoverable_signature, recoverable_signature, recid)
251
+ return nil unless result
198
252
 
253
+ internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
254
+ result = secp256k1_ecdsa_recover(context, internal_pubkey, internal_recoverable_signature, msg32)
199
255
  return nil unless result
200
256
 
201
- pubkey.read_bytes(pubkeylen.read_int)
257
+ pubkey, pubkey_len = FFI::MemoryPointer.new(:uchar, 65), FFI::MemoryPointer.new(:uint64).put_uint64(0, 65)
258
+ result = secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, flag)
259
+ raise "error serialize pubkey" unless result || pubkey_len.read_uint64 > 0
260
+
261
+ pubkey.read_string(pubkey_len.read_uint64)
202
262
  end
203
263
  end
204
264
 
@@ -1,3 +1,3 @@
1
1
  module Bitcoin
2
- VERSION = "0.0.9"
2
+ VERSION = "0.0.10"
3
3
  end
@@ -27,6 +27,7 @@ describe 'libsecp256k1' do
27
27
  priv, pub = Bitcoin::Secp256k1.generate_key_pair
28
28
  signature = Bitcoin::Secp256k1.sign("derp", priv)
29
29
  Bitcoin::Secp256k1.verify("derp", signature, pub).should == true
30
+ Bitcoin::Secp256k1.verify("DERP", signature, pub).should == true
30
31
  end
31
32
 
32
33
  it 'sign compact and recover' do
@@ -51,6 +52,27 @@ describe 'libsecp256k1' do
51
52
  first = Bitcoin::Secp256k1.sign("derp", priv)
52
53
  second = Bitcoin::Secp256k1.sign("derp", priv)
53
54
  first.should == second
55
+
56
+ priv, pub = Bitcoin::Secp256k1.generate_key_pair
57
+ second = Bitcoin::Secp256k1.sign("derp", priv)
58
+ first.should != second
59
+ end
60
+
61
+ it 'openssl vs Secp256k1' do
62
+ k = Bitcoin::Key.new("82a0c421a0f67c7a88a329b2c15f2849aa1c8cfa9c9a6513f056f80ee8eaacc4", nil, compresed=false); k.pub
63
+ k.pub.should == "0490b0854581a291b83c1945775f156da22445df99e445581321ac3aa62535ff369334316dfd157acc7bb2e4d3eb85951f6d1b7f62f6f60a09e0dbd5c87d3ffae9"
64
+
65
+ message = "hello world"
66
+ priv = [k.priv].pack("H*")
67
+
68
+ sig1 = Bitcoin::OpenSSL_EC.sign_compact(message, priv, nil, compressed=false)
69
+ sig2 = Bitcoin::Secp256k1.sign_compact(message, priv, compressed=false)
70
+
71
+ Bitcoin::OpenSSL_EC.recover_compact(message, sig1).should == k.pub
72
+ Bitcoin::Secp256k1.recover_compact(message, sig1).unpack("H*")[0].should == k.pub
73
+
74
+ Bitcoin::OpenSSL_EC.recover_compact(message, sig2).should == k.pub
75
+ Bitcoin::Secp256k1.recover_compact(message, sig2).unpack("H*")[0] == k.pub
54
76
  end
55
77
 
56
78
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitcoin-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - lian
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-13 00:00:00.000000000 Z
11
+ date: 2017-01-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: This is a ruby library for interacting with the bitcoin protocol/network
14
14
  email:
@@ -245,7 +245,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
245
245
  version: 1.3.6
246
246
  requirements: []
247
247
  rubyforge_project: bitcoin-ruby
248
- rubygems_version: 2.5.1
248
+ rubygems_version: 2.5.2
249
249
  signing_key:
250
250
  specification_version: 4
251
251
  summary: bitcoin utils and protocol in ruby