bitcoinrb 1.12.0 → 1.13.0

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -1
  3. data/bitcoinrb.gemspec +1 -6
  4. data/lib/bitcoin/bip321_uri.rb +3 -6
  5. data/lib/bitcoin/bip324/fs_chacha20.rb +4 -6
  6. data/lib/bitcoin/bip324/fs_chacha_poly1305.rb +20 -17
  7. data/lib/bitcoin/bip324.rb +3 -1
  8. data/lib/bitcoin/descriptor/checksum.rb +6 -2
  9. data/lib/bitcoin/descriptor/expression.rb +2 -2
  10. data/lib/bitcoin/descriptor/sp.rb +219 -0
  11. data/lib/bitcoin/descriptor.rb +20 -0
  12. data/lib/bitcoin/ext_key.rb +11 -7
  13. data/lib/bitcoin/key.rb +1 -1
  14. data/lib/bitcoin/message/cf_parser.rb +2 -2
  15. data/lib/bitcoin/message/fee_filter.rb +2 -2
  16. data/lib/bitcoin/message/header_and_short_ids.rb +4 -4
  17. data/lib/bitcoin/message/inventory.rb +1 -1
  18. data/lib/bitcoin/message/network_addr.rb +7 -3
  19. data/lib/bitcoin/message/ping.rb +5 -3
  20. data/lib/bitcoin/message/pong.rb +2 -2
  21. data/lib/bitcoin/message/send_cmpct.rb +2 -2
  22. data/lib/bitcoin/message/version.rb +4 -4
  23. data/lib/bitcoin/message.rb +12 -2
  24. data/lib/bitcoin/message_sign.rb +98 -38
  25. data/lib/bitcoin/mnemonic.rb +9 -4
  26. data/lib/bitcoin/psbt/input.rb +51 -33
  27. data/lib/bitcoin/psbt/key_origin_info.rb +2 -2
  28. data/lib/bitcoin/psbt/output.rb +9 -5
  29. data/lib/bitcoin/psbt/tx.rb +16 -10
  30. data/lib/bitcoin/psbt.rb +1 -1
  31. data/lib/bitcoin/rpc.rb +0 -2
  32. data/lib/bitcoin/script/script.rb +14 -4
  33. data/lib/bitcoin/secp256k1/rfc6979.rb +6 -3
  34. data/lib/bitcoin/sighash_generator.rb +2 -2
  35. data/lib/bitcoin/silent_payment/output.rb +46 -0
  36. data/lib/bitcoin/silent_payment.rb +113 -12
  37. data/lib/bitcoin/taproot/control_block.rb +1 -0
  38. data/lib/bitcoin/tx.rb +8 -6
  39. data/lib/bitcoin/tx_out.rb +2 -2
  40. data/lib/bitcoin/util.rb +5 -5
  41. data/lib/bitcoin/version.rb +1 -1
  42. data/lib/bitcoin/wallet/account.rb +2 -2
  43. data/lib/bitcoin/wallet/db.rb +3 -3
  44. data/lib/bitcoin/wallet/master_key.rb +2 -2
  45. data/lib/bitcoin/wallet/utxo.rb +2 -2
  46. data/lib/bitcoin.rb +1 -6
  47. metadata +18 -108
  48. data/exe/bitcoinrb-cli +0 -5
  49. data/exe/bitcoinrbd +0 -46
  50. data/lib/bitcoin/network/connection.rb +0 -73
  51. data/lib/bitcoin/network/message_handler.rb +0 -243
  52. data/lib/bitcoin/network/peer.rb +0 -228
  53. data/lib/bitcoin/network/peer_discovery.rb +0 -42
  54. data/lib/bitcoin/network/pool.rb +0 -135
  55. data/lib/bitcoin/network.rb +0 -13
  56. data/lib/bitcoin/node/cli.rb +0 -122
  57. data/lib/bitcoin/node/configuration.rb +0 -40
  58. data/lib/bitcoin/node/spv.rb +0 -87
  59. data/lib/bitcoin/node.rb +0 -7
  60. data/lib/bitcoin/rpc/http_server.rb +0 -84
  61. data/lib/bitcoin/rpc/request_handler.rb +0 -150
  62. data/lib/bitcoin/store/chain_entry.rb +0 -68
  63. data/lib/bitcoin/store/db/level_db.rb +0 -98
  64. data/lib/bitcoin/store/db.rb +0 -9
  65. data/lib/bitcoin/store/spv_chain.rb +0 -101
  66. data/lib/bitcoin/store/utxo_db.rb +0 -226
  67. data/lib/bitcoin/store.rb +0 -12
data/lib/bitcoin/psbt.rb CHANGED
@@ -55,7 +55,7 @@ module Bitcoin
55
55
  module_function
56
56
 
57
57
  def self.serialize_to_vector(key_type, key: nil, value: nil)
58
- key_len = key_type.itb.bytesize
58
+ key_len = Bitcoin.pack_var_int(key_type).bytesize
59
59
  key_len += key.bytesize if key
60
60
  s = Bitcoin.pack_var_int(key_len) << Bitcoin.pack_var_int(key_type)
61
61
  s << key if key
data/lib/bitcoin/rpc.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  module Bitcoin
2
2
  module RPC
3
- autoload :HttpServer, 'bitcoin/rpc/http_server'
4
- autoload :RequestHandler, 'bitcoin/rpc/request_handler'
5
3
  autoload :BitcoinCoreClient, 'bitcoin/rpc/bitcoin_core_client'
6
4
  end
7
5
  end
@@ -100,12 +100,22 @@ module Bitcoin
100
100
  if opcode
101
101
  script << (v =~ /^\d/ && Opcodes.small_int_to_opcode(v.ord) ? v.ord : opcode)
102
102
  else
103
- script << (v =~ /^[0-9]+$/ ? v.to_i : v)
103
+ script << (number_token?(v) ? v.to_i : v)
104
104
  end
105
105
  end
106
106
  script
107
107
  end
108
108
 
109
+ # Whether +token+ is a script number rather than pushed data with hex format.
110
+ # A digit only token is ambiguous since #to_s emits pushed data as hex. #to_s never emits
111
+ # a number with more than 10 digits, so a longer even-length token must be pushed data.
112
+ # @param [String] token a token of the script string.
113
+ # @return [Boolean] whether +token+ should be interpreted as a script number.
114
+ def self.number_token?(token)
115
+ return false unless token =~ /^[0-9]+$/
116
+ token.length < 12 || token.length.odd?
117
+ end
118
+
109
119
  # generate script from addr.
110
120
  # @param [String] addr address.
111
121
  # @return [Bitcoin::Script] parsed script.
@@ -491,11 +501,11 @@ module Bitcoin
491
501
  size = data.bytesize
492
502
  header = if size < OP_PUSHDATA1
493
503
  [size].pack('C')
494
- elsif size < 0xff
504
+ elsif size <= 0xff
495
505
  [OP_PUSHDATA1, size].pack('CC')
496
- elsif size < 0xffff
506
+ elsif size <= 0xffff
497
507
  [OP_PUSHDATA2, size].pack('Cv')
498
- elsif size < 0xffffffff
508
+ elsif size <= 0xffffffff
499
509
  [OP_PUSHDATA4, size].pack('CV')
500
510
  else
501
511
  raise ArgumentError, 'data size is too big.'
@@ -26,10 +26,13 @@ module Bitcoin
26
26
  # 3.2.g
27
27
  v = Bitcoin.hmac_sha256(k, v)
28
28
  # 3.2.h
29
- t = ''
30
29
  10000.times do
31
- v = Bitcoin.hmac_sha256(k, v)
32
- t = (t + v)
30
+ # T is reset for each candidate, otherwise a retry can never produce a value below the order.
31
+ t = ''
32
+ while t.bytesize < 32
33
+ v = Bitcoin.hmac_sha256(k, v)
34
+ t = (t + v)
35
+ end
33
36
  t_num = t.bth.to_i(16)
34
37
  return t_num if 1 <= t_num && t_num < Bitcoin::Secp256k1::GROUP.order
35
38
  k = Bitcoin.hmac_sha256(k, v + '00'.htb)
@@ -68,7 +68,7 @@ module Bitcoin
68
68
  hash_prevouts = Bitcoin.double_sha256(tx.inputs.map{|i|i.out_point.to_payload}.join)
69
69
  hash_sequence = Bitcoin.double_sha256(tx.inputs.map{|i|[i.sequence].pack('V')}.join)
70
70
  outpoint = tx.inputs[input_index].out_point.to_payload
71
- amount = [amount].pack('Q')
71
+ amount = [amount].pack('Q<')
72
72
  nsequence = [tx.inputs[input_index].sequence].pack('V')
73
73
  hash_outputs = Bitcoin.double_sha256(tx.outputs.map{|o|o.to_payload}.join)
74
74
  if output_script.p2wsh?
@@ -120,7 +120,7 @@ module Bitcoin
120
120
  buf << [hash_type, tx.version, tx.lock_time].pack('CVV')
121
121
  unless input_type == SIGHASH_TYPE[:anyonecanpay]
122
122
  buf << Bitcoin.sha256(tx.in.map{|i|i.out_point.to_payload}.join) # sha_prevouts
123
- buf << Bitcoin.sha256(opts[:prevouts].map(&:value).pack('Q*'))# sha_amounts
123
+ buf << Bitcoin.sha256(opts[:prevouts].map(&:value).pack('Q<*'))# sha_amounts
124
124
  buf << Bitcoin.sha256(opts[:prevouts].map{|o|o.script_pubkey.to_payload(true)}.join) # sha_scriptpubkeys
125
125
  buf << Bitcoin.sha256(tx.in.map(&:sequence).pack('V*')) # sha_sequences
126
126
  end
@@ -0,0 +1,46 @@
1
+ module Bitcoin
2
+ module SilentPayment
3
+ # Represents a detected silent payment output.
4
+ class Output
5
+ # @return [Bitcoin::TxOut] The detected transaction output.
6
+ attr_reader :tx_out
7
+
8
+ # @return [String] The tweak value (t_k) used to derive the output key (32 bytes binary).
9
+ attr_reader :tweak
10
+
11
+ # @return [Integer, nil] The label used for this output, or nil if no label was used.
12
+ attr_reader :label
13
+
14
+ # @param [Bitcoin::TxOut] tx_out The detected transaction output.
15
+ # @param [String] tweak The tweak value (t_k) as 32 bytes binary.
16
+ # @param [Integer, nil] label The label integer, or nil if no label was used.
17
+ # @raise [ArgumentError] If any parameter has an invalid type.
18
+ def initialize(tx_out, tweak, label = nil)
19
+ raise ArgumentError, "tx_out must be a Bitcoin::TxOut." unless tx_out.is_a?(Bitcoin::TxOut)
20
+ raise ArgumentError, "tweak must be a 32-byte String." unless tweak.is_a?(String) && tweak.bytesize == 32
21
+ raise ArgumentError, "label must be an Integer or nil." unless label.nil? || label.is_a?(Integer)
22
+ @tx_out = tx_out
23
+ @tweak = tweak
24
+ @label = label
25
+ end
26
+
27
+ # Returns the x-only public key of the output.
28
+ # @return [String] The x-only public key as hex string.
29
+ def pubkey
30
+ tx_out.script_pubkey.witness_data[1].bth
31
+ end
32
+
33
+ # Returns the tweak as hex string.
34
+ # @return [String] The tweak value as hex string.
35
+ def tweak_hex
36
+ tweak.bth
37
+ end
38
+
39
+ # Returns whether this output was detected using a label.
40
+ # @return [Boolean]
41
+ def labeled?
42
+ !label.nil?
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,12 +1,22 @@
1
+ require 'set'
2
+
1
3
  module Bitcoin
4
+ # BIP-352 silent payment module.
5
+ # @see https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki
2
6
  module SilentPayment
7
+ autoload :Output, 'bitcoin/silent_payment/output'
3
8
 
4
-
5
- # Derive payment
6
- # @param [Array] prevouts An array of previous output script(Bitcoin::Script).
7
- # @param [Array] private_keys An array of private key corresponding to each public key in prevouts.
8
- # @param [Array] recipients
9
- # @return [Array]
9
+ # Maximum number of silent payment addresses that can share the same scan public key
10
+ # within a single transaction. This is the maximum number of P2TR outputs that can fit
11
+ # within a 100KB transaction under current standardness rules.
12
+ K_MAX = 2323
13
+
14
+ # Derive payment point.
15
+ #
16
+ # @param [Array<Bitcoin::Script>] prevouts An array of previous output script.
17
+ # @param [Array<Bitcoin::Key>] private_keys An array of Bitcoin::Key objects corresponding to each public key in prevouts.
18
+ # @param [Array<Bech32::SilentPaymentAddr>] recipients
19
+ # @return [Array<ECDSA::Point>] An array of derived points.
10
20
  # @raise [ArgumentError]
11
21
  def derive_payment_points(prevouts, private_keys, recipients)
12
22
  raise ArgumentError, "prevouts must be Array." unless prevouts.is_a? Array
@@ -14,19 +24,19 @@ module Bitcoin
14
24
  raise ArgumentError, "prevouts and private_keys must be the same length." unless prevouts.length == private_keys.length
15
25
  raise ArgumentError, "recipients must be Array." unless recipients.is_a? Array
16
26
 
17
- outpoint_l = inputs.map{|i|i.out_point.to_hex}.sort.first
18
-
19
27
  input_pub_keys = []
20
28
  field = ECDSA::PrimeField.new(Bitcoin::Secp256k1::GROUP.order)
21
29
  sum_priv_keys = 0
22
30
  prevouts.each_with_index do |prevout, index|
23
- k = Bitcoin::Key.new(priv_key: private_keys[index].to_s(16))
31
+ key = private_keys[index]
32
+ raise ArgumentError, "private_keys element must be Bitcoin::Key." unless key.is_a? Bitcoin::Key
33
+ priv_key_int = key.priv_key.to_i(16)
24
34
  public_key = extract_public_key(prevout, inputs[index])
25
35
  next if public_key.nil?
26
- private_key = if public_key.p2tr? && k.to_point.y.odd?
27
- field.mod(-private_keys[index])
36
+ private_key = if public_key.p2tr? && key.to_point.y.odd?
37
+ field.mod(-priv_key_int)
28
38
  else
29
- private_keys[index]
39
+ priv_key_int
30
40
  end
31
41
  input_pub_keys << public_key
32
42
  sum_priv_keys = field.mod(sum_priv_keys + private_key)
@@ -34,6 +44,8 @@ module Bitcoin
34
44
  agg_pubkey = (Bitcoin::Secp256k1::GROUP.generator.to_jacobian * sum_priv_keys).to_affine
35
45
  return [] if agg_pubkey.infinity?
36
46
 
47
+ outpoint_l = inputs.map{|i|i.out_point.to_hex}.sort.first
48
+
37
49
  input_hash = Bitcoin.tagged_hash("BIP0352/Inputs", outpoint_l.htb + agg_pubkey.to_hex.htb).bth
38
50
 
39
51
  destinations = {}
@@ -42,6 +54,12 @@ module Bitcoin
42
54
  destinations[sp_addr.scan_key] = [] unless destinations.has_key?(sp_addr.scan_key)
43
55
  destinations[sp_addr.scan_key] << sp_addr.spend_key
44
56
  end
57
+
58
+ # Check K_max limit: fail if any group exceeds the limit
59
+ destinations.each_value do |spends|
60
+ raise ArgumentError, "Recipient group exceeds K_max limit (#{K_MAX})." if spends.length > K_MAX
61
+ end
62
+
45
63
  outputs = []
46
64
  destinations.each do |scan_key, spends|
47
65
  scan_key = Bitcoin::Key.new(pubkey: scan_key).to_point.to_jacobian
@@ -55,6 +73,89 @@ module Bitcoin
55
73
  outputs
56
74
  end
57
75
 
76
+
77
+ # Scan transaction outputs for silent payment outputs belonging to the receiver.
78
+ #
79
+ # @param [Array<Bitcoin::Script>] prevouts An array of previous output scripts corresponding to each input.
80
+ # @param [Bitcoin::Key] scan_private_key The receiver's scan private key (b_scan).
81
+ # @param [Bitcoin::Key] spend_pubkey The receiver's spend key. Pass a Key initialized with spend_priv_key to derive the public key.
82
+ # @param [Array<Integer>] labels An array of label integers for labeled addresses (default: []).
83
+ # @return [Array<Bitcoin::SilentPayment::Output>] An array of detected silent payment outputs.
84
+ # @raise [ArgumentError] If any of the required parameters are invalid.
85
+ def scan_sp_outputs(prevouts, scan_private_key, spend_pubkey, labels = [])
86
+ raise ArgumentError, "prevouts must be Array." unless prevouts.is_a? Array
87
+ raise ArgumentError, "scan_private_key must be Bitcoin::Key." unless scan_private_key.is_a? Bitcoin::Key
88
+ raise ArgumentError, "spend_pubkey must be Bitcoin::Key." unless spend_pubkey.is_a? Bitcoin::Key
89
+
90
+ has_taproot = !outputs.find{|o| o.script_pubkey.p2tr? }.nil?
91
+ return [] unless has_taproot
92
+ sum_pub_keys = Bitcoin::Secp256k1::GROUP.infinity.to_jacobian
93
+ maximum_witness_version = Bitcoin::Opcodes.opcode_to_small_int(Bitcoin::Opcodes::OP_1)
94
+ prevouts.each.with_index do |prevout, index|
95
+ return [] if prevout.witness_program? && prevout.witness_data.first > maximum_witness_version
96
+
97
+ public_key = extract_public_key(prevout, inputs[index])
98
+ next if public_key.nil?
99
+ sum_pub_keys += public_key.to_point.to_jacobian
100
+ end
101
+ return [] if sum_pub_keys.infinity?
102
+
103
+ field = ECDSA::PrimeField.new(Bitcoin::Secp256k1::GROUP.order)
104
+ outpoint_l = inputs.map{|i|i.out_point.to_hex}.sort.first
105
+ input_hash = Bitcoin.tagged_hash("BIP0352/Inputs", outpoint_l.htb + sum_pub_keys.to_affine.to_hex.htb).bth
106
+ ecdh_shared_secret = (sum_pub_keys * field.mod(input_hash.to_i(16) * scan_private_key.priv_key.to_i(16))).to_affine.to_hex.htb
107
+
108
+ # Pre-compute label tweak points with their label values and scalar tweaks
109
+ label_tweaks = labels.map do |m|
110
+ label_tweak = Bitcoin.tagged_hash('BIP0352/Label', scan_private_key.priv_key.htb + [m].pack('N'))
111
+ label_point = Bitcoin::Secp256k1::GROUP.generator.to_jacobian * label_tweak.bti
112
+ [m, label_tweak, label_point]
113
+ end
114
+
115
+ k = 0
116
+ results = []
117
+ found_outputs = Set.new
118
+ loop do
119
+ # Stop scanning if K_max limit is reached
120
+ break if k == K_MAX
121
+
122
+ t_k = Bitcoin.tagged_hash('BIP0352/SharedSecret', ecdh_shared_secret + [k].pack('N'))
123
+ p_k = Bitcoin::Secp256k1::GROUP.generator.to_jacobian * t_k.bti + spend_pubkey.to_point.to_jacobian
124
+ found = false
125
+ outputs.each do |output|
126
+ next unless output.script_pubkey.p2tr?
127
+ next if found_outputs.include?(output)
128
+ output_pubkey = Bitcoin::Key.from_xonly_pubkey(output.script_pubkey.witness_data[1].bth)
129
+
130
+ # Check basic match (no label)
131
+ if p_k.to_affine.x == output_pubkey.to_point.x
132
+ results << SilentPayment::Output.new(output, t_k)
133
+ found_outputs << output
134
+ k += 1
135
+ found = true
136
+ break
137
+ end
138
+
139
+ # Check labeled matches
140
+ label_tweaks.each do |label_value, label_tweak_scalar, label_point|
141
+ p_k_labeled = p_k + label_point
142
+ if p_k_labeled.to_affine.x == output_pubkey.to_point.x
143
+ # Full tweak is t_k + label_tweak (mod order)
144
+ full_tweak = field.mod(t_k.bti + label_tweak_scalar.bti).to_s(16).rjust(64, '0').htb
145
+ results << SilentPayment::Output.new(output, full_tweak, label_value)
146
+ found_outputs << output
147
+ k += 1
148
+ found = true
149
+ break
150
+ end
151
+ end
152
+ break if found
153
+ end
154
+ break unless found
155
+ end
156
+ results
157
+ end
158
+
58
159
  # Extract public keys from +prevout+ and input.
59
160
  def extract_public_key(prevout, input)
60
161
  if prevout.p2pkh?
@@ -24,6 +24,7 @@ module Bitcoin
24
24
  # @return [Bitcoin::Taproot::ControlBlock]
25
25
  def self.parse_from_payload(payload)
26
26
  raise Bitcoin::Taproot::Error, 'Invalid data length for Control Block' if payload.bytesize > TAPROOT_CONTROL_MAX_SIZE
27
+ raise Bitcoin::Taproot::Error, 'Invalid data length for Control Block' if payload.bytesize < TAPROOT_CONTROL_BASE_SIZE
27
28
  raise Bitcoin::Taproot::Error, 'Invalid data length for path in Control Block' unless (payload.bytesize - TAPROOT_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE == 0
28
29
  control, internal_key, paths = payload.unpack('Ca32a*')
29
30
  parity = control & 1
data/lib/bitcoin/tx.rb CHANGED
@@ -89,6 +89,10 @@ module Bitcoin
89
89
  to_hex.to_i(16)
90
90
  end
91
91
 
92
+ def eql?(other)
93
+ other.is_a?(Tx) && self == other
94
+ end
95
+
92
96
  def tx_hash
93
97
  Bitcoin.double_sha256(serialize_old_format).bth
94
98
  end
@@ -228,7 +232,7 @@ module Bitcoin
228
232
  # @param [Integer] input_index
229
233
  # @param [Bitcoin::Script] script_pubkey the script pubkey for target input.
230
234
  # @param [Integer] amount the amount of bitcoin, require for witness program only.
231
- # @param [Array] flags the flags used when execute script interpreter.
235
+ # @param [Integer] flags the flags used when execute script interpreter.
232
236
  # @param [Array[Bitcoin::TxOut]] prevouts Previous outputs referenced by all Tx inputs, required for taproot.
233
237
  # @return [Boolean] result
234
238
  def verify_input_sig(input_index, script_pubkey, amount: nil, flags: STANDARD_SCRIPT_VERIFY_FLAGS, prevouts: [])
@@ -236,11 +240,9 @@ module Bitcoin
236
240
  has_witness = inputs[input_index].has_witness?
237
241
  has_witness = true if script_pubkey.witness_program?
238
242
 
239
- if script_pubkey.p2sh?
240
- flags << SCRIPT_VERIFY_P2SH
241
- redeem_script = Script.parse_from_payload(script_sig.chunks.last)
242
- script_pubkey = redeem_script if redeem_script.p2wpkh?
243
- end
243
+ # The script interpreter resolves the redeem script of P2SH, including a nested witness
244
+ # program, from the scriptSig, so the scriptPubkey is passed through as it is.
245
+ flags |= SCRIPT_VERIFY_P2SH if script_pubkey.p2sh?
244
246
 
245
247
  if has_witness
246
248
  verify_input_sig_for_witness(input_index, script_pubkey, amount, flags, prevouts)
@@ -16,13 +16,13 @@ module Bitcoin
16
16
 
17
17
  def self.parse_from_payload(payload)
18
18
  buf = payload.is_a?(String) ? StringIO.new(payload) : payload
19
- value = buf.read(8).unpack1('q')
19
+ value = buf.read(8).unpack1('Q<')
20
20
  script_size = Bitcoin.unpack_var_int_from_io(buf)
21
21
  new(value: value, script_pubkey: Script.parse_from_payload(buf.read(script_size)))
22
22
  end
23
23
 
24
24
  def to_payload
25
- [value].pack('Q') << script_pubkey.to_payload(true)
25
+ [value].pack('Q<') << script_pubkey.to_payload(true)
26
26
  end
27
27
 
28
28
  def to_empty_payload
data/lib/bitcoin/util.rb CHANGED
@@ -14,7 +14,7 @@ module Bitcoin
14
14
 
15
15
  def unpack_var_string(payload)
16
16
  size, payload = unpack_var_int(payload)
17
- size > 0 ? payload.unpack("a#{size}a*") : [nil, payload]
17
+ size && size > 0 ? payload.unpack("a#{size}a*") : ['', payload.to_s]
18
18
  end
19
19
 
20
20
  def pack_var_int(i)
@@ -25,7 +25,7 @@ module Bitcoin
25
25
  elsif i <= 0xffffffff
26
26
  [0xfe, i].pack('CV')
27
27
  elsif i <= 0xffffffffffffffff
28
- [0xff, i].pack('CQ')
28
+ [0xff, i].pack('CQ<')
29
29
  else
30
30
  raise "int(#{i}) too large!"
31
31
  end
@@ -39,7 +39,7 @@ module Bitcoin
39
39
  when 0xfe
40
40
  payload.unpack('xVa*')
41
41
  when 0xff
42
- payload.unpack('xQa*')
42
+ payload.unpack('xQ<a*')
43
43
  else
44
44
  payload.unpack('Ca*')
45
45
  end
@@ -54,7 +54,7 @@ module Bitcoin
54
54
  when 0xfe
55
55
  buf.read(4)&.unpack1('V')
56
56
  when 0xff
57
- buf.read(8)&.unpack1('Q')
57
+ buf.read(8)&.unpack1('Q<')
58
58
  else
59
59
  uchar
60
60
  end
@@ -102,7 +102,7 @@ module Bitcoin
102
102
  # @return [String] the hash value with binary format.
103
103
  def tagged_hash(tag, msg)
104
104
  tag_hash = Digest::SHA256.digest(tag)
105
- Digest::SHA256.digest(tag_hash + tag_hash + msg)
105
+ Digest::SHA256.digest(tag_hash + tag_hash + msg.b)
106
106
  end
107
107
 
108
108
  # encode Base58 check address.
@@ -1,3 +1,3 @@
1
1
  module Bitcoin
2
- VERSION = "1.12.0"
2
+ VERSION = "1.13.0"
3
3
  end
@@ -33,7 +33,7 @@ module Bitcoin
33
33
  payload = buf.read
34
34
  name, payload = Bitcoin.unpack_var_string(payload)
35
35
  name = name.force_encoding('utf-8')
36
- purpose, index, receive_depth, change_depth, lookahead = payload.unpack('I*')
36
+ purpose, index, receive_depth, change_depth, lookahead = payload.unpack('V*')
37
37
  a = Account.new(account_key, purpose, index, name)
38
38
  a.receive_depth = receive_depth
39
39
  a.change_depth = change_depth
@@ -44,7 +44,7 @@ module Bitcoin
44
44
  def to_payload
45
45
  payload = account_key.to_payload
46
46
  payload << Bitcoin.pack_var_string(name.unpack1('H*').htb)
47
- payload << [purpose, index, receive_depth, change_depth, lookahead].pack('I*')
47
+ payload << [purpose, index, receive_depth, change_depth, lookahead].pack('V*')
48
48
  payload
49
49
  end
50
50
 
@@ -32,7 +32,7 @@ module Bitcoin
32
32
 
33
33
  def save_account(account)
34
34
  level_db.batch do
35
- id = [account.purpose, account.index].pack('I*').bth
35
+ id = [account.purpose, account.index].pack('V*').bth
36
36
  key = KEY_PREFIX[:account] + id
37
37
  level_db.put(key, account.to_payload)
38
38
  end
@@ -40,14 +40,14 @@ module Bitcoin
40
40
 
41
41
  def save_key(account, purpose, index, key)
42
42
  pubkey = key.pub
43
- id = [account.purpose, account.index, purpose, index].pack('I*').bth
43
+ id = [account.purpose, account.index, purpose, index].pack('V*').bth
44
44
  k = KEY_PREFIX[:key] + id
45
45
  level_db.put(k, pubkey)
46
46
  key
47
47
  end
48
48
 
49
49
  def get_keys(account)
50
- id = [account.purpose, account.index].pack('I*').bth
50
+ id = [account.purpose, account.index].pack('V*').bth
51
51
  from = KEY_PREFIX[:key] + id + '00000000'
52
52
  to = KEY_PREFIX[:key] + id + 'ffffffff'
53
53
  level_db.each(from: from, to: to).map { |k, v| v}
@@ -81,7 +81,7 @@ module Bitcoin
81
81
  encrypted_data = ''
82
82
  encrypted_data << enc.update(seed)
83
83
  encrypted_data << enc.final
84
- @seed = encrypted_data
84
+ @seed = encrypted_data.bth
85
85
  @encrypted = true
86
86
  end
87
87
 
@@ -92,7 +92,7 @@ module Bitcoin
92
92
  dec.decrypt
93
93
  dec.key, dec.iv = key_iv(dec, passphrase)
94
94
  decrypted_data = ''
95
- decrypted_data << dec.update(seed)
95
+ decrypted_data << dec.update(seed.htb)
96
96
  decrypted_data << dec.final
97
97
  @seed = decrypted_data
98
98
  @encrypted = false
@@ -18,7 +18,7 @@ module Bitcoin
18
18
  def self.parse_from_payload(payload)
19
19
  return nil if payload.nil?
20
20
 
21
- tx_hash, index, block_height, value, payload = payload.unpack('H64VVQa*')
21
+ tx_hash, index, block_height, value, payload = payload.unpack('H64VVQ<a*')
22
22
 
23
23
  buf = StringIO.new(payload)
24
24
  script_size = Bitcoin.unpack_var_int_from_io(buf)
@@ -27,7 +27,7 @@ module Bitcoin
27
27
  end
28
28
 
29
29
  def to_payload
30
- payload = [tx_hash, index, block_height.nil? ? 0 : block_height, value].pack('H64VVQ')
30
+ payload = [tx_hash, index, block_height.nil? ? 0 : block_height, value].pack('H64VVQ<')
31
31
  s = script_pubkey.to_payload
32
32
  payload << Bitcoin.pack_var_int(s.length) << s
33
33
  payload
data/lib/bitcoin.rb CHANGED
@@ -2,13 +2,12 @@
2
2
  # https://github.com/lian/bitcoin-ruby/blob/master/COPYING
3
3
 
4
4
  require 'bitcoin/version'
5
- require 'eventmachine'
6
5
  require 'schnorr'
7
6
  require 'securerandom'
7
+ require 'stringio'
8
8
  require 'json'
9
9
  require 'bech32'
10
10
  require 'base64'
11
- require 'observer'
12
11
  require 'tmpdir'
13
12
  require 'merkle'
14
13
 
@@ -36,13 +35,10 @@ module Bitcoin
36
35
  autoload :ExtKey, 'bitcoin/ext_key'
37
36
  autoload :ExtPubkey, 'bitcoin/ext_key'
38
37
  autoload :Opcodes, 'bitcoin/opcodes'
39
- autoload :Node, 'bitcoin/node'
40
38
  autoload :Base58, 'bitcoin/base58'
41
39
  autoload :Secp256k1, 'bitcoin/secp256k1'
42
40
  autoload :Mnemonic, 'bitcoin/mnemonic'
43
41
  autoload :ValidationState, 'bitcoin/validation'
44
- autoload :Network, 'bitcoin/network'
45
- autoload :Store, 'bitcoin/store'
46
42
  autoload :RPC, 'bitcoin/rpc'
47
43
  autoload :Wallet, 'bitcoin/wallet'
48
44
  autoload :BloomFilter, 'bitcoin/bloom_filter'
@@ -64,7 +60,6 @@ module Bitcoin
64
60
  autoload :SilentPayment, 'bitcoin/silent_payment'
65
61
  autoload :BIP324, 'bitcoin/bip324'
66
62
  autoload :BIP321URI, 'bitcoin/bip321_uri'
67
- autoload :BIP353, 'bitcoin/bip353'
68
63
 
69
64
  require_relative 'bitcoin/constants'
70
65
  require_relative 'bitcoin/ext/ecdsa'