bitcoin-ruby 0.0.9 → 0.0.10

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
  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