bitcoinrb 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +5 -4
  4. data/README.md +10 -0
  5. data/bitcoinrb.gemspec +4 -4
  6. data/lib/bitcoin.rb +29 -16
  7. data/lib/bitcoin/block_filter.rb +14 -0
  8. data/lib/bitcoin/chain_params.rb +9 -0
  9. data/lib/bitcoin/chainparams/signet.yml +39 -0
  10. data/lib/bitcoin/constants.rb +43 -3
  11. data/lib/bitcoin/descriptor.rb +1 -1
  12. data/lib/bitcoin/errors.rb +19 -0
  13. data/lib/bitcoin/ext/ecdsa.rb +31 -0
  14. data/lib/bitcoin/ext_key.rb +35 -19
  15. data/lib/bitcoin/key.rb +43 -26
  16. data/lib/bitcoin/message/cfcheckpt.rb +2 -2
  17. data/lib/bitcoin/message/cfheaders.rb +1 -1
  18. data/lib/bitcoin/message/cfilter.rb +1 -1
  19. data/lib/bitcoin/message/fee_filter.rb +1 -1
  20. data/lib/bitcoin/message/filter_load.rb +3 -3
  21. data/lib/bitcoin/message/header_and_short_ids.rb +1 -1
  22. data/lib/bitcoin/message/inventory.rb +1 -1
  23. data/lib/bitcoin/message/merkle_block.rb +1 -1
  24. data/lib/bitcoin/message/network_addr.rb +3 -3
  25. data/lib/bitcoin/message/ping.rb +1 -1
  26. data/lib/bitcoin/message/pong.rb +1 -1
  27. data/lib/bitcoin/message/send_cmpct.rb +2 -2
  28. data/lib/bitcoin/mnemonic.rb +2 -2
  29. data/lib/bitcoin/network/peer_discovery.rb +1 -3
  30. data/lib/bitcoin/node/configuration.rb +3 -1
  31. data/lib/bitcoin/node/spv.rb +8 -0
  32. data/lib/bitcoin/opcodes.rb +14 -1
  33. data/lib/bitcoin/payment_code.rb +2 -2
  34. data/lib/bitcoin/psbt/hd_key_path.rb +1 -1
  35. data/lib/bitcoin/psbt/input.rb +3 -3
  36. data/lib/bitcoin/psbt/output.rb +1 -1
  37. data/lib/bitcoin/psbt/tx.rb +4 -4
  38. data/lib/bitcoin/rpc/bitcoin_core_client.rb +1 -1
  39. data/lib/bitcoin/script/script.rb +52 -19
  40. data/lib/bitcoin/script/script_error.rb +27 -1
  41. data/lib/bitcoin/script/script_interpreter.rb +161 -62
  42. data/lib/bitcoin/script/tx_checker.rb +64 -14
  43. data/lib/bitcoin/secp256k1/native.rb +138 -25
  44. data/lib/bitcoin/secp256k1/ruby.rb +78 -19
  45. data/lib/bitcoin/sighash_generator.rb +156 -0
  46. data/lib/bitcoin/tx.rb +13 -80
  47. data/lib/bitcoin/tx_in.rb +1 -1
  48. data/lib/bitcoin/tx_out.rb +2 -3
  49. data/lib/bitcoin/util.rb +15 -6
  50. data/lib/bitcoin/version.rb +1 -1
  51. data/lib/bitcoin/wallet/account.rb +1 -1
  52. metadata +19 -15
@@ -36,13 +36,13 @@ module Bitcoin
36
36
  def self.parse_from_payload(payload, non_witness: false)
37
37
  buf = payload.is_a?(String) ? StringIO.new(payload) : payload
38
38
  tx = new
39
- tx.version = buf.read(4).unpack('V').first
39
+ tx.version = buf.read(4).unpack1('V')
40
40
 
41
41
  in_count = Bitcoin.unpack_var_int_from_io(buf)
42
42
  witness = false
43
43
  if in_count.zero? && !non_witness
44
44
  tx.marker = 0
45
- tx.flag = buf.read(1).unpack('c').first
45
+ tx.flag = buf.read(1).unpack1('c')
46
46
  if tx.flag.zero?
47
47
  buf.pos -= 1
48
48
  else
@@ -66,7 +66,7 @@ module Bitcoin
66
66
  end
67
67
  end
68
68
 
69
- tx.lock_time = buf.read(4).unpack('V').first
69
+ tx.lock_time = buf.read(4).unpack1('V')
70
70
 
71
71
  tx
72
72
  end
@@ -188,22 +188,22 @@ module Bitcoin
188
188
  # @param [Integer] input_index input index.
189
189
  # @param [Integer] hash_type signature hash type
190
190
  # @param [Bitcoin::Script] output_script script pubkey or script code. if script pubkey is P2WSH, set witness script to this.
191
+ # @param [Hash] opts Data required for each sig version (amount and skip_separator_index params can also be set to this parameter)
191
192
  # @param [Integer] amount bitcoin amount locked in input. required for witness input only.
192
193
  # @param [Integer] skip_separator_index If output_script is P2WSH and output_script contains any OP_CODESEPARATOR,
193
194
  # the script code needs is the witnessScript but removing everything up to and including the last executed OP_CODESEPARATOR before the signature checking opcode being executed.
194
- def sighash_for_input(input_index, output_script, hash_type: SIGHASH_TYPE[:all],
195
+ def sighash_for_input(input_index, output_script = nil, opts: {}, hash_type: SIGHASH_TYPE[:all],
195
196
  sig_version: :base, amount: nil, skip_separator_index: 0)
196
197
  raise ArgumentError, 'input_index must be specified.' unless input_index
197
198
  raise ArgumentError, 'does not exist input corresponding to input_index.' if input_index >= inputs.size
198
- raise ArgumentError, 'script_pubkey must be specified.' unless output_script
199
- raise ArgumentError, 'unsupported sig version specified.' unless SIG_VERSION.include?(sig_version)
200
-
201
- if sig_version == :witness_v0
202
- raise ArgumentError, 'amount must be specified.' unless amount
203
- sighash_for_witness(input_index, output_script, hash_type, amount, skip_separator_index)
204
- else
205
- sighash_for_legacy(input_index, output_script, hash_type)
206
- end
199
+ raise ArgumentError, 'script_pubkey must be specified.' if [:base, :witness_v0].include?(sig_version) && output_script.nil?
200
+
201
+ opts[:amount] = amount if amount
202
+ opts[:skip_separator_index] = skip_separator_index
203
+ opts[:sig_version] = sig_version
204
+ opts[:script_code] = output_script
205
+ sig_hash_gen = SigHashGenerator.load(sig_version)
206
+ sig_hash_gen.generate(self, input_index, hash_type, opts)
207
207
  end
208
208
 
209
209
  # verify input signature.
@@ -245,73 +245,6 @@ module Bitcoin
245
245
 
246
246
  private
247
247
 
248
- # generate sighash with legacy format
249
- def sighash_for_legacy(index, script_code, hash_type)
250
- ins = inputs.map.with_index do |i, idx|
251
- if idx == index
252
- i.to_payload(script_code.delete_opcode(Bitcoin::Opcodes::OP_CODESEPARATOR))
253
- else
254
- case hash_type & 0x1f
255
- when SIGHASH_TYPE[:none], SIGHASH_TYPE[:single]
256
- i.to_payload(Bitcoin::Script.new, 0)
257
- else
258
- i.to_payload(Bitcoin::Script.new)
259
- end
260
- end
261
- end
262
-
263
- outs = outputs.map(&:to_payload)
264
- out_size = Bitcoin.pack_var_int(outputs.size)
265
-
266
- case hash_type & 0x1f
267
- when SIGHASH_TYPE[:none]
268
- outs = ''
269
- out_size = Bitcoin.pack_var_int(0)
270
- when SIGHASH_TYPE[:single]
271
- return "\x01".ljust(32, "\x00") if index >= outputs.size
272
- outs = outputs[0...(index + 1)].map.with_index { |o, idx| (idx == index) ? o.to_payload : o.to_empty_payload }.join
273
- out_size = Bitcoin.pack_var_int(index + 1)
274
- end
275
-
276
- if hash_type & SIGHASH_TYPE[:anyonecanpay] != 0
277
- ins = [ins[index]]
278
- end
279
-
280
- buf = [[version].pack('V'), Bitcoin.pack_var_int(ins.size),
281
- ins, out_size, outs, [lock_time, hash_type].pack('VV')].join
282
-
283
- Bitcoin.double_sha256(buf)
284
- end
285
-
286
- # generate sighash with BIP-143 format
287
- # https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki
288
- def sighash_for_witness(index, script_pubkey_or_script_code, hash_type, amount, skip_separator_index)
289
- hash_prevouts = Bitcoin.double_sha256(inputs.map{|i|i.out_point.to_payload}.join)
290
- hash_sequence = Bitcoin.double_sha256(inputs.map{|i|[i.sequence].pack('V')}.join)
291
- outpoint = inputs[index].out_point.to_payload
292
- amount = [amount].pack('Q')
293
- nsequence = [inputs[index].sequence].pack('V')
294
- hash_outputs = Bitcoin.double_sha256(outputs.map{|o|o.to_payload}.join)
295
-
296
- script_code = script_pubkey_or_script_code.to_script_code(skip_separator_index)
297
-
298
- case (hash_type & 0x1f)
299
- when SIGHASH_TYPE[:single]
300
- hash_outputs = index >= outputs.size ? "\x00".ljust(32, "\x00") : Bitcoin.double_sha256(outputs[index].to_payload)
301
- hash_sequence = "\x00".ljust(32, "\x00")
302
- when SIGHASH_TYPE[:none]
303
- hash_sequence = hash_outputs = "\x00".ljust(32, "\x00")
304
- end
305
-
306
- if (hash_type & SIGHASH_TYPE[:anyonecanpay]) != 0
307
- hash_prevouts = hash_sequence ="\x00".ljust(32, "\x00")
308
- end
309
-
310
- buf = [ [version].pack('V'), hash_prevouts, hash_sequence, outpoint,
311
- script_code ,amount, nsequence, hash_outputs, [@lock_time, hash_type].pack('VV')].join
312
- Bitcoin.double_sha256(buf)
313
- end
314
-
315
248
  # verify input signature for legacy tx.
316
249
  def verify_input_sig_for_legacy(input_index, script_pubkey, flags)
317
250
  script_sig = inputs[input_index].script_sig
@@ -42,7 +42,7 @@ module Bitcoin
42
42
  else
43
43
  i.script_sig = Script.parse_from_payload(buf.read(sig_length))
44
44
  end
45
- i.sequence = buf.read(4).unpack('V').first
45
+ i.sequence = buf.read(4).unpack1('V')
46
46
  i
47
47
  end
48
48
 
@@ -18,14 +18,13 @@ module Bitcoin
18
18
 
19
19
  def self.parse_from_payload(payload)
20
20
  buf = payload.is_a?(String) ? StringIO.new(payload) : payload
21
- value = buf.read(8).unpack('q').first
21
+ value = buf.read(8).unpack1('q')
22
22
  script_size = Bitcoin.unpack_var_int_from_io(buf)
23
23
  new(value: value, script_pubkey: Script.parse_from_payload(buf.read(script_size)))
24
24
  end
25
25
 
26
26
  def to_payload
27
- s = script_pubkey.to_payload
28
- [value].pack('Q') << Bitcoin.pack_var_int(s.length) << s
27
+ [value].pack('Q') << script_pubkey.to_payload(true)
29
28
  end
30
29
 
31
30
  def to_empty_payload
@@ -33,7 +33,7 @@ module Bitcoin
33
33
 
34
34
  # @return an integer for a valid payload, otherwise nil
35
35
  def unpack_var_int(payload)
36
- case payload.unpack('C').first
36
+ case payload.unpack1('C')
37
37
  when 0xfd
38
38
  payload.unpack('xva*')
39
39
  when 0xfe
@@ -47,14 +47,14 @@ module Bitcoin
47
47
 
48
48
  # @return an integer for a valid payload, otherwise nil
49
49
  def unpack_var_int_from_io(buf)
50
- uchar = buf.read(1)&.unpack('C')&.first
50
+ uchar = buf.read(1)&.unpack1('C')
51
51
  case uchar
52
52
  when 0xfd
53
- buf.read(2)&.unpack('v')&.first
53
+ buf.read(2)&.unpack1('v')
54
54
  when 0xfe
55
- buf.read(4)&.unpack('V')&.first
55
+ buf.read(4)&.unpack1('V')
56
56
  when 0xff
57
- buf.read(8)&.unpack('Q')&.first
57
+ buf.read(8)&.unpack1('Q')
58
58
  else
59
59
  uchar
60
60
  end
@@ -79,7 +79,7 @@ module Bitcoin
79
79
 
80
80
  # byte convert to the sequence of bits packed eight in a byte with the least significant bit first.
81
81
  def byte_to_bit(byte)
82
- byte.unpack('b*').first
82
+ byte.unpack1('b*')
83
83
  end
84
84
 
85
85
  # padding zero to the left of binary string until bytesize.
@@ -96,6 +96,15 @@ module Bitcoin
96
96
  Digest::RMD160.hexdigest(Digest::SHA256.digest(hex.htb))
97
97
  end
98
98
 
99
+ # Generate tagged hash value.
100
+ # @param [String] tag tag value.
101
+ # @param [String] msg the message to be hashed.
102
+ # @return [String] the hash value with binary format.
103
+ def tagged_hash(tag, msg)
104
+ tag_hash = Digest::SHA256.digest(tag)
105
+ Digest::SHA256.digest(tag_hash + tag_hash + msg)
106
+ end
107
+
99
108
  # encode Base58 check address.
100
109
  # @param [String] hex the address payload.
101
110
  # @param [String] addr_version the address version for P2PKH and P2SH.
@@ -1,3 +1,3 @@
1
1
  module Bitcoin
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.0"
3
3
  end
@@ -43,7 +43,7 @@ module Bitcoin
43
43
 
44
44
  def to_payload
45
45
  payload = account_key.to_payload
46
- payload << Bitcoin.pack_var_string(name.unpack('H*').first.htb)
46
+ payload << Bitcoin.pack_var_string(name.unpack1('H*').htb)
47
47
  payload << [purpose, index, receive_depth, change_depth, lookahead].pack('I*')
48
48
  payload
49
49
  end
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.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - azuchi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-08-19 00:00:00.000000000 Z
11
+ date: 2021-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ecdsa
@@ -179,33 +179,33 @@ dependencies:
179
179
  - !ruby/object:Gem::Version
180
180
  version: 3.8.5
181
181
  - !ruby/object:Gem::Dependency
182
- name: scrypt
182
+ name: json_pure
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
185
  - - ">="
186
186
  - !ruby/object:Gem::Version
187
- version: '0'
187
+ version: 2.3.1
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: 2.3.1
195
195
  - !ruby/object:Gem::Dependency
196
- name: json_pure
196
+ name: bip-schnorr
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
199
  - - ">="
200
200
  - !ruby/object:Gem::Version
201
- version: 2.3.1
201
+ version: 0.3.2
202
202
  type: :runtime
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
206
  - - ">="
207
207
  - !ruby/object:Gem::Version
208
- version: 2.3.1
208
+ version: 0.3.2
209
209
  - !ruby/object:Gem::Dependency
210
210
  name: leveldb-native
211
211
  requirement: !ruby/object:Gem::Requirement
@@ -280,17 +280,17 @@ dependencies:
280
280
  name: webmock
281
281
  requirement: !ruby/object:Gem::Requirement
282
282
  requirements:
283
- - - "~>"
283
+ - - ">="
284
284
  - !ruby/object:Gem::Version
285
- version: '3.0'
285
+ version: 3.11.1
286
286
  type: :development
287
287
  prerelease: false
288
288
  version_requirements: !ruby/object:Gem::Requirement
289
289
  requirements:
290
- - - "~>"
290
+ - - ">="
291
291
  - !ruby/object:Gem::Version
292
- version: '3.0'
293
- description: "[WIP]The implementation of Bitcoin Protocol for Ruby."
292
+ version: 3.11.1
293
+ description: The implementation of Bitcoin Protocol for Ruby.
294
294
  email:
295
295
  - azuchi@chaintope.com
296
296
  executables:
@@ -326,10 +326,13 @@ files:
326
326
  - lib/bitcoin/chain_params.rb
327
327
  - lib/bitcoin/chainparams/mainnet.yml
328
328
  - lib/bitcoin/chainparams/regtest.yml
329
+ - lib/bitcoin/chainparams/signet.yml
329
330
  - lib/bitcoin/chainparams/testnet.yml
330
331
  - lib/bitcoin/constants.rb
331
332
  - lib/bitcoin/descriptor.rb
333
+ - lib/bitcoin/errors.rb
332
334
  - lib/bitcoin/ext.rb
335
+ - lib/bitcoin/ext/ecdsa.rb
333
336
  - lib/bitcoin/ext/json_parser.rb
334
337
  - lib/bitcoin/ext_key.rb
335
338
  - lib/bitcoin/gcs_filter.rb
@@ -429,6 +432,7 @@ files:
429
432
  - lib/bitcoin/secp256k1/native.rb
430
433
  - lib/bitcoin/secp256k1/rfc6979.rb
431
434
  - lib/bitcoin/secp256k1/ruby.rb
435
+ - lib/bitcoin/sighash_generator.rb
432
436
  - lib/bitcoin/slip39.rb
433
437
  - lib/bitcoin/slip39/share.rb
434
438
  - lib/bitcoin/slip39/sss.rb
@@ -474,8 +478,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
474
478
  - !ruby/object:Gem::Version
475
479
  version: '0'
476
480
  requirements: []
477
- rubygems_version: 3.0.3
481
+ rubygems_version: 3.2.3
478
482
  signing_key:
479
483
  specification_version: 4
480
- summary: "[WIP]The implementation of Bitcoin Protocol for Ruby."
484
+ summary: The implementation of Bitcoin Protocol for Ruby.
481
485
  test_files: []