bitcoinrb 0.2.5 → 0.2.6

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: 895222030c0d0673f1524e112cf42d8cbb8e248558ba356e156a92b7482d4344
4
- data.tar.gz: cca9f6a8777925fcf39c47a835549b1894554e2d3c67400ba330487731677a89
3
+ metadata.gz: 2dea1d2e52223f2754f748f612c5d3df9606988476ee0c1f5b1ad03e71ba0ead
4
+ data.tar.gz: baedfcc44fdacd0c2c46766a360fb76404630bd01dbaf034664d358f5564d5b8
5
5
  SHA512:
6
- metadata.gz: cbb089fdfa71ac6a9c60591789c18b78af3fac81e6ba82ac264a50cd1d464b814f8989ca62fdde78910640e241f2b7e8c516b20b9e67eb979efae86c43b9b0ab
7
- data.tar.gz: bf0b6f27f6e4819569f3d814194b202f18d829bf315591ce8fa75db0846b2ef372ca45294537918ff7d161b37947f91be05562200d7028bc39b598ec83f01b26
6
+ metadata.gz: 851b762a403ebd8a0f175171e000650b76b5380522c174cbea3c03817477aa89e98b8a3e204c0cc3c223fb281dfbc75ae936cd1b1fe6e6f6b06ae5aeca74b335
7
+ data.tar.gz: 75fd1e350ab651a01b1eae0d0b6885ca933a60efcfc237ad75de55002777806aaf805c4a724430535521c421a10111871838d97bfaf94d93766f93e433e33160
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.6.0
1
+ 2.6.2
data/.travis.yml CHANGED
@@ -1,9 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.3.8
4
3
  - 2.4.5
5
- - 2.5.3
6
- - 2.6.0
4
+ - 2.5.5
5
+ - 2.6.2
7
6
  addons:
8
7
  apt:
9
8
  packages:
data/README.md CHANGED
@@ -46,7 +46,7 @@ gem leveldb-ruby
46
46
  Add this line to your application's Gemfile:
47
47
 
48
48
  ```ruby
49
- gem 'bitcoinrb'
49
+ gem 'bitcoinrb', require: 'bitcoin'
50
50
  ```
51
51
 
52
52
  And then execute:
@@ -57,6 +57,9 @@ Or install it yourself as:
57
57
 
58
58
  $ gem install bitcoinrb
59
59
 
60
+ And then add to your .rb file:
61
+
62
+ require 'bitcoin'
60
63
 
61
64
  ## Usage
62
65
 
data/bitcoinrb.gemspec CHANGED
@@ -32,13 +32,13 @@ Gem::Specification.new do |spec|
32
32
  spec.add_runtime_dependency 'rest-client'
33
33
  spec.add_runtime_dependency 'iniparse'
34
34
  spec.add_runtime_dependency 'siphash'
35
- spec.add_runtime_dependency 'protobuf'
35
+ spec.add_runtime_dependency 'protobuf', '3.8.5'
36
36
  spec.add_runtime_dependency 'scrypt'
37
37
 
38
38
  # for options
39
39
  spec.add_development_dependency 'leveldb-ruby'
40
40
 
41
- spec.add_development_dependency 'bundler', '~> 1.11'
41
+ spec.add_development_dependency 'bundler'
42
42
  spec.add_development_dependency 'rake', '~> 10.0'
43
43
  spec.add_development_dependency 'rspec', '~> 3.0'
44
44
  spec.add_development_dependency 'timecop'
@@ -25,7 +25,7 @@ module Bitcoin
25
25
  int_val = 0
26
26
  base58_val.reverse.split(//).each_with_index do |char,index|
27
27
  raise ArgumentError, 'Value passed not a valid Base58 String.' if (char_index = ALPHABET.index(char)).nil?
28
- int_val += char_index * (SIZE**index)
28
+ int_val += char_index * (SIZE ** index)
29
29
  end
30
30
  s = int_val.to_even_length_hex
31
31
  s = '' if s == '00'
@@ -2,7 +2,7 @@ module Bitcoin
2
2
 
3
3
  class BitStreamWriter
4
4
 
5
- MAX_BIT = 2**64
5
+ MAX_BIT = 4611686018427387904 # 2**64
6
6
 
7
7
  attr_reader :stream
8
8
  attr_accessor :buffer
@@ -28,7 +28,7 @@ module Bitcoin
28
28
 
29
29
  def flush
30
30
  return if offset == 0
31
- self.stream << [buffer.to_even_length_hex].pack('H*')
31
+ self.stream << buffer.itb
32
32
  self.offset = 0
33
33
  self.buffer = 0
34
34
  end
@@ -70,7 +70,7 @@ module Bitcoin
70
70
  def work
71
71
  target = difficulty_target
72
72
  return 0 if target < 1
73
- (2**256) / (target + 1)
73
+ 115792089237316195423570985008687907853269984665640564039457584007913129639936.div(target + 1) # 115792089237316195423570985008687907853269984665640564039457584007913129639936 is 2**256
74
74
  end
75
75
 
76
76
  def ==(other)
@@ -3,6 +3,8 @@ module Bitcoin
3
3
  # Integers modulo the order of the curve(secp256k1)
4
4
  CURVE_ORDER = ECDSA::Group::Secp256k1.order
5
5
 
6
+ HARDENED_THRESHOLD = 2147483648 # 2**31
7
+
6
8
  # BIP32 Extended private key
7
9
  class ExtKey
8
10
 
@@ -83,7 +85,7 @@ module Bitcoin
83
85
 
84
86
  # whether hardened key.
85
87
  def hardened?
86
- number >= 2**31
88
+ number >= HARDENED_THRESHOLD
87
89
  end
88
90
 
89
91
  # derive new key
@@ -91,12 +93,12 @@ module Bitcoin
91
93
  # @param [Boolean] harden whether hardened key or not. If true, 2^31 is added to +number+.
92
94
  # @return [Bitcoin::ExtKey] derived new key.
93
95
  def derive(number, harden = false)
94
- number += 2**31 if harden
96
+ number += HARDENED_THRESHOLD if harden
95
97
  new_key = ExtKey.new
96
98
  new_key.depth = depth + 1
97
99
  new_key.number = number
98
100
  new_key.parent_fingerprint = fingerprint
99
- if number > (2**31 -1)
101
+ if number > (HARDENED_THRESHOLD - 1)
100
102
  data = [0x00].pack('C') << key.priv_key.htb << [number].pack('N')
101
103
  else
102
104
  data = key.pubkey.htb << [number].pack('N')
@@ -153,7 +155,7 @@ module Bitcoin
153
155
 
154
156
  # get version bytes from purpose' value.
155
157
  def self.version_from_purpose(purpose)
156
- v = purpose - 2**31
158
+ v = purpose - HARDENED_THRESHOLD
157
159
  case v
158
160
  when 49
159
161
  Bitcoin.chain_params.bip49_privkey_p2wpkh_p2sh_version
@@ -245,7 +247,7 @@ module Bitcoin
245
247
 
246
248
  # whether hardened key.
247
249
  def hardened?
248
- number >= 2**31
250
+ number >= HARDENED_THRESHOLD
249
251
  end
250
252
 
251
253
  # derive child key
@@ -254,7 +256,7 @@ module Bitcoin
254
256
  new_key.depth = depth + 1
255
257
  new_key.number = number
256
258
  new_key.parent_fingerprint = fingerprint
257
- raise 'hardened key is not support' if number > (2**31 -1)
259
+ raise 'hardened key is not support' if number > (HARDENED_THRESHOLD - 1)
258
260
  data = pub.htb << [number].pack('N')
259
261
  l = Bitcoin.hmac_sha512(chain_code, data)
260
262
  left = l[0..31].bth.to_i(16)
@@ -306,7 +308,7 @@ module Bitcoin
306
308
 
307
309
  # get version bytes from purpose' value.
308
310
  def self.version_from_purpose(purpose)
309
- v = purpose - 2**31
311
+ v = purpose - HARDENED_THRESHOLD
310
312
  case v
311
313
  when 49
312
314
  Bitcoin.chain_params.bip49_pubkey_p2wpkh_p2sh_version
@@ -6,6 +6,8 @@ module Bitcoin
6
6
  # see https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki
7
7
  class GCSFilter
8
8
 
9
+ MAX_ELEMENTS_SIZE = 4294967296 # 2**32
10
+
9
11
  attr_reader :p # Golomb-Rice coding parameter
10
12
  attr_reader :m # Inverse false positive rate
11
13
  attr_reader :n # Number of elements in the filter
@@ -26,7 +28,7 @@ module Bitcoin
26
28
  @p = p
27
29
  @m = m
28
30
  if elements
29
- raise 'elements size must be < 2**32.' if elements.size >= (2**32)
31
+ raise 'elements size must be < 2**32.' if elements.size >= MAX_ELEMENTS_SIZE
30
32
  @n = elements.size
31
33
  encoded = Bitcoin.pack_var_int(@n)
32
34
  bit_writer = Bitcoin::BitStreamWriter.new
data/lib/bitcoin/key.rb CHANGED
@@ -18,7 +18,7 @@ module Bitcoin
18
18
 
19
19
  TYPES = {uncompressed: 0x00, compressed: 0x01, p2pkh: 0x10, p2wpkh: 0x11, pw2pkh_p2sh: 0x12}
20
20
 
21
- MIN_PRIV_KEy_MOD_ORDER = 0x01
21
+ MIN_PRIV_KEY_MOD_ORDER = 0x01
22
22
  # Order of secp256k1's generator minus 1.
23
23
  MAX_PRIV_KEY_MOD_ORDER = ECDSA::Group::Secp256k1.order - 1
24
24
 
@@ -253,15 +253,13 @@ module Bitcoin
253
253
  # @param [Boolean] compressed pubkey compressed?
254
254
  # @return [String] a pubkey which generate from privkey
255
255
  def generate_pubkey(privkey, compressed: true)
256
- public_key = ECDSA::Group::Secp256k1.generator.multiply_by_scalar(privkey.to_i(16))
257
- pubkey = ECDSA::Format::PointOctetString.encode(public_key, compression: compressed)
258
- pubkey.bth
256
+ @secp256k1_module.generate_pubkey(privkey, compressed: compressed)
259
257
  end
260
258
 
261
259
  # check private key range.
262
260
  def validate_private_key_range(private_key)
263
261
  value = private_key.to_i(16)
264
- MIN_PRIV_KEy_MOD_ORDER <= value && value <= MAX_PRIV_KEY_MOD_ORDER
262
+ MIN_PRIV_KEY_MOD_ORDER <= value && value <= MAX_PRIV_KEY_MOD_ORDER
265
263
  end
266
264
 
267
265
  # Supported violations include negative integers, excessive padding, garbage
@@ -100,11 +100,12 @@ module Bitcoin
100
100
  payload << PSBT.serialize_to_vector(PSBT_IN_TYPES[:script_sig], value: final_script_sig.to_payload) if final_script_sig
101
101
  payload << PSBT.serialize_to_vector(PSBT_IN_TYPES[:script_witness], value: final_script_witness.to_payload) if final_script_witness
102
102
  payload << unknowns.map {|k,v|Bitcoin.pack_var_int(k.htb.bytesize) << k.htb << Bitcoin.pack_var_int(v.bytesize) << v}.join
103
- payload << PSBT_SEPARATOR.to_even_length_hex.htb
103
+ payload << PSBT_SEPARATOR.itb
104
104
  payload
105
105
  end
106
106
 
107
107
  # Sanity check
108
+ # @return [Boolean]
108
109
  def sane?
109
110
  return false if non_witness_utxo && witness_utxo
110
111
  return false if witness_script && witness_utxo.nil?
@@ -112,6 +113,33 @@ module Bitcoin
112
113
  true
113
114
  end
114
115
 
116
+ # Check whether input's scriptPubkey is correct witness.
117
+ # @return [Boolean]
118
+ def valid_witness_input?
119
+ return true if witness_utxo.script_pubkey.p2wpkh? # P2WPKH
120
+ return true if witness_utxo.script_pubkey.p2wsh? && witness_utxo.script_pubkey == redeem_script.to_p2wsh # P2WSH
121
+ return true if witness_utxo.script_pubkey.p2sh? && redeem_script&.witness_program? && # segwit nested in P2SH
122
+ redeem_script.to_p2sh == witness_utxo.script_pubkey && witness_script&.to_sha256 == redeem_script.witness_data[1].bth
123
+ false
124
+ end
125
+
126
+ # Check whether input's scriptPubkey is correct witness.
127
+ # @return [Boolean]
128
+ def valid_non_witness_input?
129
+ non_witness_utxo.outputs.each do |o|
130
+ return true if o.script_pubkey.p2sh? && redeem_script.to_p2sh == o.script_pubkey
131
+ end
132
+ false
133
+ end
134
+
135
+ # Check whether the signer can sign this input.
136
+ # @return [Boolean]
137
+ def ready_to_sign?
138
+ return false unless sane?
139
+ return valid_witness_input? if witness_utxo
140
+ valid_non_witness_input? # non_witness_utxo
141
+ end
142
+
115
143
  # add signature as partial sig.
116
144
  # @param [String] pubkey a public key with hex format.
117
145
  # @param [String] sig a signature.
@@ -132,7 +160,7 @@ module Bitcoin
132
160
  raise ArgumentError, 'The Partially Signed Input\'s redeem_script are different.' unless redeem_script == psbi.redeem_script
133
161
  raise ArgumentError, 'The Partially Signed Input\'s witness_script are different.' unless witness_script == psbi.witness_script
134
162
  combined = Bitcoin::PSBT::Input.new(non_witness_utxo: non_witness_utxo, witness_utxo: witness_utxo)
135
- combined.unknowns = unknowns.merge(psbi.unknowns)
163
+ combined.unknowns = Hash[unknowns.merge(psbi.unknowns).sort]
136
164
  combined.redeem_script = redeem_script
137
165
  combined.witness_script = witness_script
138
166
  combined.sighash_type = sighash_type
@@ -52,7 +52,7 @@ module Bitcoin
52
52
  payload << PSBT.serialize_to_vector(PSBT_OUT_TYPES[:witness_script], value: witness_script) if witness_script
53
53
  payload << hd_key_paths.values.map{|v|v.to_payload(PSBT_OUT_TYPES[:bip32_derivation])}.join
54
54
  payload << unknowns.map {|k,v|Bitcoin.pack_var_int(k.htb.bytesize) << k.htb << Bitcoin.pack_var_int(v.bytesize) << v}.join
55
- payload << PSBT_SEPARATOR.to_even_length_hex.htb
55
+ payload << PSBT_SEPARATOR.itb
56
56
  payload
57
57
  end
58
58
 
@@ -66,7 +66,7 @@ module Bitcoin
66
66
  combined = Bitcoin::PSBT::Output.new
67
67
  combined.redeem_script = redeem_script
68
68
  combined.witness_script = witness_script
69
- combined.unknowns = unknowns.merge(psbo.unknowns)
69
+ combined.unknowns = Hash[unknowns.merge(psbo.unknowns).sort]
70
70
  combined.hd_key_paths = hd_key_paths.merge(psbo.hd_key_paths)
71
71
  combined
72
72
  end
@@ -86,13 +86,13 @@ module Bitcoin
86
86
  # generate payload.
87
87
  # @return [String] a payload with binary format.
88
88
  def to_payload
89
- payload = PSBT_MAGIC_BYTES.to_even_length_hex.htb << 0xff.to_even_length_hex.htb
89
+ payload = PSBT_MAGIC_BYTES.itb << 0xff.itb
90
90
 
91
91
  payload << PSBT.serialize_to_vector(PSBT_GLOBAL_TYPES[:unsigned_tx], value: tx.to_payload)
92
92
 
93
93
  payload << unknowns.map {|k,v|Bitcoin.pack_var_int(k.htb.bytesize) << k.htb << Bitcoin.pack_var_int(v.bytesize) << v}.join
94
94
 
95
- payload << PSBT_SEPARATOR.to_even_length_hex.htb
95
+ payload << PSBT_SEPARATOR.itb
96
96
 
97
97
  payload << inputs.map(&:to_payload).join
98
98
  payload << outputs.map(&:to_payload).join
@@ -129,6 +129,16 @@ module Bitcoin
129
129
  end
130
130
  end
131
131
 
132
+ # Check whether the signer can sign. Specifically, check the following.
133
+ # * If a non-witness UTXO is provided, its hash must match the hash specified in the prevout
134
+ # * If a witness UTXO is provided, no non-witness signature may be created
135
+ # * If a redeemScript is provided, the scriptPubKey must be for that redeemScript
136
+ # * If a witnessScript is provided, the scriptPubKey or the redeemScript must be for that witnessScript
137
+ # @return [Boolean]
138
+ def ready_to_sign?
139
+ inputs.all?(&:ready_to_sign?)
140
+ end
141
+
132
142
  # get signature script of input specified by +index+
133
143
  # @param [Integer] index input index.
134
144
  # @return [Bitcoin::Script]
@@ -158,7 +168,8 @@ module Bitcoin
158
168
  outputs.each_with_index do |o, index|
159
169
  combined.outputs[index] = o.merge(psbt.outputs[index])
160
170
  end
161
- combined.unknowns = unknowns.merge(psbt.unknowns)
171
+
172
+ combined.unknowns = Hash[unknowns.merge(psbt.unknowns).sort]
162
173
  combined
163
174
  end
164
175
 
data/lib/bitcoin/psbt.rb CHANGED
@@ -21,7 +21,7 @@ module Bitcoin
21
21
  module_function
22
22
 
23
23
  def self.serialize_to_vector(key_type, key: nil, value: nil)
24
- key_len = key_type.to_even_length_hex.htb.bytesize
24
+ key_len = key_type.itb.bytesize
25
25
  key_len += key.bytesize if key
26
26
  s = Bitcoin.pack_var_int(key_len) << Bitcoin.pack_var_int(key_type)
27
27
  s << key if key
@@ -26,6 +26,7 @@ module Bitcoin
26
26
  def getblockheader(block_id, verbose)
27
27
  block_hash = block_id.rhex
28
28
  entry = node.chain.find_entry_by_hash(block_hash)
29
+ raise ArgumentError.new('Block not found') unless entry
29
30
  if verbose
30
31
  {
31
32
  hash: block_id,
@@ -78,23 +78,8 @@ module Bitcoin
78
78
  priv_key = FFI::MemoryPointer.new(:uchar, 32).put_bytes(0, SecureRandom.random_bytes(32))
79
79
  ret = secp256k1_ec_seckey_verify(context, priv_key)
80
80
  end
81
-
82
- internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
83
- result = secp256k1_ec_pubkey_create(context, internal_pubkey, priv_key)
84
- raise 'error creating pubkey' unless result
85
-
86
- pubkey = FFI::MemoryPointer.new(:uchar, 65)
87
- pubkey_len = FFI::MemoryPointer.new(:uint64)
88
- result = if compressed
89
- pubkey_len.put_uint64(0, 33)
90
- secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_COMPRESSED)
91
- else
92
- pubkey_len.put_uint64(0, 65)
93
- secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_UNCOMPRESSED)
94
- end
95
- raise 'error serialize pubkey' unless result || pubkey_len.read_uint64 > 0
96
-
97
- [ priv_key.read_string(32).bth, pubkey.read_string(pubkey_len.read_uint64).bth ]
81
+ private_key = priv_key.read_string(32).bth
82
+ [private_key , generate_pubkey_in_context(context, private_key, compressed: compressed) ]
98
83
  end
99
84
  end
100
85
 
@@ -104,6 +89,12 @@ module Bitcoin
104
89
  Bitcoin::Key.new(priv_key: privkey, pubkey: pubkey, compressed: compressed)
105
90
  end
106
91
 
92
+ def generate_pubkey(priv_key, compressed: true)
93
+ with_context do |context|
94
+ generate_pubkey_in_context(context, priv_key, compressed: compressed)
95
+ end
96
+ end
97
+
107
98
  # sign data.
108
99
  # @param [String] data a data to be signed with binary format
109
100
  # @param [String] privkey a private key using sign
@@ -159,7 +150,25 @@ module Bitcoin
159
150
  end
160
151
  end
161
152
 
153
+ private
154
+
155
+ def generate_pubkey_in_context(context, privkey, compressed: true)
156
+ internal_pubkey = FFI::MemoryPointer.new(:uchar, 64)
157
+ result = secp256k1_ec_pubkey_create(context, internal_pubkey, privkey.htb)
158
+ raise 'error creating pubkey' unless result
159
+
160
+ pubkey = FFI::MemoryPointer.new(:uchar, 65)
161
+ pubkey_len = FFI::MemoryPointer.new(:uint64)
162
+ result = if compressed
163
+ pubkey_len.put_uint64(0, 33)
164
+ secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_COMPRESSED)
165
+ else
166
+ pubkey_len.put_uint64(0, 65)
167
+ secp256k1_ec_pubkey_serialize(context, pubkey, pubkey_len, internal_pubkey, SECP256K1_EC_UNCOMPRESSED)
168
+ end
169
+ raise 'error serialize pubkey' unless result || pubkey_len.read_uint64 > 0
170
+ pubkey.read_string(pubkey_len.read_uint64).bth
171
+ end
162
172
  end
163
-
164
173
  end
165
174
  end
@@ -22,6 +22,11 @@ module Bitcoin
22
22
  Bitcoin::Key.new(priv_key: privkey, pubkey: pubkey, compressed: compressed)
23
23
  end
24
24
 
25
+ def generate_pubkey(privkey, compressed: true)
26
+ public_key = ECDSA::Group::Secp256k1.generator.multiply_by_scalar(privkey.to_i(16))
27
+ ECDSA::Format::PointOctetString.encode(public_key, compression: compressed).bth
28
+ end
29
+
25
30
  # sign data.
26
31
  # @param [String] data a data to be signed with binary format
27
32
  # @param [String] privkey a private key using sign
@@ -36,6 +36,7 @@ module Bitcoin
36
36
  # find block entry with the specified hash
37
37
  def find_entry_by_hash(hash)
38
38
  payload = db.get_entry_payload_from_hash(hash)
39
+ return nil unless payload
39
40
  ChainEntry.parse_from_payload(payload)
40
41
  end
41
42
 
data/lib/bitcoin/util.rb CHANGED
@@ -31,6 +31,7 @@ module Bitcoin
31
31
  end
32
32
  end
33
33
 
34
+ # @return an integer for a valid payload, otherwise nil
34
35
  def unpack_var_int(payload)
35
36
  case payload.unpack('C').first
36
37
  when 0xfd
@@ -44,15 +45,16 @@ module Bitcoin
44
45
  end
45
46
  end
46
47
 
48
+ # @return an integer for a valid payload, otherwise nil
47
49
  def unpack_var_int_from_io(buf)
48
- uchar = buf.read(1).unpack('C').first
50
+ uchar = buf.read(1)&.unpack('C')&.first
49
51
  case uchar
50
52
  when 0xfd
51
- buf.read(2).unpack('v').first
53
+ buf.read(2)&.unpack('v')&.first
52
54
  when 0xfe
53
- buf.read(4).unpack('V').first
55
+ buf.read(4)&.unpack('V')&.first
54
56
  when 0xff
55
- buf.read(8).unpack('Q').first
57
+ buf.read(8)&.unpack('Q')&.first
56
58
  else
57
59
  uchar
58
60
  end
@@ -1,3 +1,3 @@
1
1
  module Bitcoin
2
- VERSION = "0.2.5"
2
+ VERSION = "0.2.6"
3
3
  end
@@ -140,8 +140,8 @@ module Bitcoin
140
140
 
141
141
  def validate_params!(account_key, purpose, index)
142
142
  raise 'account_key must be an instance of Bitcoin::ExtPubkey.' unless account_key.is_a?(Bitcoin::ExtPubkey)
143
- raise 'Account key and index does not match.' unless account_key.number == (index + 2**31)
144
- version_bytes = Bitcoin::ExtPubkey.version_from_purpose(purpose + 2**31)
143
+ raise 'Account key and index does not match.' unless account_key.number == (index + Bitcoin::HARDENED_THRESHOLD)
144
+ version_bytes = Bitcoin::ExtPubkey.version_from_purpose(purpose + Bitcoin::HARDENED_THRESHOLD)
145
145
  raise 'The purpose and the account key do not match.' unless account_key.version == version_bytes
146
146
  end
147
147
 
@@ -71,7 +71,7 @@ module Bitcoin
71
71
  next
72
72
  end
73
73
  raise ArgumentError.new("#{path} is invalid format.") unless p.delete("'") =~ /^[0-9]+$/
74
- num = (p[-1] == "'" ? p.delete("'").to_i + 2**31 : p.to_i)
74
+ num = (p[-1] == "'" ? p.delete("'").to_i + Bitcoin::HARDENED_THRESHOLD : p.to_i)
75
75
  derived_key = derived_key.derive(num)
76
76
  end
77
77
  derived_key
data/lib/bitcoin.rb CHANGED
@@ -186,6 +186,10 @@ module Bitcoin
186
186
  hex = to_s(16)
187
187
  hex.rjust((hex.length / 2.0).ceil * 2, '0')
188
188
  end
189
+
190
+ def itb
191
+ to_even_length_hex.htb
192
+ end
189
193
  end
190
194
 
191
195
  class ::ECDSA::Signature
@@ -24,14 +24,19 @@ module OpenAssets
24
24
  version = buf.read(2)
25
25
  return nil if marker != MARKER || version != VERSION
26
26
  count = Bitcoin.unpack_var_int_from_io(buf)
27
+ return nil unless count
27
28
  quantities = []
28
29
  count.times do
29
30
  quantities << LEB128.decode_unsigned(buf, buf.pos)
30
31
  end
31
32
  metadata_length = Bitcoin.unpack_var_int_from_io(buf)
32
- return nil if buf.length < metadata_length + buf.pos
33
+ return nil if metadata_length.nil? || buf.length < metadata_length + buf.pos
33
34
  metadata = buf.read(metadata_length).each_byte.map(&:chr).join
34
35
  new(quantities, metadata)
36
+ rescue
37
+ # LEB128#decode_unsigned raise 'undefined method `unpack' for nil:NilClass'
38
+ # for invalid format such as "018f8f" (the most significant bit of the last byte should be 0)
39
+ nil
35
40
  end
36
41
 
37
42
  # generate binary payload
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitcoinrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - azuchi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-14 00:00:00.000000000 Z
11
+ date: 2019-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ecdsa
@@ -182,16 +182,16 @@ dependencies:
182
182
  name: protobuf
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
- - - ">="
185
+ - - '='
186
186
  - !ruby/object:Gem::Version
187
- version: '0'
187
+ version: 3.8.5
188
188
  type: :runtime
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
- - - ">="
192
+ - - '='
193
193
  - !ruby/object:Gem::Version
194
- version: '0'
194
+ version: 3.8.5
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: scrypt
197
197
  requirement: !ruby/object:Gem::Requirement
@@ -224,16 +224,16 @@ dependencies:
224
224
  name: bundler
225
225
  requirement: !ruby/object:Gem::Requirement
226
226
  requirements:
227
- - - "~>"
227
+ - - ">="
228
228
  - !ruby/object:Gem::Version
229
- version: '1.11'
229
+ version: '0'
230
230
  type: :development
231
231
  prerelease: false
232
232
  version_requirements: !ruby/object:Gem::Requirement
233
233
  requirements:
234
- - - "~>"
234
+ - - ">="
235
235
  - !ruby/object:Gem::Version
236
- version: '1.11'
236
+ version: '0'
237
237
  - !ruby/object:Gem::Dependency
238
238
  name: rake
239
239
  requirement: !ruby/object:Gem::Requirement
@@ -439,7 +439,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
439
439
  - !ruby/object:Gem::Version
440
440
  version: '0'
441
441
  requirements: []
442
- rubygems_version: 3.0.1
442
+ rubygems_version: 3.0.3
443
443
  signing_key:
444
444
  specification_version: 4
445
445
  summary: "[WIP]The implementation of Bitcoin Protocol for Ruby."